cpflow 4.2.0 → 5.0.0.rc.1

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.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.agents/workflows/address-review.md +216 -0
  3. data/.claude/commands/address-review.md +547 -0
  4. data/.claude/commands/update-changelog.md +367 -0
  5. data/.github/workflows/claude.yml +5 -0
  6. data/.overcommit.yml +43 -3
  7. data/.rubocop.yml +3 -3
  8. data/CHANGELOG.md +28 -4
  9. data/CONTRIBUTING.md +28 -0
  10. data/Gemfile +8 -7
  11. data/Gemfile.lock +92 -72
  12. data/README.md +55 -20
  13. data/cpflow.gemspec +5 -5
  14. data/docs/ai-github-flow-prompt.md +61 -0
  15. data/docs/ci-automation.md +335 -28
  16. data/docs/commands.md +67 -4
  17. data/docs/migrating-heroku-to-control-plane.md +12 -0
  18. data/docs/postgres.md +5 -0
  19. data/docs/redis.md +6 -0
  20. data/docs/releasing.md +153 -0
  21. data/lib/command/ai_github_flow_prompt.rb +47 -0
  22. data/lib/command/base.rb +25 -0
  23. data/lib/command/cleanup_images.rb +1 -1
  24. data/lib/command/cleanup_stale_apps.rb +1 -1
  25. data/lib/command/copy_image_from_upstream.rb +14 -3
  26. data/lib/command/deploy_image.rb +40 -9
  27. data/lib/command/exists.rb +13 -2
  28. data/lib/command/generate.rb +153 -4
  29. data/lib/command/generate_github_actions.rb +170 -0
  30. data/lib/command/generator_helpers.rb +31 -0
  31. data/lib/command/github_flow_readiness.rb +37 -0
  32. data/lib/command/promote_app_from_upstream.rb +13 -2
  33. data/lib/command/run.rb +1 -1
  34. data/lib/command/terraform/generate.rb +1 -0
  35. data/lib/command/version.rb +1 -0
  36. data/lib/constants/exit_code.rb +1 -0
  37. data/lib/core/config.rb +8 -0
  38. data/lib/core/controlplane.rb +9 -7
  39. data/lib/core/controlplane_api_direct.rb +3 -3
  40. data/lib/core/github_flow_readiness/checks.rb +143 -0
  41. data/lib/core/github_flow_readiness_service.rb +453 -0
  42. data/lib/core/repo_introspection.rb +118 -0
  43. data/lib/core/terraform_config/dsl.rb +1 -1
  44. data/lib/core/terraform_config/local_variable.rb +1 -1
  45. data/lib/cpflow/version.rb +1 -1
  46. data/lib/cpflow.rb +65 -3
  47. data/lib/generator_templates/Dockerfile +59 -3
  48. data/lib/generator_templates/controlplane.yml +27 -39
  49. data/lib/generator_templates/entrypoint.sh +1 -1
  50. data/lib/generator_templates/release_script.sh +23 -0
  51. data/lib/generator_templates/templates/app.yml +5 -8
  52. data/lib/generator_templates/templates/rails.yml +2 -11
  53. data/lib/generator_templates_sqlite/controlplane.yml +46 -0
  54. data/lib/generator_templates_sqlite/release_script.sh +25 -0
  55. data/lib/generator_templates_sqlite/templates/app.yml +15 -0
  56. data/lib/generator_templates_sqlite/templates/db.yml +6 -0
  57. data/lib/generator_templates_sqlite/templates/rails.yml +32 -0
  58. data/lib/generator_templates_sqlite/templates/storage.yml +6 -0
  59. data/lib/github_flow_templates/.github/actions/cpflow-build-docker-image/action.yml +131 -0
  60. data/lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/action.yml +24 -0
  61. data/lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/delete-app.sh +50 -0
  62. data/lib/github_flow_templates/.github/actions/cpflow-detect-release-phase/action.yml +62 -0
  63. data/lib/github_flow_templates/.github/actions/cpflow-setup-environment/action.yml +98 -0
  64. data/lib/github_flow_templates/.github/actions/cpflow-validate-config/action.yml +85 -0
  65. data/lib/github_flow_templates/.github/actions/cpflow-wait-for-health/action.yml +92 -0
  66. data/lib/github_flow_templates/.github/cpflow-help.md +73 -0
  67. data/lib/github_flow_templates/.github/workflows/cpflow-cleanup-stale-review-apps.yml +56 -0
  68. data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +142 -0
  69. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +445 -0
  70. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-staging.yml +140 -0
  71. data/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +58 -0
  72. data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +490 -0
  73. data/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +45 -0
  74. data/rakelib/create_release.rake +662 -37
  75. data/script/check_command_docs +4 -2
  76. data/script/check_cpln_links +25 -11
  77. data/script/precommit/check_command_docs +22 -0
  78. data/script/precommit/check_cpln_links +21 -0
  79. data/script/precommit/check_trailing_newlines +68 -0
  80. data/script/precommit/get_changed_files +49 -0
  81. data/script/precommit/ruby_autofix +52 -0
  82. data/script/precommit/ruby_lint +33 -0
  83. metadata +54 -14
