cpflow 5.3.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 +13 -0
- data/.agents/bin/README.md +12 -1
- 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 +8 -6
- data/.github/dependabot.yml +10 -0
- data/.github/workflows/check_cpln_links.yml +6 -1
- data/.github/workflows/claude-code-review.yml +5 -2
- data/.github/workflows/claude.yml +6 -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 +18 -11
- data/.github/workflows/cpflow-deploy-review-app.yml +25 -16
- 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 +1 -1
- 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/CHANGELOG.md +24 -1
- data/CONTRIBUTING.md +39 -2
- 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 +112 -60
- data/docs/commands.md +18 -8
- data/docs/rds-private-networking.md +12 -12
- data/docs/releasing.md +15 -4
- data/examples/controlplane.yml +5 -0
- data/lib/command/ai_github_flow_prompt.rb +1 -1
- 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 +38 -1
- data/lib/command/generate_github_actions.rb +36 -12
- data/lib/command/run.rb +224 -34
- data/lib/command/update_github_actions.rb +7 -6
- data/lib/core/controlplane.rb +145 -78
- data/lib/core/shell.rb +35 -10
- 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/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 +11 -18
|
@@ -10,7 +10,7 @@ first.
|
|
|
10
10
|
```text
|
|
11
11
|
Set up Control Plane GitHub Flow for this repo. First make sure the `cpflow` CLI is available: use the repo's existing `bundle exec cpflow` if present, otherwise install the published `cpflow` Ruby gem with `gem install cpflow`; if neither is possible, stop and report that blocker. Use the same `cpflow` invocation for the rest of the rollout. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout.
|
|
12
12
|
|
|
13
|
-
If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers
|
|
13
|
+
If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers. Keep every generated Control Plane Flow source pin synchronized at the same `vX.Y.Z`: each reusable-workflow `uses: ...@vX.Y.Z` ref, the production promotion `.cpflow` checkout ref, and its `control_plane_flow_ref` setup input. By default, `cpflow generate-github-actions` derives these values from the installed `cpflow` gem version; temporary explicit ref overrides are for unreleased testing and must keep all three values synchronized. Keep the generated `.github/actions/cpflow-*` files from that same gem unchanged; upstream reusable workflows invoke those checked-in local actions and separately check out the matching runtime source at `.cpflow`. When bumping the `cpflow` gem in a downstream repo, run `cpflow update-github-actions` (or `bundle exec cpflow update-github-actions`) and validate with `bin/test-cpflow-github-flow` in the same PR so the checked-in workflows and local actions move together. Keep the normal generated review-app setup simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For public demos, starter staging apps, and long-lived review apps, keep the app workload `type: standard` with one warm replica, set its autoscaling metric to `disabled`, and enable `capacityAI: true` so Control Plane can right-size CPU and memory allocation at that fixed replica count. Shared Postgres and other stateful workloads are the usual exceptions and should stay manually sized; Capacity AI is for supported stateless app/service workloads. If true idle scale-to-zero is explicitly required, create a separate `serverless` workload before first deploy or plan a delete/recreate migration because Control Plane will not change an existing `standard` workload to `serverless` in place. For shared review-app resources such as one staging database, use `shared_secret_grants` and `{{SHARED_SECRET_DATABASE}}` placeholders instead of hardcoding the base app secret name; this keeps review-app policy binding and cleanup automatic while avoiding per-PR database cost. Document the one-time Control Plane bootstrap command for persistent staging and production apps with `cpflow setup-app --skip-post-creation-hook`; for existing apps or later template updates, document `cpflow apply-template` and the need for the app identity to have `reveal` on the app secret policy. Do not imply the staging deploy or promotion workflows create those persistent GVCs. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
|
|
14
14
|
|
|
15
15
|
Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`.
|
|
16
16
|
|
|
@@ -46,7 +46,7 @@ Stop and report the blocker instead of generating `cpflow-*` workflow files when
|
|
|
46
46
|
The rollout is done when all of the following are true:
|
|
47
47
|
|
|
48
48
|
- `.controlplane/` exists and matches the actual app shape
|
|
49
|
-
- `.github/cpflow-help.md
|
|
49
|
+
- `.github/cpflow-help.md`, `.github/workflows/cpflow-*`, and `.github/actions/cpflow-*` are in place
|
|
50
50
|
- review apps are opt-in, staging auto-deploys from one branch, and production promotion is manual
|
|
51
51
|
- required GitHub secrets and variables are documented for the repo
|
|
52
52
|
- the production image build path is validated for the real app
|
data/docs/ci-automation.md
CHANGED
|
@@ -23,7 +23,7 @@ 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.
|
|
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
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
|
|
|
@@ -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
|
|
|
@@ -214,7 +215,8 @@ For production promotion, also configure:
|
|
|
214
215
|
- a GitHub Environment named `production`
|
|
215
216
|
- required reviewers on that environment, limited to the people or team allowed to promote production
|
|
216
217
|
- "Prevent self-review" on that environment, so the person who starts the promotion cannot approve it
|
|
217
|
-
-
|
|
218
|
+
- disable administrator bypass if your organization requires two-person control
|
|
219
|
+
- restrict deployment branches/tags to your protected release branch
|
|
218
220
|
- `CPLN_TOKEN_PRODUCTION` as an environment secret on `production`, not as a repository or organization secret
|
|
219
221
|
- `CPLN_ORG_PRODUCTION` as a production environment variable, for example `company-production`
|
|
220
222
|
- `PRODUCTION_APP_NAME` as a production environment variable, for example `my-app-production`
|
|
@@ -473,7 +475,12 @@ The generated flow uses these defaults:
|
|
|
473
475
|
makes the newest intent fail closed instead of falling back to an older operation. This permission gate applies to every
|
|
474
476
|
`+review-app-deploy` comment, whether or not a review app already exists. Later pushes to a base-repository branch PR
|
|
475
477
|
redeploy automatically without another approval because the auto-push path (`pull_request` event) does not use the
|
|
476
|
-
comment permission gate
|
|
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;
|
|
477
484
|
- fork pull requests cannot deploy via the generated `pull_request` path because the caller workflow's job-level `if:`
|
|
478
485
|
condition explicitly skips fork-originated runs. For `issue_comment` events, the caller `if:` restricts invocation to
|
|
479
486
|
the exact command shape; the reusable workflow resolves repository permission before its deploy job runs, then its
|
|
@@ -510,13 +517,16 @@ generated staging/review org and make that token disposable and unable to access
|
|
|
510
517
|
The PR-close teardown workflow runs trusted base-branch workflow code with repository secret access so it can delete fork
|
|
511
518
|
PR review apps. The generated `cpflow-delete-control-plane-app` composite action script refuses to call `cpflow delete`
|
|
512
519
|
on any app whose name does not match the review-app prefix. This shell-level guard is effective because the generated
|
|
513
|
-
delete workflow
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
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.
|
|
520
530
|
|
|
521
531
|
If you customize the generated `pull_request_target` workflow, never pass `github.event.pull_request.head.sha` or another
|
|
522
532
|
fork-controlled ref to `actions/checkout`, `git fetch`, `git merge`, `git cherry-pick`, or any other step that fetches,
|
|
@@ -698,11 +708,13 @@ wrapper-level `if:` guard shown in that file, for example
|
|
|
698
708
|
## Upstream Workflows And Actions
|
|
699
709
|
|
|
700
710
|
Most generated workflows are intentionally small wrappers. The deployment
|
|
701
|
-
logic
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
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.
|
|
706
718
|
|
|
707
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.
|
|
708
720
|
- `cpflow-build-docker-image`: builds and pushes the app image with the desired commit SHA
|
|
@@ -727,37 +739,51 @@ reusable-workflow wrappers should not pass `control_plane_flow_ref`; if you see
|
|
|
727
739
|
that input outside the production promotion setup step, regenerate with a newer
|
|
728
740
|
`cpflow`.
|
|
729
741
|
|
|
730
|
-
There are two
|
|
742
|
+
There are two coordinated inputs, and they protect different things:
|
|
731
743
|
|
|
732
|
-
- The GitHub ref locks the reusable workflow and
|
|
733
|
-
GitHub runs.
|
|
734
|
-
- The
|
|
735
|
-
|
|
736
|
-
|
|
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.
|
|
737
749
|
|
|
738
750
|
That means a downstream app cannot rely on the gem alone for GitHub Actions
|
|
739
751
|
behavior. The safe stable path is still gem-driven for generation, but
|
|
740
|
-
developers must commit generated wrappers
|
|
741
|
-
release tag:
|
|
752
|
+
developers must commit the generated wrappers and local actions from the gem
|
|
753
|
+
that matches the upstream release tag:
|
|
742
754
|
|
|
743
755
|
1. Publish a `cpflow` gem.
|
|
744
756
|
2. Install or bundle that released gem in the downstream project.
|
|
745
757
|
3. Run `cpflow generate-github-actions`.
|
|
746
|
-
4. Commit the generated wrappers
|
|
747
|
-
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`.
|
|
748
760
|
|
|
749
761
|
That release tag should point to the same source that produced the RubyGems
|
|
750
762
|
release. Downstream production automation should use release tags, not `main` or
|
|
751
763
|
feature-branch refs.
|
|
752
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
|
+
|
|
753
775
|
## Updating Generated GitHub Actions After Gem Updates
|
|
754
776
|
|
|
755
|
-
Whenever a downstream repo updates the `cpflow` gem, update
|
|
756
|
-
GitHub Actions
|
|
757
|
-
new reusable workflow YAML by itself; GitHub
|
|
758
|
-
`.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.
|
|
759
785
|
|
|
760
|
-
Use the installed gem to refresh the generated
|
|
786
|
+
Use the installed gem to refresh the generated workflows and actions:
|
|
761
787
|
|
|
762
788
|
```sh
|
|
763
789
|
cpflow update-github-actions
|
|
@@ -771,11 +797,11 @@ bundle exec cpflow update-github-actions
|
|
|
771
797
|
bin/test-cpflow-github-flow bundle exec cpflow
|
|
772
798
|
```
|
|
773
799
|
|
|
774
|
-
`cpflow update-github-actions` regenerates the
|
|
775
|
-
files from the installed gem, pins the wrapper
|
|
776
|
-
and preserves a single custom staging branch
|
|
777
|
-
workflow. Pass `--staging-branch BRANCH`
|
|
778
|
-
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.
|
|
779
805
|
|
|
780
806
|
When keeping `cpflow` in an app Gemfile, leave a comment next to the gem entry
|
|
781
807
|
so future dependency bumps include the wrapper update:
|
|
@@ -809,7 +835,8 @@ action commit, so a moving branch named like `v5.0.0` cannot be used with
|
|
|
809
835
|
runners that cannot reach GitHub should leave `CPFLOW_VERSION` unset and build
|
|
810
836
|
`cpflow` from the checked-out ref instead. When testing an unreleased upstream
|
|
811
837
|
commit SHA, leave `CPFLOW_VERSION` unset so the workflow builds `cpflow` from the
|
|
812
|
-
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.
|
|
813
840
|
|
|
814
841
|
## Testing Unreleased Upstream Changes Downstream
|
|
815
842
|
|
|
@@ -817,24 +844,26 @@ You can test a `control-plane-flow` PR in a downstream app before merging or
|
|
|
817
844
|
releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
818
845
|
|
|
819
846
|
1. Push the upstream PR branch and copy its full 40-character head SHA.
|
|
820
|
-
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:
|
|
821
849
|
|
|
822
850
|
```sh
|
|
851
|
+
ruby /path/to/control-plane-flow/bin/cpflow update-github-actions
|
|
823
852
|
bin/pin-cpflow-github-ref <upstream-pr-sha>
|
|
824
853
|
```
|
|
825
854
|
|
|
826
|
-
The
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
`CPFLOW_VERSION` is set while the wrapper is pinned to a
|
|
836
|
-
action fails before deployment because the gem and
|
|
837
|
-
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.
|
|
838
867
|
4. Run:
|
|
839
868
|
|
|
840
869
|
```sh
|
|
@@ -848,25 +877,48 @@ releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
|
848
877
|
bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
|
|
849
878
|
```
|
|
850
879
|
|
|
851
|
-
5.
|
|
852
|
-
|
|
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:
|
|
853
887
|
|
|
854
|
-
```
|
|
855
|
-
|
|
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:
|
|
903
|
+
|
|
904
|
+
```sh
|
|
905
|
+
gh workflow run cpflow-deploy-review-app.yml --ref <default-branch> -f pr_number=<pr-number>
|
|
856
906
|
```
|
|
857
907
|
|
|
858
|
-
6. Verify the deploy logs show the expected upstream commit SHA, the
|
|
859
|
-
prints the expected `cpflow` source/version, and the review app URL
|
|
860
|
-
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.
|
|
861
912
|
7. After the upstream PR merges and a gem is released, regenerate the downstream
|
|
862
913
|
wrappers from that released gem and commit the release tag. Use
|
|
863
914
|
`bin/pin-cpflow-github-ref vX.Y.Z` only for a ref-only update when the
|
|
864
915
|
generated templates are already current.
|
|
865
916
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
upstream commit.
|
|
869
|
-
|
|
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.
|
|
870
922
|
|
|
871
923
|
## Local Generated-Flow Checks
|
|
872
924
|
|
data/docs/commands.md
CHANGED
|
@@ -85,7 +85,7 @@ cpflow cleanup-images -a $APP_NAME
|
|
|
85
85
|
|
|
86
86
|
- Acts on stale apps based on the creation date of the latest image, or the GVC if no images exist
|
|
87
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)
|
|
88
|
-
- 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`
|
|
89
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
|
|
90
90
|
- `--mode=stop` returns once each workload is marked suspended; it does not wait for the workload to reach a not-ready state
|
|
91
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
|
|
@@ -232,6 +232,9 @@ Creates GitHub Actions templates for a Heroku Flow style Control Plane pipeline:
|
|
|
232
232
|
- manual promotion from staging to production
|
|
233
233
|
- nightly cleanup and PR help workflows
|
|
234
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
|
+
|
|
235
238
|
Pass `--staging-branch BRANCH` when staging should auto-deploy from a branch
|
|
236
239
|
other than `main` or `master`; the generator will bake that branch into the
|
|
237
240
|
GitHub Actions push trigger and use it as the default STAGING_APP_BRANCH.
|
|
@@ -240,13 +243,13 @@ Pass `--force` to overwrite existing generated files. Prefer
|
|
|
240
243
|
repo.
|
|
241
244
|
|
|
242
245
|
```sh
|
|
243
|
-
# Creates
|
|
246
|
+
# Creates workflow wrappers, local composite actions, and validation helpers
|
|
244
247
|
cpflow generate-github-actions
|
|
245
248
|
|
|
246
249
|
# Creates the flow with staging deploys triggered from develop
|
|
247
250
|
cpflow generate-github-actions --staging-branch develop
|
|
248
251
|
|
|
249
|
-
# Overwrites existing generated
|
|
252
|
+
# Overwrites existing generated GitHub Actions files from the installed cpflow gem
|
|
250
253
|
cpflow generate-github-actions --force
|
|
251
254
|
```
|
|
252
255
|
|
|
@@ -483,6 +486,12 @@ timeout 300 cpflow ps:wait -a $APP_NAME
|
|
|
483
486
|
(can be configured though `runner_job_timeout` in `controlplane.yml`)
|
|
484
487
|
- Waiting for a runner replica is limited to the smaller of `runner_job_timeout` and 1000 seconds.
|
|
485
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
|
|
486
495
|
- Non-interactive jobs return the Control Plane cron job status even when the job finishes before
|
|
487
496
|
Control Plane exposes a runner replica to attach logs to
|
|
488
497
|
- Injects `CPFLOW_GVC_ID` and `CPFLOW_GVC_CREATED` into the job, exposing the app's immutable GVC
|
|
@@ -579,17 +588,18 @@ cpflow terraform import
|
|
|
579
588
|
|
|
580
589
|
### `update-github-actions`
|
|
581
590
|
|
|
582
|
-
Regenerates the
|
|
583
|
-
from the currently installed cpflow gem. Use this after
|
|
584
|
-
cpflow gem so checked-in workflow wrappers move to the
|
|
585
|
-
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.
|
|
586
596
|
|
|
587
597
|
If the existing generated staging workflow uses a custom single staging
|
|
588
598
|
branch, the command preserves it. Pass `--staging-branch BRANCH` to set or
|
|
589
599
|
replace the generated staging branch explicitly.
|
|
590
600
|
|
|
591
601
|
```sh
|
|
592
|
-
# After updating the cpflow gem, refresh generated GitHub Actions
|
|
602
|
+
# After updating the cpflow gem, refresh every generated GitHub Actions file
|
|
593
603
|
cpflow update-github-actions
|
|
594
604
|
|
|
595
605
|
# When running cpflow through Bundler
|
|
@@ -6,13 +6,14 @@ path — not the public internet.
|
|
|
6
6
|
|
|
7
7
|
This guide covers the recommended setup: **CPLN Cloud Wormhole via an Agent**.
|
|
8
8
|
|
|
9
|
-
> **
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
>
|
|
13
|
-
>
|
|
14
|
-
>
|
|
15
|
-
>
|
|
9
|
+
> **Field casing verified.** Sanitized `cpln identity get <name> -o yaml-slim` exports from live orgs
|
|
10
|
+
> confirmed the `networkResources` nesting and the common `name`, `agentLink`, `FQDN`, and `ports` field casing.
|
|
11
|
+
> The current Control Plane [Identity reference](https://shakadocs.controlplane.com/reference/identity) and
|
|
12
|
+
> [Identity API](https://shakadocs.controlplane.com/api-reference/identity/get-an-identity-by-gvc-and-name)
|
|
13
|
+
> confirm the alternative `IPs` form and optional `resolverIP` spelling; neither appeared in the inspected
|
|
14
|
+
> live resources. Field names are case-sensitive: `cpln apply` can accept an unrecognized field while omitting
|
|
15
|
+
> the intended route, without pointing back to the identity YAML. Before applying in production, check the new
|
|
16
|
+
> block against these casing sources, diff your edited file against a fresh identity export, and consult
|
|
16
17
|
> `cpln <command> --help` for the latest CLI flags.
|
|
17
18
|
|
|
18
19
|
## Why private networking
|
|
@@ -234,11 +235,10 @@ cpln identity get my-app-production-identity \
|
|
|
234
235
|
Edit `identity-db.yaml` and **add** the `networkResources` block — keep every other apply-safe field
|
|
235
236
|
exactly as exported:
|
|
236
237
|
|
|
237
|
-
>
|
|
238
|
-
>
|
|
239
|
-
>
|
|
240
|
-
> `
|
|
241
|
-
> against the original `yaml-slim` export from `cpln identity get` to confirm.
|
|
238
|
+
> **Apply-safe editing:** start from a fresh `yaml-slim` export and diff your edited file against the
|
|
239
|
+
> original before applying. This helps detect unintended changes to exported fields, but it does not validate
|
|
240
|
+
> the newly added `networkResources` block. Check every key in that block, including `agentLink`, `FQDN`/`IPs`,
|
|
241
|
+
> `resolverIP`, and `ports`, against the verified casing sources above.
|
|
242
242
|
|
|
243
243
|
```yaml
|
|
244
244
|
# identity-db.yaml (after edit — abbreviated, your file will have more fields)
|
data/docs/releasing.md
CHANGED
|
@@ -23,6 +23,11 @@ Always update `CHANGELOG.md` before running the release task.
|
|
|
23
23
|
- Fixes, improvements, deprecations, removals, or security updates: patch
|
|
24
24
|
4. Merge the changelog PR before releasing.
|
|
25
25
|
|
|
26
|
+
A minimum Ruby version change is a breaking change. Merge the gemspec floor,
|
|
27
|
+
CI coverage for each supported Ruby minor, and an `Unreleased` breaking-change
|
|
28
|
+
entry together. Keep `Cpflow::VERSION` unchanged in that implementation PR.
|
|
29
|
+
The release task applies the required major version when the change ships.
|
|
30
|
+
|
|
26
31
|
If updating the changelog manually, move the relevant `Unreleased` entries into
|
|
27
32
|
a versioned header:
|
|
28
33
|
|
|
@@ -49,9 +54,13 @@ With no arguments, `rake release`:
|
|
|
49
54
|
|
|
50
55
|
1. Reads the first versioned `CHANGELOG.md` header, such as `## [4.2.0]`.
|
|
51
56
|
2. Uses that version when it is newer than the current gem version.
|
|
52
|
-
3.
|
|
53
|
-
|
|
54
|
-
4.
|
|
57
|
+
3. Keeps using that version when it matches the current gem version, including
|
|
58
|
+
on a retry after a release attempt created the version commit or tag.
|
|
59
|
+
4. Lets the existing-tag policy stop an incomplete retry instead of silently
|
|
60
|
+
selecting a different version.
|
|
61
|
+
5. Falls back to a patch bump only from a stable current version when the
|
|
62
|
+
changelog does not name the current or a newer version. Prereleases require
|
|
63
|
+
an explicit target if the changelog cannot supply one.
|
|
55
64
|
|
|
56
65
|
Other supported forms:
|
|
57
66
|
|
|
@@ -152,4 +161,6 @@ bundle exec rake "sync_github_release[4.2.0]"
|
|
|
152
161
|
```
|
|
153
162
|
|
|
154
163
|
If the tag was pushed but the gem was not published, delete or correct the tag
|
|
155
|
-
and version commit intentionally before trying again.
|
|
164
|
+
and version commit intentionally before trying again. A no-argument retry keeps
|
|
165
|
+
the changelog version authoritative and refuses to reinterpret a prerelease as
|
|
166
|
+
its stable version.
|
data/examples/controlplane.yml
CHANGED
|
@@ -104,6 +104,11 @@ aliases:
|
|
|
104
104
|
# If not specified, defaults to 21600 (6 hours).
|
|
105
105
|
runner_job_timeout: 1000
|
|
106
106
|
|
|
107
|
+
# Sets how long `cpflow run` waits for Control Plane to reconcile a cron job status
|
|
108
|
+
# after the non-interactive command prints its completion marker.
|
|
109
|
+
# If not specified, defaults to 1200 (20 minutes).
|
|
110
|
+
runner_job_status_reconciliation_timeout: 1200
|
|
111
|
+
|
|
107
112
|
# Apps with a deployed image created before this amount of days will be listed for deletion
|
|
108
113
|
# when running the command `cpflow cleanup-stale-apps`.
|
|
109
114
|
stale_app_image_deployed_days: 5
|
|
@@ -32,7 +32,7 @@ module Command
|
|
|
32
32
|
<<~PROMPT
|
|
33
33
|
Set up Control Plane GitHub Flow for this repo. First make sure the `cpflow` CLI is available: use the repo's existing `bundle exec cpflow` if present, otherwise install the published `cpflow` Ruby gem with `gem install cpflow`; if neither is possible, stop and report that blocker. Use the same `cpflow` invocation for the rest of the rollout. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone: published package versions, complete runtime scaffold, and a production Dockerfile that can build the app. If any package version is unpublished, inaccessible from CI, or requires credentials that are not already modeled in the repo or GitHub settings, stop and report the blocker instead of generating workflow files. If the repo is a legacy sample pinned to an obsolete Ruby or Bundler toolchain, if it does not even have a production Dockerfile yet, or if it is a monorepo without an already-decided single app boundary for this flow, stop and report that as a prerequisite instead of forcing the rollout.
|
|
34
34
|
|
|
35
|
-
If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default (`#{inferred_app_prefix}`) and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers
|
|
35
|
+
If `.controlplane/` is missing, run `cpflow generate`. Treat the generated app names as the repo-name default (`#{inferred_app_prefix}`) and rename them only if the project needs a different prefix. Then run `cpflow generate-github-actions` (or `cpflow generate-github-actions --staging-branch BRANCH` when staging should deploy from a branch other than `main`/`master`), keep review apps opt-in via `+review-app-deploy`, make sure any `STAGING_APP_BRANCH` repository variable is also present in the generated staging workflow's `on.push.branches` filter, and list the GitHub secrets and variables that must be configured. Do not hand-edit duplicated upstream refs into the generated wrappers. Keep every generated Control Plane Flow source pin synchronized at the same `vX.Y.Z`: each reusable-workflow `uses: ...@vX.Y.Z` ref, the production promotion `.cpflow` checkout ref, and its `control_plane_flow_ref` setup input. By default, `cpflow generate-github-actions` derives these values from the installed `cpflow` gem version; temporary explicit ref overrides are for unreleased testing and must keep all three values synchronized. Keep the generated `.github/actions/cpflow-*` files from that same gem unchanged; upstream reusable workflows invoke those checked-in local actions and separately check out the matching runtime source at `.cpflow`. When bumping the `cpflow` gem in a downstream repo, run `cpflow update-github-actions` (or `bundle exec cpflow update-github-actions`) and validate with `bin/test-cpflow-github-flow` in the same PR so the checked-in workflows and local actions move together. Keep the normal generated review-app setup simple: review apps require only `CPLN_TOKEN_STAGING` when the generated review app config can be inferred. For public demos, starter staging apps, and long-lived review apps, keep the app workload `type: standard` with one warm replica, set its autoscaling metric to `disabled`, and enable `capacityAI: true` so Control Plane can right-size CPU and memory allocation at that fixed replica count. Shared Postgres and other stateful workloads are the usual exceptions and should stay manually sized; Capacity AI is for supported stateless app/service workloads. If true idle scale-to-zero is explicitly required, create a separate `serverless` workload before first deploy or plan a delete/recreate migration because Control Plane will not change an existing `standard` workload to `serverless` in place. For shared review-app resources such as one staging database, use `shared_secret_grants` and `{{SHARED_SECRET_DATABASE}}` placeholders instead of hardcoding the base app secret name; this keeps review-app policy binding and cleanup automatic while avoiding per-PR database cost. Document the one-time Control Plane bootstrap command for persistent staging and production apps with `cpflow setup-app --skip-post-creation-hook`; for existing apps or later template updates, document `cpflow apply-template` and the need for the app identity to have `reveal` on the app secret policy. Do not imply the staging deploy or promotion workflows create those persistent GVCs. For production promotion, document a protected `production` GitHub Environment with required reviewers, prevent self-review, and `CPLN_TOKEN_PRODUCTION` stored as an environment secret, not as a repository or organization secret.
|
|
36
36
|
|
|
37
37
|
Keep Node available in the final image if asset compilation or SSR depends on ExecJS, Yarn, `pnpm`, or npm after the main install layer. Make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement. Preserve repo-defined frontend build hooks: if `config/shakapacker.yml` defines a `precompile_hook`, or React on Rails enables `config.auto_load_bundle = true`, confirm the generated Dockerfile runs that codegen step before `rails assets:precompile`. If `config/database.yml` shows SQLite in production, confirm that the generated scaffold uses persistent `db` and `storage` volumes plus a release script that runs `rails db:prepare`; otherwise keep the default Postgres workload. If the public workload is not named `rails`, set `PRIMARY_WORKLOAD` or adjust the generated workflows. Inspect the Dockerfile and package sources for private GitHub dependencies or `RUN --mount=type=ssh`; if present, wire `DOCKER_BUILD_SSH_KEY`, optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` for non-GitHub SSH hosts, and keep `DOCKER_BUILD_EXTRA_ARGS` to newline-delimited single tokens such as `--build-arg=FOO=bar`.
|
|
38
38
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Command
|
|
4
|
-
class CleanupStaleApps < Base
|
|
4
|
+
class CleanupStaleApps < Base # rubocop:disable Metrics/ClassLength
|
|
5
5
|
CLEANUP_MODE_OPTION = {
|
|
6
6
|
name: :mode,
|
|
7
7
|
params: {
|
|
@@ -24,7 +24,7 @@ module Command
|
|
|
24
24
|
LONG_DESCRIPTION = <<~DESC
|
|
25
25
|
- Acts on stale apps based on the creation date of the latest image, or the GVC if no images exist
|
|
26
26
|
- 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)
|
|
27
|
-
- With `--mode=stop`: suspends
|
|
27
|
+
- 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`
|
|
28
28
|
- `--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
|
|
29
29
|
- `--mode=stop` returns once each workload is marked suspended; it does not wait for the workload to reach a not-ready state
|
|
30
30
|
- Specify the amount of days after an app should be considered stale through `stale_app_image_deployed_days` in the `.controlplane/controlplane.yml` file
|
|
@@ -101,14 +101,38 @@ module Command
|
|
|
101
101
|
def process_app(app)
|
|
102
102
|
if mode == "stop"
|
|
103
103
|
progress.puts("Stopping app '#{app}'")
|
|
104
|
-
|
|
104
|
+
stop_configured_live_workloads(app)
|
|
105
105
|
else
|
|
106
106
|
run_cpflow_command("delete", "-a", app, "--yes")
|
|
107
107
|
end
|
|
108
108
|
end
|
|
109
109
|
|
|
110
|
+
def stop_configured_live_workloads(app)
|
|
111
|
+
app_config = config.find_app_config(app)
|
|
112
|
+
raise "Can't find config for stale app '#{app}'." unless app_config
|
|
113
|
+
|
|
114
|
+
configured_workloads = required_app_option(app_config, app, :app_workloads) +
|
|
115
|
+
required_app_option(app_config, app, :additional_workloads)
|
|
116
|
+
live_workloads = (cp.fetch_workloads(app)&.fetch("items", []) || []).map { |workload| workload.fetch("name") }
|
|
117
|
+
|
|
118
|
+
(configured_workloads & live_workloads).each do |workload|
|
|
119
|
+
step("Stopping workload '#{workload}'") do
|
|
120
|
+
cp.set_workload_suspend(workload, true, app, missing_ok: true)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def required_app_option(app_config, app, option)
|
|
126
|
+
raise "Can't find option '#{option}' for app '#{app}' in 'controlplane.yml'." unless app_config.key?(option)
|
|
127
|
+
|
|
128
|
+
value = app_config.fetch(option)
|
|
129
|
+
raise "Option '#{option}' for app '#{app}' in 'controlplane.yml' must be an array." unless value.is_a?(Array)
|
|
130
|
+
|
|
131
|
+
value
|
|
132
|
+
end
|
|
133
|
+
|
|
110
134
|
def action_description
|
|
111
|
-
mode == "stop" ? "suspend
|
|
135
|
+
mode == "stop" ? "suspend configured workloads in" : "delete"
|
|
112
136
|
end
|
|
113
137
|
|
|
114
138
|
def mode
|
|
@@ -80,6 +80,9 @@ module Command
|
|
|
80
80
|
upstream_image = cp.latest_image(@upstream, @upstream_org) if !upstream_image || upstream_image == "latest"
|
|
81
81
|
@commit = cp.extract_image_commit(upstream_image)
|
|
82
82
|
@upstream_image_url = "#{@upstream_org}.registry.cpln.io/#{upstream_image}"
|
|
83
|
+
rescue ControlplaneApiDirect::ForbiddenError => e
|
|
84
|
+
Shell.write_to_tmp_stderr(e.message)
|
|
85
|
+
false
|
|
83
86
|
end
|
|
84
87
|
end
|
|
85
88
|
|