From 19c8d98c6cb5c63e002f4215c5a87384429355e2 Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 10:14:50 -0400 Subject: [PATCH 01/13] updates --- cmd/describe_affected.go | 1 + .../commands/describe/describe-affected.mdx | 30 ++++++++++--------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/cmd/describe_affected.go b/cmd/describe_affected.go index b4664094d..229f2d7b5 100644 --- a/cmd/describe_affected.go +++ b/cmd/describe_affected.go @@ -38,6 +38,7 @@ func init() { describeAffectedCmd.PersistentFlags().Bool("include-spacelift-admin-stacks", false, "Include the Spacelift admin stack of any stack that is affected by config changes: atmos describe affected --include-spacelift-admin-stacks=true") describeAffectedCmd.PersistentFlags().Bool("include-dependents", false, "Include the dependent components and stacks: atmos describe affected --include-dependents=true") describeAffectedCmd.PersistentFlags().Bool("include-settings", false, "Include the 'settings' section for each affected component: atmos describe affected --include-settings=true") + describeAffectedCmd.PersistentFlags().Bool("upload", false, "Upload the affected components and stacks to a specified endpoint: atmos describe affected --upload=true") describeAffectedCmd.PersistentFlags().Bool("clone-target-ref", false, "Clone the target reference with which to compare the current branch: atmos describe affected --clone-target-ref=true\n"+ "If set to 'false' (default), the target reference will be checked out instead\n"+ "This requires that the target reference is already cloned by Git, and the information about it exists in the '.git' directory") diff --git a/website/docs/cli/commands/describe/describe-affected.mdx b/website/docs/cli/commands/describe/describe-affected.mdx index 0ee463f84..b399412e3 100644 --- a/website/docs/cli/commands/describe/describe-affected.mdx +++ b/website/docs/cli/commands/describe/describe-affected.mdx @@ -113,6 +113,7 @@ atmos describe affected --include-spacelift-admin-stacks=true atmos describe affected --clone-target-ref=true atmos describe affected --include-dependents=true atmos describe affected --include-settings=true +atmos describe affected --upload=true ``` # Example Output @@ -200,20 +201,21 @@ Affected components and stacks: ## Flags -| Flag | Description | Required | -|:-----------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------| -| `--ref` | [Git Reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References) with which to compare the current working branch | no | -| `--sha` | Git commit SHA with which to compare the current working branch | no | -| `--file` | If specified, write the result to the file | no | -| `--format` | Specify the output format: `json` or `yaml` (`json` is default) | no | -| `--ssh-key` | Path to PEM-encoded private key to clone private repos using SSH | no | -| `--ssh-key-password` | Encryption password for the PEM-encoded private key if the key contains
a password-encrypted PEM block | no | -| `--repo-path` | Path to the already cloned target repository with which to compare the current branch.
Conflicts with `--ref`, `--sha`, `--ssh-key` and `--ssh-key-password` | no | -| `--verbose` | Print more detailed output when cloning and checking out the target
Git repository and processing the result | no | -| `--include-spacelift-admin-stacks` | Include the Spacelift admin stack of any stack
that is affected by config changes | no | -| `--clone-target-ref` | Clone the target reference with which to compare the current branch.
`atmos describe affected --clone-target-ref=true`

If set to `false` (default), the target reference will be checked out instead
This requires that the target reference is already cloned by Git,
and the information about it exists in the `.git` directory | no | -| `--include-dependents` | Include the dependent components and stacks.
`atmos describe affected --include-dependents=true` | no | -| `--include-settings` | Include the `settings` section for each affected component.
`atmos describe affected --include-settings=true` | no | +| Flag | Description | Required | +|:-----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------| +| `--ref` | [Git Reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References) with which to compare the current working branch | no | +| `--sha` | Git commit SHA with which to compare the current working branch | no | +| `--file` | If specified, write the result to the file | no | +| `--format` | Specify the output format: `json` or `yaml` (`json` is default) | no | +| `--ssh-key` | Path to PEM-encoded private key to clone private repos using SSH | no | +| `--ssh-key-password` | Encryption password for the PEM-encoded private key if the key contains
a password-encrypted PEM block | no | +| `--repo-path` | Path to the already cloned target repository with which to compare the current branch.
Conflicts with `--ref`, `--sha`, `--ssh-key` and `--ssh-key-password` | no | +| `--verbose` | Print more detailed output when cloning and checking out the target
Git repository and processing the result | no | +| `--include-spacelift-admin-stacks` | Include the Spacelift admin stack of any stack
that is affected by config changes | no | +| `--clone-target-ref` | Clone the target reference with which to compare the current branch.
`atmos describe affected --clone-target-ref=true`

If set to `false` (default), the target reference will be checked out instead
This requires that the target reference is already cloned by Git,
and the information about it exists in the `.git` directory | no | +| `--include-dependents` | Include the dependent components and stacks.
`atmos describe affected --include-dependents=true` | no | +| `--include-settings` | Include the `settings` section for each affected component.
`atmos describe affected --include-settings=true` | no | +| `--upload` | Upload the affected components and stacks to a specified endpoint for
further processing in a CI/CD pipeline.

`atmos describe affected --upload=true`

Atmos will perform an HTTP POST request to the endpoint
`${ATMOS_PRO_BASE_URL}/api/affected-stacks`
where the base URL is defined using the `ATMOS_PRO_BASE_URL` environment variable.
The `token` for the `Authorization: Bearer ` header can be specified
using the `ATMOS_PRO_TOKEN` environment variable | no | ## Output From f1a9f163261d1c5c01eb4bce186a440d54416496 Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 11:04:23 -0400 Subject: [PATCH 02/13] updates --- .../exec/atlantis_generate_repo_config.go | 6 +- internal/exec/describe_affected.go | 18 ++- internal/exec/describe_affected_utils.go | 116 +++++++++--------- pkg/describe/describe_affected_test.go | 4 +- 4 files changed, 78 insertions(+), 66 deletions(-) diff --git a/internal/exec/atlantis_generate_repo_config.go b/internal/exec/atlantis_generate_repo_config.go index f2845f541..2f63a2f31 100644 --- a/internal/exec/atlantis_generate_repo_config.go +++ b/internal/exec/atlantis_generate_repo_config.go @@ -154,11 +154,11 @@ func ExecuteAtlantisGenerateRepoConfigAffectedOnly( var err error if repoPath != "" { - affected, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, false, false) + affected, _, _, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, false, false) } else if cloneTargetRef { - affected, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, false, false) + affected, _, _, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, false, false) } else { - affected, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, false, false) + affected, _, _, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, false, false) } if err != nil { diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index 67f401440..cea9e86f8 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" + "github.com/go-git/go-git/v5/plumbing" "github.com/spf13/cobra" cfg "github.com/cloudposse/atmos/pkg/config" @@ -94,6 +95,11 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { return err } + upload, err := flags.GetBool("upload") + if err != nil { + return err + } + cloneTargetRef, err := flags.GetBool("clone-target-ref") if err != nil { return err @@ -104,13 +110,14 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { } var affected []schema.Affected + var localRepoHead *plumbing.Reference if repoPath != "" { - affected, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, localRepoHead, _, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, includeSpaceliftAdminStacks, includeSettings) } else if cloneTargetRef { - affected, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, localRepoHead, _, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, includeSpaceliftAdminStacks, includeSettings) } else { - affected, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, localRepoHead, _, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, includeSpaceliftAdminStacks, includeSettings) } if err != nil { @@ -136,5 +143,10 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { return err } + // Upload the affected components and stacks to a specified endpoint + if upload { + fmt.Println(localRepoHead.Hash()) + } + return nil } diff --git a/internal/exec/describe_affected_utils.go b/internal/exec/describe_affected_utils.go index 7b2fe6a42..eb321fd04 100644 --- a/internal/exec/describe_affected_utils.go +++ b/internal/exec/describe_affected_utils.go @@ -39,7 +39,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { if verbose { cliConfig.Logs.Level = u.LogLevelTrace @@ -52,18 +52,18 @@ func ExecuteDescribeAffectedWithTargetRefClone( EnableDotGitCommonDir: false, }) if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } // Get the Git config of the local repo localRepoConfig, err := localRepo.Config() if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } localRepoWorktree, err := localRepo.Worktree() if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } localRepoPath := localRepoWorktree.Filesystem.Root() @@ -75,18 +75,18 @@ func ExecuteDescribeAffectedWithTargetRefClone( } if len(keys) == 0 { - return nil, localRepoIsNotGitRepoError + return nil, nil, nil, localRepoIsNotGitRepoError } // Get the origin URL of the current remoteRepo remoteUrls := localRepoConfig.Remotes[keys[0]].URLs if len(remoteUrls) == 0 { - return nil, localRepoIsNotGitRepoError + return nil, nil, nil, localRepoIsNotGitRepoError } repoUrl := remoteUrls[0] if repoUrl == "" { - return nil, localRepoIsNotGitRepoError + return nil, nil, nil, localRepoIsNotGitRepoError } // Clone the remote repo @@ -101,7 +101,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( // Create a temp dir to clone the remote repo to tempDir, err := os.MkdirTemp("", strconv.FormatInt(time.Now().Unix(), 10)) if err != nil { - return nil, err + return nil, nil, nil, err } defer removeTempDir(cliConfig, tempDir) @@ -132,12 +132,12 @@ func ExecuteDescribeAffectedWithTargetRefClone( if sshKeyPath != "" { sshKeyContent, err := os.ReadFile(sshKeyPath) if err != nil { - return nil, err + return nil, nil, nil, err } sshPublicKey, err := ssh.NewPublicKeys("git", sshKeyContent, sshKeyPassword) if err != nil { - return nil, err + return nil, nil, nil, err } // Use the SSH key to clone the repo @@ -150,12 +150,12 @@ func ExecuteDescribeAffectedWithTargetRefClone( remoteRepo, err := git.PlainClone(tempDir, false, &cloneOptions) if err != nil { - return nil, err + return nil, nil, nil, err } remoteRepoHead, err := remoteRepo.Head() if err != nil { - return nil, err + return nil, nil, nil, err } if ref != "" { @@ -170,7 +170,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( w, err := remoteRepo.Worktree() if err != nil { - return nil, err + return nil, nil, nil, err } checkoutOptions := git.CheckoutOptions{ @@ -182,13 +182,13 @@ func ExecuteDescribeAffectedWithTargetRefClone( err = w.Checkout(&checkoutOptions) if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("\nChecked out commit SHA '%s'\n", sha)) } - affected, err := executeDescribeAffected( + affected, localRepoHead, remoteRepoHead, err := executeDescribeAffected( cliConfig, localRepoPath, tempDir, @@ -199,10 +199,10 @@ func ExecuteDescribeAffectedWithTargetRefClone( includeSettings, ) if err != nil { - return nil, err + return nil, nil, nil, err } - return affected, nil + return affected, localRepoHead, remoteRepoHead, nil } // ExecuteDescribeAffectedWithTargetRefCheckout checks out the target reference, @@ -214,7 +214,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { if verbose { cliConfig.Logs.Level = u.LogLevelTrace @@ -227,18 +227,18 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( EnableDotGitCommonDir: false, }) if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } // Check the Git config of the local repo _, err = localRepo.Config() if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } localRepoWorktree, err := localRepo.Worktree() if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } localRepoPath := localRepoWorktree.Filesystem.Root() @@ -246,7 +246,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( // Create a temp dir for the target ref tempDir, err := os.MkdirTemp("", strconv.FormatInt(time.Now().Unix(), 10)) if err != nil { - return nil, err + return nil, nil, nil, err } defer removeTempDir(cliConfig, tempDir) @@ -267,7 +267,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( } if err = cp.Copy(localRepoPath, tempDir, copyOptions); err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Copied the local repo into the temp directory '%s'\n", tempDir)) @@ -277,13 +277,13 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( EnableDotGitCommonDir: false, }) if err != nil { - return nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) } // Check the Git config of the target ref _, err = remoteRepo.Config() if err != nil { - return nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) } if sha != "" { @@ -291,7 +291,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( w, err := remoteRepo.Worktree() if err != nil { - return nil, err + return nil, nil, nil, err } checkoutOptions := git.CheckoutOptions{ @@ -303,7 +303,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( err = w.Checkout(&checkoutOptions) if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Checked out commit SHA '%s'\n", sha)) @@ -317,7 +317,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( w, err := remoteRepo.Worktree() if err != nil { - return nil, err + return nil, nil, nil, err } checkoutOptions := git.CheckoutOptions{ @@ -335,13 +335,13 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( "\nrefer to https://atmos.tools/cli/commands/describe/affected for more details", ref) err = errors.New(errorMessage) } - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Checked out Git ref '%s'\n", ref)) } - affected, err := executeDescribeAffected( + affected, localRepoHead, remoteRepoHead, err := executeDescribeAffected( cliConfig, localRepoPath, tempDir, @@ -352,10 +352,10 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( includeSettings, ) if err != nil { - return nil, err + return nil, nil, nil, err } - return affected, nil + return affected, localRepoHead, remoteRepoHead, nil } // ExecuteDescribeAffectedWithTargetRepoPath uses `repo-path` to access the target repo, and processes stack configs @@ -366,7 +366,7 @@ func ExecuteDescribeAffectedWithTargetRepoPath( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { localPath := "." @@ -375,18 +375,18 @@ func ExecuteDescribeAffectedWithTargetRepoPath( EnableDotGitCommonDir: false, }) if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } // Check the Git config of the local repo _, err = localRepo.Config() if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } localRepoWorktree, err := localRepo.Worktree() if err != nil { - return nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) } localRepoPath := localRepoWorktree.Filesystem.Root() @@ -396,16 +396,16 @@ func ExecuteDescribeAffectedWithTargetRepoPath( EnableDotGitCommonDir: false, }) if err != nil { - return nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) } // Check the Git config of the remote target repo _, err = remoteRepo.Config() if err != nil { - return nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) } - affected, err := executeDescribeAffected( + affected, localRepoHead, remoteRepoHead, err := executeDescribeAffected( cliConfig, localRepoPath, targetRefPath, @@ -416,10 +416,10 @@ func ExecuteDescribeAffectedWithTargetRepoPath( includeSettings, ) if err != nil { - return nil, err + return nil, nil, nil, err } - return affected, nil + return affected, localRepoHead, remoteRepoHead, nil } func executeDescribeAffected( @@ -431,7 +431,7 @@ func executeDescribeAffected( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { if verbose { cliConfig.Logs.Level = u.LogLevelTrace @@ -439,25 +439,25 @@ func executeDescribeAffected( localRepoHead, err := localRepo.Head() if err != nil { - return nil, err + return nil, nil, nil, err } remoteRepoHead, err := remoteRepo.Head() if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Current working repo HEAD: %s", localRepoHead)) - u.LogTrace(cliConfig, fmt.Sprintf("Remote repo HEAD: %s", remoteRepoHead)) + u.LogTrace(cliConfig, fmt.Sprintf("Target repo HEAD: %s", remoteRepoHead)) currentStacks, err := ExecuteDescribeStacks(cliConfig, "", nil, nil, nil, false) if err != nil { - return nil, err + return nil, nil, nil, err } localRepoFileSystemPathAbs, err := filepath.Abs(localRepoFileSystemPath) if err != nil { - return nil, err + return nil, nil, nil, err } basePath := cliConfig.BasePath @@ -465,11 +465,11 @@ func executeDescribeAffected( // Handle `atmos` absolute base path. // Absolute base path can be set in the `base_path` attribute in `atmos.yaml`, or using the ENV var `ATMOS_BASE_PATH` (as it's done in `geodesic`) // If the `atmos` base path is absolute, find the relative path between the local repo path and the `atmos` base path. - // This relative path (the difference) is then used below to join with the remote (cloned) repo path. + // This relative path (the difference) is then used below to join with the remote (cloned) target repo path. if path.IsAbs(basePath) { basePath, err = filepath.Rel(localRepoFileSystemPathAbs, basePath) if err != nil { - return nil, err + return nil, nil, nil, err } } @@ -483,19 +483,19 @@ func executeDescribeAffected( cliConfig.StackConfigFilesRelativePaths, ) if err != nil { - return nil, err + return nil, nil, nil, err } remoteStacks, err := ExecuteDescribeStacks(cliConfig, "", nil, nil, nil, true) if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("\nGetting current working repo commit object...")) localCommit, err := localRepo.CommitObject(localRepoHead.Hash()) if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Got current working repo commit object")) @@ -503,7 +503,7 @@ func executeDescribeAffected( localTree, err := localCommit.Tree() if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Got current working repo commit tree")) @@ -511,7 +511,7 @@ func executeDescribeAffected( remoteCommit, err := remoteRepo.CommitObject(remoteRepoHead.Hash()) if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Got remote repo commit object")) @@ -519,7 +519,7 @@ func executeDescribeAffected( remoteTree, err := remoteCommit.Tree() if err != nil { - return nil, err + return nil, nil, nil, err } u.LogTrace(cliConfig, fmt.Sprintf("Got remote repo commit tree")) @@ -528,7 +528,7 @@ func executeDescribeAffected( // Find a slice of Patch objects with all the changes between the current working and remote trees patch, err := localTree.Patch(remoteTree) if err != nil { - return nil, err + return nil, nil, nil, err } var changedFiles []string @@ -555,10 +555,10 @@ func executeDescribeAffected( includeSettings, ) if err != nil { - return nil, err + return nil, nil, nil, err } - return affected, nil + return affected, localRepoHead, remoteRepoHead, nil } // findAffected returns a list of all affected components in all stacks diff --git a/pkg/describe/describe_affected_test.go b/pkg/describe/describe_affected_test.go index 41910af82..b9cc30daf 100644 --- a/pkg/describe/describe_affected_test.go +++ b/pkg/describe/describe_affected_test.go @@ -28,7 +28,7 @@ func TestDescribeAffectedWithTargetRefClone(t *testing.T) { ref := "refs/heads/main" sha := "" - affected, err := e.ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, "", "", true, true, true) + affected, _, _, err := e.ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, "", "", true, true, true) assert.Nil(t, err) affectedYaml, err := yaml.Marshal(affected) @@ -52,7 +52,7 @@ func TestDescribeAffectedWithTargetRepoPath(t *testing.T) { // This will compare this local repository with itself as the remote target, which should result in an empty `affected` list repoPath := "../../" - affected, err := e.ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, true, true, true) + affected, _, _, err := e.ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, true, true, true) assert.Nil(t, err) affectedYaml, err := yaml.Marshal(affected) From 44969a7b90d12b1b26acf020d27ce43006ee128c Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 15:25:41 -0400 Subject: [PATCH 03/13] updates --- internal/exec/describe_affected.go | 73 ++++++++++++++++++++++-- internal/exec/describe_affected_utils.go | 4 +- pkg/config/const.go | 6 ++ 3 files changed, 76 insertions(+), 7 deletions(-) diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index cea9e86f8..7f8e785c0 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -1,8 +1,13 @@ package exec import ( + "bytes" "errors" "fmt" + "io" + "net/http" + "os" + "time" "github.com/go-git/go-git/v5/plumbing" "github.com/spf13/cobra" @@ -109,15 +114,19 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { return errors.New("if the '--repo-path' flag is specified, the '--ref', '--sha', '--ssh-key' and '--ssh-key-password' flags can't be used") } + if upload { + includeDependents = true + } + var affected []schema.Affected - var localRepoHead *plumbing.Reference + var headHead, baseHead *plumbing.Reference if repoPath != "" { - affected, localRepoHead, _, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, headHead, baseHead, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, includeSpaceliftAdminStacks, includeSettings) } else if cloneTargetRef { - affected, localRepoHead, _, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, headHead, baseHead, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, includeSpaceliftAdminStacks, includeSettings) } else { - affected, localRepoHead, _, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, headHead, baseHead, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, includeSpaceliftAdminStacks, includeSettings) } if err != nil { @@ -145,7 +154,61 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { // Upload the affected components and stacks to a specified endpoint if upload { - fmt.Println(localRepoHead.Hash()) + baseUrl := os.Getenv(cfg.AtmosProBaseUrlEnvVarName) + if baseUrl == "" { + baseUrl = cfg.AtmosProDefaultBaseUrl + } + url := fmt.Sprintf("%s/%s", baseUrl, cfg.AtmosProDefaultEndpoint) + + token := os.Getenv(cfg.AtmosProTokenEnvVarName) + + body := map[string]any{ + "head_sha": headHead.Hash().String(), + "base_sha": baseHead.Hash().String(), + "stacks": affected, + } + + bodyJson, err := u.ConvertToJSON(body) + if err != nil { + return err + } + + u.LogTrace(cliConfig, fmt.Sprintf("\nUploading the affected components and stacks to %s", url)) + + bodyReader := bytes.NewReader([]byte(bodyJson)) + req, err := http.NewRequest(http.MethodPost, url, bodyReader) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + if token != "" { + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + } + + client := http.Client{ + Timeout: 10 * time.Second, + } + + resp, err := client.Do(req) + if err != nil { + return err + } + + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + u.LogError(err) + } + }(resp.Body) + + if resp.StatusCode != http.StatusOK { + err = fmt.Errorf("\nError uploading the affected components and stacks to %s\nStatus: %s", url, resp.Status) + return err + } + + u.LogTrace(cliConfig, fmt.Sprintf("\nUploaded the affected components and stacks to %s\n", url)) } return nil diff --git a/internal/exec/describe_affected_utils.go b/internal/exec/describe_affected_utils.go index eb321fd04..94a4343fa 100644 --- a/internal/exec/describe_affected_utils.go +++ b/internal/exec/describe_affected_utils.go @@ -447,8 +447,8 @@ func executeDescribeAffected( return nil, nil, nil, err } - u.LogTrace(cliConfig, fmt.Sprintf("Current working repo HEAD: %s", localRepoHead)) - u.LogTrace(cliConfig, fmt.Sprintf("Target repo HEAD: %s", remoteRepoHead)) + u.LogTrace(cliConfig, fmt.Sprintf("Current HEAD: %s", localRepoHead)) + u.LogTrace(cliConfig, fmt.Sprintf("Base HEAD: %s", remoteRepoHead)) currentStacks, err := ExecuteDescribeStacks(cliConfig, "", nil, nil, nil, false) if err != nil { diff --git a/pkg/config/const.go b/pkg/config/const.go index ba5569451..7bd85443c 100644 --- a/pkg/config/const.go +++ b/pkg/config/const.go @@ -60,4 +60,10 @@ const ( LogsFileFlag = "--logs-file" SettingsListMergeStrategyFlag = "--settings-list-merge-strategy" + + // Atmos Pro + AtmosProTokenEnvVarName = "ATMOS_PRO_TOKEN" + AtmosProBaseUrlEnvVarName = "ATMOS_PRO_BASE_URL" + AtmosProDefaultBaseUrl = "https://app.cloudposse.com" + AtmosProDefaultEndpoint = "api/affected-stacks" ) From bd3ea558fc8bc21dcbee431cb3ba53acc905422e Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 15:32:12 -0400 Subject: [PATCH 04/13] updates --- internal/exec/describe_affected.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index 7f8e785c0..5385fa36a 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -118,6 +118,10 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { includeDependents = true } + if verbose { + cliConfig.Logs.Level = u.LogLevelTrace + } + var affected []schema.Affected var headHead, baseHead *plumbing.Reference @@ -141,10 +145,6 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { } } - if verbose { - cliConfig.Logs.Level = u.LogLevelTrace - } - u.LogTrace(cliConfig, fmt.Sprintf("\nAffected components and stacks: \n")) err = printOrWriteToFile(format, file, affected) From 54713faeef53c5a3aeb2ca9e747974c366987179 Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 16:04:30 -0400 Subject: [PATCH 05/13] updates --- .../exec/atlantis_generate_repo_config.go | 6 +- internal/exec/describe_affected.go | 9 +- internal/exec/describe_affected_utils.go | 124 ++++++++++++------ pkg/describe/describe_affected_test.go | 4 +- 4 files changed, 94 insertions(+), 49 deletions(-) diff --git a/internal/exec/atlantis_generate_repo_config.go b/internal/exec/atlantis_generate_repo_config.go index 2f63a2f31..d95a82238 100644 --- a/internal/exec/atlantis_generate_repo_config.go +++ b/internal/exec/atlantis_generate_repo_config.go @@ -154,11 +154,11 @@ func ExecuteAtlantisGenerateRepoConfigAffectedOnly( var err error if repoPath != "" { - affected, _, _, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, false, false) + affected, _, _, _, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, false, false) } else if cloneTargetRef { - affected, _, _, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, false, false) + affected, _, _, _, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, false, false) } else { - affected, _, _, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, false, false) + affected, _, _, _, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, false, false) } if err != nil { diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index 5385fa36a..d1fdc2870 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -124,13 +124,14 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { var affected []schema.Affected var headHead, baseHead *plumbing.Reference + var repoUrl string if repoPath != "" { - affected, headHead, baseHead, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, headHead, baseHead, repoUrl, err = ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, verbose, includeSpaceliftAdminStacks, includeSettings) } else if cloneTargetRef { - affected, headHead, baseHead, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, headHead, baseHead, repoUrl, err = ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, sshKeyPath, sshKeyPassword, verbose, includeSpaceliftAdminStacks, includeSettings) } else { - affected, headHead, baseHead, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, includeSpaceliftAdminStacks, includeSettings) + affected, headHead, baseHead, repoUrl, err = ExecuteDescribeAffectedWithTargetRefCheckout(cliConfig, ref, sha, verbose, includeSpaceliftAdminStacks, includeSettings) } if err != nil { @@ -153,6 +154,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { } // Upload the affected components and stacks to a specified endpoint + // https://www.digitalocean.com/community/tutorials/how-to-make-http-requests-in-go if upload { baseUrl := os.Getenv(cfg.AtmosProBaseUrlEnvVarName) if baseUrl == "" { @@ -165,6 +167,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { body := map[string]any{ "head_sha": headHead.Hash().String(), "base_sha": baseHead.Hash().String(), + "repo_url": repoUrl, "stacks": affected, } diff --git a/internal/exec/describe_affected_utils.go b/internal/exec/describe_affected_utils.go index 94a4343fa..8d8586d9e 100644 --- a/internal/exec/describe_affected_utils.go +++ b/internal/exec/describe_affected_utils.go @@ -39,7 +39,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) { if verbose { cliConfig.Logs.Level = u.LogLevelTrace @@ -52,18 +52,18 @@ func ExecuteDescribeAffectedWithTargetRefClone( EnableDotGitCommonDir: false, }) if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } // Get the Git config of the local repo localRepoConfig, err := localRepo.Config() if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } localRepoWorktree, err := localRepo.Worktree() if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } localRepoPath := localRepoWorktree.Filesystem.Root() @@ -75,18 +75,18 @@ func ExecuteDescribeAffectedWithTargetRefClone( } if len(keys) == 0 { - return nil, nil, nil, localRepoIsNotGitRepoError + return nil, nil, nil, "", localRepoIsNotGitRepoError } - // Get the origin URL of the current remoteRepo + // Get the URL of the repo remoteUrls := localRepoConfig.Remotes[keys[0]].URLs if len(remoteUrls) == 0 { - return nil, nil, nil, localRepoIsNotGitRepoError + return nil, nil, nil, "", localRepoIsNotGitRepoError } repoUrl := remoteUrls[0] if repoUrl == "" { - return nil, nil, nil, localRepoIsNotGitRepoError + return nil, nil, nil, "", localRepoIsNotGitRepoError } // Clone the remote repo @@ -101,7 +101,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( // Create a temp dir to clone the remote repo to tempDir, err := os.MkdirTemp("", strconv.FormatInt(time.Now().Unix(), 10)) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } defer removeTempDir(cliConfig, tempDir) @@ -132,12 +132,12 @@ func ExecuteDescribeAffectedWithTargetRefClone( if sshKeyPath != "" { sshKeyContent, err := os.ReadFile(sshKeyPath) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } sshPublicKey, err := ssh.NewPublicKeys("git", sshKeyContent, sshKeyPassword) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } // Use the SSH key to clone the repo @@ -150,12 +150,12 @@ func ExecuteDescribeAffectedWithTargetRefClone( remoteRepo, err := git.PlainClone(tempDir, false, &cloneOptions) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } remoteRepoHead, err := remoteRepo.Head() if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } if ref != "" { @@ -170,7 +170,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( w, err := remoteRepo.Worktree() if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } checkoutOptions := git.CheckoutOptions{ @@ -182,7 +182,7 @@ func ExecuteDescribeAffectedWithTargetRefClone( err = w.Checkout(&checkoutOptions) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } u.LogTrace(cliConfig, fmt.Sprintf("\nChecked out commit SHA '%s'\n", sha)) @@ -199,10 +199,10 @@ func ExecuteDescribeAffectedWithTargetRefClone( includeSettings, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } - return affected, localRepoHead, remoteRepoHead, nil + return affected, localRepoHead, remoteRepoHead, repoUrl, nil } // ExecuteDescribeAffectedWithTargetRefCheckout checks out the target reference, @@ -214,7 +214,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) { if verbose { cliConfig.Logs.Level = u.LogLevelTrace @@ -227,26 +227,47 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( EnableDotGitCommonDir: false, }) if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } // Check the Git config of the local repo - _, err = localRepo.Config() + localRepoConfig, err := localRepo.Config() if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } localRepoWorktree, err := localRepo.Worktree() if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } localRepoPath := localRepoWorktree.Filesystem.Root() + // Get the remotes of the local repo + keys := []string{} + for k := range localRepoConfig.Remotes { + keys = append(keys, k) + } + + if len(keys) == 0 { + return nil, nil, nil, "", localRepoIsNotGitRepoError + } + + // Get the URL of the repo + remoteUrls := localRepoConfig.Remotes[keys[0]].URLs + if len(remoteUrls) == 0 { + return nil, nil, nil, "", localRepoIsNotGitRepoError + } + + repoUrl := remoteUrls[0] + if repoUrl == "" { + return nil, nil, nil, "", localRepoIsNotGitRepoError + } + // Create a temp dir for the target ref tempDir, err := os.MkdirTemp("", strconv.FormatInt(time.Now().Unix(), 10)) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } defer removeTempDir(cliConfig, tempDir) @@ -267,7 +288,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( } if err = cp.Copy(localRepoPath, tempDir, copyOptions); err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } u.LogTrace(cliConfig, fmt.Sprintf("Copied the local repo into the temp directory '%s'\n", tempDir)) @@ -277,13 +298,13 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( EnableDotGitCommonDir: false, }) if err != nil { - return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, remoteRepoIsNotGitRepoError) } // Check the Git config of the target ref _, err = remoteRepo.Config() if err != nil { - return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, remoteRepoIsNotGitRepoError) } if sha != "" { @@ -291,7 +312,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( w, err := remoteRepo.Worktree() if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } checkoutOptions := git.CheckoutOptions{ @@ -303,7 +324,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( err = w.Checkout(&checkoutOptions) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } u.LogTrace(cliConfig, fmt.Sprintf("Checked out commit SHA '%s'\n", sha)) @@ -317,7 +338,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( w, err := remoteRepo.Worktree() if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } checkoutOptions := git.CheckoutOptions{ @@ -335,7 +356,7 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( "\nrefer to https://atmos.tools/cli/commands/describe/affected for more details", ref) err = errors.New(errorMessage) } - return nil, nil, nil, err + return nil, nil, nil, "", err } u.LogTrace(cliConfig, fmt.Sprintf("Checked out Git ref '%s'\n", ref)) @@ -352,10 +373,10 @@ func ExecuteDescribeAffectedWithTargetRefCheckout( includeSettings, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } - return affected, localRepoHead, remoteRepoHead, nil + return affected, localRepoHead, remoteRepoHead, repoUrl, nil } // ExecuteDescribeAffectedWithTargetRepoPath uses `repo-path` to access the target repo, and processes stack configs @@ -366,7 +387,7 @@ func ExecuteDescribeAffectedWithTargetRepoPath( verbose bool, includeSpaceliftAdminStacks bool, includeSettings bool, -) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, error) { +) ([]schema.Affected, *plumbing.Reference, *plumbing.Reference, string, error) { localPath := "." @@ -375,34 +396,55 @@ func ExecuteDescribeAffectedWithTargetRepoPath( EnableDotGitCommonDir: false, }) if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } // Check the Git config of the local repo - _, err = localRepo.Config() + localRepoConfig, err := localRepo.Config() if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } localRepoWorktree, err := localRepo.Worktree() if err != nil { - return nil, nil, nil, errors.Join(err, localRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, localRepoIsNotGitRepoError) } localRepoPath := localRepoWorktree.Filesystem.Root() + // Get the remotes of the local repo + keys := []string{} + for k := range localRepoConfig.Remotes { + keys = append(keys, k) + } + + if len(keys) == 0 { + return nil, nil, nil, "", localRepoIsNotGitRepoError + } + + // Get the URL of the repo + remoteUrls := localRepoConfig.Remotes[keys[0]].URLs + if len(remoteUrls) == 0 { + return nil, nil, nil, "", localRepoIsNotGitRepoError + } + + repoUrl := remoteUrls[0] + if repoUrl == "" { + return nil, nil, nil, "", localRepoIsNotGitRepoError + } + remoteRepo, err := git.PlainOpenWithOptions(targetRefPath, &git.PlainOpenOptions{ DetectDotGit: false, EnableDotGitCommonDir: false, }) if err != nil { - return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, remoteRepoIsNotGitRepoError) } // Check the Git config of the remote target repo _, err = remoteRepo.Config() if err != nil { - return nil, nil, nil, errors.Join(err, remoteRepoIsNotGitRepoError) + return nil, nil, nil, "", errors.Join(err, remoteRepoIsNotGitRepoError) } affected, localRepoHead, remoteRepoHead, err := executeDescribeAffected( @@ -416,10 +458,10 @@ func ExecuteDescribeAffectedWithTargetRepoPath( includeSettings, ) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, "", err } - return affected, localRepoHead, remoteRepoHead, nil + return affected, localRepoHead, remoteRepoHead, repoUrl, nil } func executeDescribeAffected( diff --git a/pkg/describe/describe_affected_test.go b/pkg/describe/describe_affected_test.go index b9cc30daf..f74ac972f 100644 --- a/pkg/describe/describe_affected_test.go +++ b/pkg/describe/describe_affected_test.go @@ -28,7 +28,7 @@ func TestDescribeAffectedWithTargetRefClone(t *testing.T) { ref := "refs/heads/main" sha := "" - affected, _, _, err := e.ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, "", "", true, true, true) + affected, _, _, _, err := e.ExecuteDescribeAffectedWithTargetRefClone(cliConfig, ref, sha, "", "", true, true, true) assert.Nil(t, err) affectedYaml, err := yaml.Marshal(affected) @@ -52,7 +52,7 @@ func TestDescribeAffectedWithTargetRepoPath(t *testing.T) { // This will compare this local repository with itself as the remote target, which should result in an empty `affected` list repoPath := "../../" - affected, _, _, err := e.ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, true, true, true) + affected, _, _, _, err := e.ExecuteDescribeAffectedWithTargetRepoPath(cliConfig, repoPath, true, true, true) assert.Nil(t, err) affectedYaml, err := yaml.Marshal(affected) From 5360d911d9bac669095eee1ca1888c3ef5291084 Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 16:29:11 -0400 Subject: [PATCH 06/13] updates --- internal/exec/describe_affected.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index d1fdc2870..96dcfe1a6 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -207,7 +207,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { }(resp.Body) if resp.StatusCode != http.StatusOK { - err = fmt.Errorf("\nError uploading the affected components and stacks to %s\nStatus: %s", url, resp.Status) + err = fmt.Errorf("\nError uploading the affected components and stacks to %s\nStatus: %s\n", url, resp.Status) return err } From 4219d9c56ef969fd846c2ed87a515afb745d2b4c Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 20:03:17 -0400 Subject: [PATCH 07/13] updates --- cmd/describe_affected.go | 2 +- internal/exec/describe_affected.go | 13 ++- pkg/config/const.go | 9 +- .../commands/describe/describe-affected.mdx | 85 +++++++++++++++---- 4 files changed, 85 insertions(+), 24 deletions(-) diff --git a/cmd/describe_affected.go b/cmd/describe_affected.go index 229f2d7b5..a1a8542cb 100644 --- a/cmd/describe_affected.go +++ b/cmd/describe_affected.go @@ -38,7 +38,7 @@ func init() { describeAffectedCmd.PersistentFlags().Bool("include-spacelift-admin-stacks", false, "Include the Spacelift admin stack of any stack that is affected by config changes: atmos describe affected --include-spacelift-admin-stacks=true") describeAffectedCmd.PersistentFlags().Bool("include-dependents", false, "Include the dependent components and stacks: atmos describe affected --include-dependents=true") describeAffectedCmd.PersistentFlags().Bool("include-settings", false, "Include the 'settings' section for each affected component: atmos describe affected --include-settings=true") - describeAffectedCmd.PersistentFlags().Bool("upload", false, "Upload the affected components and stacks to a specified endpoint: atmos describe affected --upload=true") + describeAffectedCmd.PersistentFlags().Bool("upload", false, "Upload the affected components and stacks to a specified HTTP endpoint: atmos describe affected --upload=true") describeAffectedCmd.PersistentFlags().Bool("clone-target-ref", false, "Clone the target reference with which to compare the current branch: atmos describe affected --clone-target-ref=true\n"+ "If set to 'false' (default), the target reference will be checked out instead\n"+ "This requires that the target reference is already cloned by Git, and the information about it exists in the '.git' directory") diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index 96dcfe1a6..cf9e6fd19 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -155,14 +155,16 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { // Upload the affected components and stacks to a specified endpoint // https://www.digitalocean.com/community/tutorials/how-to-make-http-requests-in-go - if upload { + if upload && len(affected) > 0 { baseUrl := os.Getenv(cfg.AtmosProBaseUrlEnvVarName) if baseUrl == "" { baseUrl = cfg.AtmosProDefaultBaseUrl } - url := fmt.Sprintf("%s/%s", baseUrl, cfg.AtmosProDefaultEndpoint) - - token := os.Getenv(cfg.AtmosProTokenEnvVarName) + endpoint := os.Getenv(cfg.AtmosProEndpointEnvVarName) + if endpoint == "" { + endpoint = cfg.AtmosProDefaultEndpoint + } + url := fmt.Sprintf("%s/%s", baseUrl, endpoint) body := map[string]any{ "head_sha": headHead.Hash().String(), @@ -186,6 +188,9 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { req.Header.Set("Content-Type", "application/json") + // Authorization header + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization + token := os.Getenv(cfg.AtmosProTokenEnvVarName) if token != "" { req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) } diff --git a/pkg/config/const.go b/pkg/config/const.go index 7bd85443c..98765bed2 100644 --- a/pkg/config/const.go +++ b/pkg/config/const.go @@ -62,8 +62,9 @@ const ( SettingsListMergeStrategyFlag = "--settings-list-merge-strategy" // Atmos Pro - AtmosProTokenEnvVarName = "ATMOS_PRO_TOKEN" - AtmosProBaseUrlEnvVarName = "ATMOS_PRO_BASE_URL" - AtmosProDefaultBaseUrl = "https://app.cloudposse.com" - AtmosProDefaultEndpoint = "api/affected-stacks" + AtmosProBaseUrlEnvVarName = "ATMOS_PRO_BASE_URL" + AtmosProEndpointEnvVarName = "ATMOS_PRO_ENDPOINT" + AtmosProTokenEnvVarName = "ATMOS_PRO_TOKEN" + AtmosProDefaultBaseUrl = "https://app.cloudposse.com" + AtmosProDefaultEndpoint = "api/affected-stacks" ) diff --git a/website/docs/cli/commands/describe/describe-affected.mdx b/website/docs/cli/commands/describe/describe-affected.mdx index b399412e3..78ade538b 100644 --- a/website/docs/cli/commands/describe/describe-affected.mdx +++ b/website/docs/cli/commands/describe/describe-affected.mdx @@ -201,21 +201,21 @@ Affected components and stacks: ## Flags -| Flag | Description | Required | -|:-----------------------------------|:----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------| -| `--ref` | [Git Reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References) with which to compare the current working branch | no | -| `--sha` | Git commit SHA with which to compare the current working branch | no | -| `--file` | If specified, write the result to the file | no | -| `--format` | Specify the output format: `json` or `yaml` (`json` is default) | no | -| `--ssh-key` | Path to PEM-encoded private key to clone private repos using SSH | no | -| `--ssh-key-password` | Encryption password for the PEM-encoded private key if the key contains
a password-encrypted PEM block | no | -| `--repo-path` | Path to the already cloned target repository with which to compare the current branch.
Conflicts with `--ref`, `--sha`, `--ssh-key` and `--ssh-key-password` | no | -| `--verbose` | Print more detailed output when cloning and checking out the target
Git repository and processing the result | no | -| `--include-spacelift-admin-stacks` | Include the Spacelift admin stack of any stack
that is affected by config changes | no | -| `--clone-target-ref` | Clone the target reference with which to compare the current branch.
`atmos describe affected --clone-target-ref=true`

If set to `false` (default), the target reference will be checked out instead
This requires that the target reference is already cloned by Git,
and the information about it exists in the `.git` directory | no | -| `--include-dependents` | Include the dependent components and stacks.
`atmos describe affected --include-dependents=true` | no | -| `--include-settings` | Include the `settings` section for each affected component.
`atmos describe affected --include-settings=true` | no | -| `--upload` | Upload the affected components and stacks to a specified endpoint for
further processing in a CI/CD pipeline.

`atmos describe affected --upload=true`

Atmos will perform an HTTP POST request to the endpoint
`${ATMOS_PRO_BASE_URL}/api/affected-stacks`
where the base URL is defined using the `ATMOS_PRO_BASE_URL` environment variable.
The `token` for the `Authorization: Bearer ` header can be specified
using the `ATMOS_PRO_TOKEN` environment variable | no | +| Flag | Description | Required | +|:-----------------------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------| +| `--ref` | [Git Reference](https://git-scm.com/book/en/v2/Git-Internals-Git-References) with which to compare the current working branch | no | +| `--sha` | Git commit SHA with which to compare the current working branch | no | +| `--file` | If specified, write the result to the file | no | +| `--format` | Specify the output format: `json` or `yaml` (`json` is default) | no | +| `--ssh-key` | Path to PEM-encoded private key to clone private repos using SSH | no | +| `--ssh-key-password` | Encryption password for the PEM-encoded private key if the key contains
a password-encrypted PEM block | no | +| `--repo-path` | Path to the already cloned target repository with which to compare the current branch.
Conflicts with `--ref`, `--sha`, `--ssh-key` and `--ssh-key-password` | no | +| `--verbose` | Print more detailed output when cloning and checking out the target
Git repository and processing the result | no | +| `--include-spacelift-admin-stacks` | Include the Spacelift admin stack of any stack
that is affected by config changes | no | +| `--clone-target-ref` | Clone the target reference with which to compare the current branch.
`atmos describe affected --clone-target-ref=true`

If set to `false` (default), the target reference will be checked out instead
This requires that the target reference is already cloned by Git,
and the information about it exists in the `.git` directory | no | +| `--include-dependents` | Include the dependent components and stacks.
`atmos describe affected --include-dependents=true` | no | +| `--include-settings` | Include the `settings` section for each affected component.
`atmos describe affected --include-settings=true` | no | +| `--upload` | Upload the affected components and stacks to a specified HTTP endpoint.

`atmos describe affected --upload=true`

Atmos will perform an HTTP POST request
to the URL `${ATMOS_PRO_BASE_URL}/${ATMOS_PRO_ENDPOINT}`,
where the base URL is defined by the `ATMOS_PRO_BASE_URL` environment variable,
and the URL path is defined by the `ATMOS_PRO_ENDPOINT`environment variable. | no | ## Output @@ -715,3 +715,58 @@ private repo which is not itself): ```shell atmos describe affected --repo-path $GITHUB_WORKSPACE ``` + +## Upload the affected components and stacks to an HTTP endpoint + +If the `--upload=true` command-line flag is passed, Atmos will upload the affected components and stacks to a +specified HTTP endpoint. + +The endpoint can process the affected components and their dependencies in a CI/CD pipeline (e.g. execute +`terraform apply` on all the affected components in the stacks and all dependencies). + +Atmos will perform an HTTP POST request to the URL `${ATMOS_PRO_BASE_URL}/${ATMOS_PRO_ENDPOINT}`, where the base URL +is defined by the `ATMOS_PRO_BASE_URL` environment variable, and the URL path is defined by the `ATMOS_PRO_ENDPOINT` +environment variable. + +An [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization) header +`Authorization: Bearer $ATMOS_PRO_TOKEN` will be added to the HTTP request (if the `ATMOS_PRO_TOKEN` environment +variable is set) to provide credentials to authenticate with the server. + +:::note +If the `--upload=true` command-line flag is passed, the `--include-dependencies` flag is automatically set to `true`, +so the affected components will always be uploaded with their dependencies (if they are configured in Atmos stack manifests). +::: + +The payload of the HTTP POST request will be a JSON object with the following schema: + + + ```json + { + "base_sha": "6746ba4df9e87690c33297fe740011e5ccefc1f9", + "head_sha": "5360d911d9bac669095eee1ca1888c3ef5291084", + "repo_url": "https://github.com/cloudposse/atmos", + "stacks": [ + { + "component": "vpc", + "component_type": "terraform", + "component_path": "examples/quick-start/components/terraform/vpc", + "stack": "plat-ue2-dev", + "stack_slug": "plat-ue2-dev-vpc", + "affected": "stack.vars", + "included_in_dependents": false, + "dependents": [...] + } + ] + } + ``` + + +where: + +- `base_sha` - the Git commit SHA of the base branch against which the changes in the current commit are compared + +- `head_sha` - the SHA of the current Git commit + +- `repo_url` - the URL of the current repository + +- `stacks` - a list of affected components and stacks with their dependencies From f4ec5cacb86c6a2f31dc5fe55c4ebb478bdf8352 Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 20:08:49 -0400 Subject: [PATCH 08/13] updates --- website/docs/cli/commands/describe/describe-affected.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/cli/commands/describe/describe-affected.mdx b/website/docs/cli/commands/describe/describe-affected.mdx index 78ade538b..73e7950b0 100644 --- a/website/docs/cli/commands/describe/describe-affected.mdx +++ b/website/docs/cli/commands/describe/describe-affected.mdx @@ -754,7 +754,7 @@ The payload of the HTTP POST request will be a JSON object with the following sc "stack_slug": "plat-ue2-dev-vpc", "affected": "stack.vars", "included_in_dependents": false, - "dependents": [...] + "dependents": [] } ] } From edbf38f085d1988cd1698228120c192b4f792059 Mon Sep 17 00:00:00 2001 From: aknysh Date: Thu, 20 Jun 2024 20:09:37 -0400 Subject: [PATCH 09/13] updates --- website/docs/cli/commands/describe/describe-affected.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/cli/commands/describe/describe-affected.mdx b/website/docs/cli/commands/describe/describe-affected.mdx index 73e7950b0..93fec6447 100644 --- a/website/docs/cli/commands/describe/describe-affected.mdx +++ b/website/docs/cli/commands/describe/describe-affected.mdx @@ -722,7 +722,7 @@ If the `--upload=true` command-line flag is passed, Atmos will upload the affect specified HTTP endpoint. The endpoint can process the affected components and their dependencies in a CI/CD pipeline (e.g. execute -`terraform apply` on all the affected components in the stacks and all dependencies). +`terraform apply` on all the affected components in the stacks and all the dependencies). Atmos will perform an HTTP POST request to the URL `${ATMOS_PRO_BASE_URL}/${ATMOS_PRO_ENDPOINT}`, where the base URL is defined by the `ATMOS_PRO_BASE_URL` environment variable, and the URL path is defined by the `ATMOS_PRO_ENDPOINT` From c623786e877339c6cd3f164a779c9551527056ee Mon Sep 17 00:00:00 2001 From: aknysh Date: Fri, 21 Jun 2024 02:09:35 -0400 Subject: [PATCH 10/13] updates --- .../commands/describe/describe-affected.mdx | 32 +++++++++++++------ website/docs/cli/configuration.mdx | 8 ++--- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/website/docs/cli/commands/describe/describe-affected.mdx b/website/docs/cli/commands/describe/describe-affected.mdx index 93fec6447..7ff0f1768 100644 --- a/website/docs/cli/commands/describe/describe-affected.mdx +++ b/website/docs/cli/commands/describe/describe-affected.mdx @@ -133,8 +133,8 @@ Total 4215 (delta 658), reused 911 (delta 511), pack-reused 3058 Checked out Git ref 'refs/heads/main' -Current working repo HEAD: 7d37c1e890514479fae404d13841a2754be70cbf refs/heads/describe-affected -Remote repo HEAD: 40210e8d365d3d88ac13c0778c0867b679bbba69 refs/heads/main +Current HEAD: 7d37c1e890514479fae404d13841a2754be70cbf refs/heads/describe-affected +Base HEAD: 40210e8d365d3d88ac13c0778c0867b679bbba69 refs/heads/main Changed files: @@ -763,10 +763,24 @@ The payload of the HTTP POST request will be a JSON object with the following sc where: -- `base_sha` - the Git commit SHA of the base branch against which the changes in the current commit are compared - -- `head_sha` - the SHA of the current Git commit - -- `repo_url` - the URL of the current repository - -- `stacks` - a list of affected components and stacks with their dependencies +
+
`base_sha`
+
+ the Git commit SHA of the base branch against which the changes in the current commit are compared +
+ +
`head_sha`
+
+ the SHA of the current Git commit +
+ +
`repo_url`
+
+ the URL of the current repository +
+ +
`stacks`
+
+ a list of affected components and stacks with their dependencies +
+
diff --git a/website/docs/cli/configuration.mdx b/website/docs/cli/configuration.mdx index 7e594a61c..193f32359 100644 --- a/website/docs/cli/configuration.mdx +++ b/website/docs/cli/configuration.mdx @@ -753,8 +753,8 @@ logs: Checking out Git ref 'refs/remotes/origin/HEAD' ... Checked out Git ref 'refs/remotes/origin/HEAD' -Current working repo HEAD: ffd2154e1daa32357b75460b9f45d268922b51e1 refs/heads/update-logs -Remote repo HEAD: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD +Current HEAD: ffd2154e1daa32357b75460b9f45d268922b51e1 refs/heads/update-logs +Base HEAD: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD Changed files: @@ -816,8 +816,8 @@ but the command's JSON output is printed to `/dev/stdout`, allowing `jq` to pars Checking out Git ref 'refs/remotes/origin/HEAD' ... Checked out Git ref 'refs/remotes/origin/HEAD' -Current working repo HEAD: ffd2154e1daa32357b75460b9f45d268922b51e1 refs/heads/update-logs -Remote repo HEAD: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD +Current HEAD: ffd2154e1daa32357b75460b9f45d268922b51e1 refs/heads/update-logs +Base HEAD: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD # NOTE: This JSON output is printed to `/dev/stdout` From 76763f0d161df9ebb183ce5b7d802b4ed3692d41 Mon Sep 17 00:00:00 2001 From: aknysh Date: Fri, 21 Jun 2024 11:14:51 -0400 Subject: [PATCH 11/13] updates --- go.mod | 5 ++- go.sum | 10 ++++-- internal/exec/describe_affected.go | 22 +++++++++--- internal/exec/describe_affected_utils.go | 6 +++- pkg/schema/schema.go | 4 +-- .../commands/describe/describe-affected.mdx | 34 +++++++++++++++---- website/docs/cli/configuration.mdx | 4 +-- 7 files changed, 65 insertions(+), 20 deletions(-) diff --git a/go.mod b/go.mod index 68c2bbb95..b32b58f46 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/arsham/figurine v1.3.0 github.com/bmatcuk/doublestar/v4 v4.6.1 github.com/charmbracelet/bubbles v0.18.0 - github.com/charmbracelet/bubbletea v0.26.4 + github.com/charmbracelet/bubbletea v0.26.5 github.com/charmbracelet/lipgloss v0.11.0 github.com/elewis787/boa v0.1.2 github.com/fatih/color v1.17.0 @@ -26,6 +26,7 @@ require ( github.com/ivanpirog/coloredcobra v1.0.1 github.com/json-iterator/go v1.1.12 github.com/jwalton/go-supportscolor v1.2.0 + github.com/kubescape/go-git-url v0.0.30 github.com/lrstanley/bubblezone v0.0.0-20240616011544-69b11dddf9ae github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/mapstructure v1.5.0 @@ -90,6 +91,7 @@ require ( github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 // indirect github.com/cenkalti/backoff/v3 v3.2.2 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/chainguard-dev/git-urls v1.0.2 // indirect github.com/charmbracelet/x/ansi v0.1.2 // indirect github.com/charmbracelet/x/input v0.1.2 // indirect github.com/charmbracelet/x/term v0.1.1 // indirect @@ -254,6 +256,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a // indirect k8s.io/client-go v0.26.2 // indirect + k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 // indirect oras.land/oras-go/v2 v2.3.1 // indirect sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/go.sum b/go.sum index 2e7917063..b5ff502ad 100644 --- a/go.sum +++ b/go.sum @@ -383,10 +383,12 @@ github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghf github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/chainguard-dev/git-urls v1.0.2 h1:pSpT7ifrpc5X55n4aTTm7FFUE+ZQHKiqpiwNkJrVcKQ= +github.com/chainguard-dev/git-urls v1.0.2/go.mod h1:rbGgj10OS7UgZlbzdUQIQpT0k/D4+An04HJY7Ol+Y/o= github.com/charmbracelet/bubbles v0.18.0 h1:PYv1A036luoBGroX6VWjQIE9Syf2Wby2oOl/39KLfy0= github.com/charmbracelet/bubbles v0.18.0/go.mod h1:08qhZhtIwzgrtBjAcJnij1t1H0ZRjwHyGsy6AL11PSw= -github.com/charmbracelet/bubbletea v0.26.4 h1:2gDkkzLZaTjMl/dQBpNVtnvcCxsh/FCkimep7FC9c40= -github.com/charmbracelet/bubbletea v0.26.4/go.mod h1:P+r+RRA5qtI1DOHNFn0otoNwB4rn+zNAzSj/EXz6xU0= +github.com/charmbracelet/bubbletea v0.26.5 h1:90pqTPElAReb/qQUgSMUresTkfwVr0Wx+zczeHHOgxk= +github.com/charmbracelet/bubbletea v0.26.5/go.mod h1:dz8CWPlfCCGLFbBlTY4N7bjLiyOGDJEnd2Muu7pOWhk= github.com/charmbracelet/lipgloss v0.11.0 h1:UoAcbQ6Qml8hDwSWs0Y1cB5TEQuZkDPH/ZqwWWYTG4g= github.com/charmbracelet/lipgloss v0.11.0/go.mod h1:1UdRTH9gYgpcdNN5oBtjbu/IzNKtzVtb7sqN1t9LNn8= github.com/charmbracelet/x/ansi v0.1.2 h1:6+LR39uG8DE6zAmbu023YlqjJHkYXDF1z36ZwzO4xZY= @@ -907,6 +909,8 @@ github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kubescape/go-git-url v0.0.30 h1:PIbg86ae0ftee/p/Tu/6CA1ju6VoJ51G3sQWNHOm6wg= +github.com/kubescape/go-git-url v0.0.30/go.mod h1:3ddc1HEflms1vMhD9owt/3FBES070UaYTUarcjx8jDk= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= @@ -1903,6 +1907,8 @@ inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a h1:1XCVEdxrvL6c0TGOhecLuB7U9z inet.af/netaddr v0.0.0-20230525184311-b8eac61e914a/go.mod h1:e83i32mAQOW1LAqEIweALsuK2Uw4mhQadA5r7b0Wobo= k8s.io/client-go v0.26.2 h1:s1WkVujHX3kTp4Zn4yGNFK+dlDXy1bAAkIl+cFAiuYI= k8s.io/client-go v0.26.2/go.mod h1:u5EjOuSyBa09yqqyY7m3abZeovO/7D/WehVVlZ2qcqU= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5 h1:kmDqav+P+/5e1i9tFfHq1qcF3sOrDp+YEkVDAHu7Jwk= +k8s.io/utils v0.0.0-20230220204549-a5ecb0141aa5/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index cf9e6fd19..0ff7ed870 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -10,6 +10,7 @@ import ( "time" "github.com/go-git/go-git/v5/plumbing" + giturl "github.com/kubescape/go-git-url" "github.com/spf13/cobra" cfg "github.com/cloudposse/atmos/pkg/config" @@ -114,8 +115,10 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { return errors.New("if the '--repo-path' flag is specified, the '--ref', '--sha', '--ssh-key' and '--ssh-key-password' flags can't be used") } + // When uploading, always include dependents and settings for all affected components if upload { includeDependents = true + includeSettings = true } if verbose { @@ -155,7 +158,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { // Upload the affected components and stacks to a specified endpoint // https://www.digitalocean.com/community/tutorials/how-to-make-http-requests-in-go - if upload && len(affected) > 0 { + if upload { baseUrl := os.Getenv(cfg.AtmosProBaseUrlEnvVarName) if baseUrl == "" { baseUrl = cfg.AtmosProDefaultBaseUrl @@ -166,11 +169,20 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { } url := fmt.Sprintf("%s/%s", baseUrl, endpoint) + // Parse the repo URL + gitURL, err := giturl.NewGitURL(repoUrl) + if err != nil { + return err + } + body := map[string]any{ - "head_sha": headHead.Hash().String(), - "base_sha": baseHead.Hash().String(), - "repo_url": repoUrl, - "stacks": affected, + "head_sha": headHead.Hash().String(), + "base_sha": baseHead.Hash().String(), + "repo_url": repoUrl, + "repo_name": gitURL.GetRepoName(), + "repo_owner": gitURL.GetOwnerName(), + "repo_host": gitURL.GetHostName(), + "stacks": affected, } bodyJson, err := u.ConvertToJSON(body) diff --git a/internal/exec/describe_affected_utils.go b/internal/exec/describe_affected_utils.go index 8d8586d9e..db7ac3da0 100644 --- a/internal/exec/describe_affected_utils.go +++ b/internal/exec/describe_affected_utils.go @@ -490,7 +490,7 @@ func executeDescribeAffected( } u.LogTrace(cliConfig, fmt.Sprintf("Current HEAD: %s", localRepoHead)) - u.LogTrace(cliConfig, fmt.Sprintf("Base HEAD: %s", remoteRepoHead)) + u.LogTrace(cliConfig, fmt.Sprintf("BASE: %s", remoteRepoHead)) currentStacks, err := ExecuteDescribeStacks(cliConfig, "", nil, nil, nil, false) if err != nil { @@ -1506,6 +1506,8 @@ func addDependentsToAffected(cliConfig schema.CliConfiguration, affected *[]sche if err != nil { return err } + } else { + a.Dependents = []schema.Dependent{} } } @@ -1529,6 +1531,8 @@ func addDependentsToDependents(cliConfig schema.CliConfiguration, dependents *[] if err != nil { return err } + } else { + d.Dependents = []schema.Dependent{} } } diff --git a/pkg/schema/schema.go b/pkg/schema/schema.go index 9f1904f7e..09c655684 100644 --- a/pkg/schema/schema.go +++ b/pkg/schema/schema.go @@ -434,9 +434,9 @@ type Affected struct { Affected string `yaml:"affected" json:"affected" mapstructure:"affected"` File string `yaml:"file,omitempty" json:"file,omitempty" mapstructure:"file"` Folder string `yaml:"folder,omitempty" json:"folder,omitempty" mapstructure:"folder"` - Dependents []Dependent `yaml:"dependents,omitempty" json:"dependents,omitempty" mapstructure:"dependents"` + Dependents []Dependent `yaml:"dependents" json:"dependents" mapstructure:"dependents"` IncludedInDependents bool `yaml:"included_in_dependents" json:"included_in_dependents" mapstructure:"included_in_dependents"` - Settings map[any]any `yaml:"settings,omitempty" json:"settings,omitempty" mapstructure:"settings"` + Settings map[any]any `yaml:"settings" json:"settings" mapstructure:"settings"` } type BaseComponentConfig struct { diff --git a/website/docs/cli/commands/describe/describe-affected.mdx b/website/docs/cli/commands/describe/describe-affected.mdx index 7ff0f1768..0c40468c9 100644 --- a/website/docs/cli/commands/describe/describe-affected.mdx +++ b/website/docs/cli/commands/describe/describe-affected.mdx @@ -134,7 +134,7 @@ Total 4215 (delta 658), reused 911 (delta 511), pack-reused 3058 Checked out Git ref 'refs/heads/main' Current HEAD: 7d37c1e890514479fae404d13841a2754be70cbf refs/heads/describe-affected -Base HEAD: 40210e8d365d3d88ac13c0778c0867b679bbba69 refs/heads/main +BASE: 40210e8d365d3d88ac13c0778c0867b679bbba69 refs/heads/main Changed files: @@ -236,7 +236,7 @@ Each object has the following schema: "file": ".....", "folder": ".....", "dependents": [], - "included_in_dependents": "true | false" + "included_in_dependents": "true | false", "settings": {} } ``` @@ -266,7 +266,7 @@ where: - `folder` - if the Atmos component depends on an external folder, and any file in the folder was changed (see `affected.folder` below), the `folder` attributes shows the modified folder -- `dependents` - list of components that depend on the current affected component. It will be included only if the +- `dependents` - list of components that depend on the current affected component. It will be populated only if the command-line flag `--include-dependents=true` is passed (to take dependencies into account) and there are other components that depend on the affected component in the stack. Refer to [`atmos describe dependents`](/cli/commands/describe/dependents) for more details. The `dependents` property is @@ -733,8 +733,9 @@ An [Authorization](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Aut variable is set) to provide credentials to authenticate with the server. :::note -If the `--upload=true` command-line flag is passed, the `--include-dependencies` flag is automatically set to `true`, -so the affected components will always be uploaded with their dependencies (if they are configured in Atmos stack manifests). +If the `--upload=true` command-line flag is passed, the `--include-dependencies` and `--include-settings` flags are +automatically set to `true`, so the affected components will be uploaded with their dependencies and settings +(if they are configured in Atmos stack manifests). ::: The payload of the HTTP POST request will be a JSON object with the following schema: @@ -745,6 +746,9 @@ The payload of the HTTP POST request will be a JSON object with the following sc "base_sha": "6746ba4df9e87690c33297fe740011e5ccefc1f9", "head_sha": "5360d911d9bac669095eee1ca1888c3ef5291084", "repo_url": "https://github.com/cloudposse/atmos", + "repo_host": "github.com", + "repo_name": "atmos", + "repo_owner": "cloudposse", "stacks": [ { "component": "vpc", @@ -754,7 +758,8 @@ The payload of the HTTP POST request will be a JSON object with the following sc "stack_slug": "plat-ue2-dev-vpc", "affected": "stack.vars", "included_in_dependents": false, - "dependents": [] + "dependents": [], + "settings": {} } ] } @@ -779,8 +784,23 @@ where: the URL of the current repository +
`repo_name`
+
+ the name of the current repository +
+ +
`repo_owner`
+
+ the owner of the current repository +
+ +
`repo_host`
+
+ the host of the current repository +
+
`stacks`
- a list of affected components and stacks with their dependencies + a list of affected components and stacks with their dependencies and settings
diff --git a/website/docs/cli/configuration.mdx b/website/docs/cli/configuration.mdx index 193f32359..fb5f37866 100644 --- a/website/docs/cli/configuration.mdx +++ b/website/docs/cli/configuration.mdx @@ -754,7 +754,7 @@ Checking out Git ref 'refs/remotes/origin/HEAD' ... Checked out Git ref 'refs/remotes/origin/HEAD' Current HEAD: ffd2154e1daa32357b75460b9f45d268922b51e1 refs/heads/update-logs -Base HEAD: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD +BASE: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD Changed files: @@ -817,7 +817,7 @@ but the command's JSON output is printed to `/dev/stdout`, allowing `jq` to pars Checking out Git ref 'refs/remotes/origin/HEAD' ... Checked out Git ref 'refs/remotes/origin/HEAD' Current HEAD: ffd2154e1daa32357b75460b9f45d268922b51e1 refs/heads/update-logs -Base HEAD: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD +BASE: f7aa382aa8b3d48be8f06cfdb27aad344b89aff4 HEAD # NOTE: This JSON output is printed to `/dev/stdout` From f83a5df96d39e5afb7ffb9946bf3a38a05bc1062 Mon Sep 17 00:00:00 2001 From: aknysh Date: Fri, 21 Jun 2024 18:42:55 -0400 Subject: [PATCH 12/13] updates --- go.mod | 2 +- go.sum | 4 ++-- internal/exec/describe_affected.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index b32b58f46..5403a7f5f 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/google/go-github/v59 v59.0.0 github.com/google/uuid v1.6.0 github.com/hairyhenderson/gomplate/v3 v3.11.8 - github.com/hashicorp/go-getter v1.7.4 + github.com/hashicorp/go-getter v1.7.5 github.com/hashicorp/hcl v1.0.0 github.com/hashicorp/hcl/v2 v2.21.0 github.com/hashicorp/terraform-config-inspect v0.0.0-20240607080351-271db412dbcb diff --git a/go.sum b/go.sum index b5ff502ad..8700ebd4e 100644 --- a/go.sum +++ b/go.sum @@ -730,8 +730,8 @@ github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtng github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0= -github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= +github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-hclog v0.16.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index 0ff7ed870..fb7bb117f 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -223,7 +223,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { } }(resp.Body) - if resp.StatusCode != http.StatusOK { + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { err = fmt.Errorf("\nError uploading the affected components and stacks to %s\nStatus: %s\n", url, resp.Status) return err } From e01214a5b5b1a31a6c597fc83be41652b26a70b7 Mon Sep 17 00:00:00 2001 From: aknysh Date: Sat, 22 Jun 2024 00:04:21 -0400 Subject: [PATCH 13/13] updates --- internal/exec/describe_affected.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/exec/describe_affected.go b/internal/exec/describe_affected.go index fb7bb117f..690d8e600 100644 --- a/internal/exec/describe_affected.go +++ b/internal/exec/describe_affected.go @@ -223,7 +223,7 @@ func ExecuteDescribeAffectedCmd(cmd *cobra.Command, args []string) error { } }(resp.Body) - if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusMultipleChoices { + if resp.StatusCode < http.StatusOK || resp.StatusCode >= http.StatusBadRequest { err = fmt.Errorf("\nError uploading the affected components and stacks to %s\nStatus: %s\n", url, resp.Status) return err }