cpflow 5.0.0.rc.1 → 5.0.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/{lib/github_flow_templates/.github → .github}/actions/cpflow-delete-control-plane-app/action.yml +5 -0
- data/{lib/github_flow_templates/.github → .github}/actions/cpflow-detect-release-phase/action.yml +7 -0
- data/.github/actions/cpflow-setup-environment/action.yml +161 -0
- data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +69 -0
- data/.github/workflows/cpflow-delete-review-app.yml +182 -0
- data/.github/workflows/cpflow-deploy-review-app.yml +507 -0
- data/.github/workflows/cpflow-deploy-staging.yml +168 -0
- data/.github/workflows/cpflow-help-command.yml +78 -0
- data/.github/workflows/cpflow-promote-staging-to-production.yml +510 -0
- data/.github/workflows/cpflow-review-app-help.yml +51 -0
- data/.github/workflows/rspec-shared.yml +3 -0
- data/.github/workflows/trigger-docs-site.yml +90 -0
- data/.rubocop.yml +14 -1
- data/CHANGELOG.md +43 -1
- data/CONTRIBUTING.md +27 -0
- data/Gemfile.lock +2 -2
- data/README.md +7 -3
- data/cpflow.gemspec +1 -1
- data/docs/ai-github-flow-prompt.md +1 -1
- data/docs/assets/cpflow-deploying.svg +46 -0
- data/docs/ci-automation.md +111 -8
- data/docs/commands.md +11 -5
- data/docs/thruster.md +149 -0
- data/docs/troubleshooting.md +8 -0
- data/lib/command/apply_template.rb +6 -2
- data/lib/command/base.rb +1 -0
- data/lib/command/cleanup_stale_apps.rb +53 -14
- data/lib/command/delete.rb +3 -1
- data/lib/command/deploy_image.rb +5 -2
- data/lib/command/generate.rb +7 -3
- data/lib/command/generate_github_actions.rb +21 -9
- data/lib/command/generator_helpers.rb +5 -1
- data/lib/command/info.rb +3 -1
- data/lib/command/run.rb +16 -1
- data/lib/command/test.rb +1 -3
- data/lib/core/controlplane.rb +17 -6
- data/lib/core/controlplane_api.rb +3 -1
- data/lib/core/controlplane_api_direct.rb +50 -27
- data/lib/core/doctor_service.rb +2 -2
- data/lib/core/github_flow_readiness_service.rb +26 -2
- data/lib/core/repo_introspection.rb +41 -3
- data/lib/core/shell.rb +3 -1
- data/lib/core/terraform_config/policy.rb +1 -1
- data/lib/cpflow/version.rb +1 -1
- data/lib/cpflow.rb +27 -13
- data/lib/generator_templates/templates/rails.yml +4 -0
- data/lib/generator_templates_sqlite/templates/rails.yml +4 -0
- data/lib/github_flow_templates/.github/cpflow-help.md +30 -1
- data/lib/github_flow_templates/.github/workflows/cpflow-cleanup-stale-review-apps.yml +10 -44
- data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +15 -114
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +10 -413
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-staging.yml +12 -123
- data/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +10 -33
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +13 -475
- data/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +12 -30
- data/lib/github_flow_templates/bin/pin-cpflow-github-ref +72 -0
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +89 -0
- data/rakelib/create_release.rake +4 -4
- metadata +26 -17
- data/lib/github_flow_templates/.github/actions/cpflow-setup-environment/action.yml +0 -98
- /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-build-docker-image/action.yml +0 -0
- /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-delete-control-plane-app/delete-app.sh +0 -0
- /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-validate-config/action.yml +0 -0
- /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-wait-for-health/action.yml +0 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
name: Trigger docs site rebuild
|
|
2
|
+
run-name: Docs dispatch (${{ github.event_name == 'workflow_dispatch' && inputs.reason || github.event_name }}) @ ${{ github.sha }}
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [main]
|
|
7
|
+
paths:
|
|
8
|
+
- README.md
|
|
9
|
+
- CHANGELOG.md
|
|
10
|
+
- CONTRIBUTING.md
|
|
11
|
+
- docs/**
|
|
12
|
+
workflow_dispatch:
|
|
13
|
+
inputs:
|
|
14
|
+
reason:
|
|
15
|
+
description: "Reason for forcing a docs rebuild"
|
|
16
|
+
required: false
|
|
17
|
+
default: "manual"
|
|
18
|
+
# Non-main manual dispatches are skipped by the job guard below.
|
|
19
|
+
# Only use this for forcing a rebuild from main.
|
|
20
|
+
|
|
21
|
+
concurrency:
|
|
22
|
+
# Include the ref so accidental non-main manual runs cannot cancel a main dispatch
|
|
23
|
+
# before the job guard skips them.
|
|
24
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
25
|
+
# Only the most recent docs dispatch for the same ref matters.
|
|
26
|
+
# See CONTRIBUTING.md for manual cancellation/retry guidance.
|
|
27
|
+
cancel-in-progress: true
|
|
28
|
+
|
|
29
|
+
jobs:
|
|
30
|
+
notify-docs-site:
|
|
31
|
+
runs-on: ubuntu-latest
|
|
32
|
+
if: github.ref == 'refs/heads/main' # skip non-main workflow_dispatch runs
|
|
33
|
+
permissions: {}
|
|
34
|
+
timeout-minutes: 5
|
|
35
|
+
steps:
|
|
36
|
+
- name: Generate GitHub App token
|
|
37
|
+
uses: actions/create-github-app-token@d72941d797fd3113feb6b93fd0dec494b13a2547 # v1.12.0
|
|
38
|
+
id: app-token
|
|
39
|
+
with:
|
|
40
|
+
app-id: ${{ secrets.DOCS_DISPATCH_APP_ID }}
|
|
41
|
+
private-key: ${{ secrets.DOCS_DISPATCH_APP_KEY }}
|
|
42
|
+
owner: shakacode
|
|
43
|
+
repositories: controlplaneflow-com
|
|
44
|
+
|
|
45
|
+
- name: Dispatch docs-updated event
|
|
46
|
+
id: dispatch
|
|
47
|
+
uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # v3.0.0
|
|
48
|
+
with:
|
|
49
|
+
token: ${{ steps.app-token.outputs.token }}
|
|
50
|
+
repository: shakacode/controlplaneflow-com
|
|
51
|
+
event-type: docs-updated
|
|
52
|
+
client-payload: |
|
|
53
|
+
{
|
|
54
|
+
"sha": ${{ toJSON(github.sha) }},
|
|
55
|
+
"ref": ${{ toJSON(github.ref) }},
|
|
56
|
+
"reason": ${{ toJSON(inputs.reason || github.event_name) }}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- name: Summarize docs dispatch
|
|
60
|
+
if: always()
|
|
61
|
+
env:
|
|
62
|
+
DISPATCH_OUTCOME: ${{ steps.dispatch.outcome }}
|
|
63
|
+
DISPATCH_REASON: ${{ inputs.reason || github.event_name }}
|
|
64
|
+
DISPATCH_REF: ${{ github.ref }}
|
|
65
|
+
DISPATCH_SHA: ${{ github.sha }}
|
|
66
|
+
run: |
|
|
67
|
+
safe_dispatch_reason=${DISPATCH_REASON//[^a-zA-Z0-9 _.\/-]/}
|
|
68
|
+
# Ref and SHA come from GitHub; the job guard restricts ref to main,
|
|
69
|
+
# and the SHA is the triggering commit id.
|
|
70
|
+
{
|
|
71
|
+
echo "### Docs site dispatch"
|
|
72
|
+
echo "- Target repository: \`shakacode/controlplaneflow-com\`"
|
|
73
|
+
echo "- Event type: \`docs-updated\`"
|
|
74
|
+
echo "- Source ref: \`${DISPATCH_REF}\`"
|
|
75
|
+
echo "- Source SHA: \`${DISPATCH_SHA}\`"
|
|
76
|
+
echo "- Reason: \`${safe_dispatch_reason}\`"
|
|
77
|
+
echo "- Dispatch outcome: \`${DISPATCH_OUTCOME}\`"
|
|
78
|
+
echo
|
|
79
|
+
if [ "$DISPATCH_OUTCOME" = "success" ]; then
|
|
80
|
+
echo "Check the target repository workflow runs for downstream rebuild status."
|
|
81
|
+
elif [ "$DISPATCH_OUTCOME" = "skipped" ]; then
|
|
82
|
+
echo "Dispatch was skipped because a prior step did not complete successfully."
|
|
83
|
+
elif [ "$DISPATCH_OUTCOME" = "failure" ]; then
|
|
84
|
+
echo "Dispatch step failed. Inspect this job's logs and verify the App token has Contents: Write on the target repo."
|
|
85
|
+
elif [ "$DISPATCH_OUTCOME" = "cancelled" ]; then
|
|
86
|
+
echo "Dispatch step was interrupted mid-execution. Check the target repo's workflow runs because the event may or may not have been received."
|
|
87
|
+
else
|
|
88
|
+
echo "Dispatch outcome: ${DISPATCH_OUTCOME}. Inspect this job's logs before checking the target repository workflow runs."
|
|
89
|
+
fi
|
|
90
|
+
} >> "$GITHUB_STEP_SUMMARY"
|
data/.rubocop.yml
CHANGED
|
@@ -4,7 +4,7 @@ plugins:
|
|
|
4
4
|
|
|
5
5
|
AllCops:
|
|
6
6
|
TargetRubyVersion: 3.0
|
|
7
|
-
NewCops:
|
|
7
|
+
NewCops: enable
|
|
8
8
|
|
|
9
9
|
Metrics/AbcSize:
|
|
10
10
|
Enabled: false
|
|
@@ -24,3 +24,16 @@ RSpec/MultipleExpectations:
|
|
|
24
24
|
RSpec/NestedGroups:
|
|
25
25
|
Enabled: true
|
|
26
26
|
Max: 5
|
|
27
|
+
|
|
28
|
+
# Test support and Rails dummy app scripts intentionally write to stdout for
|
|
29
|
+
# verbose test output and setup messages — not actual specs.
|
|
30
|
+
RSpec/Output:
|
|
31
|
+
Exclude:
|
|
32
|
+
- spec/support/**/*
|
|
33
|
+
- spec/dummy/**/*
|
|
34
|
+
|
|
35
|
+
# Empty blocks in this spec are intentional — the DSL must render empty
|
|
36
|
+
# Terraform blocks correctly.
|
|
37
|
+
Lint/EmptyBlock:
|
|
38
|
+
Exclude:
|
|
39
|
+
- spec/core/terraform_config/dsl_spec.rb
|
data/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,46 @@ In addition to the standard keepachangelog.com categories, this project uses a l
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [5.0.0] - 2026-05-23
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
- Promotes the 5.x release-candidate line to stable. The breaking changes introduced during the 5.0.0 prerelease cycle are documented in `5.0.0.rc.1`, including the Ruby 3.0 minimum, `cpflow exists` not-found exit code change, and generated Dockerfile production-group behavior.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Promoted the 5.0.0 release-candidate line to stable. This release includes the generated GitHub Actions flow, upstream reusable workflow model, Node 24 action updates, richer review-app command feedback, generated downstream pin/validation helpers, and cleanup/run/deploy fixes documented in `5.0.0.rc.3`.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Fixed packaged `cpflow` gems failing to boot without the development-only `debug` gem installed.** [PR 314](https://github.com/shakacode/control-plane-flow/pull/314) by [Justin Gordon](https://github.com/justin808). The hidden `cpflow test` command no longer requires `debug` while loading the CLI, and coverage now exercises loading `cpflow` with `require "debug"` blocked.
|
|
28
|
+
|
|
29
|
+
## [5.0.0.rc.3] - 2026-05-23
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Added `--mode=stop` to `cleanup-stale-apps` for reversible idle-app handling.** [PR 302](https://github.com/shakacode/control-plane-flow/pull/302) by [Justin Gordon](https://github.com/justin808). Suspends all workloads via `cpflow ps:stop` instead of deleting; restore with `cpflow ps:start`. Default `--mode=delete` preserves existing behavior. Fixes [issue 295](https://github.com/shakacode/control-plane-flow/issues/295).
|
|
34
|
+
- **Added generated local helpers for downstream GitHub Actions ref pinning and validation.** [PR 308](https://github.com/shakacode/control-plane-flow/pull/308) by [Justin Gordon](https://github.com/justin808). `cpflow generate-github-actions` now writes `bin/pin-cpflow-github-ref` and `bin/test-cpflow-github-flow` so downstream repos can safely pin wrappers to release tags or full upstream commit SHAs, validate wrapper ref consistency, and test unreleased upstream workflow changes without using moving branch refs.
|
|
35
|
+
- **Added richer generated review-app command feedback.** [PR 304](https://github.com/shakacode/control-plane-flow/pull/304) by [Justin Gordon](https://github.com/justin808). Generated review-app deploy/delete/help workflows now react promptly to commands, publish structured progress/success/failure comments, and support `REVIEW_APP_DEPLOYING_ICON_URL` or `none` for the deploying indicator.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- **Changed generated GitHub Actions output to thin downstream wrappers backed by upstream reusable workflows and shared composite actions.** [PR 305](https://github.com/shakacode/control-plane-flow/pull/305) by [Justin Gordon](https://github.com/justin808). Deployment, deletion, staging, promotion, cleanup, comment formatting, Control Plane setup, and Docker image build logic now live upstream in this repository; `CPFLOW_GITHUB_ACTIONS_REF` controls which upstream ref generated wrappers use.
|
|
40
|
+
- **Documented the downstream testing and release model for reusable GitHub Actions.** [PR 308](https://github.com/shakacode/control-plane-flow/pull/308) by [Justin Gordon](https://github.com/justin808). The CI automation docs now spell out what is tied to the upstream GitHub ref, what is tied to the RubyGems version, how `CPFLOW_VERSION` changes runtime installation, and how to test an unmerged upstream PR from a downstream app.
|
|
41
|
+
- **Updated generated GitHub Actions workflow templates to Node 24-compatible action versions.** [PR 303](https://github.com/shakacode/control-plane-flow/pull/303) by [Justin Gordon](https://github.com/justin808). Uses `actions/checkout@v6` and `actions/github-script@v8`.
|
|
42
|
+
- **Shortened the generated review-app command quick reference.** [PR 290](https://github.com/shakacode/control-plane-flow/pull/290) by [Justin Gordon](https://github.com/justin808). Keeps the three `+review-app-*` commands and the setup-help pointer while reducing repeated wording in the PR-open comment.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **Relaxed the `thor` runtime dependency from `~> 1.4` to `~> 1.3`.** [PR 291](https://github.com/shakacode/control-plane-flow/pull/291) by [Justin Gordon](https://github.com/justin808). Allows cpflow to be bundled into Rails 8 apps that pull in `solid_queue` 1.1.0, which pins `thor ~> 1.3.1`. Fixes [issue 264](https://github.com/shakacode/control-plane-flow/issues/264).
|
|
47
|
+
- **Fixed `deploy-image` showing container names instead of workload names in deploy progress and endpoint summaries.** [PR 294](https://github.com/shakacode/control-plane-flow/pull/294) by [Justin Gordon](https://github.com/justin808). Also guards against duplicate work per workload by deploying only the first container whose image matches the app-image pattern. Fixes [issue 255](https://github.com/shakacode/control-plane-flow/issues/255).
|
|
48
|
+
- **Fixed `cpflow run` interactive sessions printing a confusing non-zero exit error on command failure or session close.** [PR 301](https://github.com/shakacode/control-plane-flow/pull/301) by [Justin Gordon](https://github.com/justin808). cpflow now prints an actionable `cpflow ps:stop` hint instead; exit code 64 is returned for non-zero exits and 130 for signal termination so scripted callers can still detect failure. Fixes [issue 199](https://github.com/shakacode/control-plane-flow/issues/199).
|
|
49
|
+
- **Fixed `cpflow generate` and generated GitHub Actions edge cases.** [PR 288](https://github.com/shakacode/control-plane-flow/pull/288) by [Justin Gordon](https://github.com/justin808). Detects nested production SQLite configs, normalizes folded Shakapacker precompile hooks, gates delete-review-app steps on config readiness, routes `github-script` values through environment variables, and honors HTTPS proxy settings during registry readiness checks.
|
|
50
|
+
- **Fixed generated `cpflow-setup-environment` Ruby setup when downstream apps do not provide a Ruby version file.** [PR 306](https://github.com/shakacode/control-plane-flow/pull/306) by [Justin Gordon](https://github.com/justin808). The shared action now auto-detects `.ruby-version`, `.tool-versions`, `mise.toml`, `.mise.toml`, or a `Gemfile` Ruby directive and falls back to Ruby 3.2 when none is present.
|
|
51
|
+
- **Fixed `cpflow-detect-release-phase` failing with a raw Ruby traceback when `.controlplane/controlplane.yml` is missing.** [PR 299](https://github.com/shakacode/control-plane-flow/pull/299) by [Justin Gordon](https://github.com/justin808). The generated composite action now exits with a clear missing-config message.
|
|
52
|
+
- **Fixed generated review-app delete workflows running `cpflow delete` from the wrong checkout.** [PR 307](https://github.com/shakacode/control-plane-flow/pull/307) by [Justin Gordon](https://github.com/justin808). The generated workflow checks out the downstream repository into `app/` and runs setup/delete from that working directory so `.controlplane/controlplane.yml` is available.
|
|
53
|
+
- **Fixed `cleanup-stale-apps` skipping image-less GVCs indefinitely.** [PR 310](https://github.com/shakacode/control-plane-flow/pull/310) by [Justin Gordon](https://github.com/justin808). Image-less GVCs now fall back to the GVC `created` timestamp for stale-app detection, while GVCs missing `created` are skipped instead of raising.
|
|
54
|
+
|
|
15
55
|
## [5.0.0.rc.1] - 2026-05-11
|
|
16
56
|
|
|
17
57
|
### Breaking Changes
|
|
@@ -313,7 +353,9 @@ Deprecated `cpl` gem. New gem is `cpflow`.
|
|
|
313
353
|
|
|
314
354
|
First release.
|
|
315
355
|
|
|
316
|
-
[Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0
|
|
356
|
+
[Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0...HEAD
|
|
357
|
+
[5.0.0]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.3...v5.0.0
|
|
358
|
+
[5.0.0.rc.3]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.1...v5.0.0.rc.3
|
|
317
359
|
[5.0.0.rc.1]: https://github.com/shakacode/control-plane-flow/compare/v4.2.0...v5.0.0.rc.1
|
|
318
360
|
[4.2.0]: https://github.com/shakacode/control-plane-flow/compare/v4.1.1...v4.2.0
|
|
319
361
|
[4.1.1]: https://github.com/shakacode/control-plane-flow/compare/v4.1.0...v4.1.1
|
data/CONTRIBUTING.md
CHANGED
|
@@ -27,6 +27,33 @@ gem install overcommit
|
|
|
27
27
|
overcommit --install
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
+
## Docs Site Dispatch
|
|
31
|
+
|
|
32
|
+
The `trigger-docs-site.yml` workflow notifies `shakacode/controlplaneflow-com` when docs-related files change on `main`.
|
|
33
|
+
It requires these repository secrets:
|
|
34
|
+
|
|
35
|
+
- `DOCS_DISPATCH_APP_ID`: the GitHub App ID used to create the dispatch token
|
|
36
|
+
- `DOCS_DISPATCH_APP_KEY`: the GitHub App private key PEM for that app
|
|
37
|
+
|
|
38
|
+
GitHub's REST docs for the repository dispatch endpoint list **Contents: Write** as the required repository permission for
|
|
39
|
+
GitHub App installation tokens. This is separate from **Actions: Write**, which is used by other workflow APIs. Install
|
|
40
|
+
the app on `shakacode/controlplaneflow-com` with **Contents: Write**. If the dispatch succeeds but the docs site does not
|
|
41
|
+
rebuild, check the target repo's workflow runs for the matching `docs-updated` event.
|
|
42
|
+
|
|
43
|
+
Manual runs should be started from `main`; non-main manual dispatches are skipped before token generation or docs-site
|
|
44
|
+
notification. The GitHub Actions run can therefore finish without dispatching anything when a non-main ref is selected.
|
|
45
|
+
The workflow deduplicates runs by workflow and ref with `cancel-in-progress: true`, so consecutive `main` runs can
|
|
46
|
+
supersede one another; that is expected because the newest docs state wins.
|
|
47
|
+
|
|
48
|
+
If the job fails and the summary shows `Dispatch outcome: skipped`, the dispatch step did not run because an earlier step
|
|
49
|
+
failed. Check the `Generate GitHub App token` step first, including the App ID, private key secret, installation, and target
|
|
50
|
+
repository permissions.
|
|
51
|
+
|
|
52
|
+
If a manual dispatch is canceled and no later successful `main` run replaces it, re-trigger the manual run from `main`. If
|
|
53
|
+
the run is canceled while the dispatch step is already executing, the target repo may already have received the event; check
|
|
54
|
+
the target repo workflow runs before re-triggering. Duplicate dispatches are harmless, but they can rebuild the docs site
|
|
55
|
+
twice.
|
|
56
|
+
|
|
30
57
|
## Testing
|
|
31
58
|
|
|
32
59
|
We use real apps for the tests. You'll need to have full access to a Control Plane org, and then set it as the env var `CPLN_ORG` when running the tests (or in the `.env` file):
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -65,6 +65,7 @@ Additionally, the documentation includes numerous examples and practical tips fo
|
|
|
65
65
|
14. [Migrating Postgres Database from Heroku Infrastructure](https://www.shakacode.com/control-plane-flow/docs/postgres/)
|
|
66
66
|
15. [Migrating Redis Database from Heroku Infrastructure](https://www.shakacode.com/control-plane-flow/docs/redis/)
|
|
67
67
|
16. [Tips](https://www.shakacode.com/control-plane-flow/docs/tips/)
|
|
68
|
+
17. [Thruster HTTP/2 Proxy on Control Plane](https://www.shakacode.com/control-plane-flow/docs/thruster/)
|
|
68
69
|
|
|
69
70
|
## Key Features
|
|
70
71
|
|
|
@@ -278,8 +279,8 @@ aliases:
|
|
|
278
279
|
# If not specified, defaults to 21600 (6 hours).
|
|
279
280
|
runner_job_timeout: 1000
|
|
280
281
|
|
|
281
|
-
# Apps with a deployed image created before this amount of days
|
|
282
|
-
# when running the command `cpflow cleanup-stale-apps`.
|
|
282
|
+
# Apps with a deployed image, or an image-less GVC, created before this amount of days
|
|
283
|
+
# will be listed for deletion when running the command `cpflow cleanup-stale-apps`.
|
|
283
284
|
stale_app_image_deployed_days: 5
|
|
284
285
|
|
|
285
286
|
# Images that exceed this quantity will be listed for deletion
|
|
@@ -357,9 +358,12 @@ cpflow generate
|
|
|
357
358
|
|
|
358
359
|
# Create reusable GitHub Actions for review apps, staging, and production promotion
|
|
359
360
|
cpflow generate-github-actions
|
|
361
|
+
|
|
362
|
+
# Validate the generated GitHub Actions wrapper refs and metadata
|
|
363
|
+
bin/test-cpflow-github-flow
|
|
360
364
|
```
|
|
361
365
|
|
|
362
|
-
`cpflow github-flow-readiness` exits non-zero when it finds blockers such as unpublished exact-pinned packages or a missing production Dockerfile, so use it as the gate before generation. Then review the generated `.controlplane/controlplane.yml` entries, adjust any app-specific workloads, and configure the GitHub repository variables and secrets described in [CI automation](./docs/ci-automation.md), including the optional Docker build settings for private GitHub dependencies and custom SSH known hosts. `cpflow generate` already switches to persistent `db` and `storage` volumes when `config/database.yml` shows SQLite in production and preserves detected frontend precompile hooks, but you should still confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement and that the emitted workload set matches the real app. If you want an AI agent to do this end to end, start with the [AI rollout prompt](./docs/ai-github-flow-prompt.md) or run `cpflow ai-github-flow-prompt` in the target repo rather than giving a vague "set up CI" request.
|
|
366
|
+
`cpflow github-flow-readiness` exits non-zero when it finds blockers such as unpublished exact-pinned packages or a missing production Dockerfile, so use it as the gate before generation. Then review the generated `.controlplane/controlplane.yml` entries, adjust any app-specific workloads, and configure the GitHub repository variables and secrets described in [CI automation](./docs/ci-automation.md), including the optional Docker build settings for private GitHub dependencies and custom SSH known hosts. `cpflow generate-github-actions` also writes `bin/test-cpflow-github-flow` for local validation and `bin/pin-cpflow-github-ref` for temporarily pinning downstream wrappers to an upstream commit SHA during pre-release testing. `cpflow generate` already switches to persistent `db` and `storage` volumes when `config/database.yml` shows SQLite in production and preserves detected frontend precompile hooks, but you should still confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement and that the emitted workload set matches the real app. If you want an AI agent to do this end to end, start with the [AI rollout prompt](./docs/ai-github-flow-prompt.md) or run `cpflow ai-github-flow-prompt` in the target repo rather than giving a vague "set up CI" request.
|
|
363
367
|
|
|
364
368
|
For a live example, see the [react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md) repository.
|
|
365
369
|
|
data/cpflow.gemspec
CHANGED
|
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
|
|
|
18
18
|
spec.add_dependency "dotenv", "~> 3.1"
|
|
19
19
|
spec.add_dependency "jwt", "~> 3.1"
|
|
20
20
|
spec.add_dependency "psych", "~> 5.2"
|
|
21
|
-
spec.add_dependency "thor", "~> 1.
|
|
21
|
+
spec.add_dependency "thor", "~> 1.3"
|
|
22
22
|
|
|
23
23
|
spec.files = `git ls-files -z`.split("\x0").reject do |file|
|
|
24
24
|
file.match(%r{^(coverage|pkg|spec|tmp)/})
|
|
@@ -44,7 +44,7 @@ Stop and report the blocker instead of generating `cpflow-*` workflow files when
|
|
|
44
44
|
The rollout is done when all of the following are true:
|
|
45
45
|
|
|
46
46
|
- `.controlplane/` exists and matches the actual app shape
|
|
47
|
-
- `.github/
|
|
47
|
+
- `.github/cpflow-help.md` and `.github/workflows/cpflow-*` wrappers are in place
|
|
48
48
|
- review apps are opt-in, staging auto-deploys from one branch, and production promotion is manual
|
|
49
49
|
- required GitHub secrets and variables are documented for the repo
|
|
50
50
|
- the production image build path is validated for the real app
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">Deploying</title>
|
|
3
|
+
<desc id="desc">Animated deployment progress icon for Control Plane Flow review apps.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="ring" x1="8" x2="56" y1="8" y2="56" gradientUnits="userSpaceOnUse">
|
|
6
|
+
<stop offset="0" stop-color="#3ddc97"/>
|
|
7
|
+
<stop offset="0.5" stop-color="#4f8cff"/>
|
|
8
|
+
<stop offset="1" stop-color="#ffb84d"/>
|
|
9
|
+
</linearGradient>
|
|
10
|
+
<filter id="soft-shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
11
|
+
<feDropShadow dx="0" dy="2" stdDeviation="2" flood-color="#233044" flood-opacity="0.22"/>
|
|
12
|
+
</filter>
|
|
13
|
+
</defs>
|
|
14
|
+
|
|
15
|
+
<circle cx="32" cy="32" r="28" fill="#f7fbff"/>
|
|
16
|
+
<circle cx="32" cy="32" r="23" fill="none" stroke="#d7e4f2" stroke-width="4"/>
|
|
17
|
+
|
|
18
|
+
<g>
|
|
19
|
+
<animateTransform
|
|
20
|
+
attributeName="transform"
|
|
21
|
+
type="rotate"
|
|
22
|
+
from="0 32 32"
|
|
23
|
+
to="360 32 32"
|
|
24
|
+
dur="1.1s"
|
|
25
|
+
repeatCount="indefinite"/>
|
|
26
|
+
<circle
|
|
27
|
+
cx="32"
|
|
28
|
+
cy="32"
|
|
29
|
+
r="23"
|
|
30
|
+
fill="none"
|
|
31
|
+
stroke="url(#ring)"
|
|
32
|
+
stroke-linecap="round"
|
|
33
|
+
stroke-width="4"
|
|
34
|
+
stroke-dasharray="40 110"/>
|
|
35
|
+
</g>
|
|
36
|
+
|
|
37
|
+
<g filter="url(#soft-shadow)">
|
|
38
|
+
<path d="M35.7 13.5c-7.8 3.1-13 10-15.8 20.8l9.8 9.8c10.8-2.8 17.7-8 20.8-15.8 1.7-4.4 1.4-9.7-.9-14-4.3-2.2-9.6-2.6-13.9-.8Z" fill="#ffffff"/>
|
|
39
|
+
<path d="M35.7 13.5c-7.8 3.1-13 10-15.8 20.8l9.8 9.8c10.8-2.8 17.7-8 20.8-15.8 1.7-4.4 1.4-9.7-.9-14-4.3-2.2-9.6-2.6-13.9-.8Z" fill="#4f8cff" opacity="0.18"/>
|
|
40
|
+
<path d="M35.7 13.5c-7.8 3.1-13 10-15.8 20.8l9.8 9.8c10.8-2.8 17.7-8 20.8-15.8 1.7-4.4 1.4-9.7-.9-14-4.3-2.2-9.6-2.6-13.9-.8Z" fill="none" stroke="#233044" stroke-width="2" stroke-linejoin="round"/>
|
|
41
|
+
<circle cx="39.7" cy="24.3" r="4.5" fill="#3ddc97" stroke="#233044" stroke-width="2"/>
|
|
42
|
+
<path d="M20.2 34.1 13.5 36l7.1 7.1 2-6.6-2.4-2.4Z" fill="#ffb84d" stroke="#233044" stroke-width="2" stroke-linejoin="round"/>
|
|
43
|
+
<path d="M29.9 43.8 28 50.5l-7.1-7.1 6.6-2 2.4 2.4Z" fill="#ff6b6b" stroke="#233044" stroke-width="2" stroke-linejoin="round"/>
|
|
44
|
+
<path d="M18.8 45.2c-2.4.7-4.1 2.4-5.2 5.2 2.8-1.1 4.5-2.8 5.2-5.2Z" fill="#ffb84d"/>
|
|
45
|
+
</g>
|
|
46
|
+
</svg>
|
data/docs/ci-automation.md
CHANGED
|
@@ -16,7 +16,7 @@ End-to-end rollout in one view:
|
|
|
16
16
|
|
|
17
17
|
1. `cpflow github-flow-readiness` — exits non-zero if the repo is not ready to deploy.
|
|
18
18
|
2. `cpflow generate` — creates `.controlplane/` if missing.
|
|
19
|
-
3. `cpflow generate-github-actions` — adds
|
|
19
|
+
3. `cpflow generate-github-actions` — adds thin `cpflow-*` workflow wrappers that call upstream reusable workflows.
|
|
20
20
|
4. Configure the GitHub [repository secrets and variables](#required-github-repository-settings) the workflows expect.
|
|
21
21
|
5. Push the branch, then comment `+review-app-deploy` on a PR to spin up a review environment.
|
|
22
22
|
|
|
@@ -52,10 +52,7 @@ not appear to exist in the public registries.
|
|
|
52
52
|
|
|
53
53
|
The second command writes namespaced files so they can coexist with an app's existing CI:
|
|
54
54
|
|
|
55
|
-
- `.github/
|
|
56
|
-
- `.github/actions/cpflow-delete-control-plane-app/action.yml`
|
|
57
|
-
- `.github/actions/cpflow-delete-control-plane-app/delete-app.sh`
|
|
58
|
-
- `.github/actions/cpflow-setup-environment/action.yml`
|
|
55
|
+
- `.github/cpflow-help.md`
|
|
59
56
|
- `.github/workflows/cpflow-review-app-help.yml`
|
|
60
57
|
- `.github/workflows/cpflow-help-command.yml`
|
|
61
58
|
- `.github/workflows/cpflow-deploy-review-app.yml`
|
|
@@ -63,6 +60,8 @@ The second command writes namespaced files so they can coexist with an app's exi
|
|
|
63
60
|
- `.github/workflows/cpflow-deploy-staging.yml`
|
|
64
61
|
- `.github/workflows/cpflow-promote-staging-to-production.yml`
|
|
65
62
|
- `.github/workflows/cpflow-cleanup-stale-review-apps.yml`
|
|
63
|
+
- `bin/pin-cpflow-github-ref`
|
|
64
|
+
- `bin/test-cpflow-github-flow`
|
|
66
65
|
|
|
67
66
|
`cpflow generate` also infers the app prefix from the repo directory, infers the
|
|
68
67
|
Docker base Ruby version from `.ruby-version`, `.tool-versions`, or the app's
|
|
@@ -253,14 +252,118 @@ The action will start an SSH agent, add the key, write `known_hosts`, and pass `
|
|
|
253
252
|
- Runs nightly and on demand.
|
|
254
253
|
- Deletes stale review apps using `cpflow cleanup-stale-apps`.
|
|
255
254
|
|
|
256
|
-
##
|
|
255
|
+
## Upstream Reusable Workflows
|
|
257
256
|
|
|
258
|
-
The generated workflows
|
|
257
|
+
The generated workflows are intentionally small wrappers. The deployment logic,
|
|
258
|
+
comment formatting, Control Plane CLI setup, Docker image build, and cleanup helpers
|
|
259
|
+
live in upstream reusable workflows and composite actions in this repository.
|
|
259
260
|
|
|
260
|
-
- `cpflow-setup-environment`: installs Ruby, the Control Plane CLI, and
|
|
261
|
+
- `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 reusable-workflow ref; set the `CPFLOW_VERSION` repository variable only when you want to force a published RubyGems release.
|
|
261
262
|
- `cpflow-build-docker-image`: builds and pushes the app image with the desired commit SHA
|
|
262
263
|
- `cpflow-delete-control-plane-app`: safely deletes temporary apps and refuses to touch names outside the configured review-app prefix
|
|
263
264
|
|
|
265
|
+
## Version Pins: GitHub Ref vs RubyGems
|
|
266
|
+
|
|
267
|
+
The generated `cpflow-*` workflow files are thin wrappers around reusable
|
|
268
|
+
workflows in `shakacode/control-plane-flow`. GitHub loads reusable workflows
|
|
269
|
+
from a repository ref, not from the Ruby gem, so each wrapper has an upstream
|
|
270
|
+
GitHub ref:
|
|
271
|
+
|
|
272
|
+
```yaml
|
|
273
|
+
uses: shakacode/control-plane-flow/.github/workflows/cpflow-deploy-review-app.yml@<ref>
|
|
274
|
+
with:
|
|
275
|
+
control_plane_flow_ref: <ref>
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Those two pins must stay in sync:
|
|
279
|
+
|
|
280
|
+
- `uses: ...@<ref>` chooses the upstream reusable workflow file.
|
|
281
|
+
- `control_plane_flow_ref: <ref>` tells that reusable workflow which
|
|
282
|
+
`control-plane-flow` checkout to use for shared composite actions and, when
|
|
283
|
+
`CPFLOW_VERSION` is empty, for building and installing the `cpflow` gem.
|
|
284
|
+
|
|
285
|
+
The stable release path is still gem-driven:
|
|
286
|
+
|
|
287
|
+
1. Publish a `cpflow` gem.
|
|
288
|
+
2. Install or bundle that released gem in the downstream project.
|
|
289
|
+
3. Run `cpflow generate-github-actions`.
|
|
290
|
+
4. Commit the generated wrappers that point to the matching upstream release tag
|
|
291
|
+
such as `v5.0.0`.
|
|
292
|
+
|
|
293
|
+
That release tag should point to the same source that produced the RubyGems
|
|
294
|
+
release. Downstream production automation should use release tags, not `main` or
|
|
295
|
+
feature-branch refs.
|
|
296
|
+
|
|
297
|
+
`CPFLOW_VERSION` is a runtime override. If a downstream repository sets the
|
|
298
|
+
`CPFLOW_VERSION` variable, the setup action runs `gem install cpflow -v
|
|
299
|
+
<version>`. If it is unset, the setup action builds `cpflow` from the checked-out
|
|
300
|
+
`control-plane-flow` ref. For normal releases, leave `CPFLOW_VERSION` unset while
|
|
301
|
+
pinning the wrappers to the matching `v<version>` tag, or set
|
|
302
|
+
`CPFLOW_VERSION` to that same released gem version without the leading `v`.
|
|
303
|
+
|
|
304
|
+
## Testing Unreleased Upstream Changes Downstream
|
|
305
|
+
|
|
306
|
+
You can test a `control-plane-flow` PR in a downstream app before merging or
|
|
307
|
+
releasing it. Use an immutable commit SHA from the upstream PR branch:
|
|
308
|
+
|
|
309
|
+
1. Push the upstream PR branch and copy its full 40-character head SHA.
|
|
310
|
+
2. In a downstream test branch, run:
|
|
311
|
+
|
|
312
|
+
```sh
|
|
313
|
+
bin/pin-cpflow-github-ref <upstream-pr-sha>
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
The helper updates every generated `cpflow-*` workflow wrapper. It accepts
|
|
317
|
+
release tags and full commit SHAs by default, rejects branch names such as
|
|
318
|
+
`main` or `feature/foo`, and requires `--allow-moving-ref` for short-lived
|
|
319
|
+
local experiments that should not be committed.
|
|
320
|
+
|
|
321
|
+
3. Keep `CPFLOW_VERSION` unset so the workflow builds `cpflow` from the same
|
|
322
|
+
upstream SHA that supplies the reusable workflow and composite actions.
|
|
323
|
+
4. Run:
|
|
324
|
+
|
|
325
|
+
```sh
|
|
326
|
+
bin/test-cpflow-github-flow
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Pass a local checkout command when you are validating unreleased generator
|
|
330
|
+
code before it is installed:
|
|
331
|
+
|
|
332
|
+
```sh
|
|
333
|
+
bin/test-cpflow-github-flow ruby /path/to/control-plane-flow/bin/cpflow
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
5. Open a downstream PR and trigger the real review app with a comment whose body
|
|
337
|
+
is exactly:
|
|
338
|
+
|
|
339
|
+
```text
|
|
340
|
+
+review-app-deploy
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
6. Verify the deploy logs show the expected upstream commit SHA, the setup step
|
|
344
|
+
prints the expected `cpflow` source/version, and the review app URL returns
|
|
345
|
+
HTTP 200.
|
|
346
|
+
7. After the upstream PR merges and a gem is released, regenerate or repin the
|
|
347
|
+
downstream wrappers to the release tag.
|
|
348
|
+
|
|
349
|
+
This tests the real reusable workflow, shared composite actions, and source-built
|
|
350
|
+
`cpflow` gem from one immutable upstream commit. It avoids merging upstream blind
|
|
351
|
+
and avoids running production automation against a moving branch.
|
|
352
|
+
|
|
353
|
+
## Local Generated-Flow Checks
|
|
354
|
+
|
|
355
|
+
Run this after generation or after changing a downstream wrapper ref:
|
|
356
|
+
|
|
357
|
+
```sh
|
|
358
|
+
bin/test-cpflow-github-flow
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
The helper runs `cpflow github-flow-readiness`, parses generated workflow YAML,
|
|
362
|
+
checks composite action metadata for literal GitHub expressions in descriptions,
|
|
363
|
+
checks that all generated wrappers use one upstream ref consistently, requires
|
|
364
|
+
secret-inheriting reusable workflows to pass `control_plane_flow_ref`, and runs
|
|
365
|
+
`actionlint -ignore "SC2129" .github/workflows/cpflow-*.yml`.
|
|
366
|
+
|
|
264
367
|
## Applying This to React on Rails Demo Apps
|
|
265
368
|
|
|
266
369
|
This flow is a good fit for the React on Rails demo apps because they already follow the same basic assumptions:
|
data/docs/commands.md
CHANGED
|
@@ -78,15 +78,21 @@ cpflow cleanup-images -a $APP_NAME
|
|
|
78
78
|
|
|
79
79
|
### `cleanup-stale-apps`
|
|
80
80
|
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
-
|
|
81
|
+
- Acts on stale apps based on the creation date of the latest image, or the GVC if no images exist
|
|
82
|
+
- 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 as long as both the identity and the policy exist (and are bound)
|
|
83
|
+
- With `--mode=stop`: suspends all workloads via `cpflow ps:stop` — no GVC, volumeset, or image is removed; resume with `cpflow ps:start`
|
|
84
|
+
- `--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
|
|
85
|
+
- `--mode=stop` returns once each workload is marked suspended; it does not wait for the workload to reach a not-ready state
|
|
84
86
|
- Specify the amount of days after an app should be considered stale through `stale_app_image_deployed_days` in the `.controlplane/controlplane.yml` file
|
|
85
|
-
- If `match_if_app_name_starts_with` is `true` in the `.controlplane/controlplane.yml` file, it will
|
|
87
|
+
- If `match_if_app_name_starts_with` is `true` in the `.controlplane/controlplane.yml` file, it will act on all stale apps that start with the name
|
|
86
88
|
- Will ask for explicit user confirmation
|
|
87
89
|
|
|
88
90
|
```sh
|
|
91
|
+
# Deletes stale apps (default).
|
|
89
92
|
cpflow cleanup-stale-apps -a $APP_NAME
|
|
93
|
+
|
|
94
|
+
# Stops stale apps instead of deleting them; resume with `cpflow ps:start`.
|
|
95
|
+
cpflow cleanup-stale-apps -a $APP_NAME --mode=stop
|
|
90
96
|
```
|
|
91
97
|
|
|
92
98
|
### `config`
|
|
@@ -214,7 +220,7 @@ other than `main` or `master`; the generator will bake that branch into the
|
|
|
214
220
|
GitHub Actions push trigger and use it as the default STAGING_APP_BRANCH.
|
|
215
221
|
|
|
216
222
|
```sh
|
|
217
|
-
# Creates
|
|
223
|
+
# Creates thin .github/workflows wrappers for the Control Plane flow
|
|
218
224
|
cpflow generate-github-actions
|
|
219
225
|
|
|
220
226
|
# Creates the flow with staging deploys triggered from develop
|