Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions internal/exec/atlantis_generate_repo_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ func ExecuteAtlantisGenerateRepoConfigAffectedOnly(
atmosConfig,
ref,
sha,
"",
false,
false,
stack,
Expand Down
18 changes: 17 additions & 1 deletion internal/exec/describe_affected.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/json"
"errors"
"fmt"
"net/http"
"os"

"github.com/go-git/go-git/v5/plumbing"
Expand Down Expand Up @@ -57,6 +58,7 @@ type DescribeAffectedCmdArgs struct {
AuthManager auth.AuthManager // Optional: Auth manager for credential management (from --identity flag).
HeadSHAOverride string // PR head SHA from CI event payload, used for upload correlation with Atmos Pro.
CIEventType string // CI event type (e.g., "pull_request", "push") for upload validation.
TargetBranch string // Base branch name from CI (e.g., "main"), used to auto-fetch when refs are missing.
}

//go:generate go run go.uber.org/mock/mockgen@v0.6.0 -source=$GOFILE -destination=mock_$GOFILE -package=$GOPACKAGE
Expand Down Expand Up @@ -97,6 +99,7 @@ type describeAffectedExec struct {
atmosConfig *schema.AtmosConfiguration,
ref string,
sha string,
targetBranch string,
includeSpaceliftAdminStacks bool,
includeSettings bool,
stack string,
Expand Down Expand Up @@ -272,6 +275,7 @@ func resolveBaseFromCI(describe *DescribeAffectedCmdArgs) {
describe.SHA = resolution.SHA
describe.HeadSHAOverride = resolution.HeadSHA
describe.CIEventType = resolution.EventType
describe.TargetBranch = resolution.TargetBranch

base := resolution.SHA
if base == "" {
Expand Down Expand Up @@ -328,6 +332,7 @@ func (d *describeAffectedExec) Execute(a *DescribeAffectedCmdArgs) error {
a.CLIConfig,
a.Ref,
a.SHA,
a.TargetBranch,
a.IncludeSpaceliftAdminStacks,
a.IncludeSettings,
a.Stack,
Expand Down Expand Up @@ -446,7 +451,18 @@ func (d *describeAffectedExec) uploadableQuery(args *DescribeAffectedCmdArgs, re

if uploadErr := apiClient.UploadAffectedStacks(&req); uploadErr != nil {
ui.Error("Failed to upload affected stacks to Atmos Pro")
return uploadErr

var apiErr *pro.APIError
if errors.As(uploadErr, &apiErr) && apiErr.StatusCode == http.StatusForbidden {
return errUtils.Build(errUtils.ErrFailedToUploadStacks).
WithCause(uploadErr).
WithHint("Ensure the GitHub Actions workflow has `id-token: write` permission so that Atmos can authenticate via OIDC: https://atmos-pro.com/docs/configure/github-workflows").
WithHint("Verify that this repository has the required permissions configured in Atmos Pro: https://atmos-pro.com/docs/learn/permissions").
WithHint("For a working example of a properly configured setup, see the quickstart: https://atmos-pro.com/docs/install").
Err()
}

return errUtils.Build(errUtils.ErrFailedToUploadStacks).WithCause(uploadErr).Err()
}

ui.Successf("Uploaded %d affected component(s) to Atmos Pro", len(affected))
Expand Down
14 changes: 14 additions & 0 deletions internal/exec/describe_affected_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,13 @@ func ExecuteDescribeAffectedWithTargetRefClone(
// processes stack configs, and returns a list of the affected Atmos components and stacks given two Git commits.
// This approach uses `git worktree add` to create an isolated worktree that shares the repository's
// object database but has its own HEAD, allowing checkout operations without affecting the main worktree.
// The targetBranch parameter enables auto-fetching from origin when the target commit is not available
// locally (common in CI shallow clones).
func ExecuteDescribeAffectedWithTargetRefCheckout(
atmosConfig *schema.AtmosConfiguration,
ref string,
sha string,
targetBranch string,
includeSpaceliftAdminStacks bool,
includeSettings bool,
stack string,
Expand Down Expand Up @@ -228,6 +231,17 @@ func ExecuteDescribeAffectedWithTargetRefCheckout(

// Create an isolated worktree for the target ref.
worktreePath, err := g.CreateWorktree(localRepoInfo.LocalWorktreePath, targetCommit)
if err != nil && targetBranch != "" {
// Auto-fetch the target branch and retry when the commit is not available
// locally (common in CI shallow clones).
log.Info("Target commit not available locally, fetching base branch", "branch", targetBranch)
if fetchErr := g.FetchRef(localRepoInfo.LocalWorktreePath, targetBranch); fetchErr == nil {
worktreePath, err = g.CreateWorktree(localRepoInfo.LocalWorktreePath, targetCommit)
} else {
log.Debug("Auto-fetch failed in worktree creation", "branch", targetBranch, "error", fetchErr)
Comment thread
osterman marked this conversation as resolved.
err = errors.Join(err, fetchErr)
}
}
if err != nil {
return nil, nil, nil, "", err
}
Expand Down
14 changes: 6 additions & 8 deletions internal/exec/describe_affected_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func TestDescribeAffected(t *testing.T) {
return []schema.Affected{}, nil, nil, "", nil
}

d.executeDescribeAffectedWithTargetRefCheckout = func(atmosConfig *schema.AtmosConfiguration, ref, sha string, includeSpaceliftAdminStacks, includeSettings bool, stack string, processTemplates, processYamlFunctions bool, skip []string, excludeLocked bool, authManager auth.AuthManager) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
d.executeDescribeAffectedWithTargetRefCheckout = func(atmosConfig *schema.AtmosConfiguration, ref, sha, targetBranch string, includeSpaceliftAdminStacks, includeSettings bool, stack string, processTemplates, processYamlFunctions bool, skip []string, excludeLocked bool, authManager auth.AuthManager) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
return []schema.Affected{
{
Stack: "test-stack",
Expand Down Expand Up @@ -1710,7 +1710,8 @@ func TestResolveBaseFromCI(t *testing.T) {
"sha": "headsha123456789012345678901234567890ab"
},
"base": {
"ref": "main"
"ref": "main",
"sha": "abc123def456789012345678901234567890abcd"
}
}
}`
Expand All @@ -1725,11 +1726,8 @@ func TestResolveBaseFromCI(t *testing.T) {
resolveBaseFromCI(describe)
assert.Equal(t, "pull_request", describe.CIEventType)
assert.Equal(t, "headsha123456789012345678901234567890ab", describe.HeadSHAOverride)
if describe.SHA == "" {
assert.Equal(t, "refs/remotes/origin/main", describe.Ref)
} else {
assert.NotEmpty(t, describe.SHA)
}
assert.Equal(t, "abc123def456789012345678901234567890abcd", describe.SHA)
assert.Equal(t, "main", describe.TargetBranch)
})

t.Run("GitHub Actions push event with before SHA", func(t *testing.T) {
Expand Down Expand Up @@ -1889,7 +1887,7 @@ func TestExecute_MatrixFormat(t *testing.T) {
}
d.executeDescribeAffectedWithTargetRefCheckout = func(
atmosConfig *schema.AtmosConfiguration,
ref, sha string,
ref, sha, targetBranch string,
includeSpaceliftAdminStacks, includeSettings bool,
stack string, processTemplates, processYamlFunctions bool,
skip []string, excludeLocked bool,
Expand Down
1 change: 1 addition & 0 deletions internal/exec/terraform_affected.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ func getAffectedComponents(args *DescribeAffectedCmdArgs) ([]schema.Affected, er
args.CLIConfig,
args.Ref,
args.SHA,
args.TargetBranch,
args.IncludeSpaceliftAdminStacks,
args.IncludeSettings,
args.Stack,
Expand Down
1 change: 1 addition & 0 deletions internal/exec/terraform_affected_graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ func getAffectedWithCheckout(args *DescribeAffectedCmdArgs) ([]schema.Affected,
args.CLIConfig,
args.Ref,
args.SHA,
args.TargetBranch,
args.IncludeSpaceliftAdminStacks,
args.IncludeSettings,
args.Stack,
Expand Down
5 changes: 5 additions & 0 deletions internal/exec/terraform_affected_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/stretchr/testify/assert"

"github.com/cloudposse/atmos/pkg/auth"
"github.com/cloudposse/atmos/pkg/schema"
)

Expand Down Expand Up @@ -103,13 +104,15 @@ func TestGetAffectedComponents(t *testing.T) {
cliConfig *schema.AtmosConfiguration,
ref string,
sha string,
tttttttargetBranch string,
includeSpaceliftAdminStacks bool,
includeSettings bool,
stack string,
processTemplates bool,
processYamlFunctions bool,
skip []string,
excludeLocked bool,
ttttttauthManager auth.AuthManager,
) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
return []schema.Affected{
{Component: "rds", Stack: "test-stack"},
Expand Down Expand Up @@ -190,13 +193,15 @@ func TestGetAffectedComponents(t *testing.T) {
cliConfig *schema.AtmosConfiguration,
ref string,
sha string,
tttttttargetBranch string,
includeSpaceliftAdminStacks bool,
includeSettings bool,
stack string,
processTemplates bool,
processYamlFunctions bool,
skip []string,
excludeLocked bool,
ttttttauthManager auth.AuthManager,
) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) {
return nil, nil, nil, "", errors.New("failed to checkout ref")
})
Expand Down
5 changes: 5 additions & 0 deletions pkg/ci/internal/provider/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ type BaseResolution struct {

// EventType describes the CI event (e.g., "pull_request", "push").
EventType string

// TargetBranch is the base branch name (e.g., "main") for PR events.
// Used to auto-fetch the branch when the commit is not available locally.
// Empty for non-PR events.
TargetBranch string
}

// Provider represents a CI/CD provider (GitHub Actions, GitLab CI, etc.).
Expand Down
Loading
Loading