From 73be67a0fda57ebb915a5e56a9583018c79c3923 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Wed, 21 Sep 2022 21:29:44 +0200 Subject: [PATCH 1/2] with moved commands --- cmd/kraken/commands/root.go | 14 - cmd/kraken/kraken.go | 18 - cmd/octopush/commands/process.go | 51 +++ cmd/octopush/commands/root.go | 18 + .../commands/server}/process.go | 2 +- cmd/octopush/commands/server/server.go | 16 + cmd/octopush/octopush.go | 28 ++ internal/actions/action_creator.go | 4 +- internal/cli/cli.go | 26 ++ internal/commands/process_repos.go | 8 +- internal/serverdeps/server_deps.go | 2 +- internal/services/providers/git.go | 338 ----------------- internal/services/providers/gogit.go | 339 ++++++++++++++++++ 13 files changed, 486 insertions(+), 378 deletions(-) delete mode 100644 cmd/kraken/commands/root.go delete mode 100644 cmd/kraken/kraken.go create mode 100644 cmd/octopush/commands/process.go create mode 100644 cmd/octopush/commands/root.go rename cmd/{kraken/commands => octopush/commands/server}/process.go (98%) create mode 100644 cmd/octopush/commands/server/server.go create mode 100644 cmd/octopush/octopush.go create mode 100644 internal/cli/cli.go create mode 100644 internal/services/providers/gogit.go diff --git a/cmd/kraken/commands/root.go b/cmd/kraken/commands/root.go deleted file mode 100644 index 69aee00..0000000 --- a/cmd/kraken/commands/root.go +++ /dev/null @@ -1,14 +0,0 @@ -package commands - -import "github.com/spf13/cobra" - -func CreateOctopushCmd() *cobra.Command { - cmd := &cobra.Command{ - Use: "octopush", - // Run: func(cmd *cobra.Command, args []string) { }, - } - - cmd.AddCommand(CreateOctopushProcessCmd()) - - return cmd -} diff --git a/cmd/kraken/kraken.go b/cmd/kraken/kraken.go deleted file mode 100644 index 494b764..0000000 --- a/cmd/kraken/kraken.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "os" - - "git.front.kjuulh.io/kjuulh/octopush/cmd/octopush/commands" -) - -func main() { - Execute() -} - -func Execute() { - err := commands.CreateOctopushCmd().Execute() - if err != nil { - os.Exit(1) - } -} diff --git a/cmd/octopush/commands/process.go b/cmd/octopush/commands/process.go new file mode 100644 index 0000000..35ad362 --- /dev/null +++ b/cmd/octopush/commands/process.go @@ -0,0 +1,51 @@ +package commands + +import ( + "git.front.kjuulh.io/kjuulh/octopush/internal/cli" + "git.front.kjuulh.io/kjuulh/octopush/internal/commands" + "github.com/spf13/cobra" + "go.uber.org/zap" +) + +func CreateOctopushProcessCmd(logger *zap.Logger) *cobra.Command { + + var ( + actionsRepo string + branch string + path string + ) + cmd := &cobra.Command{ + Use: "process", + RunE: func(cmd *cobra.Command, args []string) error { + if err := cmd.ParseFlags(args); err != nil { + return err + } + + ctx := cmd.Context() + + deps, err := cli.Start(ctx, logger) + if err != nil { + return err + } + + err = commands. + NewProcessRepos(logger, deps). + Process(ctx, actionsRepo, branch, path) + if err != nil { + return err + } + + return nil + }, + } + + pf := cmd.PersistentFlags() + + pf.StringVar(&actionsRepo, "actions-repo", "", "actions repo is the location of your actions, not where to apply the actions themselves, that should be self contained") + cmd.MarkPersistentFlagRequired("actions-repo") + pf.StringVar(&branch, "branch", "main", "which branch to look for actions in, will default to main") + pf.StringVar(&path, "path", "", "the location of the path inside the repository") + cmd.MarkPersistentFlagRequired("path") + + return cmd +} diff --git a/cmd/octopush/commands/root.go b/cmd/octopush/commands/root.go new file mode 100644 index 0000000..3a6654f --- /dev/null +++ b/cmd/octopush/commands/root.go @@ -0,0 +1,18 @@ +package commands + +import ( + "git.front.kjuulh.io/kjuulh/octopush/cmd/octopush/commands/server" + "github.com/spf13/cobra" + "go.uber.org/zap" +) + +func CreateOctopushCmd(logger *zap.Logger) *cobra.Command { + cmd := &cobra.Command{ + Use: "octopush", + } + + cmd.AddCommand(CreateOctopushProcessCmd(logger)) + cmd.AddCommand(server.CreateOctopushServerCmd(logger)) + + return cmd +} diff --git a/cmd/kraken/commands/process.go b/cmd/octopush/commands/server/process.go similarity index 98% rename from cmd/kraken/commands/process.go rename to cmd/octopush/commands/server/process.go index 22ed98e..04f2041 100644 --- a/cmd/kraken/commands/process.go +++ b/cmd/octopush/commands/server/process.go @@ -1,4 +1,4 @@ -package commands +package server import ( "bytes" diff --git a/cmd/octopush/commands/server/server.go b/cmd/octopush/commands/server/server.go new file mode 100644 index 0000000..90287a6 --- /dev/null +++ b/cmd/octopush/commands/server/server.go @@ -0,0 +1,16 @@ +package server + +import ( + "github.com/spf13/cobra" + "go.uber.org/zap" +) + +func CreateOctopushServerCmd(logger *zap.Logger) *cobra.Command { + cmd := &cobra.Command{ + Use: "server", + } + + cmd.AddCommand(CreateOctopushProcessCmd()) + + return cmd +} diff --git a/cmd/octopush/octopush.go b/cmd/octopush/octopush.go new file mode 100644 index 0000000..f75223c --- /dev/null +++ b/cmd/octopush/octopush.go @@ -0,0 +1,28 @@ +package main + +import ( + "os" + + "git.front.kjuulh.io/kjuulh/octopush/cmd/octopush/commands" + "git.front.kjuulh.io/kjuulh/octopush/internal/logger" + "go.uber.org/zap" +) + +func main() { + logger, err := logger.New() + if err != nil { + panic(err) + } + _ = logger.Sync() + + zap.ReplaceGlobals(logger) + + Execute(logger) +} + +func Execute(logger *zap.Logger) { + err := commands.CreateOctopushCmd(logger).Execute() + if err != nil { + os.Exit(1) + } +} diff --git a/internal/actions/action_creator.go b/internal/actions/action_creator.go index 80b71e0..7fe4ef0 100644 --- a/internal/actions/action_creator.go +++ b/internal/actions/action_creator.go @@ -23,12 +23,12 @@ type ( ActionCreator struct { logger *zap.Logger storage *storage.Service - git *providers.Git + git *providers.GoGit } ActionCreatorDeps interface { GetStorageService() *storage.Service - GetGitProvider() *providers.Git + GetGitProvider() *providers.GoGit } ) diff --git a/internal/cli/cli.go b/internal/cli/cli.go new file mode 100644 index 0000000..009bd93 --- /dev/null +++ b/internal/cli/cli.go @@ -0,0 +1,26 @@ +package cli + +import ( + "context" + + "git.front.kjuulh.io/kjuulh/curre" + "git.front.kjuulh.io/kjuulh/octopush/internal/server" + "git.front.kjuulh.io/kjuulh/octopush/internal/serverdeps" + "git.front.kjuulh.io/kjuulh/octopush/internal/services/signer" + "go.uber.org/zap" +) + +func Start(ctx context.Context, logger *zap.Logger) (*serverdeps.ServerDeps, error) { + deps := serverdeps.NewServerDeps(logger) + + err := curre.NewManager(). + Register( + server.NewStorageServer(logger.With(zap.Namespace("storage")), deps), + ). + Register( + signer.NewOpenPGPApp(deps.GetOpenPGP()), + ). + RunNonBlocking(ctx) + + return deps, err +} diff --git a/internal/commands/process_repos.go b/internal/commands/process_repos.go index 6ae32c1..fdf949b 100644 --- a/internal/commands/process_repos.go +++ b/internal/commands/process_repos.go @@ -20,14 +20,14 @@ type ( ProcessRepos struct { logger *zap.Logger storage *storage.Service - git *providers.Git + git *providers.GoGit actionCreator *actions.ActionCreator gitea *gitproviders.Gitea } ProcessReposDeps interface { GetStorageService() *storage.Service - GetGitProvider() *providers.Git + GetGitProvider() *providers.GoGit GetActionCreator() *actions.ActionCreator GetGitea() *gitproviders.Gitea } @@ -161,7 +161,7 @@ func (pr *ProcessRepos) prepareAction( return cleanupfunc, area, nil } -func (pr *ProcessRepos) clone(ctx context.Context, area *storage.Area, repoUrl string) (*providers.GitRepo, error) { +func (pr *ProcessRepos) clone(ctx context.Context, area *storage.Area, repoUrl string) (*providers.GoGitRepo, error) { pr.logger.Debug("Cloning repo", zap.String("path", area.Path), zap.String("repoUrl", repoUrl)) cloneCtx, _ := context.WithTimeout(ctx, time.Second*5) repo, err := pr.git.Clone(cloneCtx, area, repoUrl) @@ -177,7 +177,7 @@ func (pr *ProcessRepos) clone(ctx context.Context, area *storage.Area, repoUrl s return repo, nil } -func (pr *ProcessRepos) commit(ctx context.Context, area *storage.Area, repo *providers.GitRepo, repoUrl string) error { +func (pr *ProcessRepos) commit(ctx context.Context, area *storage.Area, repo *providers.GoGitRepo, repoUrl string) error { wt, err := pr.git.Add(ctx, area, repo) if err != nil { return fmt.Errorf("could not add file: %w", err) diff --git a/internal/serverdeps/server_deps.go b/internal/serverdeps/server_deps.go index a712e45..47e446f 100644 --- a/internal/serverdeps/server_deps.go +++ b/internal/serverdeps/server_deps.go @@ -53,7 +53,7 @@ func (deps *ServerDeps) GetStorageService() *storage.Service { return storage.NewService(deps.logger.With(zap.Namespace("storage")), deps.storageConfig) } -func (deps *ServerDeps) GetGitProvider() *providers.Git { +func (deps *ServerDeps) GetGitProvider() *providers.GoGit { return providers.NewGit(deps.logger.With(zap.Namespace("gitProvider")), deps.gitCfg, deps.openPGP) } diff --git a/internal/services/providers/git.go b/internal/services/providers/git.go index 27253de..cf2a3ba 100644 --- a/internal/services/providers/git.go +++ b/internal/services/providers/git.go @@ -1,339 +1 @@ package providers - -import ( - "context" - "errors" - "fmt" - "time" - - "git.front.kjuulh.io/kjuulh/octopush/internal/services/signer" - "git.front.kjuulh.io/kjuulh/octopush/internal/services/storage" - "github.com/go-git/go-git/v5" - "github.com/go-git/go-git/v5/config" - "github.com/go-git/go-git/v5/plumbing" - "github.com/go-git/go-git/v5/plumbing/object" - "github.com/go-git/go-git/v5/plumbing/transport" - "github.com/go-git/go-git/v5/plumbing/transport/http" - "github.com/go-git/go-git/v5/plumbing/transport/ssh" - "go.uber.org/zap" - "go.uber.org/zap/zapio" -) - -// Git is a native git provider, it can clone, pull -// , push and as in abstraction on native git operations -type Git struct { - logger *zap.Logger - gitConfig *GitConfig - openPGP *signer.OpenPGP -} - -type GitRepo struct { - repo *git.Repository -} - -func (gr *GitRepo) GetHEAD() (string, error) { - head, err := gr.repo.Head() - if err != nil { - return "", err - } - - return head.Name().Short(), nil -} - -type GitAuth string - -const ( - GIT_AUTH_SSH GitAuth = "ssh" - GIT_AUTH_USERNAME_PASSWORD GitAuth = "username_password" - GIT_AUTH_ACCESS_TOKEN GitAuth = "access_token" - GIT_AUTH_ANONYMOUS GitAuth = "anonymous" - GIT_AUTH_SSH_AGENT GitAuth = "ssh_agent" -) - -type GitConfig struct { - AuthOption GitAuth - User string - Password string - AccessToken string - SshPublicKeyFilePath string - SshPrivateKeyPassword string -} - -func NewGit(logger *zap.Logger, gitConfig *GitConfig, openPGP *signer.OpenPGP) *Git { - return &Git{logger: logger, gitConfig: gitConfig, openPGP: openPGP} -} - -func (g *Git) GetOriginHEADForRepo(ctx context.Context, gitRepo *GitRepo) (string, error) { - auth, err := g.GetAuth() - if err != nil { - return "", err - } - - remote, err := gitRepo.repo.Remote("origin") - if err != nil { - return "", err - } - - refs, err := remote.ListContext(ctx, &git.ListOptions{ - Auth: auth, - }) - if err != nil { - return "", err - } - - headRef := "" - for _, ref := range refs { - //g.logger.Debug(ref.String()) - if !ref.Name().IsBranch() { - headRef = ref.Target().Short() - } - } - - if headRef == "" { - return "", errors.New("no upstream HEAD branch could be found") - } - - return headRef, nil -} - -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), - zap.String("path", storageArea.Path), - ) - - auth, err := g.GetAuth() - if err != nil { - return nil, err - } - - cloneOptions := git.CloneOptions{ - URL: repoUrl, - Auth: auth, - RemoteName: "origin", - ReferenceName: plumbing.NewBranchReferenceName(branch), - SingleBranch: false, - 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 && !errors.Is(err, git.NoErrAlreadyUpToDate) { - return nil, err - } - - g.logger.Debug("done cloning repo") - - return &GitRepo{repo: repo}, nil -} - -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 nil, err - } - - cloneOptions := git.CloneOptions{ - URL: repoUrl, - Auth: auth, - RemoteName: "origin", - ReferenceName: "refs/heads/main", - SingleBranch: false, - 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 { - return &zapio.Writer{ - Log: g.logger.With(zap.String("process", "go-git")), - Level: zap.DebugLevel, - } -} - -func (g *Git) Add(ctx context.Context, storageArea *storage.Area, gitRepo *GitRepo) (*git.Worktree, error) { - worktree, err := gitRepo.repo.Worktree() - if err != nil { - return nil, err - } - - err = worktree.AddWithOptions(&git.AddOptions{ - All: true, - }) - if err != nil { - return nil, err - } - - status, err := worktree.Status() - if err != nil { - return nil, err - } - - g.logger.Debug("git status", zap.String("status", status.String())) - - return worktree, nil -} - -func (g *Git) CreateBranch(ctx context.Context, gitRepo *GitRepo) error { - worktree, err := gitRepo.repo.Worktree() - if err != nil { - return err - } - - refSpec := plumbing.NewBranchReferenceName("octopush-apply") - err = gitRepo.repo.CreateBranch(&config.Branch{ - Name: "octopush-apply", - Remote: "origin", - Merge: refSpec, - Rebase: "", - }) - if err != nil { - return fmt.Errorf("could not create branch: %w", err) - } - - err = worktree.Checkout(&git.CheckoutOptions{ - Branch: plumbing.ReferenceName(refSpec.String()), - Create: true, - Force: false, - Keep: false, - }) - if err != nil { - return fmt.Errorf("could not checkout branch: %w", err) - } - - remoteRef := plumbing.NewRemoteReferenceName("origin", "octopush-apply") - ref := plumbing.NewSymbolicReference(refSpec, remoteRef) - err = gitRepo.repo.Storer.SetReference(ref) - if err != nil { - return fmt.Errorf("could not set reference: %w", err) - } - - auth, err := g.GetAuth() - if err != nil { - return err - } - - err = worktree.PullContext(ctx, &git.PullOptions{ - RemoteName: "origin", - ReferenceName: "refs/heads/main", - SingleBranch: false, - Depth: 1, - Auth: auth, - RecurseSubmodules: 1, - Progress: g.getProgressWriter(), - Force: true, - InsecureSkipTLS: false, - CABundle: []byte{}, - }) - if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) { - return fmt.Errorf("could not pull from origin: %w", err) - } - - g.logger.Debug("done creating branches") - - return nil -} - -func (g *Git) Commit(ctx context.Context, gitRepo *GitRepo) error { - worktree, err := gitRepo.repo.Worktree() - if err != nil { - return err - } - - _, err = worktree.Commit("some-commit", &git.CommitOptions{ - All: true, - Author: &object.Signature{Name: "octopush", Email: "octopush@kasperhermansen.com", When: time.Now()}, - Committer: &object.Signature{Name: "octopush", Email: "octopush@kasperhermansen.com", When: time.Now()}, - SignKey: g.openPGP.SigningKey, - }) - if err != nil { - return err - } - - g.logger.Debug("done commiting objects") - - return nil -} - -func (g *Git) Push(ctx context.Context, gitRepo *GitRepo) error { - auth, err := g.GetAuth() - if err != nil { - return err - } - - err = gitRepo.repo.PushContext(ctx, &git.PushOptions{ - RemoteName: "origin", - RefSpecs: []config.RefSpec{}, - Auth: auth, - Progress: g.getProgressWriter(), - Prune: false, - Force: true, - InsecureSkipTLS: false, - CABundle: []byte{}, - RequireRemoteRefs: []config.RefSpec{}, - }) - if err != nil { - return err - } - - g.logger.Debug("done pushing branch") - - return nil -} - -func (g *Git) GetAuth() (transport.AuthMethod, error) { - switch g.gitConfig.AuthOption { - case GIT_AUTH_SSH: - sshKey, err := ssh.NewPublicKeysFromFile( - g.gitConfig.User, - g.gitConfig.SshPublicKeyFilePath, - g.gitConfig.SshPrivateKeyPassword, - ) - if err != nil { - return nil, err - } - return sshKey, nil - case GIT_AUTH_USERNAME_PASSWORD: - return &http.BasicAuth{ - Username: g.gitConfig.User, - Password: g.gitConfig.Password, - }, nil - case GIT_AUTH_ACCESS_TOKEN: - return &http.BasicAuth{ - Username: "required-username", - Password: g.gitConfig.AccessToken, - }, nil - case GIT_AUTH_ANONYMOUS: - return nil, nil - case GIT_AUTH_SSH_AGENT: - return ssh.NewSSHAgentAuth(g.gitConfig.User) - default: - return nil, nil - } -} diff --git a/internal/services/providers/gogit.go b/internal/services/providers/gogit.go new file mode 100644 index 0000000..edff30a --- /dev/null +++ b/internal/services/providers/gogit.go @@ -0,0 +1,339 @@ +package providers + +import ( + "context" + "errors" + "fmt" + "time" + + "git.front.kjuulh.io/kjuulh/octopush/internal/services/signer" + "git.front.kjuulh.io/kjuulh/octopush/internal/services/storage" + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/config" + "github.com/go-git/go-git/v5/plumbing" + "github.com/go-git/go-git/v5/plumbing/object" + "github.com/go-git/go-git/v5/plumbing/transport" + "github.com/go-git/go-git/v5/plumbing/transport/http" + "github.com/go-git/go-git/v5/plumbing/transport/ssh" + "go.uber.org/zap" + "go.uber.org/zap/zapio" +) + +// GoGit is a native git provider, it can clone, pull +// , push and as in abstraction on native git operations +type GoGit struct { + logger *zap.Logger + gitConfig *GitConfig + openPGP *signer.OpenPGP +} + +type GoGitRepo struct { + repo *git.Repository +} + +func (gr *GoGitRepo) GetHEAD() (string, error) { + head, err := gr.repo.Head() + if err != nil { + return "", err + } + + return head.Name().Short(), nil +} + +type GitAuth string + +const ( + GIT_AUTH_SSH GitAuth = "ssh" + GIT_AUTH_USERNAME_PASSWORD GitAuth = "username_password" + GIT_AUTH_ACCESS_TOKEN GitAuth = "access_token" + GIT_AUTH_ANONYMOUS GitAuth = "anonymous" + GIT_AUTH_SSH_AGENT GitAuth = "ssh_agent" +) + +type GitConfig struct { + AuthOption GitAuth + User string + Password string + AccessToken string + SshPublicKeyFilePath string + SshPrivateKeyPassword string +} + +func NewGit(logger *zap.Logger, gitConfig *GitConfig, openPGP *signer.OpenPGP) *GoGit { + return &GoGit{logger: logger, gitConfig: gitConfig, openPGP: openPGP} +} + +func (g *GoGit) GetOriginHEADForRepo(ctx context.Context, gitRepo *GoGitRepo) (string, error) { + auth, err := g.GetAuth() + if err != nil { + return "", err + } + + remote, err := gitRepo.repo.Remote("origin") + if err != nil { + return "", err + } + + refs, err := remote.ListContext(ctx, &git.ListOptions{ + Auth: auth, + }) + if err != nil { + return "", err + } + + headRef := "" + for _, ref := range refs { + //g.logger.Debug(ref.String()) + if !ref.Name().IsBranch() { + headRef = ref.Target().Short() + } + } + + if headRef == "" { + return "", errors.New("no upstream HEAD branch could be found") + } + + return headRef, nil +} + +func (g *GoGit) CloneBranch(ctx context.Context, storageArea *storage.Area, repoUrl string, branch string) (*GoGitRepo, error) { + g.logger.Debug( + "cloning repository", + zap.String("repoUrl", repoUrl), + zap.String("path", storageArea.Path), + ) + + auth, err := g.GetAuth() + if err != nil { + return nil, err + } + + cloneOptions := git.CloneOptions{ + URL: repoUrl, + Auth: auth, + RemoteName: "origin", + ReferenceName: plumbing.NewBranchReferenceName(branch), + SingleBranch: false, + 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 && !errors.Is(err, git.NoErrAlreadyUpToDate) { + return nil, err + } + + g.logger.Debug("done cloning repo") + + return &GoGitRepo{repo: repo}, nil +} + +func (g *GoGit) Clone(ctx context.Context, storageArea *storage.Area, repoUrl string) (*GoGitRepo, error) { + g.logger.Debug( + "cloning repository", + zap.String("repoUrl", repoUrl), + zap.String("path", storageArea.Path), + ) + + auth, err := g.GetAuth() + if err != nil { + return nil, err + } + + cloneOptions := git.CloneOptions{ + URL: repoUrl, + Auth: auth, + RemoteName: "origin", + ReferenceName: "refs/heads/main", + SingleBranch: false, + 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 &GoGitRepo{repo: repo}, nil +} + +func (g *GoGit) getProgressWriter() *zapio.Writer { + return &zapio.Writer{ + Log: g.logger.With(zap.String("process", "go-git")), + Level: zap.DebugLevel, + } +} + +func (g *GoGit) Add(ctx context.Context, storageArea *storage.Area, gitRepo *GoGitRepo) (*git.Worktree, error) { + worktree, err := gitRepo.repo.Worktree() + if err != nil { + return nil, err + } + + err = worktree.AddWithOptions(&git.AddOptions{ + All: true, + }) + if err != nil { + return nil, err + } + + status, err := worktree.Status() + if err != nil { + return nil, err + } + + g.logger.Debug("git status", zap.String("status", status.String())) + + return worktree, nil +} + +func (g *GoGit) CreateBranch(ctx context.Context, gitRepo *GoGitRepo) error { + worktree, err := gitRepo.repo.Worktree() + if err != nil { + return err + } + + refSpec := plumbing.NewBranchReferenceName("octopush-apply") + err = gitRepo.repo.CreateBranch(&config.Branch{ + Name: "octopush-apply", + Remote: "origin", + Merge: refSpec, + Rebase: "", + }) + if err != nil { + return fmt.Errorf("could not create branch: %w", err) + } + + err = worktree.Checkout(&git.CheckoutOptions{ + Branch: plumbing.ReferenceName(refSpec.String()), + Create: true, + Force: false, + Keep: false, + }) + if err != nil { + return fmt.Errorf("could not checkout branch: %w", err) + } + + remoteRef := plumbing.NewRemoteReferenceName("origin", "octopush-apply") + ref := plumbing.NewSymbolicReference(refSpec, remoteRef) + err = gitRepo.repo.Storer.SetReference(ref) + if err != nil { + return fmt.Errorf("could not set reference: %w", err) + } + + auth, err := g.GetAuth() + if err != nil { + return err + } + + err = worktree.PullContext(ctx, &git.PullOptions{ + RemoteName: "origin", + ReferenceName: "refs/heads/main", + SingleBranch: false, + Depth: 1, + Auth: auth, + RecurseSubmodules: 1, + Progress: g.getProgressWriter(), + Force: true, + InsecureSkipTLS: false, + CABundle: []byte{}, + }) + if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) { + return fmt.Errorf("could not pull from origin: %w", err) + } + + g.logger.Debug("done creating branches") + + return nil +} + +func (g *GoGit) Commit(ctx context.Context, gitRepo *GoGitRepo) error { + worktree, err := gitRepo.repo.Worktree() + if err != nil { + return err + } + + _, err = worktree.Commit("some-commit", &git.CommitOptions{ + All: true, + Author: &object.Signature{Name: "octopush", Email: "octopush@kasperhermansen.com", When: time.Now()}, + Committer: &object.Signature{Name: "octopush", Email: "octopush@kasperhermansen.com", When: time.Now()}, + SignKey: g.openPGP.SigningKey, + }) + if err != nil { + return err + } + + g.logger.Debug("done commiting objects") + + return nil +} + +func (g *GoGit) Push(ctx context.Context, gitRepo *GoGitRepo) error { + auth, err := g.GetAuth() + if err != nil { + return err + } + + err = gitRepo.repo.PushContext(ctx, &git.PushOptions{ + RemoteName: "origin", + RefSpecs: []config.RefSpec{}, + Auth: auth, + Progress: g.getProgressWriter(), + Prune: false, + Force: true, + InsecureSkipTLS: false, + CABundle: []byte{}, + RequireRemoteRefs: []config.RefSpec{}, + }) + if err != nil { + return err + } + + g.logger.Debug("done pushing branch") + + return nil +} + +func (g *GoGit) GetAuth() (transport.AuthMethod, error) { + switch g.gitConfig.AuthOption { + case GIT_AUTH_SSH: + sshKey, err := ssh.NewPublicKeysFromFile( + g.gitConfig.User, + g.gitConfig.SshPublicKeyFilePath, + g.gitConfig.SshPrivateKeyPassword, + ) + if err != nil { + return nil, err + } + return sshKey, nil + case GIT_AUTH_USERNAME_PASSWORD: + return &http.BasicAuth{ + Username: g.gitConfig.User, + Password: g.gitConfig.Password, + }, nil + case GIT_AUTH_ACCESS_TOKEN: + return &http.BasicAuth{ + Username: "required-username", + Password: g.gitConfig.AccessToken, + }, nil + case GIT_AUTH_ANONYMOUS: + return nil, nil + case GIT_AUTH_SSH_AGENT: + return ssh.NewSSHAgentAuth(g.gitConfig.User) + default: + return nil, nil + } +} -- 2.45.2 From 32eef8f3c62b9811c4449c8f5a2b2ad4f55acc76 Mon Sep 17 00:00:00 2001 From: kjuulh Date: Wed, 21 Sep 2022 21:50:08 +0200 Subject: [PATCH 2/2] with actual repos --- .../{kraken.yml => octopush.yml} | 0 .../{kraken.yml => octopush.yml} | 0 .../{kraken.yml => octopush.yml} | 0 .../{kraken.yml => octopush.yml} | 0 .../{kraken.yml => octopush.yml} | 0 go.mod | 12 ++++------ go.sum | 23 ++----------------- internal/cli/cli.go | 6 ++++- internal/serverdeps/server_deps.go | 2 +- scripts/run_client.sh | 2 ++ 10 files changed, 14 insertions(+), 31 deletions(-) rename _examples/actions/add_releaserc/{kraken.yml => octopush.yml} (100%) rename _examples/actions/docker_action/{kraken.yml => octopush.yml} (100%) rename _examples/actions/write_a_readme/{kraken.yml => octopush.yml} (100%) rename _examples/queries/find_semantic/{kraken.yml => octopush.yml} (100%) rename _examples/queries/scrape_readme/{kraken.yml => octopush.yml} (100%) diff --git a/_examples/actions/add_releaserc/kraken.yml b/_examples/actions/add_releaserc/octopush.yml similarity index 100% rename from _examples/actions/add_releaserc/kraken.yml rename to _examples/actions/add_releaserc/octopush.yml diff --git a/_examples/actions/docker_action/kraken.yml b/_examples/actions/docker_action/octopush.yml similarity index 100% rename from _examples/actions/docker_action/kraken.yml rename to _examples/actions/docker_action/octopush.yml diff --git a/_examples/actions/write_a_readme/kraken.yml b/_examples/actions/write_a_readme/octopush.yml similarity index 100% rename from _examples/actions/write_a_readme/kraken.yml rename to _examples/actions/write_a_readme/octopush.yml diff --git a/_examples/queries/find_semantic/kraken.yml b/_examples/queries/find_semantic/octopush.yml similarity index 100% rename from _examples/queries/find_semantic/kraken.yml rename to _examples/queries/find_semantic/octopush.yml diff --git a/_examples/queries/scrape_readme/kraken.yml b/_examples/queries/scrape_readme/octopush.yml similarity index 100% rename from _examples/queries/scrape_readme/kraken.yml rename to _examples/queries/scrape_readme/octopush.yml diff --git a/go.mod b/go.mod index fb618fb..ca837eb 100644 --- a/go.mod +++ b/go.mod @@ -3,23 +3,23 @@ module git.front.kjuulh.io/kjuulh/octopush go 1.19 require ( - git.front.kjuulh.io/kjuulh/curre v1.2.2 + code.gitea.io/sdk/gitea v0.15.1 + git.front.kjuulh.io/kjuulh/curre v1.3.1 github.com/ProtonMail/go-crypto v0.0.0-20220822140716-1678d6eb0cbe - github.com/ProtonMail/gopenpgp/v2 v2.4.10 github.com/gin-contrib/zap v0.0.2 github.com/gin-gonic/gin v1.8.1 github.com/go-git/go-git/v5 v5.4.2 github.com/google/uuid v1.3.0 github.com/spf13/cobra v1.5.0 github.com/stretchr/testify v1.8.0 + github.com/whilp/git-urls v1.0.0 go.uber.org/zap v1.23.0 golang.org/x/net v0.0.0-20220909164309-bea034e7d591 + gopkg.in/yaml.v3 v3.0.1 ) require ( - code.gitea.io/sdk/gitea v0.15.1 // indirect github.com/Microsoft/go-winio v0.5.2 // indirect - github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f // indirect github.com/acomagu/bufpipe v1.0.3 // indirect github.com/cloudflare/circl v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -43,13 +43,10 @@ require ( github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect - github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sergi/go-diff v1.2.0 // indirect - github.com/sirupsen/logrus v1.7.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/ugorji/go/codec v1.2.7 // indirect - github.com/whilp/git-urls v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.2 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect @@ -59,5 +56,4 @@ require ( google.golang.org/protobuf v1.28.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 5f09503..5ad6a5d 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,8 @@ code.gitea.io/gitea-vet v0.2.1/go.mod h1:zcNbT/aJEmivCAhfmkHOlT645KNOf9W2KnkLgFjGGfE= code.gitea.io/sdk/gitea v0.15.1 h1:WJreC7YYuxbn0UDaPuWIe/mtiNKTvLN8MLkaw71yx/M= code.gitea.io/sdk/gitea v0.15.1/go.mod h1:klY2LVI3s3NChzIk/MzMn7G1FHrfU7qd63iSMVoHRBA= -git.front.kjuulh.io/kjuulh/curre v1.2.2 h1:0OwWIfekrMykdQg9bdmG80I+Mjc2k4i+sy903phuDWs= -git.front.kjuulh.io/kjuulh/curre v1.2.2/go.mod h1:m7WpSehONLqPh/XF3F0BI0UOpLOfGuDmDEFI1XsM6fE= -github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +git.front.kjuulh.io/kjuulh/curre v1.3.1 h1:fPVEAZgf6qST51IEOrrEiKNASvU0aaf8kKS/zqQ3z18= +git.front.kjuulh.io/kjuulh/curre v1.3.1/go.mod h1:m7WpSehONLqPh/XF3F0BI0UOpLOfGuDmDEFI1XsM6fE= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA= @@ -11,10 +10,6 @@ github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= github.com/ProtonMail/go-crypto v0.0.0-20220822140716-1678d6eb0cbe h1:R2HeCk7SG/XpoYZlEeI1v7sId7w2AMWwzOaVqXn45FE= github.com/ProtonMail/go-crypto v0.0.0-20220822140716-1678d6eb0cbe/go.mod h1:UBYPn8k0D56RtnR8RFQMjmh4KrZzWJ5o7Z9SYjossQ8= -github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f h1:CGq7OieOz3wyQJ1fO8S0eO9TCW1JyvLrf8fhzz1i8ko= -github.com/ProtonMail/go-mime v0.0.0-20220302105931-303f85f7fe0f/go.mod h1:NYt+V3/4rEeDuaev/zw1zCq8uqVEuPHzDPo3OZrlGJ4= -github.com/ProtonMail/gopenpgp/v2 v2.4.10 h1:EYgkxzwmQvsa6kxxkgP1AwzkFqKHscF2UINxaSn6rdI= -github.com/ProtonMail/gopenpgp/v2 v2.4.10/go.mod h1:CTRA7/toc/4DxDy5Du4hPDnIZnJvXSeQ8LsRTOUJoyc= github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk= github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= @@ -130,8 +125,6 @@ github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNX github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ= github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= -github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= @@ -173,7 +166,6 @@ go.uber.org/zap v1.23.0 h1:OjGQ5KQDEUawVHxNwQgPpiypGHOxo2mNZsOqTak4fFY= go.uber.org/zap v1.23.0/go.mod h1:D+nX8jyLsMHMYrln8A0rJjFt/T/9/bGgIhAqxv5URuY= golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= @@ -183,15 +175,7 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90 h1:Y/gsMcFOcR+6S6f3YeMKl5g+dZMEWqcz5Czj/GWYbkM= golang.org/x/crypto v0.0.0-20220829220503-c86fa9a7ed90/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= -golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= -golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20200801112145-973feb4309de/go.mod h1:skQtrUTUwhdJvXM/2KKJzY8pDgNr9I/FOMqDVRPBUS4= -golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= -golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= -golang.org/x/mod v0.1.1-0.20191209134235-331c550502dd/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -210,7 +194,6 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -241,9 +224,7 @@ golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200325010219-a49f79bcc224/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 009bd93..a2182fc 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -13,6 +13,8 @@ import ( func Start(ctx context.Context, logger *zap.Logger) (*serverdeps.ServerDeps, error) { deps := serverdeps.NewServerDeps(logger) + readyChan := make(chan curre.ComponentsAreReady, 1) + err := curre.NewManager(). Register( server.NewStorageServer(logger.With(zap.Namespace("storage")), deps), @@ -20,7 +22,9 @@ func Start(ctx context.Context, logger *zap.Logger) (*serverdeps.ServerDeps, err Register( signer.NewOpenPGPApp(deps.GetOpenPGP()), ). - RunNonBlocking(ctx) + RunNonBlocking(ctx, readyChan) + + <-readyChan return deps, err } diff --git a/internal/serverdeps/server_deps.go b/internal/serverdeps/server_deps.go index 47e446f..f52a88c 100644 --- a/internal/serverdeps/server_deps.go +++ b/internal/serverdeps/server_deps.go @@ -42,7 +42,7 @@ func NewServerDeps(logger *zap.Logger) *ServerDeps { openPGPConfig := &signer.OpenPgpConfig{ PrivateKeyFilePath: "./example/testkey.private.pgp", PrivateKeyPassword: "somepassword", - PrivateKeyIdentity: "octopush@kasperhermansen.com", + PrivateKeyIdentity: "kraken@kasperhermansen.com", } deps.openPGP = signer.NewOpenPGP(logger.With(zap.Namespace("openpgp")), openPGPConfig) diff --git a/scripts/run_client.sh b/scripts/run_client.sh index d2a21c9..8ab48f4 100755 --- a/scripts/run_client.sh +++ b/scripts/run_client.sh @@ -4,6 +4,8 @@ set -e current_branch=$(git branch --show-current) +export $(cat .env | xargs) + #go run cmd/octopush/octopush.go process --actions-repo "git@git.front.kjuulh.io:kjuulh/octopush.git" --branch "$current_branch" --path "_examples/actions/write_a_readme" go run cmd/octopush/octopush.go process \ --actions-repo "git@git.front.kjuulh.io:kjuulh/octopush.git"\ -- 2.45.2