with action creator

This commit is contained in:
Kasper Juul Hermansen 2022-09-13 22:54:49 +02:00
parent 564147eb6a
commit ce55f6523c
Signed by: kjuulh
GPG Key ID: 57B6E1465221F912
9 changed files with 208 additions and 77 deletions

View File

@ -3,8 +3,8 @@ name: write-a-readme
select:
repositories:
- git@git.front.kjuulh.io:kjuulh/kraken-test.git
provider:
providers:
- gitea: git.front.kjuulh.io/kraken
organisation: "kraken"
action:
command: go run main.go
actions:
- "go run main.go"

View File

@ -17,9 +17,14 @@ func CreateKrakenProcessCmd() *cobra.Command {
var buf bytes.Buffer
err := json.NewEncoder(&buf).
Encode(struct {
RepositoryUrls []string `json:"repositoryUrls"`
Repository string `json:"repository"`
Branch string `json:"branch"`
Path string `json:"path"`
}{
RepositoryUrls: []string{"git@git.front.kjuulh.io:kjuulh/kraken.git"}})
Repository: "git@git.front.kjuulh.io:kjuulh/kraken.git",
Branch: "v0.1",
Path: "_examples/actions/write_a_readme/kraken.yml",
})
if err != nil {
panic(err)
}

View File

@ -0,0 +1,16 @@
package actions
import (
"context"
"git.front.kjuulh.io/kjuulh/kraken/internal/schema"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
)
type Action struct {
Schema *schema.KrakenSchema
}
func (a *Action) Execute(ctx context.Context, area *storage.Area) error {
return nil
}

View File

@ -0,0 +1,88 @@
package actions
import (
"context"
"fmt"
"os"
"path"
"time"
"git.front.kjuulh.io/kjuulh/kraken/internal/schema"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/providers"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
"go.uber.org/zap"
)
type (
ActionCreatorOps struct {
RepositoryUrl string
Branch string
Path string
}
ActionCreator struct {
logger *zap.Logger
storage *storage.Service
git *providers.Git
}
ActionCreatorDeps interface {
GetStorageService() *storage.Service
GetGitProvider() *providers.Git
}
)
func NewActionCreator(logger *zap.Logger, deps ActionCreatorDeps) *ActionCreator {
return &ActionCreator{
logger: logger,
storage: deps.GetStorageService(),
git: deps.GetGitProvider(),
}
}
func (ac *ActionCreator) Prepare(ctx context.Context, ops *ActionCreatorOps) (*Action, error) {
area, err := ac.storage.CreateArea(ctx)
if err != nil {
ac.logger.Error("failed to allocate area", zap.Error(err))
return nil, err
}
cloneCtx, _ := context.WithTimeout(ctx, time.Second*5)
repo, err := ac.git.Clone(cloneCtx, area, ops.RepositoryUrl)
if err != nil {
ac.logger.Error("could not clone repo", zap.Error(err))
return nil, err
}
err = ac.git.Checkout(ctx, repo, ops.Branch)
if err != nil {
return nil, err
}
executorUrl := path.Join(area.Path, ops.Path)
if _, err = os.Stat(executorUrl); os.IsNotExist(err) {
return nil, fmt.Errorf("path is invalid: %s", ops.Path)
}
contents, err := os.ReadFile(path.Join(executorUrl, "kraken.yml"))
if err != nil {
return nil, err
}
krakenSchema, err := schema.Unmarshal(string(contents))
if err != nil {
return nil, err
}
return &Action{
Schema: krakenSchema,
}, nil
}
func (ac *ActionCreator) Cleanup(ctx context.Context, area *storage.Area) {
ac.logger.Debug("Removing area", zap.String("path", area.Path))
err := ac.storage.RemoveArea(ctx, area)
if err != nil {
panic(err)
}
}

View File

