cpflow 5.2.0 → 6.0.0.rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.agents/agent-workflow.yml +26 -2
- data/.agents/bin/README.md +16 -4
- data/.agents/bin/docs +1 -1
- data/.agents/bin/lint +1 -1
- data/.agents/bin/setup +1 -1
- data/.agents/bin/test +1 -1
- data/.agents/bin/validate +2 -1
- data/.coderabbit.yaml +13 -0
- data/.github/actions/cpflow-delete-control-plane-app/action.yml +2 -1
- data/.github/actions/cpflow-setup-environment/action.yml +9 -7
- data/.github/actions/cpflow-wait-for-health/action.yml +87 -15
- data/.github/dependabot.yml +10 -0
- data/.github/pull_request_template.md +18 -0
- data/.github/workflows/check_cpln_links.yml +6 -1
- data/.github/workflows/claude-code-review.yml +5 -2
- data/.github/workflows/claude.yml +97 -4
- data/.github/workflows/coderabbit-lifecycle-review.yml +29 -0
- data/.github/workflows/command_docs.yml +7 -2
- data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +12 -5
- data/.github/workflows/cpflow-delete-review-app.yml +638 -43
- data/.github/workflows/cpflow-deploy-review-app.yml +665 -36
- data/.github/workflows/cpflow-deploy-staging.yml +16 -10
- data/.github/workflows/cpflow-help-command.yml +3 -3
- data/.github/workflows/cpflow-promote-staging-to-production.yml +7 -7
- data/.github/workflows/cpflow-review-app-help.yml +6 -14
- data/.github/workflows/rspec-shared.yml +34 -26
- data/.github/workflows/rspec-specific.yml +10 -2
- data/.github/workflows/rspec.yml +71 -4
- data/.github/workflows/rubocop.yml +9 -2
- data/.github/workflows/trigger-docs-site.yml +2 -0
- data/.rubocop.yml +6 -1
- data/AGENTS.md +6 -49
- data/CHANGELOG.md +56 -1
- data/CONTRIBUTING.md +48 -3
- data/Gemfile.lock +1 -1
- data/README.md +6 -1
- data/cpflow.gemspec +3 -15
- data/docs/ai-github-flow-prompt.md +2 -2
- data/docs/ci-automation.md +216 -99
- data/docs/commands.md +36 -9
- data/docs/rds-private-networking.md +12 -12
- data/docs/releasing.md +15 -4
- data/docs/secrets-and-env-values.md +8 -0
- data/docs/tips.md +18 -0
- data/examples/controlplane.yml +5 -0
- data/lib/command/ai_github_flow_prompt.rb +1 -1
- data/lib/command/apply_template.rb +104 -2
- data/lib/command/base.rb +52 -3
- data/lib/command/cleanup_stale_apps.rb +28 -4
- data/lib/command/copy_image_from_upstream.rb +3 -0
- data/lib/command/deploy_image.rb +54 -3
- data/lib/command/generate_github_actions.rb +36 -12
- data/lib/command/run.rb +357 -44
- data/lib/command/setup_app.rb +10 -5
- data/lib/command/update_github_actions.rb +7 -6
- data/lib/core/controlplane.rb +179 -79
- data/lib/core/controlplane_api.rb +8 -0
- data/lib/core/controlplane_api_direct.rb +257 -63
- data/lib/core/shell.rb +39 -7
- data/lib/core/timed_command.rb +111 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/cpflow.rb +1 -1
- data/lib/github_flow_templates/.github/cpflow-help.md +24 -10
- data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +10 -0
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +9 -0
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +7 -7
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +63 -3
- data/lib/patches/hash.rb +2 -2
- data/rakelib/create_release.rake +14 -14
- data/script/check_shell_scripts +66 -0
- metadata +12 -18
data/docs/ci-automation.md
CHANGED
|
@@ -23,8 +23,8 @@ End-to-end rollout in one view:
|
|
|
23
23
|
|
|
24
24
|
1. `cpflow github-flow-readiness` — exits non-zero if the repo is not ready to deploy.
|
|
25
25
|
2. `cpflow generate` — creates `.controlplane/` if missing.
|
|
26
|
-
3. `cpflow generate-github-actions` — adds `cpflow-*` workflow wrappers. Review-app, staging, cleanup, and helper workflows call upstream reusable workflows; production promotion is a normal caller-repo job so it can own the protected production Environment.
|
|
27
|
-
4. Configure the GitHub
|
|
26
|
+
3. `cpflow generate-github-actions` — adds `cpflow-*` workflow wrappers and `.github/actions/cpflow-*` composite actions. Review-app, staging, cleanup, and helper workflows call upstream reusable workflows; production promotion is a normal caller-repo job so it can own the protected production Environment.
|
|
27
|
+
4. Configure the [GitHub Actions secrets and variables](#github-actions-secrets-and-variables) the workflows expect.
|
|
28
28
|
5. Push the branch, then comment `+review-app-deploy` on a PR to spin up a review environment.
|
|
29
29
|
|
|
30
30
|
AI rollout: copy the [AI rollout prompt](./ai-github-flow-prompt.md) when you want an agent to run this setup. The prompt works whether `cpflow` is already installed or the agent needs to install it first. If `cpflow` is already available in the target repo, `cpflow ai-github-flow-prompt` prints the same prompt with the default app prefix filled in.
|
|
@@ -69,6 +69,7 @@ The second command writes namespaced files so they can coexist with an app's exi
|
|
|
69
69
|
- `.github/workflows/cpflow-deploy-staging.yml`
|
|
70
70
|
- `.github/workflows/cpflow-promote-staging-to-production.yml`
|
|
71
71
|
- `.github/workflows/cpflow-cleanup-stale-review-apps.yml`
|
|
72
|
+
- `.github/actions/cpflow-*` (the local composite actions used by those workflows)
|
|
72
73
|
- `bin/pin-cpflow-github-ref`
|
|
73
74
|
- `bin/test-cpflow-github-flow`
|
|
74
75
|
|
|
@@ -170,15 +171,18 @@ Important points:
|
|
|
170
171
|
fixed replica count. See
|
|
171
172
|
[Enable Capacity AI for Demo and Starter Staging Apps](tips.md#enable-capacity-ai-for-demo-and-starter-staging-apps).
|
|
172
173
|
|
|
173
|
-
##
|
|
174
|
+
## GitHub Actions Secrets and Variables
|
|
174
175
|
|
|
175
|
-
|
|
176
|
+
### GitHub Actions Secrets
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
whose policies only allow review/staging CI operations; it must not read production secrets or manage production
|
|
179
|
-
workloads.
|
|
178
|
+
For a normal generated review-app setup, configure one GitHub Actions secret:
|
|
180
179
|
|
|
181
|
-
|
|
180
|
+
- `CPLN_TOKEN_STAGING`: service-account token scoped to the staging Control Plane org on controlplane.com. Its policies
|
|
181
|
+
should allow only review/staging CI operations; it must not read production secrets or manage production workloads.
|
|
182
|
+
|
|
183
|
+
### GitHub Actions Variables
|
|
184
|
+
|
|
185
|
+
No GitHub Actions variables are required for review apps when `.controlplane/controlplane.yml`
|
|
182
186
|
has exactly one review app entry with `match_if_app_name_starts_with: true` and
|
|
183
187
|
that entry has a `cpln_org`. The inferred values come from that config file:
|
|
184
188
|
the review-app prefix is the app key with `match_if_app_name_starts_with: true`,
|
|
@@ -187,7 +191,7 @@ when you need to test a fork or clone against a different Control Plane org,
|
|
|
187
191
|
choose a different review-app prefix, expose a different public workload, or
|
|
188
192
|
disambiguate generated review-app config:
|
|
189
193
|
|
|
190
|
-
- `CPLN_ORG_STAGING`:
|
|
194
|
+
- `CPLN_ORG_STAGING`: Control Plane org on controlplane.com for staging and review apps. Overrides the org inferred from `cpln_org`, for example `company-staging`
|
|
191
195
|
- `REVIEW_APP_PREFIX`: override the inferred review-app prefix; required only when multiple review app prefixes exist in `controlplane.yml`
|
|
192
196
|
- `PRIMARY_WORKLOAD`: override the public workload used to discover the public endpoint and do review/production health checks; defaults to `rails`
|
|
193
197
|
- `REVIEW_APP_HEALTH_CHECK_RETRIES`: override review-app health polling attempts; defaults to `24`
|
|
@@ -211,7 +215,8 @@ For production promotion, also configure:
|
|
|
211
215
|
- a GitHub Environment named `production`
|
|
212
216
|
- required reviewers on that environment, limited to the people or team allowed to promote production
|
|
213
217
|
- "Prevent self-review" on that environment, so the person who starts the promotion cannot approve it
|
|
214
|
-
-
|
|
218
|
+
- disable administrator bypass if your organization requires two-person control
|
|
219
|
+
- restrict deployment branches/tags to your protected release branch
|
|
215
220
|
- `CPLN_TOKEN_PRODUCTION` as an environment secret on `production`, not as a repository or organization secret
|
|
216
221
|
- `CPLN_ORG_PRODUCTION` as a production environment variable, for example `company-production`
|
|
217
222
|
- `PRODUCTION_APP_NAME` as a production environment variable, for example `my-app-production`
|
|
@@ -324,6 +329,20 @@ the run early instead of deploying an image that cannot boot.
|
|
|
324
329
|
|
|
325
330
|
Review apps are different: the generated `+review-app-deploy` workflow creates
|
|
326
331
|
temporary PR apps as needed, including the identity and secret policy binding.
|
|
332
|
+
For an existing review app, each deployment runs
|
|
333
|
+
`cpflow setup-app --refresh-templates` before building and deploying the new
|
|
334
|
+
image. Refresh mode reapplies the configured `setup_app_templates` without
|
|
335
|
+
deleting the GVC or running `hooks.post_creation`, answers template replacement
|
|
336
|
+
prompts noninteractively, preserves each matching workload container's exact
|
|
337
|
+
configured app-image reference even when the app is unhealthy or workloads use
|
|
338
|
+
different image versions, and repairs the configured app and shared-secret
|
|
339
|
+
policy bindings. A missing or invalid workload image uses only an unambiguous
|
|
340
|
+
app image from ready workloads; refresh fails closed rather than selecting the
|
|
341
|
+
registry's newest image. Preserving image references keeps release-phase and
|
|
342
|
+
ordered-deploy gates in control of image rollout; a template failure stops the
|
|
343
|
+
workflow before the image build or deployment. Existing secret templates are skipped
|
|
344
|
+
as whole resources, so refresh neither changes existing values nor adds newly templated
|
|
345
|
+
keys; provision required new keys separately before deployment.
|
|
327
346
|
You still need the shared review-app runtime secret values described by your
|
|
328
347
|
templates, and the staging token must have access to create and update
|
|
329
348
|
review-app GVCs, workloads, images, identities, policies, and secrets in the
|
|
@@ -331,12 +350,13 @@ staging org.
|
|
|
331
350
|
|
|
332
351
|
If review apps share an existing staging database or another existing secret,
|
|
333
352
|
declare it with `shared_secret_grants` on the review app config entry. The
|
|
334
|
-
deploy workflow runs `setup-app` for new review apps
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
call `cpflow delete`, which removes
|
|
338
|
-
lets one shared database or license
|
|
339
|
-
|
|
353
|
+
deploy workflow runs `setup-app` for new review apps, refreshes templates for
|
|
354
|
+
existing review apps, and then runs `deploy-image`; those commands bind or
|
|
355
|
+
repair the review app identity's `reveal` permission on each configured shared
|
|
356
|
+
policy. The delete and cleanup workflows call `cpflow delete`, which removes
|
|
357
|
+
those bindings as review apps go away. This lets one shared database or license
|
|
358
|
+
secret serve many short-lived review apps without granting every review
|
|
359
|
+
identity access to unrelated app secrets.
|
|
340
360
|
|
|
341
361
|
```yaml
|
|
342
362
|
apps:
|
|
@@ -376,7 +396,11 @@ The standard path is:
|
|
|
376
396
|
references are copied by digest, commit-suffixed tags keep the commit suffix,
|
|
377
397
|
and plain numeric tags remain valid.
|
|
378
398
|
11. Expect production health and rollback readiness polling to require Control
|
|
379
|
-
Plane `status.ready` and `status.readyLatest` before checking the
|
|
399
|
+
Plane `status.ready` and `status.readyLatest` before checking the standard
|
|
400
|
+
workload endpoint. If that endpoint is unavailable, as it can be on BYOK
|
|
401
|
+
locations, the health check waits until every reported deployment location
|
|
402
|
+
is ready and not deploying, then tries their endpoints sequentially. Each
|
|
403
|
+
additional location can add up to `curl_max_time` to an attempt.
|
|
380
404
|
|
|
381
405
|
GitHub only exposes environment secrets to jobs that reference the environment
|
|
382
406
|
after configured protection rules pass. GitHub does not allow a caller job that
|
|
@@ -440,18 +464,29 @@ service-account token must remain disposable and scoped to minimum permissions.
|
|
|
440
464
|
The generated flow uses these defaults:
|
|
441
465
|
|
|
442
466
|
- same-repository pull requests can update existing review apps automatically on each push; creating the first review app
|
|
443
|
-
requires either a `+review-app-deploy` comment from
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
467
|
+
requires either a `+review-app-deploy` comment from someone whose current repository permission is `write`, `maintain`,
|
|
468
|
+
or `admin`, or a manual workflow dispatch by a repository collaborator with write access. GitHub's
|
|
469
|
+
collaborator-permission API resolves comment permissions when the command runs; `read` and `triage` access are not
|
|
470
|
+
sufficient, and an API lookup failure denies the command. Accepted triggers are recorded in a hidden, bot-authored
|
|
471
|
+
intent comment before queue admission. The mutating job authenticates the newest marker against its originating
|
|
472
|
+
Actions run and successful POST-only recording step, then rechecks the manual actor's current permission after it
|
|
473
|
+
acquires the per-PR queue. Editing or deleting
|
|
474
|
+
the original command comment therefore cannot reorder accepted work, and a permission revoked while the job waits
|
|
475
|
+
makes the newest intent fail closed instead of falling back to an older operation. This permission gate applies to every
|
|
476
|
+
`+review-app-deploy` comment, whether or not a review app already exists. Later pushes to a base-repository branch PR
|
|
477
|
+
redeploy automatically without another approval because the auto-push path (`pull_request` event) does not use the
|
|
478
|
+
comment permission gate. The reusable deploy workflow loads generated local actions through `actions/checkout`'s
|
|
479
|
+
default with no `ref:` override, which resolves to the commit GitHub recorded for the triggering event: the
|
|
480
|
+
pull-request merge revision for automatic same-repository deploys, the selected ref for manual dispatch, or the
|
|
481
|
+
default-branch revision for comment triggers. This keeps the wrapper and generated actions synchronized during an
|
|
482
|
+
upgrade or first-installation PR. Preserve the same-repository caller guard because pull-request workflow and action
|
|
483
|
+
code run with staging/review credentials;
|
|
448
484
|
- fork pull requests cannot deploy via the generated `pull_request` path because the caller workflow's job-level `if:`
|
|
449
|
-
condition explicitly skips fork-originated runs. For `issue_comment` events, the caller `if:` restricts
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
different axes, so preserve both.
|
|
453
|
-
|
|
454
|
-
deployed. Removing the source-validation guard opens a path to deploy untrusted code with repository-secret access,
|
|
485
|
+
condition explicitly skips fork-originated runs. For `issue_comment` events, the caller `if:` restricts invocation to
|
|
486
|
+
the exact command shape; the reusable workflow resolves repository permission before its deploy job runs, then its
|
|
487
|
+
source-validation step checks fork status before checking out or building PR code. These complementary guards cover
|
|
488
|
+
different axes, so preserve both. Even a write-authorized comment on a fork PR cannot deploy that fork head.
|
|
489
|
+
Removing the source-validation guard opens a path to deploy untrusted code with repository-secret access,
|
|
455
490
|
because `issue_comment` events execute with base-repository secret access. Removing the `pull_request` guard still
|
|
456
491
|
lets untrusted fork code into the staging environment even though GitHub withholds repository secrets from fork
|
|
457
492
|
`pull_request` runs. Keep both workflow guards in place because the workflow builds Docker images with repository
|
|
@@ -459,13 +494,17 @@ The generated flow uses these defaults:
|
|
|
459
494
|
- review apps are also deleted automatically when the pull request closes; that PR-close path uses `pull_request_target`
|
|
460
495
|
so it runs in the base-repository context and has repository-secret access for teardown. That is also why you must
|
|
461
496
|
never check out PR or fork code in this job; see the customization guidance below. The PR-close path does not require a
|
|
462
|
-
|
|
463
|
-
(`contents: read`, `issues: write`, `pull-requests: write`)
|
|
464
|
-
|
|
497
|
+
comment permission check. The generated `cpflow-delete-review-app.yml` pins `GITHUB_TOKEN` permissions to the minimum it needs
|
|
498
|
+
(`actions: write`, `contents: read`, `deployments: write`, `issues: write`, `pull-requests: write`). `actions: write` is used
|
|
499
|
+
only to redispatch the newest accepted deploy/delete operation when GitHub replaces the corresponding pending run;
|
|
500
|
+
if you customize this workflow, preserve that `permissions:` block because omitting it can fall back to broader
|
|
501
|
+
repository defaults;
|
|
465
502
|
- manual workflow dispatch by a repository collaborator can also delete a review app without a `+review-app-delete`
|
|
466
|
-
comment
|
|
467
|
-
|
|
468
|
-
|
|
503
|
+
comment. It is recorded in the same intent order as comment and automatic triggers, and the actor's current repository
|
|
504
|
+
permission is rechecked after queue admission;
|
|
505
|
+
- write-authorized comments on fork PRs still do not deploy the fork head; the workflow posts no PR comment or command
|
|
506
|
+
reaction in this case. The authorization job records no accepted intent, and the skip appears in its
|
|
507
|
+
`Prepare accepted review app intent` log. Review the fork code
|
|
469
508
|
carefully, then move the change to a branch in the base repository if it needs a generated review app. That build will
|
|
470
509
|
run with repository-secret access;
|
|
471
510
|
- production promotion is manual and uses production environment secrets separately from review and staging.
|
|
@@ -478,13 +517,16 @@ generated staging/review org and make that token disposable and unable to access
|
|
|
478
517
|
The PR-close teardown workflow runs trusted base-branch workflow code with repository secret access so it can delete fork
|
|
479
518
|
PR review apps. The generated `cpflow-delete-control-plane-app` composite action script refuses to call `cpflow delete`
|
|
480
519
|
on any app whose name does not match the review-app prefix. This shell-level guard is effective because the generated
|
|
481
|
-
delete workflow
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
520
|
+
delete workflow loads generated actions through `actions/checkout`'s default with no `ref:` override, which resolves to
|
|
521
|
+
the commit GitHub recorded for the triggering event (`GITHUB_SHA`, the base-branch tip under `pull_request_target`). Its
|
|
522
|
+
separate app checkout has no `ref:` override either, so `pull_request_target` teardown uses base-branch code for both
|
|
523
|
+
paths rather than PR or fork code. If you customize this
|
|
524
|
+
workflow, never check out PR or fork code in the same job as the delete step; doing so could let a PR replace the guard
|
|
525
|
+
script itself and would also make `hooks.pre_deletion` come from the PR's `controlplane.yml`. This is still not a token
|
|
526
|
+
policy, so use a scoped staging service account limited to review/staging operations. A configured
|
|
527
|
+
`hooks.pre_deletion` command still runs through the latest PR-built image on all delete paths: PR-close teardown,
|
|
528
|
+
`+review-app-delete` comments, manual dispatch, and scheduled cleanup. Review-app credentials must remain disposable
|
|
529
|
+
even during deletion.
|
|
488
530
|
|
|
489
531
|
If you customize the generated `pull_request_target` workflow, never pass `github.event.pull_request.head.sha` or another
|
|
490
532
|
fork-controlled ref to `actions/checkout`, `git fetch`, `git merge`, `git cherry-pick`, or any other step that fetches,
|
|
@@ -545,6 +587,18 @@ deploy key scoped to the minimum private dependency access, and never use a pers
|
|
|
545
587
|
|
|
546
588
|
## Generated Workflow Behavior
|
|
547
589
|
|
|
590
|
+
The deploy and delete workflows share a per-PR concurrency group, but GitHub keeps at most one running and one pending
|
|
591
|
+
member of a group and may replace the pending member without FIFO ordering. Each authorized trigger therefore records a
|
|
592
|
+
hidden `github-actions[bot]` intent marker containing its operation and originating workflow-run identity before it joins
|
|
593
|
+
the queue. Whichever job survives reads the complete marker ledger, authenticates the newest marker against the Actions
|
|
594
|
+
run API and the source run's successful POST-only recording step, revalidates a manual actor's current permission, and either performs that operation or redispatches the matching
|
|
595
|
+
generated workflow on the default branch. Internal redispatches reuse the existing marker only through a bot-owned
|
|
596
|
+
handoff bound to the returned workflow-run ID and the exact successful source dispatch step; the superseded source job
|
|
597
|
+
then stops before mutable work, and values entered manually in the internal handoff field are rejected. This convergence
|
|
598
|
+
covers automatic PR events, manual dispatches, mixed-case comment admission, authorization
|
|
599
|
+
completion in a different order from event creation, and edits or deletion of the original command comment. Invalid,
|
|
600
|
+
forged, missing, or permission-revoked newest intents fail closed and never fall back to older work.
|
|
601
|
+
|
|
548
602
|
`cpflow-review-app-help.yml`
|
|
549
603
|
|
|
550
604
|
- Posts a quick reference when a pull request opens, including on fork-based PRs.
|
|
@@ -563,26 +617,47 @@ deploy key scoped to the minimum private dependency access, and never use a pers
|
|
|
563
617
|
- For manual dispatch, provide the PR number; the workflow rejects fork PRs at runtime because it builds Docker images
|
|
564
618
|
with repository secrets.
|
|
565
619
|
- Redeploys an existing review app automatically on later PR pushes.
|
|
566
|
-
- Creates a GitHub deployment and comments with the review URL and logs.
|
|
620
|
+
- Creates a transient, non-production GitHub deployment and comments with the review URL and logs.
|
|
567
621
|
- Leaves PR pushes alone until the first review app is explicitly requested, which keeps demo-app costs down.
|
|
622
|
+
- When that no-app PR path succeeds without building or deploying, writes a prominent `Docker image not built` job
|
|
623
|
+
summary and returns the reusable-workflow output `image_built=false`. A downstream job can inspect
|
|
624
|
+
`needs.deploy.outputs.image_built`; a green deploy job with `false` is not Docker-image validation.
|
|
625
|
+
- Repositories that require production-image validation before merge should add a separate required build job when
|
|
626
|
+
Dockerfile, runtime-version, or dependency files change. The cost-saving review-app path intentionally does not create
|
|
627
|
+
an app or build an image until `+review-app-deploy` is requested.
|
|
568
628
|
- Supports cost-conscious review apps when paired with one warm replica, Capacity AI, and a disabled autoscaling
|
|
569
629
|
metric for public demos, starter staging apps, and long-lived review apps; see
|
|
570
630
|
[Enable Capacity AI for Demo and Starter Staging Apps](tips.md#enable-capacity-ai-for-demo-and-starter-staging-apps).
|
|
571
|
-
- Accepts `+review-app-deploy` only
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
631
|
+
- Accepts `+review-app-deploy` only when GitHub reports the commenter has `write`, `maintain`, or `admin` repository
|
|
632
|
+
permission. `read` and `triage` are denied, permission is checked again after queue admission, and lookup failures fail
|
|
633
|
+
closed. Manual dispatch follows the same post-queue permission rule.
|
|
634
|
+
- Skips fork-based PR deploys because the workflow builds Docker images with repository secrets. An authorized comment on a
|
|
635
|
+
fork PR still does not deploy the fork head, and manual dispatch must use a base-repository PR number. A fork-targeted
|
|
636
|
+
request records no accepted intent and skips the mutating job. To give a fork PR a review app, review the code carefully first, then
|
|
575
637
|
move the change to a branch in the base repository. The build will then run with repository-secret access.
|
|
638
|
+
- Rejects comment, manual, and internal deploy requests for a closed pull request before recording a durable intent, then
|
|
639
|
+
rechecks that the pull request is still open after queue admission. A doomed deploy therefore cannot supersede the
|
|
640
|
+
automatic close-triggered deletion that cleans up an existing review app.
|
|
576
641
|
|
|
577
642
|
`cpflow-delete-review-app.yml`
|
|
578
643
|
|
|
579
644
|
- Deletes the review app on `+review-app-delete`.
|
|
580
|
-
- Also supports manual workflow dispatch by a repository collaborator
|
|
645
|
+
- Also supports manual workflow dispatch by a repository collaborator. The comment-time permission gate does not apply,
|
|
646
|
+
but the dispatching actor's repository permission is rechecked after queue admission.
|
|
581
647
|
- Also deletes it automatically when the pull request closes through a `pull_request_target` event, so repository secrets
|
|
582
648
|
are available for teardown; `hooks.pre_deletion` still executes through the latest PR-built image on this path, so
|
|
583
649
|
review-app credentials must remain disposable.
|
|
584
|
-
-
|
|
585
|
-
|
|
650
|
+
- After Control Plane deletion succeeds, marks every GitHub deployment for the exact `review/<app-name>` environment
|
|
651
|
+
inactive so the repository does not retain a stale active review deployment, while skipping deployments whose latest
|
|
652
|
+
status is already inactive so repeated teardown is idempotent. Deploy and delete workflows share one per-PR
|
|
653
|
+
concurrency queue; the accepted-intent reconciliation described above compensates for GitHub replacing pending runs,
|
|
654
|
+
ensuring the newest accepted operation eventually wins and an older deploy cannot publish the final state after a
|
|
655
|
+
newer deletion. If GitHub deployment cleanup fails after Control Plane deletion, the workflow reports
|
|
656
|
+
that partial outcome accurately and still fails so the cleanup can be retried.
|
|
657
|
+
- Accepts `+review-app-delete` only when GitHub reports the commenter has `write`, `maintain`, or `admin` repository
|
|
658
|
+
permission. `read` and `triage` are denied, permission is checked again after queue admission, and lookup failures fail
|
|
659
|
+
closed. Manual dispatch uses the same post-queue actor check; automatic PR-close teardown does not use a manual actor
|
|
660
|
+
permission check.
|
|
586
661
|
|
|
587
662
|
`cpflow-deploy-staging.yml`
|
|
588
663
|
|
|
@@ -633,11 +708,13 @@ wrapper-level `if:` guard shown in that file, for example
|
|
|
633
708
|
## Upstream Workflows And Actions
|
|
634
709
|
|
|
635
710
|
Most generated workflows are intentionally small wrappers. The deployment
|
|
636
|
-
logic
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
ref for
|
|
711
|
+
logic and comment formatting live in upstream reusable workflows. The canonical
|
|
712
|
+
composite actions live in this repository and the gem copies them into each
|
|
713
|
+
downstream repository at `.github/actions/cpflow-*`; the reusable workflows use
|
|
714
|
+
those regular local action paths. They separately check out the matching
|
|
715
|
+
upstream ref at `.cpflow` for the `cpflow` runtime source. Production promotion
|
|
716
|
+
is expanded into the caller repository so it can own `environment: production`,
|
|
717
|
+
but follows the same local-action and `.cpflow` source split.
|
|
641
718
|
|
|
642
719
|
- `cpflow-setup-environment`: installs Ruby, the Control Plane CLI, and `cpflow`, then logs into the target org. By default it builds `cpflow` from the checked-out upstream `control-plane-flow` ref; set the `CPFLOW_VERSION` repository variable only when you want to force a published RubyGems release.
|
|
643
720
|
- `cpflow-build-docker-image`: builds and pushes the app image with the desired commit SHA
|
|
@@ -662,37 +739,51 @@ reusable-workflow wrappers should not pass `control_plane_flow_ref`; if you see
|
|
|
662
739
|
that input outside the production promotion setup step, regenerate with a newer
|
|
663
740
|
`cpflow`.
|
|
664
741
|
|
|
665
|
-
There are two
|
|
742
|
+
There are two coordinated inputs, and they protect different things:
|
|
666
743
|
|
|
667
|
-
- The GitHub ref locks the reusable workflow and
|
|
668
|
-
GitHub runs.
|
|
669
|
-
- The
|
|
670
|
-
|
|
671
|
-
|
|
744
|
+
- The GitHub ref locks the reusable workflow and the `.cpflow` runtime source
|
|
745
|
+
checkout that GitHub runs.
|
|
746
|
+
- The installed Ruby gem supplies the generated local composite actions and
|
|
747
|
+
wrappers. `CPFLOW_VERSION`, when configured, separately locks the published
|
|
748
|
+
`cpflow` runtime installed by the setup action.
|
|
672
749
|
|
|
673
750
|
That means a downstream app cannot rely on the gem alone for GitHub Actions
|
|
674
751
|
behavior. The safe stable path is still gem-driven for generation, but
|
|
675
|
-
developers must commit generated wrappers
|
|
676
|
-
release tag:
|
|
752
|
+
developers must commit the generated wrappers and local actions from the gem
|
|
753
|
+
that matches the upstream release tag:
|
|
677
754
|
|
|
678
755
|
1. Publish a `cpflow` gem.
|
|
679
756
|
2. Install or bundle that released gem in the downstream project.
|
|
680
757
|
3. Run `cpflow generate-github-actions`.
|
|
681
|
-
4. Commit the generated wrappers
|
|
682
|
-
such as `v5.0.0`.
|
|
758
|
+
4. Commit the generated wrappers and `.github/actions/cpflow-*` files; the
|
|
759
|
+
wrappers should point to the matching upstream release tag such as `v5.0.0`.
|
|
683
760
|
|
|
684
761
|
That release tag should point to the same source that produced the RubyGems
|
|
685
762
|
release. Downstream production automation should use release tags, not `main` or
|
|
686
763
|
feature-branch refs.
|
|
687
764
|
|
|
765
|
+
Generated cross-repository reusable-workflow calls deliberately use an exact
|
|
766
|
+
release tag such as `v5.0.0`. This is the intentional downstream exception to
|
|
767
|
+
the repository's full-SHA external-action policy: it keeps the installed gem,
|
|
768
|
+
generated wrappers, generated local actions, and upstream workflow on one
|
|
769
|
+
reviewed release update contract. It does not extend to external actions inside
|
|
770
|
+
those workflows, which remain pinned to full commit SHAs with readable release
|
|
771
|
+
comments. Unreleased downstream validation temporarily replaces the exact tag
|
|
772
|
+
with the upstream PR's full commit SHA as described below; moving version
|
|
773
|
+
aliases and branches remain forbidden.
|
|
774
|
+
|
|
688
775
|
## Updating Generated GitHub Actions After Gem Updates
|
|
689
776
|
|
|
690
|
-
Whenever a downstream repo updates the `cpflow` gem, update
|
|
691
|
-
GitHub Actions
|
|
692
|
-
new reusable workflow YAML by itself; GitHub
|
|
693
|
-
`.github/
|
|
777
|
+
Whenever a downstream repo updates the `cpflow` gem, update all checked-in
|
|
778
|
+
GitHub Actions files in the same PR. The gem version does not make GitHub load
|
|
779
|
+
new reusable workflow YAML or local action files by itself; GitHub uses the
|
|
780
|
+
workflow ref and `.github/actions/cpflow-*` files committed in the repository.
|
|
781
|
+
|
|
782
|
+
For a new repository that does not have generated wrappers yet, run
|
|
783
|
+
`cpflow generate-github-actions` first. Use the update command below for later
|
|
784
|
+
gem upgrades.
|
|
694
785
|
|
|
695
|
-
Use the installed gem to refresh the generated
|
|
786
|
+
Use the installed gem to refresh the generated workflows and actions:
|
|
696
787
|
|
|
697
788
|
```sh
|
|
698
789
|
cpflow update-github-actions
|
|
@@ -706,11 +797,11 @@ bundle exec cpflow update-github-actions
|
|
|
706
797
|
bin/test-cpflow-github-flow bundle exec cpflow
|
|
707
798
|
```
|
|
708
799
|
|
|
709
|
-
`cpflow update-github-actions` regenerates the
|
|
710
|
-
files from the installed gem, pins the wrapper
|
|
711
|
-
and preserves a single custom staging branch
|
|
712
|
-
workflow. Pass `--staging-branch BRANCH`
|
|
713
|
-
staging branch explicitly.
|
|
800
|
+
`cpflow update-github-actions` regenerates the workflow wrappers, local
|
|
801
|
+
composite actions, and helper files from the installed gem, pins the wrapper
|
|
802
|
+
`uses:` refs to `v<gem-version>`, and preserves a single custom staging branch
|
|
803
|
+
from the existing generated staging workflow. Pass `--staging-branch BRANCH`
|
|
804
|
+
when changing or restoring a custom staging branch explicitly.
|
|
714
805
|
|
|
715
806
|
When keeping `cpflow` in an app Gemfile, leave a comment next to the gem entry
|
|
716
807
|
so future dependency bumps include the wrapper update:
|
|
@@ -744,7 +835,8 @@ action commit, so a moving branch named like `v5.0.0` cannot be used with
|
|
|
744
835
|
runners that cannot reach GitHub should leave `CPFLOW_VERSION` unset and build
|
|
745
836
|
`cpflow` from the checked-out ref instead. When testing an unreleased upstream
|
|
746
837
|
commit SHA, leave `CPFLOW_VERSION` unset so the workflow builds `cpflow` from the
|
|
747
|
-
same source that supplies the reusable workflow
|
|
838
|
+
same source that supplies the reusable workflow. Refresh the generated local
|
|
839
|
+
actions from that checkout before testing as described below.
|
|
748
840
|
|
|
749
841
|
## Testing Unreleased Upstream Changes Downstream
|
|
750
842
|
|
|
@@ -752,24 +844,26 @@ You can test a `control-plane-flow` PR in a downstream app before merging or
|
|
|
752
844
|
releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
753
845
|
|
|
754
846
|
1. Push the upstream PR branch and copy its full 40-character head SHA.
|
|
755
|
-
2. In a downstream test branch,
|
|
847
|
+
2. In a downstream test branch, regenerate from the upstream checkout and then
|
|
848
|
+
pin the wrappers to its exact SHA:
|
|
756
849
|
|
|
757
850
|
```sh
|
|
851
|
+
ruby /path/to/control-plane-flow/bin/cpflow update-github-actions
|
|
758
852
|
bin/pin-cpflow-github-ref <upstream-pr-sha>
|
|
759
853
|
```
|
|
760
854
|
|
|
761
|
-
The
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
`CPFLOW_VERSION` is set while the wrapper is pinned to a
|
|
771
|
-
action fails before deployment because the gem and
|
|
772
|
-
proven to match.
|
|
855
|
+
The update command copies the PR checkout's canonical composite actions into
|
|
856
|
+
`.github/actions/cpflow-*`. The pin helper then updates every generated
|
|
857
|
+
reusable-workflow `uses:` ref plus the production workflow's pinned
|
|
858
|
+
`control-plane-flow` checkout and setup validation ref. It accepts release
|
|
859
|
+
tags and full commit SHAs by default, rejects branch names such as `main` or
|
|
860
|
+
`feature/foo`, and requires `--allow-moving-ref` for short-lived local
|
|
861
|
+
experiments that should not be committed.
|
|
862
|
+
|
|
863
|
+
3. Keep `CPFLOW_VERSION` unset so the workflow builds `cpflow` from the pinned
|
|
864
|
+
upstream SHA. If `CPFLOW_VERSION` is set while the wrapper is pinned to a
|
|
865
|
+
SHA, the setup action fails before deployment because the published gem and
|
|
866
|
+
upstream source cannot be proven to match.
|
|
773
867
|
4. Run:
|
|
774
868
|
|
|
775
869
|
```sh
|
|
@@ -783,25 +877,48 @@ releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
|
783
877
|
bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
|
|
784
878
|
```
|
|
785
879
|
|
|
786
|
-
5.
|
|
787
|
-
|
|
880
|
+
5. Push the downstream test branch, then choose the remote validation path that
|
|
881
|
+
matches the repository's installation state.
|
|
882
|
+
|
|
883
|
+
For an existing installation, where `cpflow-deploy-review-app.yml` is already
|
|
884
|
+
present on the default branch, dispatch the workflow definition and generated
|
|
885
|
+
local actions from the unmerged downstream test branch against a suitable open
|
|
886
|
+
base-repository PR:
|
|
887
|
+
|
|
888
|
+
```sh
|
|
889
|
+
gh workflow run cpflow-deploy-review-app.yml --ref <downstream-test-branch> -f pr_number=<pr-number>
|
|
890
|
+
```
|
|
891
|
+
|
|
892
|
+
The `--ref` selects the downstream wrapper and local-action commit under test;
|
|
893
|
+
`pr_number` selects the application source to deploy. Do not use a
|
|
894
|
+
`+review-app-deploy` comment for this pre-merge validation: `issue_comment`
|
|
895
|
+
always loads the workflow definition from the default branch, so it cannot
|
|
896
|
+
validate unmerged wrappers or local actions.
|
|
897
|
+
|
|
898
|
+
For a first installation, GitHub will not dispatch a workflow that does not
|
|
899
|
+
yet exist on the default branch, even when `--ref` names the installation
|
|
900
|
+
branch. Treat the rollout as staged: run the local contract before merging,
|
|
901
|
+
review the generated diff, merge it, and dispatch the merged workflow
|
|
902
|
+
immediately afterward against a suitable open base-repository PR:
|
|
788
903
|
|
|
789
|
-
```
|
|
790
|
-
|
|
904
|
+
```sh
|
|
905
|
+
gh workflow run cpflow-deploy-review-app.yml --ref <default-branch> -f pr_number=<pr-number>
|
|
791
906
|
```
|
|
792
907
|
|
|
793
|
-
6. Verify the deploy logs show the expected upstream commit SHA, the
|
|
794
|
-
prints the expected `cpflow` source/version, and the review app URL
|
|
795
|
-
HTTP 200.
|
|
908
|
+
6. Verify the dispatched deploy logs show the expected upstream commit SHA, the
|
|
909
|
+
setup step prints the expected `cpflow` source/version, and the review app URL
|
|
910
|
+
returns HTTP 200. After merge, `+review-app-deploy` remains the normal
|
|
911
|
+
maintainer-facing trigger for subsequent review apps.
|
|
796
912
|
7. After the upstream PR merges and a gem is released, regenerate the downstream
|
|
797
913
|
wrappers from that released gem and commit the release tag. Use
|
|
798
914
|
`bin/pin-cpflow-github-ref vX.Y.Z` only for a ref-only update when the
|
|
799
915
|
generated templates are already current.
|
|
800
916
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
upstream commit.
|
|
804
|
-
|
|
917
|
+
For an existing installation, this tests the real reusable workflows, the
|
|
918
|
+
unmerged regenerated local composite actions, and the source-built `cpflow` gem
|
|
919
|
+
against one immutable upstream commit. A first installation gets the same remote
|
|
920
|
+
proof immediately after its locally validated files reach the default branch.
|
|
921
|
+
Both paths avoid testing against a moving upstream branch.
|
|
805
922
|
|
|
806
923
|
## Local Generated-Flow Checks
|
|
807
924
|
|
data/docs/commands.md
CHANGED
|
@@ -29,6 +29,8 @@ cpflow ai-github-flow-prompt
|
|
|
29
29
|
- Publishes (creates or updates) those at Control Plane infrastructure
|
|
30
30
|
- Picks templates from the `.controlplane/templates` directory
|
|
31
31
|
- Templates are ordinary Control Plane templates but with variable preprocessing
|
|
32
|
+
- Use `--preserve-existing-runtime` to retain each workload container's configured app image, even when the workload is unready, and skip existing secret resources entirely while applying other template changes
|
|
33
|
+
- Missing or invalid workload images use only an unambiguous app image from ready workloads; refresh fails before applying templates when no safe fallback exists
|
|
32
34
|
|
|
33
35
|
**Preprocessed template variables:**
|
|
34
36
|
|
|
@@ -83,7 +85,7 @@ cpflow cleanup-images -a $APP_NAME
|
|
|
83
85
|
|
|
84
86
|
- Acts on stale apps based on the creation date of the latest image, or the GVC if no images exist
|
|
85
87
|
- With `--mode=delete` (default): deletes the whole app (GVC with all workloads, all volumesets and all images), and unbinds the app from the secrets policy and any configured `shared_secret_grants` policies as long as both the identity and each policy exist (and are bound)
|
|
86
|
-
- With `--mode=stop`: suspends
|
|
88
|
+
- With `--mode=stop`: suspends configured workloads that exist in the live GVC through Control Plane — no GVC, volumeset, or image is removed; resume with `cpflow ps:start`
|
|
87
89
|
- `--mode=stop` only suspends workloads listed in `app_workloads` + `additional_workloads`; workloads present in the live GVC but missing from the config are skipped silently
|
|
88
90
|
- `--mode=stop` returns once each workload is marked suspended; it does not wait for the workload to reach a not-ready state
|
|
89
91
|
- Specify the amount of days after an app should be considered stale through `stale_app_image_deployed_days` in the `.controlplane/controlplane.yml` file
|
|
@@ -230,6 +232,9 @@ Creates GitHub Actions templates for a Heroku Flow style Control Plane pipeline:
|
|
|
230
232
|
- manual promotion from staging to production
|
|
231
233
|
- nightly cleanup and PR help workflows
|
|
232
234
|
|
|
235
|
+
It also copies cpflow's composite actions into `.github/actions/cpflow-*`
|
|
236
|
+
so every local `uses:` target is checked in and can be audited directly.
|
|
237
|
+
|
|
233
238
|
Pass `--staging-branch BRANCH` when staging should auto-deploy from a branch
|
|
234
239
|
other than `main` or `master`; the generator will bake that branch into the
|
|
235
240
|
GitHub Actions push trigger and use it as the default STAGING_APP_BRANCH.
|
|
@@ -238,13 +243,13 @@ Pass `--force` to overwrite existing generated files. Prefer
|
|
|
238
243
|
repo.
|
|
239
244
|
|
|
240
245
|
```sh
|
|
241
|
-
# Creates
|
|
246
|
+
# Creates workflow wrappers, local composite actions, and validation helpers
|
|
242
247
|
cpflow generate-github-actions
|
|
243
248
|
|
|
244
249
|
# Creates the flow with staging deploys triggered from develop
|
|
245
250
|
cpflow generate-github-actions --staging-branch develop
|
|
246
251
|
|
|
247
|
-
# Overwrites existing generated
|
|
252
|
+
# Overwrites existing generated GitHub Actions files from the installed cpflow gem
|
|
248
253
|
cpflow generate-github-actions --force
|
|
249
254
|
```
|
|
250
255
|
|
|
@@ -479,8 +484,27 @@ timeout 300 cpflow ps:wait -a $APP_NAME
|
|
|
479
484
|
and also overridden per job through `--cpu` and `--memory`)
|
|
480
485
|
- By default, the job is stopped if it takes longer than 6 hours to finish
|
|
481
486
|
(can be configured though `runner_job_timeout` in `controlplane.yml`)
|
|
487
|
+
- Waiting for a runner replica is limited to the smaller of `runner_job_timeout` and 1000 seconds.
|
|
488
|
+
A terminal cron status fails immediately, and reaching the observation deadline reports the last safe status
|
|
489
|
+
- With non-interactive log methods 2 and 3, after a command prints its completion marker, Control Plane
|
|
490
|
+
has up to 20 minutes to reconcile the cron job to a terminal status. This can be configured through
|
|
491
|
+
`runner_job_status_reconciliation_timeout` in `controlplane.yml`; timing out exits nonzero and reports
|
|
492
|
+
the job, replica, and last observed status
|
|
493
|
+
- Log method 1 does not emit a completion marker, so its job-status polling is not covered by the
|
|
494
|
+
post-command reconciliation timeout
|
|
482
495
|
- Non-interactive jobs return the Control Plane cron job status even when the job finishes before
|
|
483
496
|
Control Plane exposes a runner replica to attach logs to
|
|
497
|
+
- Injects `CPFLOW_GVC_ID` and `CPFLOW_GVC_CREATED` into the job, exposing the app's immutable GVC
|
|
498
|
+
identity, so that a command such as a release script can tell which GVC incarnation it is running in.
|
|
499
|
+
These change when a GVC is deleted and recreated under the same name, and only then, unlike
|
|
500
|
+
`CPLN_GVC_ALIAS`, which is also embedded in mutable derived values such as the app domain and so
|
|
501
|
+
cannot be attributed to recreation alone
|
|
502
|
+
- `CPFLOW_GVC_CREATED` is the GVC's creation timestamp as returned by the Control Plane API and passed
|
|
503
|
+
through unmodified, currently an ISO 8601 UTC timestamp with millisecond precision and a `Z` suffix
|
|
504
|
+
(e.g. `2026-08-28T00:54:48.648Z`)
|
|
505
|
+
- Both variables are always set, and are empty when the GVC cannot be read, so that a consumer can
|
|
506
|
+
fail closed. They are never omitted, because the runner inherits the original workload's
|
|
507
|
+
environment and an omitted variable could otherwise expose a stale inherited value
|
|
484
508
|
|
|
485
509
|
```sh
|
|
486
510
|
# Opens shell (bash by default).
|
|
@@ -504,7 +528,8 @@ cpflow run -a $APP_NAME -- rails db:migrate
|
|
|
504
528
|
# - stop the job
|
|
505
529
|
cpflow run -a $APP_NAME --detached -- rails db:migrate
|
|
506
530
|
|
|
507
|
-
#
|
|
531
|
+
# Quote the whole command to intentionally opt into shell syntax such as an env assignment.
|
|
532
|
+
# Separately supplied command arguments are passed literally.
|
|
508
533
|
cpflow run -a $APP_NAME -- 'SOME_ENV_VAR=some_value rails db:migrate'
|
|
509
534
|
|
|
510
535
|
# Uses a different image (which may not be promoted yet).
|
|
@@ -539,6 +564,7 @@ cpflow run -a $APP_NAME --entrypoint /app/alternative-entrypoint.sh -- rails db:
|
|
|
539
564
|
- Runs a post-creation hook after the app is created if `hooks.post_creation` is specified in the `.controlplane/controlplane.yml` file
|
|
540
565
|
- If the hook exits with a non-zero code, the command will stop executing and also exit with a non-zero code
|
|
541
566
|
- Use `--skip-post-creation-hook` to skip the hook if specified in `controlplane.yml`
|
|
567
|
+
- Use `--refresh-templates` to apply configured templates noninteractively to an existing app while preserving each workload's configured app image even when workloads are unready or use mixed image versions, skipping existing secret resources entirely, repairing secrets access bindings, and skipping the post-creation hook
|
|
542
568
|
|
|
543
569
|
```sh
|
|
544
570
|
cpflow setup-app -a $APP_NAME
|
|
@@ -562,17 +588,18 @@ cpflow terraform import
|
|
|
562
588
|
|
|
563
589
|
### `update-github-actions`
|
|
564
590
|
|
|
565
|
-
Regenerates the
|
|
566
|
-
from the currently installed cpflow gem. Use this after
|
|
567
|
-
cpflow gem so checked-in workflow wrappers move to the
|
|
568
|
-
release tag, for example `v5.
|
|
591
|
+
Regenerates the cpflow workflow wrappers, local composite actions, and
|
|
592
|
+
helper files from the currently installed cpflow gem. Use this after
|
|
593
|
+
updating the cpflow gem so checked-in workflow wrappers move to the
|
|
594
|
+
matching upstream release tag, for example `v5.3.0`, and the
|
|
595
|
+
generated action implementations move with them.
|
|
569
596
|
|
|
570
597
|
If the existing generated staging workflow uses a custom single staging
|
|
571
598
|
branch, the command preserves it. Pass `--staging-branch BRANCH` to set or
|
|
572
599
|
replace the generated staging branch explicitly.
|
|
573
600
|
|
|
574
601
|
```sh
|
|
575
|
-
# After updating the cpflow gem, refresh generated GitHub Actions
|
|
602
|
+
# After updating the cpflow gem, refresh every generated GitHub Actions file
|
|
576
603
|
cpflow update-github-actions
|
|
577
604
|
|
|
578
605
|
# When running cpflow through Bundler
|