with action creator
This commit is contained in:
parent
564147eb6a
commit
ce55f6523c
@ -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"
|
||||
|
@ -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)
|
||||
}
|
||||
|
16
internal/actions/action.go
Normal file
16
internal/actions/action.go
Normal 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
|
||||
}
|
88
internal/actions/action_creator.go
Normal file
88
internal/actions/action_creator.go
Normal 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)
|
||||
}
|
||||
}
|
@ -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)
|
||||
})
|
||||
|
@ -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"
|
||||
@ -21,13 +17,13 @@ type (
|
||||
logger *zap.Logger
|
||||
storage *storage.Service
|
||||
git *providers.Git
|
||||
action *actions.Action
|
||||
actionCreator *actions.ActionCreator
|
||||
}
|
||||
|
||||
ProcessReposDeps interface {
|
||||
GetStorageService() *storage.Service
|
||||
GetGitProvider() *providers.Git
|
||||
GetAction() *actions.Action
|
||||
GetActionCreator() *actions.ActionCreator
|
||||
}
|
||||
)
|
||||
|
||||
@ -36,13 +32,24 @@ func NewProcessRepos(logger *zap.Logger, deps ProcessReposDeps) *ProcessRepos {
|
||||
logger: logger,
|
||||
storage: deps.GetStorageService(),
|
||||
git: deps.GetGitProvider(),
|
||||
action: deps.GetAction(),
|
||||
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,53 +77,25 @@ 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)
|
||||
err = action.Execute(ctx, area)
|
||||
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)
|
||||
return err
|
||||
}
|
||||
|
||||
err = pr.commit(ctx, area, repo)
|
||||
@ -120,20 +103,13 @@ func (pr *ProcessRepos) processRepo(ctx context.Context, repoUrl string, errChan
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}, false)
|
||||
if err != nil {
|
||||
pr.logger.Error("could not run action", zap.Error(err))
|
||||
errChan <- err
|
||||
return
|
||||
}
|
||||
|
||||
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
25
internal/schema/kraken.go
Normal 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
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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")),
|
||||
|
Loading…
Reference in New Issue
Block a user