cpflow 4.2.0 → 5.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/update-changelog.md +367 -0
  3. data/.github/workflows/claude.yml +5 -0
  4. data/.overcommit.yml +43 -3
  5. data/.rubocop.yml +3 -3
  6. data/CHANGELOG.md +28 -4
  7. data/CONTRIBUTING.md +6 -0
  8. data/Gemfile +8 -7
  9. data/Gemfile.lock +92 -72
  10. data/README.md +43 -15
  11. data/cpflow.gemspec +5 -5
  12. data/docs/ai-github-flow-prompt.md +61 -0
  13. data/docs/ci-automation.md +335 -28
  14. data/docs/commands.md +65 -4
  15. data/docs/releasing.md +153 -0
  16. data/lib/command/ai_github_flow_prompt.rb +47 -0
  17. data/lib/command/base.rb +14 -0
  18. data/lib/command/cleanup_images.rb +1 -1
  19. data/lib/command/cleanup_stale_apps.rb +1 -1
  20. data/lib/command/copy_image_from_upstream.rb +14 -3
  21. data/lib/command/exists.rb +13 -2
  22. data/lib/command/generate.rb +153 -4
  23. data/lib/command/generate_github_actions.rb +170 -0
  24. data/lib/command/generator_helpers.rb +31 -0
  25. data/lib/command/github_flow_readiness.rb +37 -0
  26. data/lib/command/run.rb +1 -1
  27. data/lib/command/terraform/generate.rb +1 -0
  28. data/lib/command/version.rb +1 -0
  29. data/lib/constants/exit_code.rb +1 -0
  30. data/lib/core/controlplane.rb +9 -7
  31. data/lib/core/controlplane_api_direct.rb +3 -3
  32. data/lib/core/github_flow_readiness/checks.rb +143 -0
  33. data/lib/core/github_flow_readiness_service.rb +453 -0
  34. data/lib/core/repo_introspection.rb +118 -0
  35. data/lib/core/terraform_config/dsl.rb +1 -1
  36. data/lib/core/terraform_config/local_variable.rb +1 -1
  37. data/lib/cpflow/version.rb +1 -1
  38. data/lib/cpflow.rb +65 -3
  39. data/lib/generator_templates/Dockerfile +59 -3
  40. data/lib/generator_templates/controlplane.yml +27 -39
  41. data/lib/generator_templates/entrypoint.sh +1 -1
  42. data/lib/generator_templates/release_script.sh +23 -0
  43. data/lib/generator_templates/templates/app.yml +5 -8
  44. data/lib/generator_templates/templates/rails.yml +2 -11
  45. data/lib/generator_templates_sqlite/controlplane.yml +46 -0
  46. data/lib/generator_templates_sqlite/release_script.sh +25 -0
  47. data/lib/generator_templates_sqlite/templates/app.yml +15 -0
  48. data/lib/generator_templates_sqlite/templates/db.yml +6 -0
  49. data/lib/generator_templates_sqlite/templates/rails.yml +32 -0
  50. data/lib/generator_templates_sqlite/templates/storage.yml +6 -0
  51. data/lib/github_flow_templates/.github/actions/cpflow-build-docker-image/action.yml +131 -0
  52. data/lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/action.yml +24 -0
  53. data/lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/delete-app.sh +50 -0
  54. data/lib/github_flow_templates/.github/actions/cpflow-detect-release-phase/action.yml +62 -0
  55. data/lib/github_flow_templates/.github/actions/cpflow-setup-environment/action.yml +98 -0
  56. data/lib/github_flow_templates/.github/actions/cpflow-validate-config/action.yml +85 -0
  57. data/lib/github_flow_templates/.github/actions/cpflow-wait-for-health/action.yml +92 -0
  58. data/lib/github_flow_templates/.github/cpflow-help.md +47 -0
  59. data/lib/github_flow_templates/.github/workflows/cpflow-cleanup-stale-review-apps.yml +56 -0
  60. data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +142 -0
  61. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +445 -0
  62. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-staging.yml +140 -0
  63. data/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +53 -0
  64. data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +490 -0
  65. data/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +46 -0
  66. data/rakelib/create_release.rake +662 -37
  67. data/script/check_command_docs +4 -2
  68. data/script/check_cpln_links +25 -11
  69. data/script/precommit/check_command_docs +22 -0
  70. data/script/precommit/check_cpln_links +21 -0
  71. data/script/precommit/check_trailing_newlines +68 -0
  72. data/script/precommit/get_changed_files +49 -0
  73. data/script/precommit/ruby_autofix +52 -0
  74. data/script/precommit/ruby_lint +33 -0
  75. metadata +52 -14
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dc6063b9255b39b0e28fba089bec5fd9ac88d05db3902c4f3f79d89afa6c38f0
4
- data.tar.gz: febd4388547d3ed2a25ca0f9c8231d704891f26457c2860bb3586bf9ad75f745
3
+ metadata.gz: e14982bee2d97f3eb32cc1d9927989313b7a91b025c4096d062360353822aa65
4
+ data.tar.gz: 29b22bf0f213441d8ee82d115c84c13fa6bd9306b86ca1618a2540a45a1d389e
5
5
  SHA512:
