feature/add-actions (#9)

Co-authored-by: kjuulh <contact@kjuulh.io>
Reviewed-on: kjuulh/kraken#9
This commit is contained in:
Kasper Juul Hermansen 2022-09-14 23:40:58 +02:00
parent ce55f6523c
commit 0cb923a3a5
12 changed files with 275 additions and 42 deletions

View File

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

View File

@ -3,7 +3,10 @@ package main
import "github.com/bitfield/script"
func main() {
script.
_, err := script.
Echo("# Readme").
WriteFile("README.md")
if err != nil {
panic(err)
}
}

View File

@ -11,7 +11,7 @@ import (
func CreateKrakenProcessCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "process",
Run: func(cmd *cobra.Command, args []string) {
Run: func(cmd *cobra.Command, _ []string) {
client := http.Client{}
var buf bytes.Buffer
@ -22,8 +22,8 @@ func CreateKrakenProcessCmd() *cobra.Command {
Path string `json:"path"`
}{
Repository: "git@git.front.kjuulh.io:kjuulh/kraken.git",
Branch: "v0.1",
Path: "_examples/actions/write_a_readme/kraken.yml",
Branch: "feature/add-actions",
Path: "_examples/actions/write_a_readme/",
})
if err != nil {
panic(err)

View File

@ -15,6 +15,8 @@ func main() {
}
_ = logger.Sync()
zap.ReplaceGlobals(logger)
Execute(logger)
}

View File

@ -2,15 +2,38 @@ package actions
import (
"context"
"errors"
"git.front.kjuulh.io/kjuulh/kraken/internal/actions/builders"
"git.front.kjuulh.io/kjuulh/kraken/internal/schema"
"git.front.kjuulh.io/kjuulh/kraken/internal/services/storage"
"go.uber.org/zap"
)
type Action struct {
Schema *schema.KrakenSchema
Schema *schema.KrakenSchema
SchemaPath string
}
func (a *Action) Execute(ctx context.Context, area *storage.Area) error {
for _, action := range a.Schema.Actions {
switch action.Type {
case "go":
exe, err := builders.NewGo(zap.L()).Build(ctx, a.SchemaPath, action.Entry)
if err != nil {
return err
}
err = exe(ctx, area.Path)
if err != nil {
return err
}
zap.L().Debug("Execution done")
default:
return errors.New("could not determine action type")
}
}
return nil
}

View File

@ -47,18 +47,13 @@ func (ac *ActionCreator) Prepare(ctx context.Context, ops *ActionCreatorOps) (*A
return nil, err
}
cloneCtx, _ := context.WithTimeout(ctx, time.Second*5)
repo, err := ac.git.Clone(cloneCtx, area, ops.RepositoryUrl)
cloneCtx, _ := context.WithTimeout(ctx, time.Second*10)
_, err = ac.git.CloneBranch(cloneCtx, area, ops.RepositoryUrl, ops.Branch)
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)
@ -74,8 +69,10 @@ func (ac *ActionCreator) Prepare(ctx context.Context, ops *ActionCreatorOps) (*A
return nil, err
}
ac.logger.Debug("Action creator done")
return &Action{
Schema: krakenSchema,
Schema: krakenSchema,
SchemaPath: executorUrl,
}, nil
}

View File

@ -0,0 +1,46 @@
package builders
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"go.uber.org/zap"
)
type Go struct {
logger *zap.Logger
}
func NewGo(logger *zap.Logger) *Go {
return &Go{logger: logger}
}
type GoExecutable func(ctx context.Context, victimPath string) error
func (g *Go) Build(ctx context.Context, modulePath, entryPath string) (GoExecutable, error) {
g.logger.Debug("Building go binary", zap.String("actiondir", modulePath), zap.String("entry", entryPath))
if _, err := os.Stat(fmt.Sprintf("%s/%s", modulePath, entryPath)); os.IsNotExist(err) {
return nil, errors.New("could not find entry")
}
err := exec.CommandContext(
ctx,
"/bin/bash",
"-c",
fmt.Sprintf("(cd %s; go build -o main %s)", modulePath, entryPath),
).Run()
if err != nil {
return nil, err
}
g.logger.Debug("Go binary built!")
return func(ctx context.Context, victimPath string) error {
g.logger.Debug("Executing script", zap.String("victim", victimPath))
return exec.CommandContext(ctx, "/bin/bash", "-c", fmt.Sprintf("(cd %s; %s/main)", victimPath, modulePath)).Run()
}, nil
}

View File

@ -34,6 +34,9 @@ func CommandRoute(logger *zap.Logger, app *gin.Engine, deps *serverdeps.ServerDe
ctx := context.WithValue(context.Background(), jobs.JobId{}, jobId)
processRepos := commands.NewProcessRepos(logger, deps)
err = processRepos.Process(ctx, repository, branch, path)
if err != nil {
logger.Error("could not process repo", zap.Error(err))
}
}(request.Repository, request.Branch, request.Path, jobId)
c.Status(http.StatusAccepted)

View File

