Skip to content

Commit

Permalink
refactor(directives): git-overwrite -> git-clear
Browse files Browse the repository at this point in the history
Signed-off-by: Hidde Beydals <[email protected]>
  • Loading branch information
hiddeco committed Oct 3, 2024
1 parent 0c8cd9b commit 466c762
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 194 deletions.
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

Check warning on line 43 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L41-L43

Added lines #L41 - L43 were not covered by tests
}
cfg, err := configToStruct[GitOverwriteConfig](stepCtx.Config)
if err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored},
fmt.Errorf("could not convert config into %s config: %w", g.Name(), err)

Check warning on line 48 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L45-L48

Added lines #L45 - L48 were not covered by tests
}
return g.runPromotionStep(ctx, stepCtx, cfg)

Check warning on line 50 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L50

Added line #L50 was not covered by tests
}

// 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 GitOverwriteConfig,
) (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,
)

Check warning on line 68 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L65-L68

Added lines #L65 - L68 were not covered by tests
}
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)

Check warning on line 73 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L72-L73

Added lines #L72 - L73 were not covered by tests
}
// 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)

Check warning on line 80 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L79-L80

Added lines #L79 - L80 were not covered by tests
}
if err = workTree.Clear(); err != nil {
return PromotionStepResult{Status: kargoapi.PromotionPhaseErrored},
fmt.Errorf("error clearing working tree at %s: %w", cfg.Path, err)

Check warning on line 84 in internal/directives/git_tree_clearer.go

View check run for this annotation

Codecov / codecov/patch

internal/directives/git_tree_clearer.go#L83-L84

Added lines #L83 - L84 were not covered by tests
}
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 @@ -135,8 +114,7 @@ func Test_gitTreeOverwriter_runPromotionStep(t *testing.T) {
WorkDir: workDir,
},
GitOverwriteConfig{
InPath: "src",
OutPath: "master",
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.

14 changes: 14 additions & 0 deletions internal/directives/schemas/git-clear-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "GitOverwriteConfig",
"type": "object",
"additionalProperties": false,
"required": ["path"],
"properties": {
"path": {
"type": "string",
"description": "Path to a working directory of a local repository from which to remove all files, excluding the .git/ directory.",
"minLength": 1
}
}
}
19 changes: 0 additions & 19 deletions internal/directives/schemas/git-overwrite-config.json

This file was deleted.

15 changes: 6 additions & 9 deletions internal/directives/zz_config_types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 466c762

Please sign in to comment.