Skip to content

Commit

Permalink
refactor(directives): git-overwrite -> git-clear (#2643)
Browse files Browse the repository at this point in the history
Signed-off-by: Hidde Beydals <[email protected]>
  • Loading branch information
hiddeco authored Oct 3, 2024
1 parent 0c8cd9b commit 609a937
Show file tree
Hide file tree
Showing 10 changed files with 143 additions and 220 deletions.
27 changes: 12 additions & 15 deletions docs/docs/20-quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,9 @@ the previous section.
- branch: stage/test
create: true
path: ./out
- uses: git-clear
config:
path: ./out
- uses: kustomize-set-image
as: update-image
config:
Expand All @@ -372,11 +375,7 @@ the previous section.
- uses: kustomize-build
config:
path: ./main/stages/test
outPath: ./manifests.yaml
- uses: git-overwrite
config:
inPath: ./manifests.yaml
outPath: ./out
outPath: ./out/manifests.yaml
- uses: git-commit
as: commit
config:
Expand Down Expand Up @@ -420,6 +419,9 @@ the previous section.
- branch: stage/uat
create: true
path: ./out
- uses: git-clear
config:
path: ./out
- uses: kustomize-set-image
as: update-image
config:
Expand All @@ -429,11 +431,7 @@ the previous section.
- uses: kustomize-build
config:
path: ./main/stages/test
outPath: ./manifests.yaml
- uses: git-overwrite
config:
inPath: ./manifests.yaml
outPath: ./out
outPath: ./out/manifests.yaml
- uses: git-commit
as: commit
config:
Expand Down Expand Up @@ -477,6 +475,9 @@ the previous section.
- branch: stage/prod
create: true
path: ./out
- uses: git-clear
config:
path: ./out
- uses: kustomize-set-image
as: update-image
config:
Expand All @@ -486,11 +487,7 @@ the previous section.
- uses: kustomize-build
config:
path: ./main/stages/test
outPath: ./manifests.yaml
- uses: git-overwrite
config:
inPath: ./manifests.yaml
outPath: ./out
outPath: ./out/manifests.yaml
- uses: git-commit
as: commit
config:
Expand Down
87 changes: 87 additions & 0 deletions internal/directives/git_tree_clearer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package directives

import (
"context"
"fmt"

securejoin "github.com/cyphar/filepath-securejoin"
"github.com/xeipuuv/gojsonschema"

kargoapi "github.com/akuity/kargo/api/v1alpha1"
"github.com/akuity/kargo/internal/controller/git"
)

func init() {
builtins.RegisterPromotionStepRunner(newGitTreeClearer(), nil)
}

// gitTreeClearer is an implementation of the PromotionStepRunner interface
// that removes the content of a Git working tree.
type gitTreeClearer struct {
schemaLoader gojsonschema.JSONLoader
}

// newGitTreeClearer returns an implementation of the PromotionStepRunner
// interface that removes the content of a Git working tree.
func newGitTreeClearer() PromotionStepRunner {
r := &gitTreeClearer{}
r.schemaLoader = getConfigSchemaLoader(r.Name())
return r
}

// Name implements the PromotionStepRunner interface.
func (g *gitTreeClearer) Name() string {
return "git-clear"
}

// RunPromotionStep implements the PromotionStepRunner interface.
func (g *gitTreeClearer) RunPromotionStep(
ctx context.Context,
stepCtx *PromotionStepContext,
) (PromotionStepResult, error) {
if err := g.validate(stepCtx.Config); err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, err
}
cfg, err := configToStruct[GitClearConfig](stepCtx.Config)
if err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored},
fmt.Errorf("could not convert config into %s config: %w", g.Name(), err)
}
return g.runPromotionStep(ctx, stepCtx, cfg)
}

// validate validates gitTreeClearer configuration against a JSON schema.
func (g *gitTreeClearer) validate(cfg Config) error {
return validate(g.schemaLoader, gojsonschema.NewGoLoader(cfg), g.Name())
}

