cpflow 5.0.0 → 5.0.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.
- checksums.yaml +4 -4
- data/.claude/commands/update-changelog.md +88 -23
- data/.github/actions/cpflow-resolve-review-config/action.yml +137 -0
- data/.github/actions/cpflow-setup-environment/action.yml +118 -0
- data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +26 -21
- data/.github/workflows/cpflow-delete-review-app.yml +21 -18
- data/.github/workflows/cpflow-deploy-review-app.yml +23 -19
- data/.github/workflows/cpflow-deploy-staging.yml +15 -11
- data/.github/workflows/cpflow-help-command.yml +0 -6
- data/.github/workflows/cpflow-promote-staging-to-production.yml +30 -5
- data/.github/workflows/cpflow-review-app-help.yml +1 -10
- data/CHANGELOG.md +23 -1
- data/Gemfile.lock +1 -1
- data/docs/ai-github-flow-prompt.md +1 -1
- data/docs/ci-automation.md +165 -29
- data/lib/command/ai_github_flow_prompt.rb +1 -1
- data/lib/cpflow/version.rb +1 -1
- data/lib/generator_templates/Dockerfile +1 -0
- data/lib/generator_templates/entrypoint.sh +42 -2
- data/lib/github_flow_templates/.github/cpflow-help.md +79 -83
- data/lib/github_flow_templates/.github/workflows/cpflow-cleanup-stale-review-apps.yml +4 -9
- data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +2 -9
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +3 -9
- data/lib/github_flow_templates/.github/workflows/cpflow-deploy-staging.yml +3 -8
- data/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +0 -9
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +10 -8
- data/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +4 -10
- data/lib/github_flow_templates/bin/pin-cpflow-github-ref +3 -1
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +23 -8
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1371f70bf636d92e0dacd78322ad6ef7d87e29fbec6c853e487a01205be1528
|
|
4
|
+
data.tar.gz: 9ad5116ccb84cc7e3757922c3c0580785caa1cfff96aed768c65d63c7ff01e93
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6c96a1db55e94a5e22efa0640d51129566aa6afb16c8ea9887f5cf709a313ef3b1a690d5b64ba932b50cb1fb72efe85e7fa3371f8941b60242486d6fc1322566
|
|
7
|
+
data.tar.gz: 5a91cc36014d13c3b36ea3af7620758821d1fa0000bab12b1742d47fe0240015353c59b5dae6d981680b7746bcaa9154bd44f00a1fc240dce651cd57926a253b
|
|
@@ -166,13 +166,16 @@ This repo does **not** have an `update_changelog` rake task — the slash comman
|
|
|
166
166
|
```
|
|
167
167
|
|
|
168
168
|
Note: this repo uses `...HEAD`, not `...main`. Match the existing convention.
|
|
169
|
-
- Add a new compare link for the stamped version
|
|
169
|
+
- Add a new compare link for the stamped version:
|
|
170
170
|
|
|
171
171
|
```markdown
|
|
172
172
|
[4.3.0]: https://github.com/shakacode/control-plane-flow/compare/v4.2.0...v4.3.0
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
- **For stable releases**, skip prerelease tags — compare from the previous **stable** tag. A stable release that coalesces prior RCs (e.g., `v5.0.0.rc.0`, `v5.0.0.rc.1`) still uses the last stable tag as the left side (e.g., `v4.2.0...v5.0.0`), not the latest RC tag.
|
|
176
|
+
- **For prereleases**, compare from the immediately previous tag (which may be a prior RC/beta or the last stable tag).
|
|
177
|
+
|
|
178
|
+
3. **For `rc`/`beta` modes**: Insert the new RC/beta section above any prior prereleases — do NOT collapse them. Each RC/beta is a separately-tagged release that users install, and they need to see what changed between, say, `rc.0` and `rc.1`. See "For Prerelease Versions" below. Coalescing happens only at the stable release.
|
|
176
179
|
|
|
177
180
|
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
181
|
|
|
@@ -267,9 +270,11 @@ If the user passed `release`, `rc`, `beta`, or an explicit version string as an
|
|
|
267
270
|
- Update `[Unreleased]` to compare from the new tag to `HEAD`
|
|
268
271
|
- Add a new compare link for the stamped version
|
|
269
272
|
|
|
270
|
-
5. **For `rc`/`beta`**: collapse prior prerelease sections
|
|
273
|
+
5. **For `rc`/`beta`**: Do NOT collapse prior prerelease sections — each RC/beta gets its own section so users can see what changed between prereleases. Just insert the new section above the prior ones and add a new compare link. See "For Prerelease Versions" below.
|
|
274
|
+
|
|
275
|
+
6. **For stable `release` (or explicit stable version) when prior `rc`/`beta` sections exist for the same base version**: Do NOT just stamp `## [5.0.0]` above the prior RC sections. Instead, follow the "For Prerelease to Stable Version Release" process below — it replaces steps 3–4 here with the coalesce + curate flow (combine all RC sections into the new stable section, move any matching `[Unreleased]` entries in, drop prerelease-only noise, and use the previous **stable** tag in the compare link).
|
|
271
276
|
|
|
272
|
-
|
|
277
|
+
7. **Verify** the stamped header and diff links match the requested version. If anything looks off, fix it before continuing.
|
|
273
278
|
|
|
274
279
|
If no argument was passed, skip this step -- entries stay in `## [Unreleased]`.
|
|
275
280
|
|
|
@@ -310,32 +315,92 @@ When the user passes `rc` or `beta` as an argument:
|
|
|
310
315
|
|
|
311
316
|
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
317
|
|
|
313
|
-
3. **
|
|
314
|
-
|
|
315
|
-
-
|
|
316
|
-
-
|
|
317
|
-
-
|
|
318
|
-
- Add any new user-visible changes from commits since the last prerelease
|
|
319
|
-
-
|
|
320
|
-
-
|
|
318
|
+
3. **Do NOT collapse prior prereleases.** Each RC/beta is a separately-tagged release that users install — they need to see what changed between, for example, `rc.0` and `rc.1` (especially when diagnosing a regression in a specific RC). Each successive `bundle exec rake release` reads only the top-most `## [VERSION]` section (the RC you just stamped — see the "Version Stamping" section above), so as long as each RC has its own section the corresponding GitHub release gets its own focused notes. Instead:
|
|
319
|
+
|
|
320
|
+
- Insert the new prerelease version section immediately after `## [Unreleased]`, **above** any prior prerelease sections (preserves newest-first ordering)
|
|
321
|
+
- Move any entries from `## [Unreleased]` that belong to this prerelease into the new section
|
|
322
|
+
- Leave prior prerelease sections (e.g., `## [5.0.0.rc.0]`) untouched — keep their entries and their compare links at the bottom of the file
|
|
323
|
+
- Add any new user-visible changes from commits since the last prerelease tag to the new section only
|
|
324
|
+
- Add a new compare link at the bottom comparing the previous prerelease tag (or the last stable tag if this is the first RC) to the new prerelease tag
|
|
325
|
+
- Update the `[Unreleased]` compare link to point from the new prerelease tag to `HEAD`
|
|
326
|
+
|
|
327
|
+
**Resulting structure** after stamping `5.0.0.rc.1` (with `5.0.0.rc.0` already shipped on top of stable `4.2.0`):
|
|
328
|
+
|
|
329
|
+
```markdown
|
|
330
|
+
## [Unreleased]
|
|
331
|
+
|
|
332
|
+
## [5.0.0.rc.1] - 2026-05-25
|
|
333
|
+
|
|
334
|
+
### Fixed
|
|
335
|
+
|
|
336
|
+
- **Fix regression introduced in rc.0**. [PR 320](https://github.com/shakacode/control-plane-flow/pull/320) by [Justin Gordon](https://github.com/justin808).
|
|
337
|
+
|
|
338
|
+
## [5.0.0.rc.0] - 2026-05-10
|
|
339
|
+
|
|
340
|
+
### Added
|
|
341
|
+
|
|
342
|
+
- **New feature**. [PR 315](https://github.com/shakacode/control-plane-flow/pull/315) by [Justin Gordon](https://github.com/justin808).
|
|
343
|
+
|
|
344
|
+
## [4.2.0] - 2026-04-01
|
|
345
|
+
|
|
346
|
+
...
|
|
347
|
+
|
|
348
|
+
[Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.1...HEAD
|
|
349
|
+
[5.0.0.rc.1]: https://github.com/shakacode/control-plane-flow/compare/v5.0.0.rc.0...v5.0.0.rc.1
|
|
350
|
+
[5.0.0.rc.0]: https://github.com/shakacode/control-plane-flow/compare/v4.2.0...v5.0.0.rc.0
|
|
351
|
+
[4.2.0]: https://github.com/shakacode/control-plane-flow/compare/v4.1.1...v4.2.0
|
|
352
|
+
```
|
|
321
353
|
|
|
322
|
-
|
|
354
|
+
Both RC sections remain intact with their own compare links until the stable release coalesces them.
|
|
355
|
+
|
|
356
|
+
**Coalescing happens only at the stable release** — see "For Prerelease to Stable Version Release" below.
|
|
357
|
+
|
|
358
|
+
**Note**: The new version header must be inserted **immediately after `## [Unreleased]`** (see Step 4). This ensures correct newest-first ordering of version headers.
|
|
323
359
|
|
|
324
360
|
### For Prerelease to Stable Version Release
|
|
325
361
|
|
|
326
|
-
When releasing from prerelease to a stable version (e.g., `v5.0.0.rc.
|
|
362
|
+
When releasing from prerelease to a stable version (e.g., `v5.0.0.rc.2` -> `v5.0.0`), this is where the accumulated prerelease sections get coalesced into one stable section. **Curate carefully** — users landing on the stable version don't care about intermediate prerelease state, and noise here makes the upgrade story harder to read.
|
|
363
|
+
|
|
364
|
+
#### Step 1: Coalesce all prerelease sections into one stable section
|
|
365
|
+
|
|
366
|
+
- Replace `## [5.0.0.rc.0]`, `## [5.0.0.rc.1]`, `## [5.0.0.beta.1]`, etc. with a single `## [5.0.0] - YYYY-MM-DD` section
|
|
367
|
+
- **Move any remaining entries from `## [Unreleased]` into the new stable section** — anything still under `[Unreleased]` at stable-release time is shipping in this stable version. Leave `## [Unreleased]` with only its header (no entries).
|
|
368
|
+
- Combine entries from all prerelease sections and the moved `[Unreleased]` entries, consolidating duplicate category headings (e.g., merge multiple `### Fixed` sections into one under the preferred order from "Category Organization")
|
|
369
|
+
- Remove the orphaned compare links at the bottom of the file for the coalesced prerelease versions
|
|
370
|
+
- Add the `[5.0.0]` compare link pointing from the previous stable tag (e.g., `v4.2.0`) to `v5.0.0` — **not** from the latest RC tag
|
|
371
|
+
- Update the `[Unreleased]` compare link to point from `v5.0.0` to `HEAD`
|
|
372
|
+
|
|
373
|
+
#### Step 2: Curate the entries — REMOVE these
|
|
374
|
+
|
|
375
|
+
1. **Prerelease-only fixes** — bugs introduced during the prerelease cycle and fixed in a later RC. If the bug never shipped in a stable release, the fix is noise to stable users.
|
|
376
|
+
- Investigate when a bug was introduced: `git log --oneline v<last_stable>..v<rc_that_fixed_the_bug>` — if this commit range doesn't contain the bug's introduction (i.e., the introducing commit predates the RC cycle), the bug was already in the last stable release and the fix belongs in the stable section. If the introduction *is* in this range, the bug never shipped in stable, so drop the fix.
|
|
377
|
+
- Check the PR description for what was broken and when
|
|
378
|
+
|
|
379
|
+
2. **Refinements to prerelease-only features** — if a new feature was introduced in `rc.0` and then iterated in `rc.1`/`rc.2`, keep only the final description and drop the iteration history
|
|
380
|
+
|
|
381
|
+
3. **Internal/contributor-only tooling** — CI tweaks, build script changes, generator handling of prerelease version formats, local-dev tooling fixes. These don't belong in a user-facing changelog.
|
|
382
|
+
|
|
383
|
+
#### Step 3: Curate the entries — KEEP these
|
|
384
|
+
|
|
385
|
+
1. **User-facing fixes for bugs that existed in the previous stable** — if `rc.2` fixes a bug that was in `4.2.0`, that fix matters to stable users upgrading
|
|
386
|
+
|
|
387
|
+
2. **Compatibility fixes** — Ruby/Rails version support, dependency relaxations, etc.
|
|
388
|
+
|
|
389
|
+
3. **All breaking changes** — API/CLI changes, removed methods, configuration changes, exit code changes, generator output changes. Even if a breaking change was introduced and refined across multiple prereleases, the final breaking change description belongs in stable.
|
|
390
|
+
|
|
391
|
+
4. **Performance/security improvements affecting all users**
|
|
392
|
+
|
|
393
|
+
#### Step 4: Investigation process for each entry
|
|
394
|
+
|
|
395
|
+
For each entry from a prerelease section, ask:
|
|
327
396
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
- Combine all prerelease entries into the stable release section
|
|
397
|
+
- Was this bug present in the last stable release? If no, drop.
|
|
398
|
+
- Was this feature introduced in an earlier prerelease and then superseded? If yes, keep only the final state.
|
|
399
|
+
- Does this matter to someone upgrading from the last stable to this stable? If no, drop.
|
|
332
400
|
|
|
333
|
-
|
|
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
|
|
401
|
+
#### Step 5: Final read-through
|
|
337
402
|
|
|
338
|
-
|
|
403
|
+
Read the resulting stable section as if you're a user upgrading from the previous stable. Every entry should be something you'd want to know about. If an entry only makes sense to someone who tracked the RC cycle, drop it.
|
|
339
404
|
|
|
340
405
|
## Examples
|
|
341
406
|
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
name: Resolve Review App Config
|
|
2
|
+
description: Infers review app prefix and Control Plane org from controlplane.yml
|
|
3
|
+
|
|
4
|
+
inputs:
|
|
5
|
+
configured_cpln_org_staging:
|
|
6
|
+
description: Optional override for the staging Control Plane org.
|
|
7
|
+
required: false
|
|
8
|
+
default: ""
|
|
9
|
+
configured_review_app_prefix:
|
|
10
|
+
description: Optional override for the review app prefix.
|
|
11
|
+
required: false
|
|
12
|
+
default: ""
|
|
13
|
+
pr_number:
|
|
14
|
+
description: Pull request number used to build the review app name.
|
|
15
|
+
required: false
|
|
16
|
+
default: ""
|
|
17
|
+
working_directory:
|
|
18
|
+
description: Directory containing .controlplane/controlplane.yml.
|
|
19
|
+
required: false
|
|
20
|
+
default: "."
|
|
21
|
+
|
|
22
|
+
outputs:
|
|
23
|
+
review_app_prefix:
|
|
24
|
+
description: Resolved review app prefix.
|
|
25
|
+
value: ${{ steps.resolve.outputs.review_app_prefix }}
|
|
26
|
+
cpln_org:
|
|
27
|
+
description: Resolved Control Plane org.
|
|
28
|
+
value: ${{ steps.resolve.outputs.cpln_org }}
|
|
29
|
+
app_name:
|
|
30
|
+
description: Resolved review app name when pr_number is present; omitted when pr_number is empty.
|
|
31
|
+
value: ${{ steps.resolve.outputs.app_name }}
|
|
32
|
+
|
|
33
|
+
runs:
|
|
34
|
+
using: composite
|
|
35
|
+
steps:
|
|
36
|
+
- name: Resolve review app config
|
|
37
|
+
id: resolve
|
|
38
|
+
shell: bash
|
|
39
|
+
working-directory: ${{ inputs.working_directory }}
|
|
40
|
+
env:
|
|
41
|
+
CONFIGURED_CPLN_ORG_STAGING: ${{ inputs.configured_cpln_org_staging }}
|
|
42
|
+
CONFIGURED_REVIEW_APP_PREFIX: ${{ inputs.configured_review_app_prefix }}
|
|
43
|
+
PR_NUMBER: ${{ inputs.pr_number }}
|
|
44
|
+
run: |
|
|
45
|
+
set -euo pipefail
|
|
46
|
+
|
|
47
|
+
ruby <<'RUBY'
|
|
48
|
+
require "yaml"
|
|
49
|
+
|
|
50
|
+
def safe_load_yaml_file(path)
|
|
51
|
+
contents = File.read(path)
|
|
52
|
+
|
|
53
|
+
if YAML.method(:safe_load).parameters.any? { |type, name| type == :key && name == :aliases }
|
|
54
|
+
YAML.safe_load(contents, aliases: true)
|
|
55
|
+
else
|
|
56
|
+
YAML.safe_load(contents, [], [], true)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def validate_github_env_value!(name, value)
|
|
61
|
+
return if value.match?(/\A[A-Za-z0-9-]+\z/)
|
|
62
|
+
|
|
63
|
+
warn "::error::#{name} must contain only letters, numbers, and hyphens so it is a valid Control Plane name and can be safely written to GitHub environment files."
|
|
64
|
+
exit 1
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
begin
|
|
68
|
+
config = safe_load_yaml_file(".controlplane/controlplane.yml")
|
|
69
|
+
unless config.is_a?(Hash)
|
|
70
|
+
warn "::error::.controlplane/controlplane.yml must be a YAML mapping; got #{config.class}: #{config.inspect}"
|
|
71
|
+
exit 1
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
apps = config["apps"]
|
|
75
|
+
unless apps.is_a?(Hash)
|
|
76
|
+
warn "::error::.controlplane/controlplane.yml must define an apps mapping; got #{apps.class}: #{apps.inspect}"
|
|
77
|
+
exit 1
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
review_apps = apps.select do |_name, app_config|
|
|
81
|
+
app_config.is_a?(Hash) && app_config["match_if_app_name_starts_with"] == true
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
prefix = ENV.fetch("CONFIGURED_REVIEW_APP_PREFIX", "").strip
|
|
85
|
+
if prefix.empty?
|
|
86
|
+
if review_apps.length == 1
|
|
87
|
+
prefix = review_apps.keys.first
|
|
88
|
+
elsif review_apps.empty?
|
|
89
|
+
warn "::error::Set REVIEW_APP_PREFIX or define exactly one app with match_if_app_name_starts_with: true in .controlplane/controlplane.yml."
|
|
90
|
+
exit 1
|
|
91
|
+
else
|
|
92
|
+
warn "::error::Set REVIEW_APP_PREFIX because .controlplane/controlplane.yml defines multiple review app prefixes: #{review_apps.keys.sort.join(', ')}."
|
|
93
|
+
exit 1
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
app_config = apps[prefix]
|
|
98
|
+
unless app_config.is_a?(Hash) && app_config["match_if_app_name_starts_with"] == true
|
|
99
|
+
warn "::error::Review app prefix '#{prefix}' must match an app in .controlplane/controlplane.yml with match_if_app_name_starts_with: true."
|
|
100
|
+
exit 1
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
cpln_org = ENV.fetch("CONFIGURED_CPLN_ORG_STAGING", "").strip
|
|
104
|
+
cpln_org = app_config["cpln_org"].to_s.strip if cpln_org.empty?
|
|
105
|
+
if cpln_org.empty?
|
|
106
|
+
warn "::error::Set CPLN_ORG_STAGING or cpln_org for review app prefix '#{prefix}' in .controlplane/controlplane.yml."
|
|
107
|
+
exit 1
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
pr_number = ENV.fetch("PR_NUMBER", "").strip
|
|
111
|
+
unless pr_number.empty? || pr_number.match?(/\A[1-9][0-9]*\z/)
|
|
112
|
+
warn "::error::PR_NUMBER must be a positive integer; got: #{pr_number.inspect}"
|
|
113
|
+
exit 1
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
app_name = pr_number.empty? ? "" : "#{prefix}-#{pr_number}"
|
|
117
|
+
|
|
118
|
+
validate_github_env_value!("REVIEW_APP_PREFIX", prefix)
|
|
119
|
+
validate_github_env_value!("CPLN_ORG", cpln_org)
|
|
120
|
+
validate_github_env_value!("APP_NAME", app_name) unless app_name.empty?
|
|
121
|
+
|
|
122
|
+
File.open(ENV.fetch("GITHUB_ENV"), "a") do |file|
|
|
123
|
+
file.puts "REVIEW_APP_PREFIX=#{prefix}"
|
|
124
|
+
file.puts "CPLN_ORG=#{cpln_org}"
|
|
125
|
+
file.puts "APP_NAME=#{app_name}" unless app_name.empty?
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
File.open(ENV.fetch("GITHUB_OUTPUT"), "a") do |file|
|
|
129
|
+
file.puts "review_app_prefix=#{prefix}"
|
|
130
|
+
file.puts "cpln_org=#{cpln_org}"
|
|
131
|
+
file.puts "app_name=#{app_name}" unless app_name.empty?
|
|
132
|
+
end
|
|
133
|
+
rescue StandardError => e
|
|
134
|
+
warn "::error::Could not resolve review app config from .controlplane/controlplane.yml: #{e.class}: #{e.message}"
|
|
135
|
+
exit 1
|
|
136
|
+
end
|
|
137
|
+
RUBY
|
|
@@ -37,6 +37,13 @@ inputs:
|
|
|
37
37
|
without publishing a release.
|
|
38
38
|
required: false
|
|
39
39
|
default: ""
|
|
40
|
+
control_plane_flow_ref:
|
|
41
|
+
description: >-
|
|
42
|
+
Full GitHub workflow ref for the control-plane-flow reusable workflow, for
|
|
43
|
+
example shakacode/control-plane-flow/.github/workflows/deploy.yml@refs/tags/v5.0.1.
|
|
44
|
+
When cpflow_version is set, this must point at the matching release tag.
|
|
45
|
+
required: false
|
|
46
|
+
default: ""
|
|
40
47
|
|
|
41
48
|
runs:
|
|
42
49
|
using: composite
|
|
@@ -83,6 +90,7 @@ runs:
|
|
|
83
90
|
- name: Install Control Plane CLI and cpflow gem
|
|
84
91
|
shell: bash
|
|
85
92
|
env:
|
|
93
|
+
CONTROL_PLANE_FLOW_REF: ${{ inputs.control_plane_flow_ref }}
|
|
86
94
|
CPLN_CLI_VERSION: ${{ inputs.cpln_cli_version }}
|
|
87
95
|
CPFLOW_VERSION: ${{ inputs.cpflow_version }}
|
|
88
96
|
CPFLOW_SOURCE_DIR: ${{ github.action_path }}/../../..
|
|
@@ -95,6 +103,116 @@ runs:
|
|
|
95
103
|
|
|
96
104
|
CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
|
|
97
105
|
|
|
106
|
+
normalize_version() {
|
|
107
|
+
local version="${1#v}"
|
|
108
|
+
version="${version//-/.}"
|
|
109
|
+
|
|
110
|
+
if [[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9A-Za-z]+)*$ ]]; then
|
|
111
|
+
echo "${version}"
|
|
112
|
+
fi
|
|
113
|
+
# Empty output means an unrecognized format; callers check for that.
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
extract_ref_name() {
|
|
117
|
+
local ref="${1##*@}"
|
|
118
|
+
ref="${ref#refs/tags/}"
|
|
119
|
+
echo "${ref}"
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
normalize_release_ref() {
|
|
123
|
+
local ref
|
|
124
|
+
ref="$(extract_ref_name "$1")"
|
|
125
|
+
|
|
126
|
+
# Intentional: non-v refs return success with empty stdout; callers
|
|
127
|
+
# treat empty output as "not a release tag".
|
|
128
|
+
[[ "${ref}" == v* ]] || return 0
|
|
129
|
+
normalize_version "${ref}"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
verify_release_ref_matches_checkout() {
|
|
133
|
+
local ref
|
|
134
|
+
local remote_url="https://github.com/shakacode/control-plane-flow.git"
|
|
135
|
+
local tag_refs
|
|
136
|
+
local tag_commit=""
|
|
137
|
+
local checkout_commit
|
|
138
|
+
|
|
139
|
+
ref="$(extract_ref_name "$1")"
|
|
140
|
+
[[ "${ref}" == v* ]] || return 1
|
|
141
|
+
|
|
142
|
+
git_ls_remote_tag() {
|
|
143
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
144
|
+
timeout 20 git ls-remote --tags "${remote_url}" "refs/tags/${ref}" "refs/tags/${ref}^{}"
|
|
145
|
+
else
|
|
146
|
+
git ls-remote --tags "${remote_url}" "refs/tags/${ref}" "refs/tags/${ref}^{}"
|
|
147
|
+
fi
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if ! tag_refs="$(git_ls_remote_tag 2>&1)"; then
|
|
151
|
+
echo "::error::Could not verify the control-plane-flow workflow ref against ${remote_url}. Runners that set CPFLOW_VERSION need outbound HTTPS access to GitHub for this tag check. Leave CPFLOW_VERSION unset when testing a commit SHA or branch. Details: ${tag_refs}"
|
|
152
|
+
exit 1
|
|
153
|
+
fi
|
|
154
|
+
|
|
155
|
+
if [[ -z "${tag_refs}" ]]; then
|
|
156
|
+
echo "::error::CPFLOW_VERSION can only be used with an existing control-plane-flow release tag. No remote tag found for workflow ref ${CONTROL_PLANE_FLOW_REF}."
|
|
157
|
+
exit 1
|
|
158
|
+
fi
|
|
159
|
+
|
|
160
|
+
while read -r sha tag_ref; do
|
|
161
|
+
if [[ "${tag_ref}" == "refs/tags/${ref}^{}" ]]; then
|
|
162
|
+
tag_commit="${sha}"
|
|
163
|
+
break
|
|
164
|
+
fi
|
|
165
|
+
|
|
166
|
+
if [[ "${tag_ref}" == "refs/tags/${ref}" ]]; then
|
|
167
|
+
tag_commit="${sha}"
|
|
168
|
+
fi
|
|
169
|
+
done <<< "${tag_refs}"
|
|
170
|
+
|
|
171
|
+
if [[ -z "${tag_commit}" ]]; then
|
|
172
|
+
echo "::error::Could not resolve the commit for release tag ${ref}."
|
|
173
|
+
exit 1
|
|
174
|
+
fi
|
|
175
|
+
|
|
176
|
+
checkout_commit="$(git -C "${CPFLOW_SOURCE_DIR}" rev-parse HEAD)"
|
|
177
|
+
if [[ "${checkout_commit}" != "${tag_commit}" ]]; then
|
|
178
|
+
echo "::error::control-plane-flow workflow ref ${CONTROL_PLANE_FLOW_REF} resolved to ${checkout_commit}, but release tag ${ref} points to ${tag_commit}. Use the real release tag ref, not a moving branch, or leave CPFLOW_VERSION unset."
|
|
179
|
+
exit 1
|
|
180
|
+
fi
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
is_rubygems_version() {
|
|
184
|
+
[[ "${1}" =~ ^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9A-Za-z]+)*$ ]]
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
validate_cpflow_version_pin() {
|
|
188
|
+
[[ -z "${CPFLOW_VERSION}" ]] && return 0
|
|
189
|
+
|
|
190
|
+
local actual_version
|
|
191
|
+
local expected_version
|
|
192
|
+
|
|
193
|
+
if ! is_rubygems_version "${CPFLOW_VERSION}"; then
|
|
194
|
+
echo "::error::CPFLOW_VERSION must be a RubyGems version usable by 'gem install cpflow -v', such as 5.0.0 or 5.0.0.rc.1. Do not include a leading v, and use dot-separated prereleases instead of dash-separated prereleases."
|
|
195
|
+
exit 1
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
actual_version="$(normalize_version "${CPFLOW_VERSION}")"
|
|
199
|
+
expected_version="$(normalize_release_ref "${CONTROL_PLANE_FLOW_REF}")"
|
|
200
|
+
|
|
201
|
+
if [[ -z "${expected_version}" ]]; then
|
|
202
|
+
echo "::error::CPFLOW_VERSION can only be used when the control-plane-flow reusable workflow is pinned to a release tag like v${CPFLOW_VERSION}. Dot and dash prerelease tags are accepted, for example v5.0.0.rc.1 or v5.0.0-rc.1. Current workflow ref: ${CONTROL_PLANE_FLOW_REF:-<empty>}. Leave CPFLOW_VERSION unset when testing a commit SHA or branch so cpflow is built from the same source as the reusable workflow."
|
|
203
|
+
exit 1
|
|
204
|
+
fi
|
|
205
|
+
|
|
206
|
+
verify_release_ref_matches_checkout "${CONTROL_PLANE_FLOW_REF}"
|
|
207
|
+
|
|
208
|
+
if [[ "${actual_version}" != "${expected_version}" ]]; then
|
|
209
|
+
echo "::error::CPFLOW_VERSION must match the control-plane-flow reusable workflow tag. CPFLOW_VERSION=${CPFLOW_VERSION}, normalized CPFLOW_VERSION=${actual_version}, workflow ref=${CONTROL_PLANE_FLOW_REF}, expected CPFLOW_VERSION=${expected_version}."
|
|
210
|
+
exit 1
|
|
211
|
+
fi
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
validate_cpflow_version_pin
|
|
215
|
+
|
|
98
216
|
npm_global_prefix="${HOME}/.npm-global"
|
|
99
217
|
mkdir -p "${npm_global_prefix}"
|
|
100
218
|
echo "${npm_global_prefix}/bin" >> "$GITHUB_PATH"
|
|
@@ -2,12 +2,10 @@ name: Cleanup Stale Review Apps
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
workflow_call:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
description:
|
|
8
|
-
required:
|
|
9
|
-
type: string
|
|
10
|
-
default: main
|
|
5
|
+
secrets:
|
|
6
|
+
CPLN_TOKEN_STAGING:
|
|
7
|
+
description: Control Plane token for the staging org that owns review apps.
|
|
8
|
+
required: true
|
|
11
9
|
|
|
12
10
|
permissions:
|
|
13
11
|
contents: read
|
|
@@ -28,8 +26,8 @@ jobs:
|
|
|
28
26
|
- name: Checkout control-plane-flow actions
|
|
29
27
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
30
28
|
with:
|
|
31
|
-
repository:
|
|
32
|
-
ref: ${{
|
|
29
|
+
repository: ${{ job.workflow_repository }}
|
|
30
|
+
ref: ${{ job.workflow_sha }}
|
|
33
31
|
path: .cpflow
|
|
34
32
|
persist-credentials: false
|
|
35
33
|
|
|
@@ -37,33 +35,40 @@ jobs:
|
|
|
37
35
|
uses: ./.cpflow/.github/actions/cpflow-validate-config
|
|
38
36
|
env:
|
|
39
37
|
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
40
|
-
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
|
|
41
|
-
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
|
|
42
38
|
with:
|
|
43
39
|
required: |
|
|
44
40
|
secret:CPLN_TOKEN_STAGING
|
|
45
|
-
|
|
46
|
-
|
|
41
|
+
|
|
42
|
+
- name: Checkout caller repository
|
|
43
|
+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
44
|
+
with:
|
|
45
|
+
path: app
|
|
46
|
+
persist-credentials: false
|
|
47
|
+
|
|
48
|
+
- name: Resolve review app config
|
|
49
|
+
id: review-config
|
|
50
|
+
uses: ./.cpflow/.github/actions/cpflow-resolve-review-config
|
|
51
|
+
with:
|
|
52
|
+
working_directory: app
|
|
53
|
+
configured_cpln_org_staging: ${{ vars.CPLN_ORG_STAGING }}
|
|
54
|
+
configured_review_app_prefix: ${{ vars.REVIEW_APP_PREFIX }}
|
|
47
55
|
|
|
48
56
|
- name: Setup environment
|
|
49
57
|
uses: ./.cpflow/.github/actions/cpflow-setup-environment
|
|
50
58
|
with:
|
|
51
59
|
token: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
52
|
-
org: ${{
|
|
60
|
+
org: ${{ steps.review-config.outputs.cpln_org }}
|
|
53
61
|
working_directory: .cpflow
|
|
54
62
|
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
|
|
55
63
|
cpflow_version: ${{ vars.CPFLOW_VERSION }}
|
|
56
|
-
|
|
57
|
-
- name: Checkout caller repository
|
|
58
|
-
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
59
|
-
with:
|
|
60
|
-
persist-credentials: false
|
|
64
|
+
control_plane_flow_ref: ${{ job.workflow_ref }}
|
|
61
65
|
|
|
62
66
|
- name: Remove stale review apps
|
|
67
|
+
working-directory: app
|
|
63
68
|
env:
|
|
64
|
-
REVIEW_APP_PREFIX: ${{
|
|
65
|
-
|
|
69
|
+
REVIEW_APP_PREFIX: ${{ steps.review-config.outputs.review_app_prefix }}
|
|
70
|
+
CPLN_ORG: ${{ steps.review-config.outputs.cpln_org }}
|
|
66
71
|
shell: bash
|
|
67
72
|
run: |
|
|
68
73
|
set -euo pipefail
|
|
69
|
-
cpflow cleanup-stale-apps -a "${REVIEW_APP_PREFIX}" --org "${
|
|
74
|
+
cpflow cleanup-stale-apps -a "${REVIEW_APP_PREFIX}" --org "${CPLN_ORG}" --yes
|
|
@@ -2,12 +2,10 @@ name: Delete Review App
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
workflow_call:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
description:
|
|
8
|
-
required:
|
|
9
|
-
type: string
|
|
10
|
-
default: main
|
|
5
|
+
secrets:
|
|
6
|
+
CPLN_TOKEN_STAGING:
|
|
7
|
+
description: Control Plane token for the staging org that owns review apps.
|
|
8
|
+
required: true
|
|
11
9
|
|
|
12
10
|
permissions:
|
|
13
11
|
contents: read
|
|
@@ -21,8 +19,6 @@ concurrency:
|
|
|
21
19
|
cancel-in-progress: false
|
|
22
20
|
|
|
23
21
|
env:
|
|
24
|
-
APP_NAME: ${{ vars.REVIEW_APP_PREFIX }}-${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
|
|
25
|
-
CPLN_ORG: ${{ vars.CPLN_ORG_STAGING }}
|
|
26
22
|
PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number || github.event.inputs.pr_number }}
|
|
27
23
|
|
|
28
24
|
jobs:
|
|
@@ -62,8 +58,8 @@ jobs:
|
|
|
62
58
|
- name: Checkout control-plane-flow actions
|
|
63
59
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
|
|
64
60
|
with:
|
|
65
|
-
repository:
|
|
66
|
-
ref: ${{
|
|
61
|
+
repository: ${{ job.workflow_repository }}
|
|
62
|
+
ref: ${{ job.workflow_sha }}
|
|
67
63
|
path: .cpflow
|
|
68
64
|
persist-credentials: false
|
|
69
65
|
|
|
@@ -72,13 +68,9 @@ jobs:
|
|
|
72
68
|
uses: ./.cpflow/.github/actions/cpflow-validate-config
|
|
73
69
|
env:
|
|
74
70
|
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
75
|
-
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
|
|
76
|
-
REVIEW_APP_PREFIX: ${{ vars.REVIEW_APP_PREFIX }}
|
|
77
71
|
with:
|
|
78
72
|
required: |
|
|
79
73
|
secret:CPLN_TOKEN_STAGING
|
|
80
|
-
variable:CPLN_ORG_STAGING
|
|
81
|
-
variable:REVIEW_APP_PREFIX
|
|
82
74
|
pull_request_friendly: "true"
|
|
83
75
|
|
|
84
76
|
- name: Checkout repository
|
|
@@ -88,15 +80,26 @@ jobs:
|
|
|
88
80
|
path: app
|
|
89
81
|
persist-credentials: false
|
|
90
82
|
|
|
83
|
+
- name: Resolve review app config
|
|
84
|
+
if: steps.config.outputs.ready == 'true'
|
|
85
|
+
id: review-config
|
|
86
|
+
uses: ./.cpflow/.github/actions/cpflow-resolve-review-config
|
|
87
|
+
with:
|
|
88
|
+
working_directory: app
|
|
89
|
+
configured_cpln_org_staging: ${{ vars.CPLN_ORG_STAGING }}
|
|
90
|
+
configured_review_app_prefix: ${{ vars.REVIEW_APP_PREFIX }}
|
|
91
|
+
pr_number: ${{ env.PR_NUMBER }}
|
|
92
|
+
|
|
91
93
|
- name: Setup environment
|
|
92
94
|
if: steps.config.outputs.ready == 'true'
|
|
93
95
|
uses: ./.cpflow/.github/actions/cpflow-setup-environment
|
|
94
96
|
with:
|
|
95
97
|
token: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
96
|
-
org: ${{
|
|
98
|
+
org: ${{ steps.review-config.outputs.cpln_org }}
|
|
97
99
|
working_directory: app
|
|
98
100
|
cpln_cli_version: ${{ vars.CPLN_CLI_VERSION }}
|
|
99
101
|
cpflow_version: ${{ vars.CPFLOW_VERSION }}
|
|
102
|
+
control_plane_flow_ref: ${{ job.workflow_ref }}
|
|
100
103
|
|
|
101
104
|
- name: Set workflow links
|
|
102
105
|
if: steps.config.outputs.ready == 'true'
|
|
@@ -134,9 +137,9 @@ jobs:
|
|
|
134
137
|
if: steps.config.outputs.ready == 'true'
|
|
135
138
|
uses: ./.cpflow/.github/actions/cpflow-delete-control-plane-app
|
|
136
139
|
with:
|
|
137
|
-
app_name: ${{
|
|
138
|
-
cpln_org: ${{
|
|
139
|
-
review_app_prefix: ${{
|
|
140
|
+
app_name: ${{ steps.review-config.outputs.app_name }}
|
|
141
|
+
cpln_org: ${{ steps.review-config.outputs.cpln_org }}
|
|
142
|
+
review_app_prefix: ${{ steps.review-config.outputs.review_app_prefix }}
|
|
140
143
|
working_directory: app
|
|
141
144
|
|
|
142
145
|
# Finalizer still runs after delete failures, but only after config validation
|