Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make pr-based promotions work with kargo render #1674

Merged
merged 7 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ RUN GRPC_HEALTH_PROBE_VERSION=v0.4.15 && \
# - supports development
# - not used for official image builds
####################################################################################################
FROM ghcr.io/akuity/kargo-render:v0.1.0-rc.35 as back-end-dev
FROM ghcr.io/akuity/kargo-render:v0.1.0-rc.37 as back-end-dev

USER root

Expand Down Expand Up @@ -103,7 +103,7 @@ CMD ["pnpm", "dev"]
# - the official image we publish
# - purposefully last so that it is the default target when building
####################################################################################################
FROM ghcr.io/akuity/kargo-render:v0.1.0-rc.35 as final
FROM ghcr.io/akuity/kargo-render:v0.1.0-rc.37 as final

USER root

Expand Down
24 changes: 19 additions & 5 deletions internal/controller/git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ type RepoCredentials struct {
Password string `json:"password,omitempty"`
}

// CommitOptions represents options for committing changes to a git repository.
type CommitOptions struct {
// AllowEmpty indicates whether an empty commit should be allowed.
AllowEmpty bool
}

// Repo is an interface for interacting with a git repository.
type Repo interface {
// AddAll stages pending changes for commit.
Expand All @@ -46,7 +52,7 @@ type Repo interface {
// Checkout checks out the specified branch.
Checkout(branch string) error
// Commit commits staged changes to the current branch.
Commit(message string) error
Commit(message string, opts *CommitOptions) error
// CreateChildBranch creates a new branch that is a child of the current
// branch.
CreateChildBranch(branch string) error
Expand Down Expand Up @@ -135,7 +141,7 @@ func Clone(
repoCreds RepoCredentials,
opts *CloneOptions,
) (Repo, error) {
homeDir, err := os.MkdirTemp("", "")
homeDir, err := os.MkdirTemp("", "repo-")
if err != nil {
return nil, fmt.Errorf("error creating home directory for repo %q: %w", repoURL, err)
}
Expand All @@ -162,7 +168,7 @@ func (r *repo) AddAllAndCommit(message string) error {
if err := r.AddAll(); err != nil {
return err
}
return r.Commit(message)
return r.Commit(message, nil)
}

func (r *repo) Clean() error {
Expand Down Expand Up @@ -226,8 +232,16 @@ func (r *repo) Checkout(branch string) error {
return nil
}

func (r *repo) Commit(message string) error {
if _, err := libExec.Exec(r.buildCommand("commit", "-m", message)); err != nil {
func (r *repo) Commit(message string, opts *CommitOptions) error {
if opts == nil {
opts = &CommitOptions{}
}
cmdTokens := []string{"commit", "-m", message}
if opts.AllowEmpty {
cmdTokens = append(cmdTokens, "--allow-empty")
}

if _, err := libExec.Exec(r.buildCommand(cmdTokens...)); err != nil {
return fmt.Errorf("error committing changes to branch %q: %w", r.currentBranch, err)
}
return nil
Expand Down
12 changes: 11 additions & 1 deletion internal/controller/promotion/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import (
"github.com/akuity/kargo/internal/logging"
)

const tmpPrefix = "repo-scrap-"

// gitMechanism is an implementation of the Mechanism interface that uses Git to
// update configuration in a repository. It is easily configured to support
// different types of configuration management tools.
Expand Down Expand Up @@ -45,6 +47,7 @@ type gitMechanism struct {
applyConfigManagementFn func(
update kargoapi.GitRepoUpdate,
newFreight kargoapi.FreightReference,
sourceCommit string,
homeDir string,
workingDir string,
) ([]string, error)
Expand All @@ -61,6 +64,7 @@ func newGitMechanism(
applyConfigManagementFn func(
update kargoapi.GitRepoUpdate,
newFreight kargoapi.FreightReference,
sourceCommit string,
homeDir string,
workingDir string,
) ([]string, error),
Expand Down Expand Up @@ -294,11 +298,17 @@ func (g *gitMechanism) gitCommit(
}
}

sourceCommitID, err := repo.LastCommitID()
if err != nil {
return "", err // TODO: Wrap this
}

var changes []string
if g.applyConfigManagementFn != nil {
if changes, err = g.applyConfigManagementFn(
update,
newFreight,
sourceCommitID,
repo.HomeDir(),
repo.WorkingDir(),
); err != nil {
Expand All @@ -310,7 +320,7 @@ func (g *gitMechanism) gitCommit(
// Sometimes we don't write to the same branch we read from...
if readRef != writeBranch {
var tempDir string
tempDir, err = os.MkdirTemp("", "")
tempDir, err = os.MkdirTemp("", tmpPrefix)
if err != nil {
return "", fmt.Errorf("error creating temp directory for pending changes: %w", err)
}
Expand Down
24 changes: 12 additions & 12 deletions internal/controller/promotion/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@ func TestNewGitMechanism(t *testing.T) {
func([]kargoapi.GitRepoUpdate) []kargoapi.GitRepoUpdate {
return nil
},
func(kargoapi.GitRepoUpdate, kargoapi.FreightReference, string, string) ([]string, error) {
func(
kargoapi.GitRepoUpdate,
kargoapi.FreightReference,
string, string, string,
) ([]string, error) {
return nil, nil
},
)
Expand Down Expand Up @@ -466,16 +470,15 @@ func TestMoveRepoContents(t *testing.T) {
const subdirCount = 50
const fileCount = 50
// Create dummy repo dir
srcDir, err := createDummyRepoDir(subdirCount, fileCount)
srcDir, err := createDummyRepoDir(t, subdirCount, fileCount)
defer os.RemoveAll(srcDir)
krancour marked this conversation as resolved.
Show resolved Hide resolved
require.NoError(t, err)
// Double-check the setup
dirEntries, err := os.ReadDir(srcDir)
require.NoError(t, err)
require.Len(t, dirEntries, subdirCount+fileCount+1)
// Create destination dir
destDir, err := os.MkdirTemp("", "")
defer os.RemoveAll(destDir)
destDir := t.TempDir()
require.NoError(t, err)
// Move
err = moveRepoContents(srcDir, destDir)
Expand All @@ -499,7 +502,7 @@ func TestDeleteRepoContents(t *testing.T) {
const subdirCount = 50
const fileCount = 50
// Create dummy repo dir
dir, err := createDummyRepoDir(subdirCount, fileCount)
dir, err := createDummyRepoDir(t, subdirCount, fileCount)
defer os.RemoveAll(dir)
require.NoError(t, err)
// Double-check the setup
Expand Down Expand Up @@ -580,19 +583,16 @@ func TestBuildCommitMessage(t *testing.T) {
}
}

func createDummyRepoDir(dirCount, fileCount int) (string, error) {
func createDummyRepoDir(t *testing.T, dirCount, fileCount int) (string, error) {
// Create a directory
dir, err := os.MkdirTemp("", "")
if err != nil {
return dir, err
}
dir := t.TempDir()
// Add a dummy .git/ subdir
if err = os.Mkdir(filepath.Join(dir, ".git"), 0755); err != nil {
if err := os.Mkdir(filepath.Join(dir, ".git"), 0755); err != nil {
return dir, err
}
// Add some dummy dirs
for i := 0; i < dirCount; i++ {
if err = os.Mkdir(
if err := os.Mkdir(
filepath.Join(dir, fmt.Sprintf("dir-%d", i)),
0755,
); err != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/controller/promotion/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ type helmer struct {
func (h *helmer) apply(
update kargoapi.GitRepoUpdate,
newFreight kargoapi.FreightReference,
_ string, // TODO: sourceCommit would be a nice addition to the commit message
homeDir string,
workingDir string,
) ([]string, error) {
Expand Down
6 changes: 3 additions & 3 deletions internal/controller/promotion/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ func TestHelmerApply(t *testing.T) {
kargoapi.FreightReference{}, // The way the tests are structured, this value doesn't matter
"",
"",
"",
)
testCase.assertions(t, changes, err)
})
Expand Down Expand Up @@ -344,12 +345,11 @@ func TestBuildValuesFilesChanges(t *testing.T) {

func TestBuildChartDependencyChanges(t *testing.T) {
// Set up a couple of fake Chart.yaml files
testDir, err := os.MkdirTemp("", "")
require.NoError(t, err)
testDir := t.TempDir()
defer os.RemoveAll(testDir)

testChartsDir := filepath.Join(testDir, "charts")
err = os.Mkdir(testChartsDir, 0755)
err := os.Mkdir(testChartsDir, 0755)
require.NoError(t, err)

testFooChartDir := filepath.Join(testChartsDir, "foo")
Expand Down
1 change: 1 addition & 0 deletions internal/controller/promotion/kustomize.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ type kustomizer struct {
func (k *kustomizer) apply(
update kargoapi.GitRepoUpdate,
newFreight kargoapi.FreightReference,
_ string, // TODO: sourceCommit would be a nice addition to the commit message
_ string,
workingDir string,
) ([]string, error) {
Expand Down
1 change: 1 addition & 0 deletions internal/controller/promotion/kustomize_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ func TestKustomizerApply(t *testing.T) {
},
"",
"",
"",
)
testCase.assertions(t, changes, err)
})
Expand Down
22 changes: 21 additions & 1 deletion internal/controller/promotion/pullrequest.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,27 @@ func pullRequestBranchName(project, stage string) string {
// we like (i.e. not a descendant of base), recreate it.
func preparePullRequestBranch(repo git.Repo, prBranch string, base string) error {
origBranch := repo.CurrentBranch()
if err := repo.Checkout(base); err != nil {
baseBranchExists, err := repo.RemoteBranchExists(base)
if err != nil {
return err
}
if !baseBranchExists {
// Base branch doesn't exist. Create it!
if err = repo.CreateOrphanedBranch(base); err != nil {
return err
}
if err = repo.Commit(
"Initial commit",
&git.CommitOptions{
AllowEmpty: true,
},
); err != nil {
return err
}
if err = repo.Push(false); err != nil {
return err
}
} else if err = repo.Checkout(base); err != nil {
return err
}
prBranchExists, err := repo.RemoteBranchExists(prBranch)
Expand Down
Loading
Loading