-
-
Notifications
You must be signed in to change notification settings - Fork 174
Support explicit CI git checkout and bundle Docker CLI #2812
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
Merged
+775
−198
Merged
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
9d14f46
feat(ci): support explicit git clone checkout
osterman 3315a62
fix(docs): satisfy skill editorconfig
osterman 9a1d717
chore(ci): validate editorconfig before commit
osterman 785edb4
fix(ci): install atmos for pre-commit validation
osterman df8510f
fix(ci): use validate-capable atmos release
osterman a8a68c1
test(docker): expect bundled docker cli
osterman 3d6efee
fix(ci): mirror Docker Hub pulls through Google
osterman f996805
fix(test): resolve CI toolchain cache binaries
osterman df2cb8f
fix(pre-commit): remove Go build hook
osterman 57110b7
test(git-clone): cover CI-mode resolution edge cases
osterman 5ddaec9
Merge origin/main into osterman/support-ci-git-clone
osterman 0cfc8dd
fix(tests): close TOCTOU race in Terraform/OpenTofu binary resolution
osterman 3f217e6
fix(tests): fail loudly instead of returning an empty path on lookup …
osterman 9e9c60b
Merge branch 'main' into osterman/support-ci-git-clone
osterman 1436770
Merge branch 'main' into osterman/support-ci-git-clone
osterman 8ea8ecd
Merge branch 'main' into osterman/support-ci-git-clone
osterman b41e99a
Merge origin/main into osterman/support-ci-git-clone
osterman 6dca8da
Merge branch 'main' into osterman/support-ci-git-clone
osterman fdbb83f
fix(test): isolate toolchain install-path from the real shared cache dir
osterman c0181b8
fix(test): isolate remaining toolchain-path leak, widen resolution retry
osterman a62452a
Merge branch 'main' into osterman/support-ci-git-clone
osterman 9343ec5
Merge branch 'main' into osterman/support-ci-git-clone
osterman a68e195
test(ci): add lookup forensics for the Windows toolchain-vanishing flake
osterman 96666c3
fix(test): stop telemetry test deleting the shared Atmos cache root
osterman 4193f0a
docs(fixes): record telemetry-test shared-cache-root fix
osterman 2682303
Merge branch 'main' into osterman/support-ci-git-clone
osterman 1bd63df
refactor(cmd): remove hand-rolled argv parsing for CI git-clone boots…
osterman 285bc51
fix(ci): exclude docs.docker.com from link check (connection resets)
osterman 4357390
fix(test): address CodeRabbit findings on PR #2812
osterman 6fa52e2
fix(git): use CI context branch name, not raw ref, in no-arg checkout
osterman 91e3572
revert(ci): drop the ci-bootstrap-clone native-ci job
osterman bb2d6a3
docs(fix-log): fix missing comma per CodeRabbit review
osterman 87fa547
Merge branch 'main' into osterman/support-ci-git-clone
osterman f0c83bc
Merge remote-tracking branch 'origin/main' into osterman/support-ci-g…
osterman 076c295
fix(test): recognize packer-only manifest error in build tolerance check
osterman 258ecbf
Merge branch 'main' into osterman/support-ci-git-clone
aknysh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package git | ||
|
|
||
| import ( | ||
| "github.com/spf13/cobra" | ||
|
|
||
| "github.com/cloudposse/atmos/pkg/ci" | ||
| "github.com/cloudposse/atmos/pkg/flags" | ||
| ) | ||
|
|
||
| // CICloneBootstrapRequested reports whether the invoked command is a | ||
| // no-argument `atmos git clone` running under a detected CI provider that has | ||
| // not explicitly opted out of CI checkout (--ci=false / ATMOS_CI=false). | ||
| // | ||
| // RootCmd's config-init-error path (cmd/root.go) uses this to tolerate a | ||
| // missing or malformed atmos.yaml: the CI bootstrap clone runs in an empty | ||
| // workspace (e.g. replacing actions/checkout) where no atmos.yaml can exist | ||
| // yet. This must only be called after Cobra has parsed cmd's flags (true from | ||
| // PersistentPreRun onward), since it reads the real --ci flag via | ||
| // resolveCICloneMode instead of re-parsing os.Args by hand. | ||
| func CICloneBootstrapRequested(cmd *cobra.Command, args []string) bool { | ||
| if !isCloneCommand(cmd) { | ||
| return false | ||
| } | ||
|
|
||
| // --all bulk-clones every configured repository -- never the single-repo | ||
| // CI bootstrap case, even with zero positional args. | ||
| if all, _ := cmd.Flags().GetBool(flagAll); all { | ||
| return false | ||
| } | ||
|
|
||
| // A native-arg separator (`clone -- --no-tags`) signals a deliberate, | ||
| // hand-crafted invocation, not the zero-argument auto-bootstrap case. | ||
| positional, separated := flags.SplitArgsAtDash(cmd, args) | ||
| if len(positional) != 0 || len(separated) != 0 { | ||
| return false | ||
| } | ||
|
|
||
| if ci.Detect() == nil { | ||
| return false | ||
| } | ||
|
|
||
| // resolveCICloneMode returns ciCloneModeAuto even when --ci/ATMOS_CI is | ||
| // malformed (its error is for the caller to report); treating that the | ||
| // same as "auto" here defers the actual error to parseCloneFlags in the | ||
| // command's own RunE, where it belongs. | ||
| mode, _ := resolveCICloneMode(cmd) | ||
| return mode != ciCloneModeDisabled | ||
| } | ||
|
|
||
| // isCloneCommand reports whether cmd is the `atmos git clone` leaf, checked | ||
| // by name/parent rather than pointer identity so callers can exercise this | ||
| // with a lightweight test command tree instead of the package's real | ||
| // singletons. | ||
| func isCloneCommand(cmd *cobra.Command) bool { | ||
| return cmd != nil && | ||
| cmd.Name() == cloneCmd.Name() && | ||
| cmd.Parent() != nil && | ||
| cmd.Parent().Name() == gitCmd.Name() | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,145 @@ | ||
| package git | ||
|
|
||
| import ( | ||
| "os" | ||
| "testing" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| "github.com/stretchr/testify/assert" | ||
| "github.com/stretchr/testify/require" | ||
| // The GitHub CI provider is already blank-imported by clone.go, registering | ||
| // it for ci.Detect() package-wide. | ||
| ) | ||
|
|
||
| // newBootstrapTestCommand builds a lightweight "git clone" command tree | ||
| // (mirroring the real gitCmd/cloneCmd parent/name relationship) with the same | ||
| // --ci/--all bool flags the real clone command registers, then parses rawArgs | ||
| // through it exactly as Cobra would before invoking PersistentPreRun/RunE. | ||
| // Returns the clone leaf and the resulting positional args. | ||
| func newBootstrapTestCommand(t *testing.T, rawArgs []string) (*cobra.Command, []string) { | ||
| t.Helper() | ||
|
|
||
| root := &cobra.Command{Use: "atmos"} | ||
| git := &cobra.Command{Use: gitCmd.Name()} | ||
| clone := &cobra.Command{Use: cloneCmd.Name()} | ||
| clone.Flags().Bool(flagCI, false, "") | ||
| clone.Flags().Bool(flagAll, false, "") | ||
| root.AddCommand(git) | ||
| git.AddCommand(clone) | ||
|
|
||
| require.NoError(t, clone.ParseFlags(rawArgs)) | ||
| return clone, clone.Flags().Args() | ||
| } | ||
|
|
||
| func withCleanATMOSCIEnv(t *testing.T, value string) { | ||
| t.Helper() | ||
| if value == "" { | ||
| original, wasSet := os.LookupEnv("ATMOS_CI") | ||
| os.Unsetenv("ATMOS_CI") | ||
| t.Cleanup(func() { | ||
| if wasSet { | ||
| _ = os.Setenv("ATMOS_CI", original) | ||
| return | ||
| } | ||
| os.Unsetenv("ATMOS_CI") | ||
| }) | ||
| return | ||
| } | ||
| t.Setenv("ATMOS_CI", value) | ||
| } | ||
|
|
||
| func TestCICloneBootstrapRequested(t *testing.T) { | ||
| tests := []struct { | ||
| name string | ||
| rawArgs []string | ||
| ciDetected bool | ||
| atmosCIEnv string | ||
| wantRequest bool | ||
| }{ | ||
| { | ||
| name: "no CI provider detected", | ||
| rawArgs: nil, | ||
| ciDetected: false, | ||
| wantRequest: false, | ||
| }, | ||
| { | ||
| name: "CI detected, no args, auto mode", | ||
| rawArgs: nil, | ||
| ciDetected: true, | ||
| wantRequest: true, | ||
| }, | ||
| { | ||
| name: "explicit --ci=false opts out", | ||
| rawArgs: []string{"--ci=false"}, | ||
| ciDetected: true, | ||
| wantRequest: false, | ||
| }, | ||
| { | ||
| name: "ATMOS_CI=false opts out", | ||
| rawArgs: nil, | ||
| ciDetected: true, | ||
| atmosCIEnv: "false", | ||
| wantRequest: false, | ||
| }, | ||
| { | ||
| name: "ATMOS_CI uppercase TRUE is accepted (no drift vs pflag ParseBool)", | ||
| rawArgs: nil, | ||
| ciDetected: true, | ||
| atmosCIEnv: "TRUE", | ||
| wantRequest: true, | ||
| }, | ||
| { | ||
| name: "positional argument disqualifies bootstrap", | ||
| rawArgs: []string{"my-repo"}, | ||
| ciDetected: true, | ||
| wantRequest: false, | ||
| }, | ||
| { | ||
| name: "native args after -- disqualify bootstrap", | ||
| rawArgs: []string{"--", "--no-tags"}, | ||
| ciDetected: true, | ||
| wantRequest: false, | ||
| }, | ||
| { | ||
| name: "--all disqualifies bootstrap", | ||
| rawArgs: []string{"--all"}, | ||
| ciDetected: true, | ||
| wantRequest: false, | ||
| }, | ||
| { | ||
| name: "invalid ATMOS_CI value defers to auto (RunE reports the real error)", | ||
| rawArgs: nil, | ||
| ciDetected: true, | ||
| atmosCIEnv: "sometimes", | ||
| wantRequest: true, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| if tt.ciDetected { | ||
| t.Setenv("GITHUB_ACTIONS", "true") | ||
| } else { | ||
| t.Setenv("GITHUB_ACTIONS", "false") | ||
| } | ||
| withCleanATMOSCIEnv(t, tt.atmosCIEnv) | ||
|
|
||
| cmd, args := newBootstrapTestCommand(t, tt.rawArgs) | ||
| assert.Equal(t, tt.wantRequest, CICloneBootstrapRequested(cmd, args)) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestCICloneBootstrapRequested_WrongCommand(t *testing.T) { | ||
| t.Setenv("GITHUB_ACTIONS", "true") | ||
| withCleanATMOSCIEnv(t, "") | ||
|
|
||
| root := &cobra.Command{Use: "atmos"} | ||
| terraform := &cobra.Command{Use: "terraform"} | ||
| plan := &cobra.Command{Use: "plan"} | ||
| root.AddCommand(terraform) | ||
| terraform.AddCommand(plan) | ||
|
|
||
| assert.False(t, CICloneBootstrapRequested(plan, nil)) | ||
| assert.False(t, CICloneBootstrapRequested(nil, nil)) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.