Skip to content

feat: add atmos pro install command with workflow scaffolding - #2288

Open
Erik Osterman (Cloud Posse) (osterman) wants to merge 27 commits into
mainfrom
osterman/pro-install-cmd
Open

Erik Osterman (Cloud Posse) (osterman) wants to merge 27 commits into
mainfrom
osterman/pro-install-cmd

Conversation

@osterman

@osterman Erik Osterman (Cloud Posse) (osterman) commented Apr 6, 2026 •

Copy link
Copy Markdown
Member

what

  • Add new atmos pro install command that scaffolds Atmos Pro configuration files into a project
  • Modernize the pro command from legacy direct-registration pattern to the CommandProvider registry pattern (like cmd/ci/, cmd/ai/)
  • Generate 4 GitHub Actions workflows: plan, apply, drift-detection, drift-remediation
  • Generate profiles/github/atmos.yaml auth profile with OIDC placeholder values
  • Generate stacks/mixins/atmos-pro.yaml mixin and update stacks/deploy/_defaults.yaml
  • Display a "Next Steps" markdown guide after installation covering OIDC, IAM roles, workspace setup
  • Support --yes, --force, --dry-run flags with interactive charm/huh confirmation prompts

why

  • Users need a streamlined way to onboard to Atmos Pro without manually creating workflow files, auth profiles, and stack configuration
  • The pro command was the last remaining command using the old registration pattern — this brings it in line with the modern CommandProvider architecture
  • Cannot assume reference architecture conventions, so generated files use generic templates with placeholders and guide users through remaining manual steps

references

Summary by CodeRabbit

  • New Features

    • Added a new "pro" command group with install, lock, and unlock subcommands.
    • pro install scaffolds Atmos Pro integration (workflows, auth profiles, mixin, .atmos.d), offers dry-run preview, non-interactive confirm (--yes), and overwrite (--force); prints next steps and can open onboarding URL.
    • pro lock/unlock manage stack locks with component/stack, message, and TTL controls.
  • Documentation

    • New CLI docs, blog post, and roadmap entry describing the Pro install flow.
  • Chores

    • Standard flags now include a --force option.

…vider

Modernize the `pro` command from the legacy direct-registration pattern to the
CommandProvider registry pattern, and add a new `atmos pro install` subcommand
that scaffolds GitHub Actions workflows, auth profiles, and stack configuration
for Atmos Pro integration.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added the size/l Large size PR label Apr 6, 2026
@mergify mergify Bot added the triage Needs triage label Apr 6, 2026
@coderabbitai

coderabbitai Bot commented Apr 6, 2026 •

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a new cohesive cmd/pro package with a pro command provider and subcommands (install, lock, unlock); implements pro install to scaffold Atmos Pro workflows/config and interactive UX; introduces pkg/pro/install installer with templates/options/tests; and extends standard flags with --force.

Changes