@@ -1,28 +1,335 @@
1
- # CI Automation, Review Apps, Staging, and Promoting to Production
2
-
3
- ## Setting up Tokens for CI Automation
4
-
5
- This example uses Github Actions. The same applies to Circle CI and other similar CI/CD tools.
6
-
7
- 1. Ensure that you have two orgs:
8
- 1. `company-staging` (for staging deployments, developers have access)
9
- 2. `company-production` (for production deployments, limited access)
10
- 2. Create the token for staging org and set on Github repository secrets and variables:
11
- 1. Go to the Control Plane UI for your organization's staging org
12
- 2. Make a new service account called `github-actions-staging`
13
- 3. Assign to the group `superusers`
14
- 4. Click "Keys" and create a one with description "Github Actions" and copy the token (or download it).
15
- 5. Add this key to your Github repository **secrets** as `CPLN_TOKEN_STAGING`
16
- 6. Add another key to your Github repository **variables** as `CPLN_ORG_STAGING` with the name of the staging org, like `company-staging`
17
- 3. Create the token for production org, and set on Github repository secrets and variables.
18
- 1. Go to the Control Plane UI for your organization's production org
19
- 2. Make a new service account called `github-actions-production`
20
- 3. Assign to the group `superusers`
21
- 4. Click "Keys" and create a one with description "Github Actions" and copy the token (or download it).
22
- 5. Add this key to your Github repository **secrets** as `CPLN_TOKEN_PRODUCTION`
23
- 6. Add another key to your Github repository **variables** as `CPLN_ORG_PRODUCTION` with the name of the production org, like `company-production`
24
- 4. Create a few more ENV **variables** for the app name and the app prefix:
25
- 1. `STAGING_APP_NAME` - the name of the app in Control Plane for staging, which is the GVC name, like `app-name-staging`
26
- 2. `PRODUCTION_APP_NAME` - the name of the app in Control Plane for production, which is the GVC name, like `app-name-production`
27
- 3. `REVIEW_APP_PREFIX` - the prefix for the review apps in Control Plane. The Review apps are named `$REVIEW_APP_PREFIX-pr-$PR_NUMBER`
28
- 5. All in all, you should have 2 secrets and 5 variables set in your Github repository
1
+ # GitHub Actions Flow for Review Apps, Staging, and Production
2
+
3
+ This document describes the reusable GitHub Actions scaffolding generated by `cpflow generate-github-actions`.
4
+
5
+ The goal is to bring the Heroku Flow model into any `cpflow` project:
6
+
7
+ 1. Comment `+review-app-deploy` on a pull request to create or update a review app.
8
+ 2. Push more commits to the PR to auto-redeploy that review app.
9
+ 3. Push to the staging branch to auto-deploy staging.
10
+ 4. Promote the already-built staging artifact to production from the Actions tab.
11
+ 5. Let a nightly workflow clean up stale review apps.
12
+
13
+ ## Quick Start
14
+
15
+ End-to-end rollout in one view:
16
+
17
+ 1. `cpflow github-flow-readiness` exits non-zero if the repo is not ready to deploy.
18
+ 2. `cpflow generate` creates `.controlplane/` if missing.
19
+ 3. `cpflow generate-github-actions` adds the `cpflow-*` composite actions and workflows.
20
+ 4. Configure the GitHub [repository secrets and variables](#required-github-repository-settings) the workflows expect.
21
+ 5. Push the branch, then comment `+review-app-deploy` on a PR to spin up a review environment.
22
+
23
+ See [Bootstrap a Project](#bootstrap-a-project) for command details, [Repo Readiness Checklist](#repo-readiness-checklist) for what "ready" means, and [AI Playbook](#ai-playbook) to run the rollout through an agent.
24
+
25
+ ## Bootstrap a Project
26
+
27
+ Run these commands from the project root:
28
+
29
+ ```sh
30
+ # Check the repo for common rollout blockers before generating files
31
+ cpflow github-flow-readiness
32
+
33
+ # Print the current AI rollout prompt for this repo, if you want to hand it to an agent
34
+ cpflow ai-github-flow-prompt
35
+
36
+ # Create .controlplane/ if it does not exist yet
37
+ cpflow generate
38
+
39
+ # Add reusable GitHub Actions for the Control Plane flow
40
+ cpflow generate-github-actions
41
+
42
+ # Or, run this instead when staging should trigger from a branch other than main/master:
43
+ cpflow generate-github-actions --staging-branch develop
44
+ ```
45
+
46
+ These local bootstrap commands do not require `cpln` to be installed yet. Install and
47
+ log into the Control Plane CLI before any command that talks to the real platform.
48
+ `cpflow github-flow-readiness` is the fastest gate: it exits non-zero when the repo is
49
+ missing a production Dockerfile, missing Rails runtime files, pinned to a legacy
50
+ Ruby or Bundler toolchain, or depends on exact-pinned gem or npm versions that do
51
+ not appear to exist in the public registries.
52
+
53
+ The second command writes namespaced files so they can coexist with an app's existing CI:
54
+
55
+ - `.github/actions/cpflow-build-docker-image/action.yml`
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`
59
+ - `.github/workflows/cpflow-review-app-help.yml`
60
+ - `.github/workflows/cpflow-help-command.yml`
61
+ - `.github/workflows/cpflow-deploy-review-app.yml`
62
+ - `.github/workflows/cpflow-delete-review-app.yml`
63
+ - `.github/workflows/cpflow-deploy-staging.yml`
64
+ - `.github/workflows/cpflow-promote-staging-to-production.yml`
65
+ - `.github/workflows/cpflow-cleanup-stale-review-apps.yml`
66
+
67
+ `cpflow generate` also infers the app prefix from the repo directory, infers the
68
+ Docker base Ruby version from `.ruby-version`, `.tool-versions`, or the app's
69
+ `Gemfile`, preserves repo-defined frontend precompile hooks such as Shakapacker
70
+ `precompile_hook` commands or React on Rails auto bundle generation, and
71
+ switches to persistent SQLite `db` and `storage` templates when
72
+ `config/database.yml` shows SQLite in production.
73
+
74
+ `cpflow github-flow-readiness` checks public RubyGems and npm registry metadata
75
+ for exact-pinned direct dependencies. In air-gapped or egress-restricted
76
+ environments those checks may report `unknown` instead of failing hard; confirm
77
+ the deployment runner has the package access your app needs before rollout.
78
+
79
+ ## Repo Readiness Checklist
80
+
81
+ Before generating this flow, confirm that the target repository is already a
82
+ deployable application rather than a partial sample:
83
+
84
+ - the repo can be cloned and installed from scratch with published gem and npm
85
+ package versions
86
+ - the repo does not depend on unpublished or inaccessible package versions unless
87
+ the deployment flow also provisions the credentials needed to fetch them
88
+ - the repo is not just a historical generator snapshot pinned to an obsolete
89
+ Ruby or Bundler toolchain with no validated production build path
90
+ - the app has its real runtime scaffold checked in, for example a complete Rails
91
+ app with the boot files needed to run `bin/rails` and `bin/dev`
92
+ - the repo root maps to one deployable app; multi-app monorepos need a separate
93
+ rollout decision before using this one-app-per-repo flow
94
+ - the production Dockerfile can build the app's assets and any SSR or renderer
95
+ bundles that production needs
96
+ - any repo-defined frontend codegen or precompile hooks are preserved before
97
+ `rails assets:precompile`
98
+ - the runtime workloads, release command, and required secrets are known well
99
+ enough to model in `.controlplane/`
100
+
101
+ If any of those fail, stop and fix the application first. Do not merge
102
+ `cpflow-*` workflows into a repository that is not yet runnable from a clean
103
+ clone, because the result will be a misleading "deployment flow" for an app that
104
+ still cannot build or boot.
105
+
106
+ ## Required `.controlplane/controlplane.yml` Structure
107
+
108
+ The generated workflows assume that `.controlplane/controlplane.yml` defines:
109
+
110
+ - one staging app
111
+ - one review-app prefix with `match_if_app_name_starts_with: true`
112
+ - one production app with `upstream` pointing to staging
113
+
114
+ Typical shape:
115
+
116
+ ```yaml
117
+ aliases:
118
+ common: &common
119
+ cpln_org: my-org-staging
120
+ default_location: aws-us-east-2
121
+ setup_app_templates:
122
+ - app
123
+ - postgres
124
+ - redis
125
+ - rails
126
+ app_workloads:
127
+ - rails
128
+ additional_workloads:
129
+ - postgres
130
+ - redis
131
+
132
+ apps:
133
+ my-app-staging:
134
+ <<: *common
135
+
136
+ my-app-review:
137
+ <<: *common
138
+ match_if_app_name_starts_with: true
139
+ hooks:
140
+ post_creation: bundle exec rails db:prepare
141
+ pre_deletion: bundle exec rails db:drop
142
+
143
+ my-app-production:
144
+ <<: *common
145
+ allow_org_override_by_env: false
146
+ allow_app_override_by_env: false
147
+ cpln_org: my-org-production
148
+ upstream: my-app-staging
149
+ release_script: release_script.sh
150
+ ```
151
+
152
+ Important points:
153
+
154
+ - `REVIEW_APP_PREFIX` in GitHub Actions must match the review config key prefix, for example `my-app-review`.
155
+ - `match_if_app_name_starts_with: true` is what allows a single config entry to back `my-app-review-123`, `my-app-review-456`, and cleanup commands like `cpflow cleanup-stale-apps -a my-app-review`.
156
+ - `upstream: my-app-staging` is what lets the production promotion workflow copy the exact staging artifact.
157
+ - If your main web workload is not named `rails`, set the optional `PRIMARY_WORKLOAD` repository variable described below.
158
+
159
+ ## Required GitHub Repository Settings
160
+
161
+ Configure these repository secrets:
162
+
163
+ - `CPLN_TOKEN_STAGING`: token for the staging Control Plane org
164
+ - `CPLN_TOKEN_PRODUCTION`: token for the production Control Plane org
165
+
166
+ Configure these repository variables:
167
+
168
+ - `CPLN_ORG_STAGING`: staging org name, for example `company-staging`
169
+ - `CPLN_ORG_PRODUCTION`: production org name, for example `company-production`
170
+ - `STAGING_APP_NAME`: staging GVC name, for example `my-app-staging`
171
+ - `PRODUCTION_APP_NAME`: production GVC name, for example `my-app-production`
172
+ - `REVIEW_APP_PREFIX`: review-app prefix, for example `my-app-review`
173
+ - `STAGING_APP_BRANCH`: optional branch that auto-deploys staging. If you use a custom branch, either pass it to `cpflow generate-github-actions --staging-branch BRANCH` during generation or edit `cpflow-deploy-staging.yml` so its `on.push.branches` list includes the same branch.
174
+ - `PRIMARY_WORKLOAD`: optional workload name used to discover the public endpoint and do production health checks; defaults to `rails`
175
+ - `DOCKER_BUILD_EXTRA_ARGS`: optional newline-delimited single `docker build` tokens passed through to `cpflow build-image`, for example `--build-arg=FOO=bar` or `--secret=id=npmrc,src=.npmrc`
176
+ - `DOCKER_BUILD_SSH_KNOWN_HOSTS`: optional multi-line `known_hosts` content used with `DOCKER_BUILD_SSH_KEY` when the build needs SSH access to hosts other than GitHub.com
177
+
178
+ Recommended org layout:
179
+
180
+ - keep review apps and staging in a staging org that developers can access
181
+ - keep production in a separate org with tighter access controls
182
+
183
+ Optional repository secret for private dependency builds:
184
+
185
+ - `DOCKER_BUILD_SSH_KEY`: private SSH key used when the Dockerfile needs `RUN --mount=type=ssh` to fetch private GitHub dependencies during image build
186
+
187
+ ## Docker Builds with Private Dependencies
188
+
189
+ Some apps need extra Docker build configuration before the generated workflows are turnkey. Common examples are:
190
+
191
+ - `pnpm`, `npm`, `yarn`, or Bundler dependencies pulled from private GitHub repositories
192
+ - Dockerfiles that already use `RUN --mount=type=ssh`
193
+ - builds that need extra `--build-arg`, `--secret`, or related `docker build` flags
194
+
195
+ The generated `cpflow-build-docker-image` action supports this without hardcoding app-specific logic:
196
+
197
+ - set `DOCKER_BUILD_SSH_KEY` if the Docker build needs SSH access to GitHub
198
+ - optionally set `DOCKER_BUILD_SSH_KNOWN_HOSTS` when the SSH build host is not GitHub.com or you need custom host entries
199
+ - set `DOCKER_BUILD_EXTRA_ARGS` when you need extra `docker build` flags
200
+
201
+ For example, a repo that installs private dependencies from GitHub during Docker build can set:
202
+
203
+ ```text
204
+ DOCKER_BUILD_SSH_KEY=<private deploy key secret>
205
+ DOCKER_BUILD_SSH_KNOWN_HOSTS=git.example.com ssh-ed25519 AAAA...
206
+ DOCKER_BUILD_EXTRA_ARGS=--build-arg=BUNDLE_WITHOUT=development:test
207
+ ```
208
+
209
+ The action will start an SSH agent, add the key, write `known_hosts`, and pass `--ssh=default` to `cpflow build-image`. When `DOCKER_BUILD_SSH_KNOWN_HOSTS` is unset, the generated action uses pinned GitHub.com host keys by default. If your Dockerfile relies on `RUN --mount=type=ssh`, validate the build locally with `cpflow build-image -a <app> --ssh=default` before relying on CI.
210
+
211
+ ## Generated Workflow Behavior
212
+
213
+ `cpflow-review-app-help.yml`
214
+
215
+ - Posts a quick reference when a pull request opens, including on fork-based PRs.
216
+
217
+ `cpflow-help-command.yml`
218
+
219
+ - Replies to `+review-app-help` on a pull request with the commands and required repo settings.
220
+
221
+ `cpflow-deploy-review-app.yml`
222
+
223
+ - Creates a review app when someone comments `+review-app-deploy`.
224
+ - Redeploys an existing review app automatically on later PR pushes.
225
+ - Creates a GitHub deployment and comments with the review URL and logs.
226
+ - Leaves PR pushes alone until the first review app is explicitly requested, which keeps demo-app costs down.
227
+ - Accepts `+review-app-deploy` only from trusted commenters (`OWNER`, `MEMBER`, or `COLLABORATOR`).
228
+ - Skips fork-based PR deploys because the workflow builds Docker images with repository secrets.
229
+
230
+ `cpflow-delete-review-app.yml`
231
+
232
+ - Deletes the review app on `+review-app-delete`.
233
+ - Also deletes it automatically when the pull request closes.
234
+ - Accepts `+review-app-delete` only from trusted commenters (`OWNER`, `MEMBER`, or `COLLABORATOR`).
235
+
236
+ `cpflow-deploy-staging.yml`
237
+
238
+ - Builds and deploys the staging app on pushes to the generated staging branch filter.
239
+ - Falls back to `main` or `master` when `STAGING_APP_BRANCH` is unset and no custom branch was generated.
240
+ - Custom staging branches must be present in the workflow's `on.push.branches` filter; repository variables alone cannot trigger a branch GitHub Actions is not listening to.
241
+ - Fails fast when required staging repo settings are missing instead of surfacing opaque `cpflow` errors.
242
+
243
+ `cpflow-promote-staging-to-production.yml`
244
+
245
+ - Manually promotes the staging artifact to production with a confirmation input.
246
+ - Verifies that production has the env var names staging expects.
247
+ - Runs a health check against `PRIMARY_WORKLOAD`.
248
+ - Attempts a rollback of every configured application workload if the new production image does not come up healthy.
249
+ - Creates a GitHub release after a successful promotion.
250
+
251
+ `cpflow-cleanup-stale-review-apps.yml`
252
+
253
+ - Runs nightly and on demand.
254
+ - Deletes stale review apps using `cpflow cleanup-stale-apps`.
255
+
256
+ ## Composite Actions
257
+
258
+ The generated workflows share these local composite actions:
259
+
260
+ - `cpflow-setup-environment`: installs Ruby, the Control Plane CLI, and the `cpflow` gem, then logs into the target org
261
+ - `cpflow-build-docker-image`: builds and pushes the app image with the desired commit SHA
262
+ - `cpflow-delete-control-plane-app`: safely deletes temporary apps and refuses to touch names outside the configured review-app prefix
263
+
264
+ ## Applying This to React on Rails Demo Apps
265
+
266
+ This flow is a good fit for the React on Rails demo apps because they already follow the same basic assumptions:
267
+
268
+ - the deployable app is a Rails project
269
+ - the primary web workload is usually `rails`
270
+ - review environments should be temporary and opt-in
271
+ - staging should auto-follow a single branch
272
+ - production should promote the already-tested staging image
273
+
274
+ In practice, porting the flow into a demo app usually follows five phases.
275
+
276
+ **Before generating:**
277
+
278
+ 1. Confirm the repo passes the readiness checklist above.
279
+ 2. Generate `.controlplane/` if the app does not have it yet.
280
+ 3. Generate the `cpflow-*` GitHub Actions files.
281
+
282
+ **Verify the generated scaffold:**
283
+
284
+ 4. Update `.controlplane/controlplane.yml` with staging, review, and production entries.
285
+ 5. Confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement.
286
+ 6. For SQLite-backed apps, confirm that the generated scaffold switched to persistent `db` and `storage` volumes, mounted them into the main workload, and added a release script that runs `rails db:prepare`.
287
+
288
+ **Adapt for the app's runtime:**
289
+
290
+ 7. Keep Node available in the final app image whenever Rails asset compilation or SSR depends on ExecJS or frontend package managers at build or runtime.
291
+ 8. Preserve repo-defined frontend precompile hooks, such as Shakapacker `precompile_hook` commands or React on Rails `config.auto_load_bundle = true`, before `rails assets:precompile`.
292
+ 9. Add any additional app workloads the app needs at runtime, for example `sidekiq`, a Node renderer, or any other process type that should deploy the same application image.
293
+ 10. Adjust `PRIMARY_WORKLOAD` only if the public workload is not named `rails`.
294
+
295
+ **Wire up GitHub secrets, variables, and private builds:**
296
+
297
+ 11. Make sure the repo variables and secrets line up with the configured app names.
298
+ 12. If the Dockerfile pulls private dependencies over SSH, configure `DOCKER_BUILD_SSH_KEY`, add `DOCKER_BUILD_SSH_KNOWN_HOSTS` when the host is not GitHub.com, and validate that the image can build with `RUN --mount=type=ssh`.
299
+
300
+ **Validate and push:**
301
+
302
+ 13. Validate the real production Docker build before relying on the workflows, especially if asset compilation or SSR requires Node, extra system packages, multiple processes, extra Docker build flags, or persistent writable paths.
303
+ 14. Expect review app deploys to run only for branches in the base repository; fork PRs still get help comments, but deploys are skipped because the workflow uses repository secrets.
304
+
305
+ ## AI Playbook
306
+
307
+ If you want an AI agent to apply this flow to another project, start with
308
+ `cpflow github-flow-readiness`, then use the standalone
309
+ [AI rollout prompt](./ai-github-flow-prompt.md). It captures the exact wording,
310
+ hard stop conditions, and definition of done for this workflow. You can also
311
+ run `cpflow ai-github-flow-prompt` from inside the target repo to print the
312
+ current prompt with that repo's default app prefix already filled in.
313
+
314
+ Short version:
315
+
316
+ ```text
317
+ Set up Control Plane GitHub Flow for this repo. Start with `cpflow github-flow-readiness` and stop on any reported blockers. The repo must be deployable from a clean clone, with published package versions and a production Dockerfile that can really build the app. Stop and report blockers for unpublished packages, inaccessible private dependencies, legacy toolchains, or missing production build paths instead of generating workflows blindly. Then run `cpflow generate` if `.controlplane/` is missing, run `cpflow generate-github-actions`, adapt the generated scaffold to the real workloads, document the required GitHub secrets and variables, validate the real build path locally, push the branch, and check the GitHub Actions results.
318
+ ```
319
+
320
+ Expand that prompt with app-specific requirements before editing files:
321
+
322
+ - verify the repo is a real deployable app, not a partial code sample or a demo pinned to unpublished package versions
323
+ - stop and report a scope decision when the repo is a monorepo or contains multiple deployable apps without an already-decided single flow target
324
+ - inspect the production Dockerfile and make sure it can build the app's assets in CI
325
+ - make sure the generated Dockerfile uses a Ruby base image compatible with the app's declared Ruby requirement
326
+ - preserve repo-defined frontend precompile hooks, such as Shakapacker `precompile_hook` commands or React on Rails `config.auto_load_bundle = true`
327
+ - keep Node available in the final image if Rails or SSR depends on ExecJS, Yarn, or `pnpm` after the main `npm install` layer
328
+ - if `config/database.yml` shows SQLite in production, confirm that `cpflow generate` emitted persistent `db` and `storage` volumes plus a `rails db:prepare` release script; otherwise keep the default Postgres workload
329
+ - inspect the production Dockerfile and package sources for private GitHub dependencies, and wire `DOCKER_BUILD_SSH_KEY` plus `DOCKER_BUILD_SSH_KNOWN_HOSTS` when the build uses `RUN --mount=type=ssh` against non-GitHub hosts
330
+ - add extra `app_workloads` and template files for any runtime sidecars, workers, or renderer processes
331
+ - make sure any sidecar process exposed to sibling workloads binds to `0.0.0.0` instead of container-local `localhost`
332
+ - make sure sidecar caches or bundle directories live in writable paths for the runtime user, such as `tmp/`, instead of root-owned image paths
333
+ - keep workflow files generic and put app names, org names, branch names, and Docker build knobs in repository `vars` and `secrets`
334
+
335
+ When the agent applies this to a project, it should avoid hardcoding app names or org names into the workflow files. Those belong in repository `vars` and `secrets`.
data/docs/commands.md CHANGED
@@ -11,6 +11,18 @@ This `-a` option is used in most of the commands and will pick all other app con
11
11
 
12
12
  ## Commands
13
13
 
14
+ ### `ai-github-flow-prompt`
15
+
16
+ Prints a copy-paste prompt for an AI agent to roll out the reusable Control Plane GitHub Flow:
17
+ - verifies the repo is deployable from a clean clone before generating files
18
+ - scaffolds `.controlplane/` and `cpflow-*` GitHub Actions files when the repo qualifies
19
+ - stops on external blockers or product decisions instead of forcing a broken rollout
20
+
21
+ ```sh
22
+ # Prints the recommended AI rollout prompt for the current repo
23
+ cpflow ai-github-flow-prompt
24
+ ```
25
+
14
26
  ### `apply-template`
15
27
 
16
28
  - Applies application-specific configs from templates (e.g., for every review-app)
@@ -93,13 +105,16 @@ cpflow config -a $APP_NAME
93
105
 
94
106
  - Copies an image (by default the latest) from a source org to the current org
95
107
  - The source app must be specified either through the `CPLN_UPSTREAM` env var or `upstream` in the `.controlplane/controlplane.yml` file
96
- - Additionally, the token for the source org must be provided through `--upstream-token` or `-t`
108
+ - The token for the source org must be provided through `--upstream-token`/`-t` or the `CPLN_UPSTREAM_TOKEN` env var
97
109
  - A `cpln` profile will be temporarily created to pull the image from the source org
98
110
 
99
111
  ```sh
100
112
  # Copies the latest image from the source org to the current org.
101
113
  cpflow copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN
102
114
 
115
+ # Equivalent call using an env var (avoids exposing the token via the OS process table).
116
+ CPLN_UPSTREAM_TOKEN=$UPSTREAM_TOKEN cpflow copy-image-from-upstream -a $APP_NAME
117
+
103
118
  # Copies a specific image from the source org to the current org.
104
119
  cpflow copy-image-from-upstream -a $APP_NAME --upstream-token $UPSTREAM_TOKEN --image appimage:123
105
120
  ```
@@ -127,6 +142,7 @@ cpflow delete -a $APP_NAME -w $WORKLOAD_NAME
127
142
  - Runs a release script before deploying if `release_script` is specified in the `.controlplane/controlplane.yml` file and `--run-release-phase` is provided
128
143
  - The release script is run in the context of `cpflow run` with the latest image
129
144
  - If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
145
+ - If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
130
146
 
131
147
  ```sh
132
148
  cpflow deploy-image -a $APP_NAME
@@ -158,20 +174,66 @@ cpflow env -a $APP_NAME
158
174
  ### `exists`
159
175
 
160
176
  - Shell-checks if an application (GVC) exists, useful in scripts, e.g.:
177
+ - Exits 0 when the app exists, 3 when it does not exist, and 64 for other errors.
161
178
 
162
179
  ```sh
163
- if [ cpflow exists -a $APP_NAME ]; ...
180
+ cpflow exists -a "$APP_NAME"
181
+ status=$?
182
+ if [ "$status" -eq 0 ]; then
183
+ echo "exists"
184
+ elif [ "$status" -eq 3 ]; then
185
+ echo "not found"
186
+ else
187
+ echo "error: cpflow exists exited $status"
188
+ fi
164
189
  ```
165
190
 
166
191
  ### `generate`
167
192
 
168
- Creates base Control Plane config and template files
193
+ Creates base Control Plane config and template files for a Rails project:
194
+ - infers the app prefix from the current directory and wires staging, review, and production entries
195
+ - infers the Docker base Ruby version from `.ruby-version`, `.tool-versions`, or the app's `Gemfile`
196
+ - preserves repo-defined asset precompile hooks, including React on Rails auto bundle generation
197
+ - detects SQLite in `config/database.yml` and generates persistent `db` and `storage` volume templates instead of the default Postgres workload
169
198
 
170
199
  ```sh
171
- # Creates .controlplane directory with Control Plane config and other templates
200
+ # Creates .controlplane directory with Control Plane config and starter templates
172
201
  cpflow generate
173
202
  ```
174
203
 
204
+ ### `generate-github-actions`
205
+
206
+ Creates GitHub Actions templates for a Heroku Flow style Control Plane pipeline:
207
+ - on-demand review apps for pull requests
208
+ - automatic staging deploys from your main branch
209
+ - manual promotion from staging to production
210
+ - nightly cleanup and PR help workflows
211
+
212
+ Pass `--staging-branch BRANCH` when staging should auto-deploy from a branch
213
+ other than `main` or `master`; the generator will bake that branch into the
214
+ GitHub Actions push trigger and use it as the default STAGING_APP_BRANCH.
215
+
216
+ ```sh
217
+ # Creates .github/actions and .github/workflows files for the Control Plane flow
218
+ cpflow generate-github-actions
219
+
220
+ # Creates the flow with staging deploys triggered from develop
221
+ cpflow generate-github-actions --staging-branch develop
222
+ ```
223
+
224
+ ### `github-flow-readiness`
225
+
226
+ Checks the current repository for common rollout blockers before adding the Control Plane GitHub flow:
227
+ - Rails runtime scaffold present
228
+ - modern Ruby and Bundler toolchain
229
+ - installable exact-pinned direct gem and npm package versions
230
+ - production Dockerfile presence and SQLite production hints
231
+
232
+ ```sh
233
+ # Checks the current repo for common rollout blockers
234
+ cpflow github-flow-readiness
235
+ ```
236
+
175
237
  ### `info`
176
238
 
177
239
  - Displays the diff between defined/available apps/workloads (apps equal GVCs)
@@ -295,6 +357,7 @@ cpflow open-console -a $APP_NAME
295
357
  - Runs `cpflow deploy-image` to deploy the image
296
358
  - If `.controlplane/controlplane.yml` includes the `release_script`, `cpflow deploy-image` will use the `--run-release-phase` option
297
359
  - If the release script exits with a non-zero code, the command will stop executing and also exit with a non-zero code
360
+ - If `use_digest_image_ref` is `true` in the `.controlplane/controlplane.yml` file or `--use-digest-image-ref` option is provided, deployed image's reference will include its digest
298
361
 
299
362
  ```sh
300
363
  cpflow promote-app-from-upstream -a $APP_NAME -t $UPSTREAM_TOKEN
@@ -19,6 +19,10 @@ without compromising your current environment.
19
19
  Consider migrating just the web dyno first, and get other types of dynos working afterward. You can also move the
20
20
  add-ons to Control Plane later once the app works as expected.
21
21
 
22
+ If you are ready to replace Heroku add-ons as part of the migration, review the Control Plane Template Catalog options for
23
+ [PostgreSQL](https://shakadocs.controlplane.com/template-catalog/templates/postgres) and
24
+ [Redis](https://shakadocs.controlplane.com/template-catalog/templates/redis).
25
+
22
26
  First, create a new Heroku app with all the add-ons, copying the data from the current staging app.
23
27
 
24
28
  Then, copy project-specific configs to a `.controlplane/` directory at the top of your project. `cpflow` will pick those up
@@ -236,12 +240,20 @@ For the review app resources, these should be handled as env vars in the templat
236
240
  Notice that `APP_GVC` is the app name, which is used as the database name on RDS, so that each review app gets its own
237
241
  database on the one RDS instance used for all review apps, which would be, e.g., `my-app-review-1234`.
238
242
 
243
+ For teams that prefer a Control Plane-hosted PostgreSQL workload over RDS for some environments, see the
244
+ [PostgreSQL Template Catalog page](https://shakadocs.controlplane.com/template-catalog/templates/postgres) for the current
245
+ supported template, storage, PgBouncer, and backup options.
246
+
239
247
  ### Redis and Memcached for Review Apps
240
248
 
241
249
  So long as no persistence is needed for Redis and Memcached, we have templates for workloads that should be sufficient
242
250
  for review apps in the `templates/` directory of this repository. Using these templates results in considerable cost
243
251
  savings compared to paying for the resources on Heroku.
244
252
 
253
+ For Redis environments that need more than the simple review-app template, see the
254
+ [Redis Template Catalog page](https://shakadocs.controlplane.com/template-catalog/templates/redis) for Sentinel, persistence,
255
+ public access, and backup options.
256
+
245
257
  ```yaml
246
258
  - name: MEMCACHE_SERVERS
247
259
  value: memcached.APP_GVC.cpln.local
data/docs/postgres.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Migrating Postgres database from Heroku infrastructure
2
2
 
3
+ If you are replacing Heroku Postgres or another pre-provisioned database service, also review the
4
+ [Control Plane PostgreSQL Template Catalog page](https://shakadocs.controlplane.com/template-catalog/templates/postgres). The
5
+ catalog template covers a single-instance PostgreSQL workload with persistent storage, optional PgBouncer, and optional
6
+ scheduled backups.
7
+
3
8
  One of the biggest problems that will appear when moving from Heroku infrastructure is migrating the database. And
4
9
  despite it being rather easy if done between Heroku-hosted databases or non-Heroku-hosted databases (as Postgres has
5
10
  tools to do that naturally) it is not easily possible between Heroku and anything outside Heroku,
data/docs/redis.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Migrating Redis databases
2
2
 
3
+ If you are replacing a Heroku Redis add-on or another pre-provisioned Redis service, also review the
4
+ [Control Plane Redis Template Catalog page](https://shakadocs.controlplane.com/template-catalog/templates/redis). The catalog
5
+ template covers a Redis master-replica deployment with Redis Sentinel, optional persistent storage, and optional backups.
6
+ It is the better fit when you need Redis Sentinel, public endpoint access, or backup options beyond what the `redis` and
7
+ `redis2` repo templates provide.
8
+
3
9
  There are two templates examples in this repo:
4
10
  - `redis` - basic non-persistent template. It is good for review-apps or staging or where no persistence is required
5
11
  - `redis2` - basic persistent template. Good for production where persistence is needed, but cluster is overkill.