func (g *gitTreeClearer) runPromotionStep(
_ context.Context,
stepCtx *PromotionStepContext,
cfg GitClearConfig,
) (PromotionStepResult, error) {
p, err := securejoin.SecureJoin(stepCtx.WorkDir, cfg.Path)
if err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored}, fmt.Errorf(
"error joining path %s with work dir %s: %w",
cfg.Path, stepCtx.WorkDir, err,
)
}
workTree, err := git.LoadWorkTree(p, nil)
if err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored},
fmt.Errorf("error loading working tree from %s: %w", cfg.Path, err)
}
// workTree.Clear() won't remove any files that aren't indexed. This is a bit
// of a hack to ensure that we don't have any untracked files in the working
// tree so that workTree.Clear() will remove everything.
if err = workTree.AddAll(); err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored},
fmt.Errorf("error adding all files to working tree at %s: %w", cfg.Path, err)
}
if err = workTree.Clear(); err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored},
fmt.Errorf("error clearing working tree at %s: %w", cfg.Path, err)
}
return PromotionStepResult{Status: kargoapi.PromotionPhaseSucceeded}, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,41 +22,25 @@ func Test_gitTreeOverwriter_validate(t *testing.T) {
expectedProblems []string
}{
{
name: "inPath not specified",
name: "path not specified",
config: Config{},
expectedProblems: []string{
"(root): inPath is required",
"(root): path is required",
},
},
{
name: "inPath is empty string",
name: "path is empty string",
config: Config{
"inPath": "",
"path": "",
},
expectedProblems: []string{
"inPath: String length must be greater than or equal to 1",
},
},
{
name: "outPath not specified",
config: Config{},
expectedProblems: []string{
"(root): outPath is required",
},
},
{
name: "outPath is empty string",
config: Config{
"outPath": "",
},
expectedProblems: []string{
"outPath: String length must be greater than or equal to 1",
"path: String length must be greater than or equal to 1",
},
},
}

r := newGitTreeOverwriter()
runner, ok := r.(*gitTreeOverwriter)
r := newGitTreeClearer()
runner, ok := r.(*gitTreeClearer)
require.True(t, ok)

for _, testCase := range testCases {
Expand Down Expand Up @@ -101,7 +85,9 @@ func Test_gitTreeOverwriter_runPromotionStep(t *testing.T) {
},
)
require.NoError(t, err)
defer repo.Close()
t.Cleanup(func() {
_ = repo.Close()
})
// "master" is still the default branch name for a new repository
// unless you configure it otherwise.
workTreePath := filepath.Join(workDir, "master")
Expand All @@ -115,16 +101,9 @@ func Test_gitTreeOverwriter_runPromotionStep(t *testing.T) {
err = os.WriteFile(filepath.Join(workTree.Dir(), "original.txt"), []byte("foo"), 0600)
require.NoError(t, err)

// Write another file to a different directory. This will be the source
// directory for the gitTreeOverwriter.
srcDir := filepath.Join(workDir, "src")
err = os.Mkdir(srcDir, 0700)
require.NoError(t, err)
err = os.WriteFile(filepath.Join(srcDir, "new.txt"), []byte("bar"), 0600)
require.NoError(t, err)

r := newGitTreeOverwriter()
runner, ok := r.(*gitTreeOverwriter)
// Run the directive
r := newGitTreeClearer()
runner, ok := r.(*gitTreeClearer)
require.True(t, ok)

res, err := runner.runPromotionStep(
Expand All @@ -134,9 +113,8 @@ func Test_gitTreeOverwriter_runPromotionStep(t *testing.T) {
Stage: "fake-stage",
WorkDir: workDir,
},
GitOverwriteConfig{
InPath: "src",
OutPath: "master",
GitClearConfig{
Path: "master",
},
)
require.NoError(t, err)
Expand All @@ -146,9 +124,6 @@ func Test_gitTreeOverwriter_runPromotionStep(t *testing.T) {
_, err = os.Stat(filepath.Join(workTree.Dir(), "original.txt"))
require.Error(t, err)
require.True(t, os.IsNotExist(err))
// Make sure new files are present
_, err = os.Stat(filepath.Join(workTree.Dir(), "new.txt"))
require.NoError(t, err)
// Make sure the .git directory is still there
_, err = os.Stat(filepath.Join(workTree.Dir(), ".git"))
require.NoError(t, err)
Expand Down
127 changes: 0 additions & 127 deletions internal/directives/git_tree_overwriter.go

This file was deleted.

Loading

0 comments on commit 609a937

Please sign in to comment.