v0.1 #8

Merged
kjuulh merged 15 commits from v0.1 into main 2022-09-18 16:49:35 +02:00
9 changed files with 208 additions and 77 deletions
Showing only changes of commit ce55f6523c - Show all commits

View File

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

View File

@ -17,9 +17,14 @@ func CreateKrakenProcessCmd() *cobra.Command {
var buf bytes.Buffer var buf bytes.Buffer
err := json.NewEncoder(&buf). err := json.NewEncoder(&buf).
Encode(struct { 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 { if err != nil {
panic(err) 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 := app.Group("commands")
commandRoute.POST("processRepos", func(c *gin.Context) { commandRoute.POST("processRepos", func(c *gin.Context) {
type processReposRequest struct { type processReposRequest struct {
RepositoryUrls []string `json:"repositoryUrls"` Repository string `json:"repository"`
Branch string `json:"branch"`
Path string `json:"path"`
} }
var request processReposRequest var request processReposRequest
err := c.BindJSON(&request) err := c.BindJSON(&request)
@ -28,11 +30,11 @@ func CommandRoute(logger *zap.Logger, app *gin.Engine, deps *serverdeps.ServerDe
jobId := uuid.New().String() 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) ctx := context.WithValue(context.Background(), jobs.JobId{}, jobId)
processRepos := commands.NewProcessRepos(logger, deps) processRepos := commands.NewProcessRepos(logger, deps)
err = processRepos.Process(ctx, repositoryUrls) err = processRepos.Process(ctx, repository, branch, path)
}(request.RepositoryUrls, jobId) }(request.Repository, request.Branch, request.Path, jobId)
c.Status(http.StatusAccepted) c.Status(http.StatusAccepted)
}) })

View File

@ -3,14 +3,10 @@ package commands
import ( import (
"context" "context"
"fmt" "fmt"
"io/fs"
"os"
"path"
"path/filepath"
"sync" "sync"
"time" "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/providers"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage" "git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
"go.uber.org/zap" "go.uber.org/zap"
@ -21,13 +17,13 @@ type (
logger *zap.Logger logger *zap.Logger
storage *storage.Service storage *storage.Service
git *providers.Git git *providers.Git
action *actions.Action actionCreator *actions.ActionCreator
} }
ProcessReposDeps interface { ProcessReposDeps interface {
GetStorageService() *storage.Service GetStorageService() *storage.Service
GetGitProvider() *providers.Git GetGitProvider() *providers.Git
GetAction() *actions.Action GetActionCreator() *actions.ActionCreator
} }
) )
@ -36,13 +32,24 @@ func NewProcessRepos(logger *zap.Logger, deps ProcessReposDeps) *ProcessRepos {
logger: logger, logger: logger,
storage: deps.GetStorageService(), storage: deps.GetStorageService(),
git: deps.GetGitProvider(), 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) 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 := sync.WaitGroup{}
wg.Add(len(repositoryUrls)) wg.Add(len(repositoryUrls))
@ -51,7 +58,11 @@ func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) er
defer func() { defer func() {
wg.Done() 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) }(ctx, repoUrl)
} }
@ -66,53 +77,25 @@ func (pr *ProcessRepos) Process(ctx context.Context, repositoryUrls []string) er
return nil 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) cleanup, area, err := pr.prepareAction(ctx)
defer func() { defer func() {
if cleanup != nil { if cleanup != nil {
cleanup(ctx, errChan) cleanup(ctx)
} }
}() }()
if err != nil { if err != nil {
errChan <- err return err
return
} }
repo, err := pr.clone(ctx, area, repoUrl) repo, err := pr.clone(ctx, area, repoUrl)
if err != nil { if err != nil {
errChan <- err return err
return
} }
err = pr.action.Run( err = action.Execute(ctx, area)
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 { if err != nil {
return fmt.Errorf("could not create readme: %w", err) return err
}
_, err = file.WriteString("# Readme")
if err != nil {
return fmt.Errorf("could not write readme: %w", err)
} }
err = pr.commit(ctx, area, repo) err = pr.commit(ctx, area, repo)
@ -120,20 +103,13 @@ func (pr *ProcessRepos) processRepo(ctx context.Context, repoUrl string, errChan
return err 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)) pr.logger.Debug("processing done", zap.String("path", area.Path), zap.String("repoUrl", repoUrl))
return nil
} }
func (pr *ProcessRepos) prepareAction( func (pr *ProcessRepos) prepareAction(
ctx context.Context, 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") pr.logger.Debug("Creating area")
area, err := pr.storage.CreateArea(ctx) area, err := pr.storage.CreateArea(ctx)
if err != nil { if err != nil {
@ -141,12 +117,11 @@ func (pr *ProcessRepos) prepareAction(
return nil, nil, err 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)) pr.logger.Debug("Removing area", zap.String("path", area.Path))
err = pr.storage.RemoveArea(ctx, area) err = pr.storage.RemoveArea(ctx, area)
if err != nil { if err != nil {
errChan <- err panic(err)
return
} }
} }

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 package serverdeps
import ( 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/actions"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/providers" "git.front.kjuulh.io/kjuulh/kraken/internal/services/providers"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/signer" "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"))) 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 { func (deps *ServerDeps) GetOpenPGP() *signer.OpenPGP {
return deps.openPGP return deps.openPGP
} }

View File

@ -70,7 +70,7 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
Auth: auth, Auth: auth,
RemoteName: "origin", RemoteName: "origin",
ReferenceName: "refs/heads/main", ReferenceName: "refs/heads/main",
SingleBranch: true, SingleBranch: false,
NoCheckout: false, NoCheckout: false,
Depth: 1, Depth: 1,
RecurseSubmodules: 1, RecurseSubmodules: 1,
@ -90,6 +90,21 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
return &GitRepo{repo: repo}, nil 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 { func (g *Git) getProgressWriter() *zapio.Writer {
return &zapio.Writer{ return &zapio.Writer{
Log: g.logger.With(zap.String("process", "go-git")), Log: g.logger.With(zap.String("process", "go-git")),