Cohort / File(s) Summary
Pro command package
cmd/pro/pro.go, cmd/pro/lock.go, cmd/pro/unlock.go, cmd/pro/pro_test.go, cmd/root.go
Introduce pro command provider, register install, lock, unlock subcommands, add provider tests, and blank-import cmd/pro in root for side-effect registration.
Removed legacy pro files
cmd/pro.go (deleted), cmd/pro_lock.go (deleted), cmd/pro_unlock.go (deleted), cmd/pro_lock_test.go (deleted), cmd/pro_unlock_test.go (deleted), cmd/pro_test.go (deleted)
Remove previous scattered pro command implementations and their tests replaced by the new cmd/pro package.
pro install CLI & docs
cmd/pro/install.go, cmd/pro/markdown/atmos_pro_install.md, cmd/pro/markdown/atmos_pro_install_next_steps.md, website/docs/cli/commands/pro/pro-install.mdx, website/blog/2026-04-06-pro-install-command.mdx
Add pro install Cobra command (flags: --yes/-y, --force/-f, --dry-run), embedded long/help Markdown, confirmation and overwrite prompts, dry-run support, reporting, next-steps output and docs/blog.
Installer core & options
pkg/pro/install/install.go, pkg/pro/install/options.go, pkg/pro/install/install_test.go
Add installer package with Installer, Install/DryRun, FileWriter interface and OSFileWriter, functional options (WithBasePath, WithStacksBasePath, WithForce, WithDryRun, WithOnConflict), conflict handling, and tests using mock writers.
Installer templates
pkg/pro/install/templates.go, pkg/pro/install/templates/... (workflows/, profiles/, atmos.d/, mixins/, atmos.yaml)
Embed templates for GitHub Actions workflows, auth profiles (github-plan/github-apply), mixin, CI drop-ins, and atmos.yaml anchor used by the installer.
Installer templates docs
pkg/pro/install/templates/profiles/README.md, pkg/pro/install/templates/profiles/*, pkg/pro/install/templates/mixins/atmos-pro.yaml
Add profiles README and profile templates plus mixin YAML for Pro workflow triggers and guidance.
Flags framework
pkg/flags/standard_builder.go, pkg/flags/standard_options.go, pkg/flags/standard_parser.go, pkg/flags/standard_builder_test.go
Add Force bool to StandardOptions, implement WithForce() builder, populate Force during parsing, and add unit test for --force flag.
Website roadmap
website/src/data/roadmap.js
Add roadmap entry for pro-install feature.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as "atmos pro install"
    participant Config as "Resolve Paths"
    participant Prompt as "User Prompt"
    participant Installer as "Installer"
    participant FS as "FileWriter (OS/Mock)"
    participant Browser as "Browser (open URL)"
    User->>CLI: run command (flags)
    CLI->>Config: resolve install paths (global flags / config)
    alt not --yes and not --dry-run
        CLI->>Prompt: confirm installation?
        Prompt-->>CLI: confirm/decline
    end
    CLI->>Installer: create installer (BasePath, StacksBasePath, Force, OnConflict)
    alt --dry-run
        Installer->>FS: check file existence (no writes)
        FS-->>Installer: existence info
        Installer-->>CLI: dry-run report
    else
        Installer->>FS: check file existence
        alt conflict and not --force
            CLI->>Prompt: "Overwrite <path>?"
            Prompt-->>Installer: decision
        end
        Installer->>FS: mkdir/write files
        FS-->>Installer: write results
        Installer-->>CLI: install result (created/updated/skipped)
        alt not --yes
            CLI->>Prompt: "Open onboarding workspace?"
            Prompt-->>CLI: decision
            alt open chosen
                CLI->>Browser: open workspace URL
                Browser-->>CLI: success/fail
            end
        end
    end
    CLI->>User: print report & next steps
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • aknysh
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.21% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and specifically describes the main change: adding a new atmos pro install command with workflow scaffolding, which aligns with the primary objective of the changeset.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch osterman/pro-install-cmd

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (6)
cmd/pro/lock.go (1)

10-16: Add concrete command examples to help output.

The command definition is clear, but it lacks Example usage, which makes first-time usage harder.

💡 Suggested improvement
 var lockCmd = &cobra.Command{
 	Use:   "lock",
 	Short: "Lock a stack",
 	Long:  `This command calls the atmos pro API and locks a stack`,
+	Example: `  $ atmos pro lock -c vpc -s plat-ue2-dev
+  $ atmos pro lock -c vpc -s plat-ue2-dev -m "maintenance window" -t 1800`,
 	Args:  cobra.NoArgs,
 	RunE:  e.ExecuteProLockCommand,
 }

As per coding guidelines: "Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/pro/lock.go` around lines 10 - 16, Add concrete usage examples to the
Cobra command definition for lockCmd: populate the Example field on lockCmd with
one or more realistic command lines (e.g., basic usage and a usage with common
flags/env) so users see how to call the command; update the lockCmd declaration
(the variable named lockCmd that uses e.ExecuteProLockCommand) to include
Example: "<example strings>" and ensure examples follow Cobra/Go doc conventions
and reflect typical invocations of the pro lock command.
cmd/pro/unlock.go (1)

10-16: Add examples to pro unlock help.

The command is missing Example guidance for common usage.

💡 Suggested improvement
 var unlockCmd = &cobra.Command{
 	Use:   "unlock",
 	Short: "Unlock a stack",
 	Long:  `This command calls the atmos pro API and unlocks a stack`,
+	Example: `  $ atmos pro unlock -c vpc -s plat-ue2-dev`,
 	Args:  cobra.NoArgs,
 	RunE:  e.ExecuteProUnlockCommand,
 }

As per coding guidelines: "Provide comprehensive help text for all commands and flags, include examples in command help, and follow Go's documentation conventions in Cobra command definitions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/pro/unlock.go` around lines 10 - 16, The unlockCmd Cobra command is
missing an Example field in its help; add an Example string to the unlockCmd
definition (near the existing Use/Short/Long/Args/RunE) showing common usage
patterns (e.g., basic unlock, unlocking with flags or environment examples) so
users see concrete commands in help output; update the unlockCmd variable's
struct to include Example: with one or more lines illustrating typical
invocations that correspond to the behavior implemented by
ExecuteProUnlockCommand.
pkg/pro/install/templates/atmos-pro-terraform-drift-detection.yaml (1)

11-36: Add overlap and hang protection for scheduled drift detection.

Line 11 schedule can stack runs under load. Add workflow/job guards to keep one active run and cap execution time.

♻️ Suggested hardening
 on:
   schedule:
     - cron: "0 */4 * * *"
   workflow_dispatch: {}

+concurrency:
+  group: atmos-pro-drift-detection
+  cancel-in-progress: false
+
 permissions:
   id-token: write
   contents: read
   issues: write

 jobs:
   detect:
+    timeout-minutes: 60
     runs-on: ubuntu-latest
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/pro/install/templates/atmos-pro-terraform-drift-detection.yaml` around
lines 11 - 36, Add concurrency and job timeout to prevent overlapping and
hanging runs: add a top-level concurrency stanza with a unique group (e.g.,
using vars.ATMOS_VERSION or 'atmos-drift-detect') and cancel-in-progress: true
to keep only one active workflow, and add timeout-minutes under the detect job
(or use a step-level timeout wrapper) to cap execution time for the job that
runs the "Detect Drift" step which executes atmos pro drift detect; update the
file to include these keys around the existing schedule and the detect job to
ensure overlap and hang protection.
pkg/pro/install/templates/atmos-pro-terraform-drift-remediation.yaml (1)

11-37: Prevent duplicate remediation runs per issue.

Line 11 onward allows multiple runs for the same issue when labels are toggled/reapplied. Add a concurrency key on issue number to avoid overlapping remediations.

♻️ Suggested hardening
 on:
   issues:
     types:
       - labeled

+concurrency:
+  group: atmos-pro-drift-remediation-${{ github.event.issue.number }}
+  cancel-in-progress: true
+
 permissions:
   id-token: write
   contents: read
   issues: write
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/pro/install/templates/atmos-pro-terraform-drift-remediation.yaml` around
lines 11 - 37, Add a GitHub Actions concurrency block to the remediate job to
ensure only one remediation runs per issue at a time: inside the job named
"remediate" add a concurrency stanza with a group key that includes the issue
number (e.g., group: remediate-issue-${{ github.event.issue.number }}) and set
cancel-in-progress to false so new triggers for the same issue are queued and do
not overlap with the running run.
pkg/pro/install/install.go (1)