@ -16,7 +16,9 @@ func CommandRoute(logger *zap.Logger, app *gin.Engine, deps *serverdeps.ServerDe
commandRoute := app.Group("commands")
commandRoute.POST("processRepos", func(c *gin.Context) {
type processReposRequest struct {
RepositoryUrls []string `json:"repositoryUrls"`
Repository string `json:"repository"`
Branch string `json:"branch"`
Path string `json:"path"`
}
var request processReposRequest
err := c.BindJSON(&request)
@ -28,11 +30,11 @@ func CommandRoute(logger *zap.Logger, app *gin.Engine, deps *serverdeps.ServerDe
jobId := uuid.New().String()
go func(repositoryUrls []string, jobId string) {
go func(repository string, branch string, path string, jobId string) {
ctx := context.WithValue(context.Background(), jobs.JobId{}, jobId)
processRepos := commands.NewProcessRepos(logger, deps)
err = processRepos.Process(ctx, repositoryUrls)
}(request.RepositoryUrls, jobId)
err = processRepos.Process(ctx, repository, branch, path)
}(request.Repository, request.Branch, request.Path, jobId)
c.Status(http.StatusAccepted)
})

View File

@ -3,14 +3,10 @@ package commands
import (
"context"
"fmt"
"io/fs"
"os"
"path"
"path/filepath"
"sync"
"time"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/actions"
"git.front.kjuulh.io/kjuulh/kraken/internal/actions"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/providers"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
"go.uber.org/zap"
@ -18,31 +14,42 @@ import (
type (
ProcessRepos struct {
logger *zap.Logger
storage *storage.Service
git *providers.Git
action *actions.Action
logger *zap.Logger
storage *storage.Service
git *providers.Git
actionCreator *actions.ActionCreator
}
ProcessReposDeps interface {
GetStorageService() *storage.Service
GetGitProvider() *providers.Git
GetAction() *actions.Action
GetActionCreator() *actions.ActionCreator
}
)
func NewProcessRepos(logger *zap.Logger, deps ProcessReposDeps) *ProcessRepos {
return &ProcessRepos{
logger: logger,
storage: deps.GetStorageService(),
git: deps.GetGitProvider(),
action: deps.GetAction(),
logger: logger,
storage: deps.GetStorageService(),
git: deps.GetGitProvider(),
actionCreator: deps.GetActionCreator(),
}
}
func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) error {
func (pr *ProcessRepos) Process(ctx context.Context, repository string, branch string, actionPath string) error {
errChan := make(chan error, 1)
action, err := pr.actionCreator.Prepare(ctx, &actions.ActionCreatorOps{
RepositoryUrl: repository,
Branch: branch,
Path: actionPath,
})
if err != nil {
return err
}
repositoryUrls := make([]string, 0)
wg := sync.WaitGroup{}
wg.Add(len(repositoryUrls))
@ -51,7 +58,11 @@ func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) er
defer func() {
wg.Done()
}()
pr.processRepo(ctx, repoUrl, errChan)
err := pr.processRepo(ctx, repoUrl, action)
if err != nil {
pr.logger.Error("could not process repo", zap.Error(err))
errChan <- err
}
}(ctx, repoUrl)
}
@ -66,74 +77,39 @@ func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) er
return nil
}
func (pr *ProcessRepos) processRepo(ctx context.Context, repoUrl string, errChan chan error) {
func (pr *ProcessRepos) processRepo(ctx context.Context, repoUrl string, action *actions.Action) error {
cleanup, area, err := pr.prepareAction(ctx)
defer func() {
if cleanup != nil {
cleanup(ctx, errChan)
cleanup(ctx)
}
}()
if err != nil {
errChan <- err
return
return err
}
repo, err := pr.clone(ctx, area, repoUrl)
if err != nil {
errChan <- err
return
return err
}
err = pr.action.Run(
ctx,
area,
func(_ context.Context, area *storage.Area) (bool, error) {
pr.logger.Debug("checking predicate", zap.String("area", area.Path))
// TODO: Run predicate instead
contains := false
filepath.WalkDir(area.Path, func(_ string, d fs.DirEntry, _ error) error {
if d.Name() == "roadmap.md" {
contains = true
}
return nil
})
return contains, nil
},
func(_ context.Context, area *storage.Area) error {
pr.logger.Debug("running action", zap.String("area", area.Path))
// TODO: Run action instead
readme := path.Join(area.Path, "README.md")
file, err := os.Create(readme)
if err != nil {
return fmt.Errorf("could not create readme: %w", err)
}
_, err = file.WriteString("# Readme")
if err != nil {
return fmt.Errorf("could not write readme: %w", err)
}
err = pr.commit(ctx, area, repo)
if err != nil {
return err
}
return nil
}, false)
err = action.Execute(ctx, area)
if err != nil {
pr.logger.Error("could not run action", zap.Error(err))
errChan <- err
return
return err
}
err = pr.commit(ctx, area, repo)
if err != nil {
return err
}
pr.logger.Debug("processing done", zap.String("path", area.Path), zap.String("repoUrl", repoUrl))
return nil
}
func (pr *ProcessRepos) prepareAction(
ctx context.Context,
) (func(ctx context.Context, errChan chan error), *storage.Area, error) {
) (func(ctx context.Context), *storage.Area, error) {
pr.logger.Debug("Creating area")
area, err := pr.storage.CreateArea(ctx)
if err != nil {
@ -141,12 +117,11 @@ func (pr *ProcessRepos) prepareAction(
return nil, nil, err
}
cleanupfunc := func(ctx context.Context, errChan chan error) {
cleanupfunc := func(ctx context.Context) {
pr.logger.Debug("Removing area", zap.String("path", area.Path))
err = pr.storage.RemoveArea(ctx, area)
if err != nil {
errChan <- err
return
panic(err)
}
}

25
internal/schema/kraken.go Normal file
View File

@ -0,0 +1,25 @@
package schema
import "gopkg.in/yaml.v3"
type KrakenSchema struct {
ApiVersion string `yaml:"apiVersion"`
Name string `yaml:"name"`
Select struct {
Repositories []string `yaml:"repositories"`
Providers []struct {
Gitea string `yaml:"gitea"`
Organisation string `yaml:"organisation"`
} `yaml:"providers"`
} `yaml:"select"`
Actions []string `yaml:"actions"`
}
func Unmarshal(raw string) (*KrakenSchema, error) {
k := &KrakenSchema{}
err := yaml.Unmarshal([]byte(raw), k)
if err != nil {
return nil, err
}
return k, nil
}

View File

@ -1,6 +1,7 @@
package serverdeps
import (
actionc "git.front.kjuulh.io/kjuulh/kraken/internal/actions"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/actions"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/providers"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/signer"
@ -59,6 +60,10 @@ func (deps *ServerDeps) GetAction() *actions.Action {
return actions.NewAction(deps.logger.With(zap.Namespace("action")))
}
func (deps *ServerDeps) GetActionCreator() *actionc.ActionCreator {
return actionc.NewActionCreator(deps.logger.With(zap.Namespace("action")), deps)
}
func (deps *ServerDeps) GetOpenPGP() *signer.OpenPGP {
return deps.openPGP
}

View File

@ -70,7 +70,7 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
Auth: auth,
RemoteName: "origin",
ReferenceName: "refs/heads/main",
SingleBranch: true,
SingleBranch: false,
NoCheckout: false,
Depth: 1,
RecurseSubmodules: 1,
@ -90,6 +90,21 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
return &GitRepo{repo: repo}, nil
}
func (g *Git) Checkout(ctx context.Context, gitRepo *GitRepo, branch string) error {
wt, err := gitRepo.repo.Worktree()
if err != nil {
return err
}
return wt.Checkout(&git.CheckoutOptions{
Hash: [20]byte{},
Branch: plumbing.NewBranchReferenceName(branch),
Create: false,
Force: false,
Keep: false,
})
}
func (g *Git) getProgressWriter() *zapio.Writer {
return &zapio.Writer{
Log: g.logger.With(zap.String("process", "go-git")),