6
- metadata.gz: ef1a7b52cfd4166056d66e5997b497bee2dadfbaf31185ef276ac5c030937acae95866400edcfe43fece6c9304d5865a811a615632f25f0586b0cf08ced74be9
7
- data.tar.gz: 0fe9f702f59c555935d21fbb2fd9eec3285c99ed3f915414ffafa40330e4cc9066a122f577098e7e4f2f162146775c607db516c137464986983dcfbda7318272
6
+ metadata.gz: 993fe9b78e665e737aab285e5bafd066f523c58f4f7cfcdebc3a829293aeb2d700d65ac731ab533cda9ec51d2c0c06f953712cf66ca6ee3d5007ba5501fcee0f
7
+ data.tar.gz: b3dee476a72d21cfdbfa9032c3d249c8cc3c15bb1b297b7a4c2103be30ef5b167648aacf592d3c866b65a256cf09eff0ac4c502931e1d9451915633ff4fa7172
@@ -0,0 +1,367 @@
1
+ # Update Changelog
2
+
3
+ You are helping to add an entry to the CHANGELOG.md file for the cpflow gem (the `shakacode/control-plane-flow` repository).
4
+
5
+ ## Arguments
6
+
7
+ This command accepts an optional argument: `$ARGUMENTS`
8
+
9
+ - **No argument** (`/update-changelog`): Add entries to `[Unreleased]` without stamping a version header. Use this during development.
10
+ - **`release`** (`/update-changelog release`): Add entries and stamp a version header. Auto-compute the next version based on changes (breaking -> major, added features -> minor, fixes -> patch). Then `bundle exec rake release` (with no args) will pick up this version automatically.
11
+ - **`rc`** (`/update-changelog rc`): Same as `release`, but stamps an RC prerelease version (e.g., `5.0.0.rc.0`). Auto-increments the RC index if prior RCs exist for the same base version.
12
+ - **`beta`** (`/update-changelog beta`): Same as `rc`, but stamps a beta prerelease version (e.g., `5.0.0.beta.0`).
13
+ - **Explicit version** (`/update-changelog 5.0.0.rc.10`): Add entries and stamp the exact version provided. Skips auto-computation — use this when you already know the target version. The version string must look like a RubyGems-style version (with optional `.rc.N`, `.beta.N`, `.alpha.N`, `.pre.N`, or `.test.N` suffix).
14
+
15
+ ## When to Use This
16
+
17
+ This command serves three use cases at different points in the release lifecycle:
18
+
19
+ **During development** -- Add entries to `[Unreleased]` as PRs merge:
20
+
21
+ - Run `/update-changelog` to find merged PRs missing from the changelog
22
+ - Entries accumulate under `## [Unreleased]`
23
+
24
+ **Before a release** -- Stamp a version header and prepare for release:
25
+
26
+ - Run `/update-changelog release` (or `rc`, `beta`, or an explicit version like `5.0.0.rc.10`) to add entries AND stamp the version header
27
+ - The version is auto-computed from changes (breaking -> major, features -> minor, fixes -> patch) — skipped when an explicit version is provided
28
+ - The command automatically commits, pushes, and opens a PR — review and merge it
29
+ - Then run `bundle exec rake release` (no args needed -- it reads the version from CHANGELOG.md)
30
+ - The release task automatically creates a GitHub release from the changelog section
31
+
32
+ **After a release you forgot to update the changelog for** -- Catch-up mode:
33
+
34
+ - The command can retroactively find commits between tags and add missing entries
35
+ - Ask the user whether to stamp a version header or add to `[Unreleased]`
36
+
37
+ ### Why changelog comes BEFORE the release
38
+
39
+ - `bundle exec rake release` automatically creates a GitHub release if a changelog section exists -- no separate `sync_github_release` step needed
40
+ - The release task warns if no changelog section is found for the target version
41
+ - A premature version header (if release fails) is harmless -- you'll release eventually
42
+ - A missing changelog after release means the GitHub release must be created manually via `bundle exec rake "sync_github_release[X.Y.Z]"`
43
+
44
+ ## Auto-Computing the Next Version
45
+
46
+ When stamping a version header (`release`, `rc`, or `beta`), compute the next version as follows:
47
+
48
+ 1. **Find the latest stable version tag** using semver sort:
49
+
50
+ ```bash
51
+ git tag -l 'v*' --sort=-v:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -1
52
+ ```
53
+
54
+ 2. **Determine bump type from changelog content**:
55
+ - If changes include `### Breaking Changes` (or `#### Breaking Changes`) -> **major** bump
56
+ - If changes include `### Added`, `### New Features`, `### Features`, or `### Enhancements` -> **minor** bump
57
+ - If changes only include `### Fixed`, `### Security`, `### Improved`, `### Changed`, `### Deprecated`, or `### Removed` -> **patch** bump
58
+
59
+ Note: the `rake release` task validates the bump level against these headings via `expected_bump_type_from_changelog_section` in `rakelib/create_release.rake`. If the bump does not match, the release is aborted unless `RELEASE_VERSION_POLICY_OVERRIDE=true` is set.
60
+
61
+ 3. **Compute the version**:
62
+ - For `release`: Apply the bump to the latest stable tag (e.g., `4.2.0` + minor -> `4.3.0`; `4.2.0` + major -> `5.0.0`)
63
+ - For `rc`: Apply the bump, then find the next RC index based **only on git tags** (e.g., if `v5.0.0.rc.0` tag exists -> `5.0.0.rc.1`). **Do NOT use changelog headers** to determine the next index — a version header in the changelog is a draft that may not have been released yet. Only git tags represent shipped versions.
64
+ - For `beta`: Same as RC but with beta suffix
65
+
66
+ 4. **Verify**: Check that the computed version is newer than ALL existing tags (stable and prerelease). If not, ask the user what to do.
67
+
68
+ 5. **Show the computed version to the user and ask for confirmation** before stamping the header. If the bump type is ambiguous (e.g., changes could reasonably be classified as patch vs minor, or the changelog headings don't clearly signal the bump level), explain your reasoning for the suggested bump and ask the user to confirm or override before proceeding.
69
+
70
+ ## Critical Requirements
71
+
72
+ 1. **User-visible changes only**: Only add changelog entries for user-visible changes:
73
+ - New features and CLI commands
74
+ - Bug fixes
75
+ - Breaking changes (CLI behavior, exit codes, generator output, configuration schema)
76
+ - Deprecations
77
+ - Performance improvements
78
+ - Security fixes
79
+ - Changes to public APIs, command flags, or configuration options
80
+
81
+ 2. **Do NOT add entries for**:
82
+ - Linting fixes
83
+ - Code formatting / RuboCop changes
84
+ - Internal refactoring
85
+ - Test updates
86
+ - Documentation fixes (unless they fix incorrect docs about behavior)
87
+ - CI/CD-only changes (workflow tweaks that don't affect users)
88
+
89
+ ## Formatting Requirements
90
+
91
+ ### Entry Format
92
+
93
+ Each changelog entry MUST follow this exact format:
94
+
95
+ ```markdown
96
+ - **Bold description of change**. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808). Optional additional context or details.
97
+ ```
98
+
99
+ **Important formatting rules**:
100
+
101
+ - Start with a dash and space: `- `
102
+ - Use **bold** for the main description (or for breaking-change scope labels — see below)
103
+ - End the bold description with a period before the link
104
+ - Always link to the PR: `[PR 278](https://github.com/shakacode/control-plane-flow/pull/278)` - **NO hash symbol**
105
+ - Always link to the author by their display name: `by [Justin Gordon](https://github.com/justin808)`. Match the existing style in `CHANGELOG.md` — full name preferred when known, GitHub handle as a fallback.
106
+ - End with a period after the author link
107
+ - Additional details can be added after the main entry, using proper indentation for multi-line entries
108
+
109
+ ### Breaking Changes Format
110
+
111
+ Breaking changes in this repo typically open with the literal phrase `BREAKING CHANGE:` to maximize visibility (see existing entries in `## [Unreleased]`). Example:
112
+
113
+ ```markdown
114
+ - BREAKING CHANGE: `cpflow exists` now returns exit code 3 when the app is not found, preserving 64 for real errors so scripts can distinguish not-found from API/auth failures. Affected callers: only scripts that branched specifically on `[ $? -eq 64 ]` as a "not found" signal — those will now misroute "not found" into the error branch and must switch to checking for exit 3. Scripts that treat any non-zero exit as "not found" are unaffected. The change is isolated to `lib/command/exists.rb` and `lib/constants/exit_code.rb` (`NOT_FOUND = 3`), so users hitting a regression can bisect by file. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
115
+ ```
116
+
117
+ For breaking changes that warrant a step-by-step migration guide, append it inline:
118
+
119
+ ```markdown
120
+ - BREAKING CHANGE: Description of the breaking change. See migration guide below. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
121
+
122
+ **Migration Guide:**
123
+
124
+ 1. Step one
125
+ 2. Step two
126
+ ```
127
+
128
+ ### Category Organization
129
+
130
+ Entries should be organized under these section headings **in the following order** (most critical first):
131
+
132
+ **Preferred section order:**
133
+
134
+ 1. `### Breaking Changes` - Breaking changes (FIRST - most critical for upgrading users)
135
+ 2. `### Added` - New features
136
+ 3. `### Changed` - Changes to existing functionality
137
+ 4. `### Improved` - Improvements to existing features
138
+ 5. `### Fixed` - Bug fixes
139
+ 6. `### Deprecated` - Deprecation notices
140
+ 7. `### Removed` - Removed features
141
+ 8. `### Security` - Security-related changes
142
+
143
+ **Rationale:** Breaking changes come first because they are the most critical information for anyone upgrading. Users need to know immediately if their code will break before seeing what new features are available.
144
+
145
+ **Note**: This project uses `###` (three hashes) for category headings because version headers use `##` (two hashes). Do not use `####` for category headings — that pattern belongs to projects whose version headers are `###`.
146
+
147
+ **Only include section headings that have entries.**
148
+
149
+ ### Version Stamping
150
+
151
+ This repo does **not** have an `update_changelog` rake task — the slash command itself performs the stamping. After adding entries, do the following manually:
152
+
153
+ 1. **Insert the version header** immediately after `## [Unreleased]` (and any short prose under it that belongs to Unreleased), in the form:
154
+
155
+ ```markdown
156
+ ## [4.3.0] - 2026-05-05
157
+ ```
158
+
159
+ Use today's date in `YYYY-MM-DD` form.
160
+
161
+ 2. **Update the compare links** at the bottom of the file:
162
+ - The `[unreleased]` link must compare from the new version tag to `HEAD`:
163
+
164
+ ```markdown
165
+ [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v4.3.0...HEAD
166
+ ```
167
+
168
+ Note: this repo uses `...HEAD`, not `...main`. Match the existing convention.
169
+ - Add a new compare link for the stamped version, comparing the previous tag to the new one:
170
+
171
+ ```markdown
172
+ [4.3.0]: https://github.com/shakacode/control-plane-flow/compare/v4.2.0...v4.3.0
173
+ ```
174
+
175
+ 3. **For `rc`/`beta` modes**: collapse prior prerelease sections of the same base version into a single section (see "For Prerelease Versions" below). Remove the orphaned compare links for the collapsed prerelease versions.
176
+
177
+ The `rake release` task reads the first `## [VERSION]` header (skipping `Unreleased`) and uses it as the target version when newer than the current gem version. So once the changelog PR merges, `bundle exec rake release` (no args) will pick up the version automatically.
178
+
179
+ ### Finding the Most Recent Version
180
+
181
+ To determine the most recent version:
182
+
183
+ 1. **Check git tags** to find the latest released version:
184
+
185
+ ```bash
186
+ git tag --sort=-v:refname | head -10
187
+ ```
188
+
189
+ This shows tags like `v4.2.0`, `v4.1.1`, etc.
190
+
191
+ 2. **Check the CHANGELOG.md** for version headers (note: changelog uses versions WITHOUT the `v` prefix):
192
+ - `## [4.2.0] - 2026-04-15` (stable version)
193
+ - `## [4.2.0.rc.0] - 2026-04-10` (prerelease, if/when used)
194
+
195
+ 3. **Use this regex pattern** to find version headers in the changelog:
196
+
197
+ ```regex
198
+ ^## \[([^\]]+)\]( - \d{4}-\d{2}-\d{2})?
199
+ ```
200
+
201
+ 4. **The first match after `## [Unreleased]`** is the most recent version in the changelog.
202
+
203
+ **IMPORTANT**: Git tags use `v` prefix (e.g., `v4.2.0`). Changelog **headers** use versions WITHOUT the `v` prefix (e.g., `## [4.2.0]`), but compare **links** at the bottom of the file MUST use the `v` prefix to match the git tag (e.g., `.../compare/v4.1.1...v4.2.0`). Strip the `v` only for changelog headers, not for compare link URLs.
204
+
205
+ ## Process
206
+
207
+ ### For Regular Changelog Updates
208
+
209
+ #### Step 1: Fetch and read current state
210
+
211
+ - **CRITICAL**: Run `git fetch origin main` to ensure you have the latest commits
212
+ - After fetching, use `origin/main` for all comparisons, NOT local `main` branch
213
+ - Read the current CHANGELOG.md to understand the existing structure
214
+
215
+ #### Step 2: Reconcile tags with changelog sections (DO THIS FIRST)
216
+
217
+ **This step catches missing version sections and is the #1 source of errors when skipped.**
218
+
219
+ 1. Get the latest git tag: `git tag --sort=-v:refname | head -5`
220
+ 2. Get the most recent version header in CHANGELOG.md (the first `## [VERSION] - DATE` after `## [Unreleased]`)
221
+ 3. **Compare them.** If the latest git tag (minus the `v` prefix) does NOT appear anywhere in the changelog version headers, there are tagged releases missing from the changelog. **Important**: Don't just compare against the _top_ changelog header — a version header may exist _above_ the latest tag if it was stamped as a draft before tagging. Check whether the tag's version appears in _any_ `## [X.Y.Z]` header. For example:
222
+ - Latest tag: `v4.2.0`, and no `## [4.2.0]` header exists anywhere in CHANGELOG.md
223
+ - **Result: `4.2.0` is missing and needs its own section**
224
+ - But if `## [5.0.0]` is the top header (a draft, not yet tagged) and `## [4.2.0]` exists below it, then nothing is missing — the top header is simply a pre-release draft
225
+
226
+ 4. For EACH missing tagged version (there may be multiple):
227
+ a. Find commits in that tag vs the previous tag: `git log --oneline PREV_TAG..MISSING_TAG`
228
+ b. Extract PR numbers and fetch details for user-visible changes
229
+ c. Check which entries currently in `## [Unreleased]` actually belong to this tagged version (compare PR numbers against the commit list)
230
+ d. **Create a new version section** immediately before the previous version section:
231
+
232
+ ```markdown
233
+ ## [4.2.0] - 2026-04-15
234
+ ```
235
+
236
+ e. **Move** matching entries from Unreleased into the new section
237
+ f. **Add** any new entries for PRs in that tag that aren't in the changelog at all
238
+ g. **Update version diff links** at the bottom of the file:
239
+ - Update `[unreleased]` to compare from the newest tag to `HEAD`
240
+ - Add a link for each new version section
241
+
242
+ 5. Get the tag date with: `git log -1 --format="%Y-%m-%d" TAG_NAME`
243
+
244
+ #### Step 3: Add new entries for post-tag commits
245
+
246
+ 1. Run `git log --oneline LATEST_TAG..origin/main` to find commits after the latest tag (LATEST_TAG is the most recent git tag, i.e., the same one identified in Step 2)
247
+ 2. Extract PR numbers: `git log --oneline LATEST_TAG..origin/main | grep -oE "#[0-9]+" | sort -u`
248
+ 3. If Step 2 found no missing tagged versions, verify no tag is ahead of main: `git log --oneline origin/main..LATEST_TAG` should be empty. If not, entries in "Unreleased" may belong to that tagged version — Step 2 should have caught this, so re-check.
249
+ 4. For each PR number, check if it's already in CHANGELOG.md: `grep "PR XXX" CHANGELOG.md`
250
+ 5. For PRs not yet in the changelog:
251
+ - Get PR details: `gh pr view NUMBER --json title,body,author --repo shakacode/control-plane-flow`
252
+ - **Never ask the user for PR details** - get them from git history or the GitHub API
253
+ - Validate that the change is user-visible (per the criteria above). Skip CI, lint, refactoring, test-only changes.
254
+ - Add the entry to `## [Unreleased]` under the appropriate category heading
255
+
256
+ #### Step 4: Stamp version header (only when a version mode or explicit version is given)
257
+
258
+ If the user passed `release`, `rc`, `beta`, or an explicit version string as an argument:
259
+
260
+ 1. Determine the target version (auto-computed for `release`/`rc`/`beta`, exact for an explicit version) using the rules in "Auto-Computing the Next Version" above.
261
+
262
+ 2. Confirm the version with the user.
263
+
264
+ 3. **Stamp the header** by inserting `## [TARGET_VERSION] - YYYY-MM-DD` immediately after the `## [Unreleased]` block (after any short prose lines under Unreleased that should remain there).
265
+
266
+ 4. **Update compare links** at the bottom of the file:
267
+ - Update `[Unreleased]` to compare from the new tag to `HEAD`
268
+ - Add a new compare link for the stamped version
269
+
270
+ 5. **For `rc`/`beta`**: collapse prior prerelease sections of the same base version (see below) and remove their orphaned compare links.
271
+
272
+ 6. **Verify** the stamped header and diff links match the requested version. If anything looks off, fix it before continuing.
273
+
274
+ If no argument was passed, skip this step -- entries stay in `## [Unreleased]`.
275
+
276
+ #### Step 5: Verify and finalize
277
+
278
+ 1. **Verify formatting**:
279
+ - Bold description with period (or `BREAKING CHANGE:` prefix for breaking changes)
280
+ - Proper PR link (NO hash symbol)
281
+ - Proper author link
282
+ - Consistent with existing entries
283
+ - File ends with a newline character
284
+ - **No duplicate section headings** (e.g., don't create two `### Fixed` sections — merge entries into the existing heading)
285
+ 2. **Verify version sections are in order** (Unreleased -> newest tag -> older tags)
286
+ 3. **Verify version diff links** at the bottom of the file are correct (compare links MUST use the `v` prefix to match git tags; the `[Unreleased]` target is `HEAD`, not `main`)
287
+ 4. **Show the user** a summary of what was done:
288
+ - Which version sections were created
289
+ - Which entries were moved from Unreleased
290
+ - Which new entries were added
291
+ - Which PRs were skipped (and why)
292
+ 5. If in `release`/`rc`/`beta` mode or explicit-version mode, **automatically commit, push, and open a PR**:
293
+ - Verify the working tree only has `CHANGELOG.md` changes; if there are other uncommitted changes, warn the user and stop
294
+ - Verify the current branch is `main` (`git branch --show-current`); if not, warn the user and stop
295
+ - Create a feature branch following the user's branch-naming convention (e.g., `jg/changelog-4.3.0` or `changelog-4.3.0`)
296
+ - Stage only `CHANGELOG.md` (`git add CHANGELOG.md`) and commit with message `Update CHANGELOG.md for VERSION` (using the stamped version)
297
+ - Push and open a PR with the changelog diff as the body
298
+ - If the push or PR creation fails, the CHANGELOG is already stamped locally — fix the issue (e.g., authentication, branch protection), then run `git push -u origin <branch>` and `gh pr create` manually
299
+ - Remind the user to run `bundle exec rake release` (no args) after the PR merges to publish and auto-create the GitHub release
300
+
301
+ ### For Prerelease Versions (RC and Beta)
302
+
303
+ When the user passes `rc` or `beta` as an argument:
304
+
305
+ 1. **Find the latest tag** (stable or prerelease) using semver sort:
306
+
307
+ ```bash
308
+ git tag -l 'v*' --sort=-v:refname | head -10
309
+ ```
310
+
311
+ 2. **Auto-compute the next prerelease version** using the process in "Auto-Computing the Next Version" above. Use RubyGems format (`5.0.0.rc.0`), not `5.0.0-rc.0`.
312
+
313
+ 3. **Always collapse prior prereleases into the current prerelease** (this is the default behavior):
314
+ - Combine all prior prerelease changelog entries into the new prerelease version section
315
+ - Remove previous prerelease version sections (e.g., remove `## [5.0.0.rc.0]` when creating `## [5.0.0.rc.1]`)
316
+ - When collapsing, **consolidate duplicate category headings** — if both the Unreleased section and a prior prerelease section have `### Fixed`, merge all entries under a single `### Fixed` heading
317
+ - **Remove orphaned version diff links** at the bottom of the file for collapsed prerelease sections
318
+ - Add any new user-visible changes from commits since the last prerelease
319
+ - Update version diff links to point from the last stable version to the new prerelease
320
+ - This keeps the changelog clean with a single prerelease section that accumulates all changes since the last stable release
321
+
322
+ **Note**: The new version header must be inserted **immediately after `## [Unreleased]`** (see Step 4). This ensures correct ordering of version headers.
323
+
324
+ ### For Prerelease to Stable Version Release
325
+
326
+ When releasing from prerelease to a stable version (e.g., `v5.0.0.rc.1` -> `v5.0.0`):
327
+
328
+ 1. **Remove all prerelease version labels** from the changelog:
329
+ - Change `## [5.0.0.rc.0]`, `## [5.0.0.rc.1]`, etc. to a single `## [5.0.0]` section
330
+ - Also handle beta versions: `## [5.0.0.beta.1]` etc.
331
+ - Combine all prerelease entries into the stable release section
332
+
333
+ 2. **Consolidate duplicate entries**:
334
+ - If bug fixes or changes were made to features introduced in earlier prereleases, keep only the final state
335
+ - Remove redundant changelog entries for fixes to prerelease features
336
+ - Keep the most recent/accurate description of each change
337
+
338
+ 3. **Update version diff links** at the bottom to point to the stable version (and remove the orphaned prerelease compare links)
339
+
340
+ ## Examples
341
+
342
+ Run this command to see real formatting examples from the codebase:
343
+
344
+ ```bash
345
+ grep -B 1 -A 3 "^### " CHANGELOG.md | head -40
346
+ ```
347
+
348
+ ### Good Entry Example
349
+
350
+ ```markdown
351
+ - Added the GitHub Actions flow generator and readiness checks for staging, review-app, and production-promotion workflows. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
352
+ ```
353
+
354
+ ### Breaking Change Example
355
+
356
+ ```markdown
357
+ - BREAKING CHANGE: `cpflow generate` now writes `bundle config set with 'production'` in the generated Dockerfile, dropping the previous `'staging production'` group set. Apps that placed gems specifically under a `staging:` group in their `Gemfile` (e.g. APM agents, observability libraries that should ship to staging) must move those gems into the `production:` group before regenerating, or the regenerated Dockerfile will exclude them at install time. New scaffolds are unaffected. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
358
+ ```
359
+
360
+ ## Additional Notes
361
+
362
+ - Keep descriptions concise but informative
363
+ - Focus on the "what" and "why", not the "how"
364
+ - Use past tense for the description
365
+ - Be consistent with existing formatting in the changelog
366
+ - Always ensure the file ends with a trailing newline
367
+ - See `docs/releasing.md` for the full release process this command feeds into
@@ -24,6 +24,8 @@ jobs:
24
24
  issues: read
25
25
  id-token: write
26
26
  actions: read # Required for Claude to read CI results on PRs
27
+ checks: read
28
+ statuses: read
27
29
  steps:
28
30
  - name: Checkout repository
29
31
  uses: actions/checkout@v4
@@ -34,11 +36,14 @@ jobs:
34
36
  id: claude
35
37
  uses: anthropics/claude-code-action@v1
36
38
  with:
39
+ github_token: ${{ github.token }}
37
40
  claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
38
41
 
39
42
  # This is an optional setting that allows Claude to read CI results on PRs
40
43
  additional_permissions: |
41
44
  actions: read
45
+ checks: read
46
+ statuses: read
42
47
 
43
48
  # Optional: Give a custom prompt to Claude. If this is not specified, Claude will perform the instructions specified in the comment that tagged it.
44
49
  # prompt: 'Update the pull request description to include a summary of changes.'
data/.overcommit.yml CHANGED
@@ -1,14 +1,54 @@
1
1
  PreCommit:
2
+ RubyAutoFix:
3
+ enabled: true
4
+ parallelize: false
5
+ required_executable: "./script/precommit/ruby_autofix"
6
+ command: ["./script/precommit/ruby_autofix", "staged"]
7
+ requires_files: true
8
+ include:
9
+ - "**/*.rb"
10
+ - "**/*.rake"
11
+ - "**/*.ru"
12
+
13
+ TrailingNewlines:
14
+ enabled: true
15
+ parallelize: false
16
+ required_executable: "./script/precommit/check_trailing_newlines"
17
+ command: ["./script/precommit/check_trailing_newlines", "staged"]
18
+ requires_files: true
19
+ include:
20
+ - "**/*"
21
+
2
22
  ValidateLinks:
3
23
  enabled: true
4
- command: ["bash", "./script/check_cpln_links"]
24
+ required_executable: "./script/precommit/check_cpln_links"
25
+ command: ["./script/precommit/check_cpln_links", "staged"]
26
+ requires_files: true
27
+ include:
28
+ - "**/*.md"
29
+
5
30
  CommandDocs:
6
31
  enabled: true
7
- command: ["bundle", "exec", "rake", "check_command_docs"]
32
+ required_executable: "./script/precommit/check_command_docs"
33
+ command: ["./script/precommit/check_command_docs", "staged"]
34
+ requires_files: true
35
+ include:
36
+ - "lib/command/**/*.rb"
37
+ - "docs/commands.md"
38
+ - "script/update_command_docs"
39
+ - "script/check_command_docs"
40
+ - "Rakefile"
41
+
8
42
  RuboCop:
9
43
  enabled: true
10
44
  on_warn: fail
11
- command: ["bundle", "exec", "rubocop"]
45
+ required_executable: "./script/precommit/ruby_lint"
46
+ command: ["./script/precommit/ruby_lint", "staged"]
47
+ requires_files: true
48
+ include:
49
+ - "**/*.rb"
50
+ - "**/*.rake"
51
+ - "**/*.ru"
12
52
 
13
53
  # PrePush:
14
54
  # RSpec:
data/.rubocop.yml CHANGED
@@ -1,10 +1,10 @@
1
- require:
1
+ plugins:
2
2
  - rubocop-rake
3
3
  - rubocop-rspec
4
4
 
5
5
  AllCops:
6
- TargetRubyVersion: 2.7
7
- NewCops: enable
6
+ TargetRubyVersion: 3.0
7
+ NewCops: disable
8
8
 
9
9
  Metrics/AbcSize:
10
10
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -6,19 +6,41 @@ All notable changes to this project's source code will be documented in this fil
6
6
 
7
7
  Please follow the recommendations outlined at [keepachangelog.com](https://keepachangelog.com). Please use the existing headings and styling as a guide, and add a link for the version diff at the bottom of the file. Also, please update the `Unreleased` link to compare it to the latest release version.
8
8
 
9
+ In addition to the standard keepachangelog.com categories, this project uses a local `### Breaking Changes` heading at the top of each version section to surface backwards-incompatible changes. The release tooling treats that heading as a signal to require a major version bump (see `expected_bump_type_from_changelog_section` in `rakelib/create_release.rake`).
10
+
9
11
  ## Versions
10
12
 
11
13
  ## [Unreleased]
12
14
 
13
- Changes since the last non-beta release.
14
-
15
15
  _Please add entries here for your pull requests that have not yet been released._
16
16
 
17
+ ## [5.0.0.rc.0] - 2026-05-05
18
+
19
+ ### Breaking Changes
20
+
21
+ - BREAKING CHANGE: Bumped minimum Ruby version from 2.7.0 to 3.0.0. Users still on Ruby 2.7 must upgrade to Ruby 3.0 or newer before installing cpflow 5.x. [PR 258](https://github.com/shakacode/control-plane-flow/pull/258) by [Justin Gordon](https://github.com/justin808).
22
+ - BREAKING CHANGE: `cpflow exists` now returns exit code 3 when the app is not found, preserving 64 for real errors so scripts can distinguish not-found from API/auth failures. Affected callers: only scripts that branched specifically on `[ $? -eq 64 ]` as a "not found" signal — those will now misroute "not found" into the error branch and must switch to checking for exit 3. Scripts that treat any non-zero exit as "not found" are unaffected. The change is isolated to `lib/command/exists.rb` and `lib/constants/exit_code.rb` (`NOT_FOUND = 3`), so users hitting a regression can bisect by file. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
23
+ - BREAKING CHANGE: `cpflow generate` now writes `bundle config set with 'production'` in the generated Dockerfile, dropping the previous `'staging production'` group set. Apps that placed gems specifically under a `staging:` group in their `Gemfile` (e.g. APM agents, observability libraries that should ship to staging) must move those gems into the `production:` group before regenerating, or the regenerated Dockerfile will exclude them at install time. New scaffolds are unaffected. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
24
+
25
+ ### Added
26
+
27
+ - Added the GitHub Actions flow generator and readiness checks for staging, review-app, and production-promotion workflows. [PR 278](https://github.com/shakacode/control-plane-flow/pull/278) by [Justin Gordon](https://github.com/justin808).
28
+
29
+ ### Changed
30
+
31
+ - Updated runtime dependencies: `dotenv` (~> 2.8.1 → ~> 3.1), `jwt` (~> 2.8.1 → ~> 3.1), `psych` (~> 5.1.0 → ~> 5.2), and `thor` (~> 1.2.1 → ~> 1.4). [PR 258](https://github.com/shakacode/control-plane-flow/pull/258) by [Justin Gordon](https://github.com/justin808).
32
+
33
+ ## [4.2.0] - 2026-02-19
34
+
35
+ ### Added
36
+
37
+ - Suppress Node.js deprecation warnings from internal `cpln` calls by setting `NODE_NO_WARNINGS=1`, producing cleaner cpflow output. [PR 256](https://github.com/shakacode/control-plane-flow/pull/256) by [Judah Meek](https://github.com/Judahmeek).
38
+
17
39
  ### Fixed
18
40
 
19
41
  - Fixed issue where `run` command could hang indefinitely when updating runner workload. [PR 260](https://github.com/shakacode/control-plane-flow/pull/260) by [Sergey Tarasov](https://github.com/dzirtusss).
20
42
 
21
- ### Changed
43
+ ### Security
22
44
 
23
45
  - Redact sensitive data (Authorization headers, tokens) from `--trace` output. [PR 261](https://github.com/shakacode/control-plane-flow/pull/261) by [Sergey Tarasov](https://github.com/dzirtusss).
24
46
 
@@ -291,7 +313,9 @@ Deprecated `cpl` gem. New gem is `cpflow`.
291
313
 
292
314
  First release.
293
315
 
294
- [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v4.1.1...HEAD
316
+ [Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.0...HEAD
317
+ [5.0.0.rc.0]: https://github.com/shakacode/control-plane-flow/compare/v4.2.0...v5.0.0.rc.0
318
+ [4.2.0]: https://github.com/shakacode/control-plane-flow/compare/v4.1.1...v4.2.0
295
319
  [4.1.1]: https://github.com/shakacode/control-plane-flow/compare/v4.1.0...v4.1.1
296
320
  [4.1.0]: https://github.com/shakacode/control-plane-flow/compare/v4.0.0...v4.1.0
297
321
  [4.0.0]: https://github.com/shakacode/control-plane-flow/compare/v3.0.1...v4.0.0
data/CONTRIBUTING.md CHANGED
@@ -71,3 +71,9 @@ CPLN_ORG=your-org-for-tests bundle exec rspec --tag slow
71
71
  ```sh
72
72
  cpflow test
73
73
  ```
74
+
75
+ ## Releasing
76
+
77
+ See [Releasing the Gem](./docs/releasing.md) for the changelog-first Ruby gem release process. In short: run
78
+ `/update-changelog release`, merge the generated changelog PR, then run `bundle exec rake release`. This project
79
+ releases only the `cpflow` RubyGem; there is no npm publishing step.
data/Gemfile CHANGED
@@ -5,13 +5,14 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem "debug", "~> 1"
8
- gem "overcommit", "~> 0.60.0"
8
+ gem "gem-release", "~> 2.2"
9
+ gem "overcommit", "~> 0.69.0"
9
10
  gem "rake", "~> 13.0"
10
- gem "rspec", "~> 3.12.0"
11
+ gem "rspec", "~> 3.13"
11
12
  gem "rspec-retry", "~> 0.6.2"
12
- gem "rubocop", "~> 1.64.1"
13
- gem "rubocop-rake", "~> 0.6.0"
14
- gem "rubocop-rspec", "~> 3.0.1"
13
+ gem "rubocop", "~> 1.81"
14
+ gem "rubocop-rake", "~> 0.7.1"
15
+ gem "rubocop-rspec", "~> 3.8"
15
16
  gem "simplecov", "~> 0.22.0"
16
- gem "timecop", "~> 0.9.6"
17
- gem "webmock", "~> 3.18.1"
17
+ gem "timecop", "~> 0.9.10"
18
+ gem "webmock", "~> 3.26"