276-299: Edge case: prepending import to files with YAML document markers.

If _defaults.yaml starts with --- (YAML document marker) or comments, prepending import: creates a multi-document file or puts the import before the marker. This is an edge case but worth noting.

Possible enhancement
 // No import section found - prepend one.
+// Handle files starting with document marker.
+if strings.HasPrefix(strings.TrimSpace(content), "---") {
+	// Insert after the document marker line
+	for idx, line := range lines {
+		if strings.TrimSpace(line) == "---" {
+			result := make([]string, 0, len(lines)+2)
+			result = append(result, lines[:idx+1]...)
+			result = append(result, "import:")
+			result = append(result, importLine)
+			result = append(result, lines[idx+1:]...)
+			return strings.Join(result, "\n")
+		}
+	}
+}
 importSection := "import:\n" + importLine + "\n\n"
 return importSection + content
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/pro/install/install.go` around lines 276 - 299, The addImport function
incorrectly prepends an import section before leading YAML document markers or
comments; update addImport to detect and preserve a leading YAML document marker
("---") and any consecutive leading comment lines (lines starting with "#") by
inserting the new "import:" section after those markers/comments instead of at
the file start; modify the logic in addImport (use the existing lines slice and
importLine/importSection names) to scan from the top for a contiguous block of
empty lines, a single initial "---" and subsequent comment lines, compute the
insertion index after that block, and insert the import section there when no
existing "import:" header is found.
cmd/pro/install.go (1)

54-96: Add perf.Track to runInstall.

Per coding guidelines, public functions with I/O should include performance tracking. The runInstall function performs file operations and user prompts.

Suggested fix
 func runInstall(cmd *cobra.Command, _ []string) error {
+	defer perf.Track(nil, "pro.runInstall")()
+
 	yes, _ := cmd.Flags().GetBool("yes")

Also add the import:

+	"github.com/cloudposse/atmos/pkg/perf"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/pro/install.go` around lines 54 - 96, Add a perf.Track call to runInstall
to measure its I/O work: invoke perf.Track at the start of runInstall (and defer
its finish) so the whole function runtime including resolveInstallPaths,
flags.PromptForConfirmation, installer.DryRun and installer.Install is recorded;
also add the perf import to the file. Ensure the tracking uses a clear name
(e.g., "cmd.pro.install.runInstall") and that the defer is placed immediately
after starting the track so all subsequent operations are covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/pro/lock.go`:
- Around line 21-22: The help text for the flags registered on lockCmd is
inconsistent with their actual default values; update the flag registrations so
the declared defaults match runtime defaults by setting the StringP for
"message" to default "Locked by Atmos" and the Int32P for "ttl" to default 30
(keep the help text as-is), i.e., change the default values passed to
lockCmd.PersistentFlags().StringP("message", "m", ...) and
lockCmd.PersistentFlags().Int32P("ttl", "t", ...).

In `@cmd/pro/unlock.go`:
- Around line 19-20: The flag descriptions for the unlock command are incorrect:
update the two calls to unlockCmd.PersistentFlags().StringP("component", "c",
...) and unlockCmd.PersistentFlags().StringP("stack", "s", ...) to say "Specify
the Atmos component to unlock" and "Specify the Atmos stack to unlock"
respectively so the help text accurately reflects the command action.

In `@pkg/pro/install/install.go`:
- Around line 140-146: The current block treats any ReadFile error as a silent
skip; update the logic around i.writer.FileExists/defaultsPath and
i.writer.ReadFile so that when ReadFile returns an error you capture and report
it instead of silently appending to result.SkippedFiles: keep the successful
path (if err == nil && !hasImport(...)) that appends to result.UpdatedFiles, but
in the else branch when err != nil log or record the error (e.g. append a
formatted error to result.Errors or add an entry to a result.FileErrors map
keyed by i.defaultsRelPath()) using the actual err from i.writer.ReadFile and
then mark the file appropriately (SkippedFiles or FailedFiles); reference the
symbols defaultsPath, i.writer.ReadFile, hasImport, i.defaultsRelPath,
result.UpdatedFiles and result.SkippedFiles when making the change.

In `@pkg/pro/install/templates/atmos-pro-terraform-apply.yaml`:
- Line 42: The inline shell command `atmos terraform apply ${{ inputs.component
}} -s ${{ inputs.stack }} --auto-approve` interpolates unquoted workflow inputs
and is vulnerable to command injection and breaking on spaces; fix it by quoting
each interpolation (e.g., wrap `${{ inputs.component }}` and `${{ inputs.stack
}}` in quotes) so the shell treats them as single arguments, or pass them as
action inputs/arguments safely rather than concatenating into an unquoted bash
line; locate the command string and update the `${{ inputs.component }}` and
`${{ inputs.stack }}` usages to be quoted before executing.

In `@pkg/pro/install/templates/atmos-pro-terraform-plan.yaml`:
- Line 42: The workflow invokes the shell with unquoted inputs in the command
"atmos terraform plan ${{ inputs.component }} -s ${{ inputs.stack }}", which is
unsafe for values with spaces or special chars; update that invocation to wrap
both inputs in quotes so the shell sees each input as a single argument (i.e.,
quote the expressions for inputs.component and inputs.stack in the atmos
terraform plan command) and ensure any downstream usage still expects a single
argument per input.

---

Nitpick comments:
In `@cmd/pro/install.go`:
- Around line 54-96: Add a perf.Track call to runInstall to measure its I/O
work: invoke perf.Track at the start of runInstall (and defer its finish) so the
whole function runtime including resolveInstallPaths,
flags.PromptForConfirmation, installer.DryRun and installer.Install is recorded;
also add the perf import to the file. Ensure the tracking uses a clear name
(e.g., "cmd.pro.install.runInstall") and that the defer is placed immediately
after starting the track so all subsequent operations are covered.

In `@cmd/pro/lock.go`:
- Around line 10-16: Add concrete usage examples to the Cobra command definition
for lockCmd: populate the Example field on lockCmd with one or more realistic
command lines (e.g., basic usage and a usage with common flags/env) so users see
how to call the command; update the lockCmd declaration (the variable named
lockCmd that uses e.ExecuteProLockCommand) to include Example: "<example
strings>" and ensure examples follow Cobra/Go doc conventions and reflect
typical invocations of the pro lock command.

In `@cmd/pro/unlock.go`:
- Around line 10-16: The unlockCmd Cobra command is missing an Example field in
its help; add an Example string to the unlockCmd definition (near the existing
Use/Short/Long/Args/RunE) showing common usage patterns (e.g., basic unlock,
unlocking with flags or environment examples) so users see concrete commands in
help output; update the unlockCmd variable's struct to include Example: with one
or more lines illustrating typical invocations that correspond to the behavior
implemented by ExecuteProUnlockCommand.

In `@pkg/pro/install/install.go`:
- Around line 276-299: The addImport function incorrectly prepends an import
section before leading YAML document markers or comments; update addImport to
detect and preserve a leading YAML document marker ("---") and any consecutive
leading comment lines (lines starting with "#") by inserting the new "import:"
section after those markers/comments instead of at the file start; modify the
logic in addImport (use the existing lines slice and importLine/importSection
names) to scan from the top for a contiguous block of empty lines, a single
initial "---" and subsequent comment lines, compute the insertion index after
that block, and insert the import section there when no existing "import:"
header is found.

In `@pkg/pro/install/templates/atmos-pro-terraform-drift-detection.yaml`:
- Around line 11-36: Add concurrency and job timeout to prevent overlapping and
hanging runs: add a top-level concurrency stanza with a unique group (e.g.,
using vars.ATMOS_VERSION or 'atmos-drift-detect') and cancel-in-progress: true
to keep only one active workflow, and add timeout-minutes under the detect job
(or use a step-level timeout wrapper) to cap execution time for the job that
runs the "Detect Drift" step which executes atmos pro drift detect; update the
file to include these keys around the existing schedule and the detect job to
ensure overlap and hang protection.

In `@pkg/pro/install/templates/atmos-pro-terraform-drift-remediation.yaml`:
- Around line 11-37: Add a GitHub Actions concurrency block to the remediate job
to ensure only one remediation runs per issue at a time: inside the job named
"remediate" add a concurrency stanza with a group key that includes the issue
number (e.g., group: remediate-issue-${{ github.event.issue.number }}) and set
cancel-in-progress to false so new triggers for the same issue are queued and do
not overlap with the running run.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e65ba3fd-a7da-434a-acba-2db874ea01e6

📥 Commits

Reviewing files that changed from the base of the PR and between d0e8092 and 2aa3040.

📒 Files selected for processing (25)
  • cmd/pro.go
  • cmd/pro/install.go
  • cmd/pro/lock.go
  • cmd/pro/markdown/atmos_pro_install.md
  • cmd/pro/markdown/atmos_pro_install_next_steps.md
  • cmd/pro/pro.go
  • cmd/pro/pro_test.go
  • cmd/pro/unlock.go
  • cmd/pro_lock.go
  • cmd/pro_lock_test.go
  • cmd/pro_test.go
  • cmd/pro_unlock.go
  • cmd/pro_unlock_test.go
  • cmd/root.go
  • pkg/pro/install/install.go
  • pkg/pro/install/install_test.go
  • pkg/pro/install/options.go
  • pkg/pro/install/templates.go
  • pkg/pro/install/templates/atmos-pro-mixin.yaml
  • pkg/pro/install/templates/atmos-pro-terraform-apply.yaml
  • pkg/pro/install/templates/atmos-pro-terraform-drift-detection.yaml
  • pkg/pro/install/templates/atmos-pro-terraform-drift-remediation.yaml
  • pkg/pro/install/templates/atmos-pro-terraform-plan.yaml
  • pkg/pro/install/templates/defaults-snippet.yaml
  • pkg/pro/install/templates/github-profile-atmos.yaml
💤 Files with no reviewable changes (6)
  • cmd/pro_test.go
  • cmd/pro.go
  • cmd/pro_unlock_test.go
  • cmd/pro_unlock.go
  • cmd/pro_lock_test.go
  • cmd/pro_lock.go

Comment thread cmd/pro/lock.go Outdated
Comment thread cmd/pro/unlock.go Outdated
Comment thread pkg/pro/install/install.go Outdated
Comment thread pkg/pro/install/templates/atmos-pro-terraform-apply.yaml Outdated
Comment thread pkg/pro/install/templates/atmos-pro-terraform-plan.yaml Outdated
Align scaffolded templates with a production Atmos Pro deployment:
- Delete hallucinated drift-remediation workflow
- Replace drift-detection with affected-stacks and list-instances workflows
- Add sha input, concurrency, ATMOS_PRO_WORKSPACE_ID, --upload-status to plan/apply
- Use `atmos terraform deploy` (not apply --auto-approve) for apply workflow
- Split single auth profile into github-plan and github-apply profiles
- Add drift_detection detect/remediate and github_environment to mixin
- Prevent command injection by passing inputs via env vars in run blocks
- Organize templates into subfolders (workflows/, profiles/, mixins/, stacks/)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add OnConflict callback to installer options for handling file conflicts:
- With --force: overwrite all files without prompting
- Interactive TTY (no --force): prompt per-file via PromptForConfirmation
- Non-TTY (no --force): error out via ErrInteractiveNotAvailable

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

♻️ Duplicate comments (1)
pkg/pro/install/install.go (1)

141-146: ⚠️ Potential issue | 🟡 Minor

Handle _defaults.yaml read failures explicitly in dry-run results.

Right now, Line 141 read failures are reported as “skipped,” which hides real errors (e.g., permissions) and misleads the preview output.

Suggested adjustment
 	if i.writer.FileExists(defaultsPath) {
 		content, err := i.writer.ReadFile(defaultsPath)
-		if err == nil && !hasImport(string(content), "mixins/atmos-pro") {
+		if err != nil {
+			// Surface read failure clearly in dry-run output strategy.
+			result.SkippedFiles = append(result.SkippedFiles, i.defaultsRelPath())
+			// Consider extending InstallResult with FileErrors for precise reporting.
+		} else if !hasImport(string(content), "mixins/atmos-pro") {
 			result.UpdatedFiles = append(result.UpdatedFiles, i.defaultsRelPath())
 		} else {
 			result.SkippedFiles = append(result.SkippedFiles, i.defaultsRelPath())
 		}
 	} else {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/pro/install/install.go` around lines 141 - 146, The current logic treats