@ -48,7 +48,7 @@ func (pr *ProcessRepos) Process(ctx context.Context, repository string, branch s
return err
}
repositoryUrls := make([]string, 0)
repositoryUrls := action.Schema.Select.Repositories
wg := sync.WaitGroup{}
wg.Add(len(repositoryUrls))
@ -60,7 +60,6 @@ func (pr *ProcessRepos) Process(ctx context.Context, repository string, branch s
}()
err := pr.processRepo(ctx, repoUrl, action)
if err != nil {
pr.logger.Error("could not process repo", zap.Error(err))
errChan <- err
}
}(ctx, repoUrl)
@ -113,7 +112,6 @@ func (pr *ProcessRepos) prepareAction(
pr.logger.Debug("Creating area")
area, err := pr.storage.CreateArea(ctx)
if err != nil {
pr.logger.Error("failed to allocate area", zap.Error(err))
return nil, nil, err
}
@ -133,13 +131,11 @@ func (pr *ProcessRepos) clone(ctx context.Context, area *storage.Area, repoUrl s
cloneCtx, _ := context.WithTimeout(ctx, time.Second*5)
repo, err := pr.git.Clone(cloneCtx, area, repoUrl)
if err != nil {
pr.logger.Error("could not clone repo", zap.Error(err))
return nil, err
}
err = pr.git.CreateBranch(ctx, repo)
if err != nil {
pr.logger.Error("could not create branch", zap.Error(err))
return nil, err
}
@ -157,9 +153,12 @@ func (pr *ProcessRepos) commit(ctx context.Context, area *storage.Area, repo *pr
return fmt.Errorf("could not get diff: %w", err)
}
err = pr.git.Push(ctx, repo)
if err != nil {
return fmt.Errorf("could not push to repo: %w", err)
dryrun := true
if !dryrun {
err = pr.git.Push(ctx, repo)
if err != nil {
return fmt.Errorf("could not push to repo: %w", err)
}
}
return nil
}

View File

@ -12,7 +12,10 @@ type KrakenSchema struct {
Organisation string `yaml:"organisation"`
} `yaml:"providers"`
} `yaml:"select"`
Actions []string `yaml:"actions"`
Actions []struct {
Type string `yaml:"type"`
Entry string `yaml:"entry"`
} `yaml:"actions"`
}
func Unmarshal(raw string) (*KrakenSchema, error) {

View File

@ -53,7 +53,7 @@ func NewGit(logger *zap.Logger, gitConfig *GitConfig, openPGP *signer.OpenPGP) *
return &Git{logger: logger, gitConfig: gitConfig, openPGP: openPGP}
}
func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl string) (*GitRepo, error) {
func (g *Git) CloneBranch(ctx context.Context, storageArea *storage.Area, repoUrl string, branch string) (*GitRepo, error) {
g.logger.Debug(
"cloning repository",
zap.String("repoUrl", repoUrl),
@ -69,8 +69,8 @@ func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl stri
URL: repoUrl,
Auth: auth,
RemoteName: "origin",
ReferenceName: "refs/heads/main",
SingleBranch: false,
ReferenceName: plumbing.NewBranchReferenceName(branch),
SingleBranch: true,
NoCheckout: false,
Depth: 1,
RecurseSubmodules: 1,
@ -90,19 +90,41 @@ 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()
func (g *Git) Clone(ctx context.Context, storageArea *storage.Area, repoUrl string) (*GitRepo, error) {
g.logger.Debug(
"cloning repository",
zap.String("repoUrl", repoUrl),
zap.String("path", storageArea.Path),
)
auth, err := g.GetAuth()
if err != nil {
return err
return nil, err
}
return wt.Checkout(&git.CheckoutOptions{
Hash: [20]byte{},
Branch: plumbing.NewBranchReferenceName(branch),
Create: false,
Force: false,
Keep: false,
})
cloneOptions := git.CloneOptions{
URL: repoUrl,
Auth: auth,
RemoteName: "origin",
ReferenceName: "refs/heads/main",
SingleBranch: true,
NoCheckout: false,
Depth: 1,
RecurseSubmodules: 1,
Progress: g.getProgressWriter(),
Tags: 0,
InsecureSkipTLS: false,
CABundle: []byte{},
}
repo, err := git.PlainCloneContext(ctx, storageArea.Path, false, &cloneOptions)
if err != nil {
return nil, err
}
g.logger.Debug("done cloning repo")
return &GitRepo{repo: repo}, nil
}
func (g *Git) getProgressWriter() *zapio.Writer {

View File

@ -11,15 +11,15 @@
### Not in scope
- [ ] Pooled runners
- [ ] CLI with options
- [ ] Server app
- [ ] Git hosting providers
- Pooled runners
- CLI with options
- Server app
- Git hosting providers
## Version 0.1
- [ ] Setup a way to choose actions and predicates
- [ ] Allow instantiation of actions, kraken template repo etc.
- [x] Setup a way to choose actions and predicates
- [x] Allow instantiation of actions, kraken template repo etc.
- [ ] Create pr for gitea provider
- [ ] Think about some sort of isolation
- [ ] Create CLI to trigger action