feat: more comprehensive `depot ci migrate` workflow by lukevmorris · Pull Request #463 · depot/cli

and others added 30 commits

March 20, 2026 21:11
Adds a new migrate2 command that optimistically migrates GitHub Actions
workflows into .depot/workflows/ with inline corrections:
- Remaps runs-on labels (standard GitHub → Depot equivalents, nonstandard → default)
- Removes unsupported triggers with explanatory comments
- Comments out uncorrectable jobs (e.g. matrix + self-hosted)
- Adds a header comment per file summarizing changes
- Prints a summary with next steps (commit, install app, import secrets/vars)

No API calls or authentication required — purely local file transformation.
Supported triggers render in green, unsupported triggers in red,
giving immediate visual feedback in the multi-select prompt.
…oups

Workflows with at least one supported trigger appear under
'These workflows have supported triggers. Which should we migrate?'
(pre-selected). Workflows with only unsupported triggers appear in a
separate group: 'These workflows have unsupported triggers. Migrate anyway?'
(not pre-selected).
Use depot.dev/orgs/{org}/workflows for app install link and
depot.dev/orgs/{org}/workflows/settings for secrets/variables import.
Clarify that workflows won't run without configured secrets.
…cing

Bold 'Migrated' and 'Next steps:' headers, add breathing room between
sections, and wrap the long secrets/variables line.
When multiple jobs share the same runs-on mapping (e.g. ubuntu-24.04 to
depot-ubuntu-24.04), the header now shows a single line with 'throughout'
instead of repeating the same change for every job.
When all runs-on changes are standard GitHub labels mapped to Depot
equivalents, the header now shows a single line:
'Changed GitHub runs-on labels to their Depot equivalents'
instead of listing each mapping. Nonstandard labels still get
per-mapping detail.
The migrate2 command now:
- Ensures authentication (token + org ID) before proceeding
- Detects the repo from the git origin remote
- Calls MigrationService.GetInstallation to verify the Depot Code
  Access app is installed, has access to the repo, and has the
  required permissions — exiting early with actionable URLs if not
- Then proceeds with the existing workflow migration
- Updated next steps to reference `depot ci import-secrets`

Also adds NewMigrationClient to the RPC helpers and includes the
generated MigrationService proto/connect code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extracts the auth + repo detection + installation preflight check
into a reusable validateInstallation function. The new subcommand
runs just that sequence, useful for diagnosing Code Access app
configuration issues without running a full migration.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rename the subcommand and internal function/types to use the
shorter, more natural "preflight" naming throughout.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extracts the workflow copying/transformation logic into a standalone
copyWorkflows function and exposes it as a subcommand. This allows
running just the workflow migration step independently of the
preflight check.

The top-level migrate2 command still runs both preflight + copy-workflows
in sequence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Calls MigrationService.ImportSecretsAndVars to create a one-shot
GitHub Actions workflow that imports secrets and variables from the
source repo into Depot CI. Resolves auth and detects the repo
independently — no preflight required since this is the final step
in the migration flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Org tokens (prefixed "depot_org_") carry their org context already
so no --org flag is needed. Any other token type requires an explicit
org ID via --org or depot org switch.

Both preflight and import-secrets-and-vars use the shared helper.
Tests updated to call copyWorkflows directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Next steps now show:
1. The detected default branch name (e.g. "main") for push/merge
2. Secret/variable counts with two import options:
   - depot ci migrate2 import-secrets-and-vars (automatic)
   - depot ci secrets add / depot ci vars add (manual)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
git symbolic-ref fails when origin/HEAD isn't set (common after
bare clones). Now falls back to checking if origin/main or
origin/master exists.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The command now explains what it will do, then offers to preview the
workflow YAML (dry run) before creating it. In interactive mode:
- Shows branch name, file path, and full YAML content
- Asks for confirmation before proceeding
With --yes, skips the preview and creates immediately.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Append \n to confirm titles so there's visual spacing between
the title and the Yes/No options.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standalone huh.NewConfirm().Run() renders inline with no trailing
space. Wrapping in huh.NewForm(huh.NewGroup(...)).Run() gives the
form renderer control over layout including bottom padding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Make it clear that the workflow is pushed to the repo and runs
immediately, rather than just being "created".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Switches from cmd.Flags() to cmd.PersistentFlags() so --token,
--org, --yes, and --overwrite propagate to subcommands. Adds -y
as a shorthand for --yes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
--overwrite is only relevant for commands that write to .depot/.
Moved from persistent flags to local flags on the parent migrate2
command and the copy-workflows subcommand.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Shows e.g. "Migrated 3 workflow(s) to .depot/workflows/ (2 skipped)"
when the user deselects workflows during interactive selection.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The migrated count in the summary already conveys this.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Removes the old migrate command and renames migrate2 to migrate.
Helper functions (parseWorkflowDirWithWarnings, detectRepoFromGitRemote,
etc.) extracted into migrate_helpers.go.

Command tree is now:
  depot ci migrate                        # preflight + copy-workflows
  depot ci migrate preflight              # auth + installation check
  depot ci migrate copy-workflows         # workflow transform + copy
  depot ci migrate import-secrets-and-vars # import secrets/vars from GitHub

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

cursor[bot]

graphite-app[bot]

cursor[bot]

cursor[bot]

@lukevmorris

Without this guard, a non-interactive invocation (piped, in CI, etc.)
skips the confirmation prompts and silently pushes a temporary branch
with a workflow to the user's GitHub repository. This aligns the
behavior with copyWorkflows, which already returns an error when
not in a terminal and --yes is not set.