any ReadFile error from i.writer.ReadFile(defaultsPath) as a skipped file;
change it to handle read failures explicitly by checking if err != nil first and
recording the failure in the dry-run result (e.g., append i.defaultsRelPath() to
a result.Errors/FailedFiles slice or set result.Error with context) instead of
result.SkippedFiles, and only use hasImport(string(content), "mixins/atmos-pro")
to decide UpdatedFiles vs SkippedFiles when err == nil; modify the block around
i.writer.ReadFile, hasImport, and i.defaultsRelPath() to reflect this explicit
error path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/pro/install.go`:
- Around line 40-42: The current code returns a silent fallback ("." / "stacks")
whenever InitCliConfig returns an error; change this so InitCliConfig errors are
propagated to the caller (or a clear user-facing warning is emitted) instead of
using the default paths, except when the error explicitly indicates a "config
not found" condition; locate the call to InitCliConfig in the install flow (the
function handling install paths in cmd/pro/install.go), check for a specific
sentinel or typed error (e.g., ErrConfigNotFound) and only allow fallback in
that case, otherwise return the InitCliConfig error (or log a clear, actionable
message and return an error) so we don't write scaffolding into unintended
locations.
- Around line 31-35: Replace direct installCmd.Flags().BoolP(...) calls in
init() with a StandardParser: declare a package-level var installParser
*flags.StandardParser, initialize it in init() via flags.NewStandardParser(...)
using flags.WithBoolFlag for "yes" (short "y"), "force" (short "f") and
"dry-run" (no short), then call installParser.RegisterFlags(installCmd); remove
the BoolP bindings. In runInstall(), call
installParser.BindFlagsToViper(installCmd, v) to bind flags into Viper so flag
parsing follows the repo's standard pattern.

In `@pkg/pro/install/install.go`:
- Around line 273-279: The current code calls addImport(...) and then
unconditionally writes the updated file via i.writer.WriteFile, bypassing the
per-file conflict flow; change this to respect the installer's conflict policy
by invoking the existing OnConflict flow (or the installer option that handles
--force) before mutating the file: after computing updated := addImport(...),
call the installer conflict-check helper (e.g., OnConflict(relPath) or the
method that returns whether to overwrite when not forced), and only proceed to
i.writer.WriteFile(fullPath, ...), append to result.UpdatedFiles and return nil
if the conflict handler permits the overwrite (or if force is true); otherwise
skip writing and do not modify result.UpdatedFiles. Ensure you reference
addImport, i.writer.WriteFile, OnConflict (or the installer conflict helper),
fullPath, relPath, and result.UpdatedFiles in your change so the write respects
the user's conflict choice.

In `@pkg/pro/install/templates/profiles/README.md`:
- Around line 32-52: The example YAML blocks use a top-level identities: key but
the real schema expects auth.identities; update both example blocks so
identities is nested under an auth: mapping (i.e., replace the top-level
identities: with auth: then indent identities: under it), preserving the
existing identity name (<tenant>-<stage>/terraform), kind (aws/assume-role),
via/provider, and principal/assume_role fields so the examples match the
auth.identities schema.

In `@pkg/pro/install/templates/workflows/atmos-pro-terraform-plan.yaml`:
- Around line 15-17: The workflow defines an optional input named sha but later
uses it directly in the checkout action (ref: ${{ inputs.sha }}), which can be
empty and cause checkout to default to HEAD; either make the input required by
adding "sha: required: true" to the inputs block so callers must pass it, or
update the checkout reference to use a deterministic fallback (e.g., replace
uses of ref: ${{ inputs.sha }} with a safe expression that falls back to
github.sha when inputs.sha is empty) so the plan runs against the intended
commit; locate the inputs block containing "sha" and the checkout step
referencing inputs.sha to apply one of these fixes.

---

Duplicate comments:
In `@pkg/pro/install/install.go`:
- Around line 141-146: The current logic treats any ReadFile error from
i.writer.ReadFile(defaultsPath) as a skipped file; change it to handle read
failures explicitly by checking if err != nil first and recording the failure in
the dry-run result (e.g., append i.defaultsRelPath() to a
result.Errors/FailedFiles slice or set result.Error with context) instead of
result.SkippedFiles, and only use hasImport(string(content), "mixins/atmos-pro")
to decide UpdatedFiles vs SkippedFiles when err == nil; modify the block around
i.writer.ReadFile, hasImport, and i.defaultsRelPath() to reflect this explicit
error path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6e0af561-14f8-4fa3-a246-d890f1733496

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa3040 and 0bfc225.

📒 Files selected for processing (15)
  • cmd/pro/install.go
  • cmd/pro/markdown/atmos_pro_install_next_steps.md
  • pkg/pro/install/install.go
  • pkg/pro/install/install_test.go
  • pkg/pro/install/options.go
  • pkg/pro/install/templates.go
  • pkg/pro/install/templates/mixins/atmos-pro.yaml
  • pkg/pro/install/templates/profiles/README.md
  • pkg/pro/install/templates/profiles/github-apply.yaml
  • pkg/pro/install/templates/profiles/github-plan.yaml
  • pkg/pro/install/templates/stacks/defaults-snippet.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-affected-stacks.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-list-instances.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-apply.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-plan.yaml
✅ Files skipped from review due to trivial changes (8)
  • pkg/pro/install/templates/stacks/defaults-snippet.yaml
  • pkg/pro/install/templates/profiles/github-apply.yaml
  • pkg/pro/install/templates/mixins/atmos-pro.yaml
  • cmd/pro/markdown/atmos_pro_install_next_steps.md
  • pkg/pro/install/templates/profiles/github-plan.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-apply.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-affected-stacks.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-list-instances.yaml
🚧 Files skipped from review as they are similar to previous changes (3)
  • pkg/pro/install/options.go
  • pkg/pro/install/install_test.go
  • pkg/pro/install/templates.go

Comment thread cmd/pro/install.go
Comment thread cmd/pro/install.go
Comment thread pkg/pro/install/install.go Outdated
Comment thread pkg/pro/install/templates/profiles/README.md
Comment thread pkg/pro/install/templates/workflows/atmos-pro-terraform-plan.yaml
Fix lock flag help text to clarify effective defaults without changing
sentinel values, fix unlock flag descriptions (copy-paste "lock" → "unlock"),
and handle ReadFile error explicitly in DryRun. Add WithForce() to
StandardOptionsBuilder for consistent --force flag across commands.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Apr 7, 2026 •

Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues found.

Scanned Files

None

@osterman Erik Osterman (Cloud Posse) (osterman) added the minor New features that do not break anything label Apr 7, 2026
@github-actions

github-actions Bot commented Apr 7, 2026 •

Copy link
Copy Markdown

Note

Release Documentation Complete ✅

  • Changelog: website/blog/2026-04-06-pro-install-command.mdx
  • Roadmap: website/src/data/roadmap.js

Thank you!

@github-actions

github-actions Bot commented Apr 7, 2026

Copy link
Copy Markdown

Warning

Release Documentation Required

This PR is labeled minor or major and requires documentation updates:

  • Changelog entry - Add a blog post in website/blog/YYYY-MM-DD-feature-name.mdx
  • Roadmap update - Update website/src/data/roadmap.js with the new milestone

Alternatively: If this change doesn't require release documentation, remove the minor or major label.

Refactor install flags to use flags.NewStandardParser() with Viper
integration for proper CLI > ENV > config precedence. Surface warning
when atmos config fails to load instead of silent fallback. Respect
OnConflict policy before mutating existing _defaults.yaml. Fix profile
README examples to match auth.identities schema. Add sha fallback in
workflow checkout steps to prevent empty-ref defaulting to HEAD.
Add blog post and roadmap entry for pro install command.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@codecov

codecov Bot commented Apr 7, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 70.05650% with 318 lines in your changes missing coverage. Please review.
✅ Project coverage is 80.53%. Comparing base (1bc4cd3) to head (930a6d1).
⚠️ Report is 103 commits behind head on main.

Files with missing lines Patch % Lines
pkg/mcp/install/install.go 66.13% 82 Missing and 46 partials ⚠️
cmd/mcp/client/install.go 34.16% 99 Missing and 7 partials ⚠️
cmd/pro/install.go 80.00% 39 Missing and 19 partials ⚠️
pkg/mcp/client/session.go 34.61% 16 Missing and 1 partial ⚠️
pkg/mcp/client/config.go 75.00% 4 Missing and 2 partials ⚠️
pkg/pro/install/install.go 98.13% 2 Missing ⚠️
cmd/pro/commit.go 83.33% 1 Missing ⚠️

❌ Your patch check has failed because the patch coverage (70.05%) is below the target coverage (80.00%). You can increase the patch coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #2288      +/-   ##
==========================================
- Coverage   80.58%   80.53%   -0.06%     
==========================================
  Files        1524     1529       +5     
  Lines      144122   145142    +1020     
==========================================
+ Hits       116142   116888     +746     
- Misses      21466    21666     +200     
- Partials     6514     6588      +74     
Flag Coverage Δ
unittests 80.53% <70.05%> (-0.06%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cmd/pro/lock.go 100.00% <100.00%> (ø)
cmd/pro/pro.go 100.00% <100.00%> (ø)
cmd/pro/unlock.go 100.00% <100.00%> (ø)
cmd/root.go 71.04% <ø> (ø)
pkg/flags/standard_builder.go 95.84% <100.00%> (+0.07%) ⬆️
pkg/flags/standard_options.go 25.00% <ø> (ø)
pkg/flags/standard_parser.go 95.56% <100.00%> (+0.02%) ⬆️
pkg/mcp/client/mcpconfig.go 82.66% <100.00%> (+2.36%) ⬆️
pkg/pro/install/options.go 100.00% <100.00%> (ø)
pkg/schema/mcp.go 100.00% <100.00%> (ø)
... and 7 more

... and 7 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…and roadmap

- Replace hardcoded deploy/_defaults.yaml with .atmos.d/ci.yaml and
  .atmos.d/atmos-pro.yaml drop-in configuration files
- Create minimal atmos.yaml when missing as anchor for drop-in configs
- Add documentation page for atmos pro install command
- Add blog post and roadmap entry for the feature
- Fix next steps links to use atmos-pro.com URLs consistently
- Wrap filenames in backticks in status output
- Add blank line before next steps markdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add browser prompt after installation to open workspace creation page
- Update ci.yaml template with full output/summary/checks config
- Simplify atmos-pro.yaml to commented workspace_id with !env reference
- Fix next steps to use consistent "See: ..." link style

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add OSFileWriter tests (WriteFile, ReadFile, FileExists, MkdirAll)
- Add error path tests (MkdirAll failure, WriteFile failure)
- Add DryRun with existing files and force override tests
- Add custom stacks path test
- Add WithOnConflict option test
- Add reportResult and reportDryRun tests
- Add ProCommandProvider nil-return method tests
- Add embedded markdown content tests
- pkg/pro/install coverage: 100%

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (1)
cmd/pro/pro_test.go (1)

153-192: Assert the rendered report, not just “no panic”.

These subtests will miss regressions in created/updated/skipped reporting because they never inspect what reportResult or reportDryRun actually emit. Capture the UI stream, or route the formatter through an injected writer, and assert the rendered lines instead.

As per coding guidelines, "Test behavior, not implementation. Never test stub functions. Avoid tautological tests. Make code testable via dependency injection. No coverage theater."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/pro/pro_test.go` around lines 153 - 192, The tests for reportResult and
reportDryRun only assert “no panic” and miss regressions in the actual output;
update the tests to capture and assert the rendered report text by routing the
formatter to a test writer or capturing the UI output instead of only calling
reportResult/reportDryRun. Specifically, modify TestReportResult and
TestReportDryRun to provide a bytes.Buffer (or captured UI stream) to the code
path used by reportResult and reportDryRun, call those functions with the
InstallResult cases, and assert that the buffer contains the expected lines for
CreatedFiles, UpdatedFiles, and SkippedFiles (and the empty-result case) so the
tests verify actual rendered output.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@cmd/pro/install.go`:
- Around line 76-78: The post-install workspace prompt is invoked
unconditionally via promptOpenWorkspace() even when the --yes flag (variable
yes) is set; update the code to skip or short-circuit promptOpenWorkspace when
yes is true (either by gating calls with if !yes { promptOpenWorkspace(...) } or
by passing the yes flag into promptOpenWorkspace and handling it there), and
apply the same change to the other promptOpenWorkspace invocations in this file
so interactive runs with --yes do not stop for an extra prompt.
- Around line 52-67: resolveInstallPaths currently calls cfg.InitCliConfig with
an empty schema.ConfigAndStacksInfo which ignores global flags; update
runInstall to call flags.ParseGlobalFlags(cmd, &cfgInfo) to populate a
schema.ConfigAndStacksInfo variable (e.g., cfgInfo) and then pass that populated
cfgInfo into cfg.InitCliConfig instead of an empty struct, ensuring
resolveInstallPaths (and the similar block around lines 70-80) use the parsed
global flags when resolving basePath and stacksBasePath; keep function names:
resolveInstallPaths, runInstall, cfg.InitCliConfig, schema.ConfigAndStacksInfo,
and flags.ParseGlobalFlags to locate the changes.

In `@pkg/flags/standard_builder.go`:
- Around line 164-172: The WithForce() builder registers a duplicate shorthand
"-f" colliding with WithFormat(); update StandardOptionsBuilder.WithForce to
stop passing the shorthand to WithBoolFlag (use no shorthand / empty string) so
it only registers the long name "force" and env var via WithEnvVars("force",
"ATMOS_FORCE"); leave perf.Track, the append to b.options, and WithEnvVars
intact.

In `@pkg/pro/install/install.go`:
- Around line 117-129: DryRun and Install currently append paths to
InstallResult.CreatedFiles even when an existing file will be overwritten;
populate InstallResult.UpdatedFiles instead for existing files that will be
modified. Update Installer.DryRun (where you check i.writer.FileExists(fullPath)
&& !i.opts.Force) to append f.RelPath to result.SkippedFiles when not forcing,
but when forcing append to result.UpdatedFiles (not CreatedFiles); do the
analogous change in Installer.Install where confirmed overwrites or --force
cause writes (use InstallResult.UpdatedFiles rather than CreatedFiles) and keep
creating new paths in CreatedFiles only when the file did not previously exist.
Ensure checks reference writer.FileExists, opts.Force, and any confirmation flow
used in Install.
- Around line 139-144: The root config entry currently returned in the slice as
a fileSpec with RelPath "atmos.yaml" is treated like other scaffolded files and
gets routed through writeFile(), which allows overwriting an existing user
config; change the behavior so "atmos.yaml" is marked create-only and skipped if
the file already exists. Update the fileSpec for atmos.yaml (and the other
similar entries around the 193-205 range) to include a create-only policy flag
or a special field checked by writeFile(), then modify writeFile() to detect
that flag and return without prompting or writing when the destination exists;
reference the fileSpec construction for atmos.yaml and the writeFile() function
to implement this guard.

---

Nitpick comments:
In `@cmd/pro/pro_test.go`:
- Around line 153-192: The tests for reportResult and reportDryRun only assert
“no panic” and miss regressions in the actual output; update the tests to
capture and assert the rendered report text by routing the formatter to a test
writer or capturing the UI output instead of only calling
reportResult/reportDryRun. Specifically, modify TestReportResult and
TestReportDryRun to provide a bytes.Buffer (or captured UI stream) to the code
path used by reportResult and reportDryRun, call those functions with the
InstallResult cases, and assert that the buffer contains the expected lines for
CreatedFiles, UpdatedFiles, and SkippedFiles (and the empty-result case) so the
tests verify actual rendered output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6c27f3d3-6e4e-40ac-b2e7-ad93d23a8359

📥 Commits

Reviewing files that changed from the base of the PR and between 0bfc225 and cd0b554.

📒 Files selected for processing (21)
  • cmd/pro/install.go
  • cmd/pro/lock.go
  • cmd/pro/markdown/atmos_pro_install.md
  • cmd/pro/markdown/atmos_pro_install_next_steps.md
  • cmd/pro/pro_test.go
  • cmd/pro/unlock.go
  • pkg/flags/standard_builder.go
  • pkg/flags/standard_options.go
  • pkg/flags/standard_parser.go
  • pkg/pro/install/install.go
  • pkg/pro/install/install_test.go
  • pkg/pro/install/templates.go
  • pkg/pro/install/templates/atmos.d/atmos-pro.yaml
  • pkg/pro/install/templates/atmos.d/ci.yaml
  • pkg/pro/install/templates/atmos.yaml
  • pkg/pro/install/templates/profiles/README.md
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-apply.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-plan.yaml
  • website/blog/2026-04-06-pro-install-command.mdx
  • website/docs/cli/commands/pro/pro-install.mdx
  • website/src/data/roadmap.js
✅ Files skipped from review due to trivial changes (8)
  • pkg/pro/install/templates/atmos.yaml
  • pkg/pro/install/templates/atmos.d/atmos-pro.yaml
  • pkg/pro/install/templates/atmos.d/ci.yaml
  • website/blog/2026-04-06-pro-install-command.mdx
  • cmd/pro/markdown/atmos_pro_install_next_steps.md
  • website/src/data/roadmap.js
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-plan.yaml
  • pkg/pro/install/templates/workflows/atmos-pro-terraform-apply.yaml
🚧 Files skipped from review as they are similar to previous changes (2)
  • cmd/pro/unlock.go
  • pkg/pro/install/templates.go

Comment thread cmd/pro/install.go
Comment thread cmd/pro/install.go
Comment thread pkg/flags/standard_builder.go
Comment thread pkg/pro/install/install.go
Comment thread pkg/pro/install/install.go
Address CodeRabbit review on flag default values by extracting named
constants to satisfy the add-constant revive linter rule.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mergify

mergify Bot commented Apr 12, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Apr 12, 2026
Resolve conflict in roadmap.js by keeping both pro-commit and pro-install milestones.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…oCmd

The file was in package cmd but referenced proCmd which is defined in
package pro (cmd/pro/pro.go), causing build failures on all platforms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use absolute paths and log warnings instead of assert for cleanup errors,
matching the robust pattern already in TestProcessCustomYamlTags. Add
pre-test cleanup to remove stale state from prior test runs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mergify

mergify Bot commented May 26, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label May 26, 2026
# Conflicts:
#	internal/exec/stack_processor_utils.go
#	pkg/config/cache_lock_unix.go
@mergify

mergify Bot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Jun 10, 2026
@mergify

mergify Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

💥 This pull request now has conflicts. Could you fix it Erik Osterman (Cloud Posse) (@osterman)? 🙏

@mergify mergify Bot added the conflict This PR has conflicts label Aug 1, 2026

This branch was successfully deployed

1 active deployment
preview — 930a6d11 Deployed Jul 2, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

conflict This PR has conflicts minor New features that do not break anything needs-cloudposse Needs Cloud Posse assistance size/l Large size PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant