cpflow 5.0.0.rc.1 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/{lib/github_flow_templates/.github → .github}/actions/cpflow-delete-control-plane-app/action.yml +5 -0
  3. data/{lib/github_flow_templates/.github → .github}/actions/cpflow-detect-release-phase/action.yml +7 -0
  4. data/.github/actions/cpflow-setup-environment/action.yml +161 -0
  5. data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +69 -0
  6. data/.github/workflows/cpflow-delete-review-app.yml +182 -0
  7. data/.github/workflows/cpflow-deploy-review-app.yml +507 -0
  8. data/.github/workflows/cpflow-deploy-staging.yml +168 -0
  9. data/.github/workflows/cpflow-help-command.yml +78 -0
  10. data/.github/workflows/cpflow-promote-staging-to-production.yml +510 -0
  11. data/.github/workflows/cpflow-review-app-help.yml +51 -0
  12. data/.github/workflows/rspec-shared.yml +3 -0
  13. data/.github/workflows/trigger-docs-site.yml +90 -0
  14. data/.rubocop.yml +14 -1
  15. data/CHANGELOG.md +43 -1
  16. data/CONTRIBUTING.md +27 -0
  17. data/Gemfile.lock +2 -2
  18. data/README.md +7 -3
  19. data/cpflow.gemspec +1 -1
  20. data/docs/ai-github-flow-prompt.md +1 -1
  21. data/docs/assets/cpflow-deploying.svg +46 -0
  22. data/docs/ci-automation.md +111 -8
  23. data/docs/commands.md +11 -5
  24. data/docs/thruster.md +149 -0
  25. data/docs/troubleshooting.md +8 -0
  26. data/lib/command/apply_template.rb +6 -2
  27. data/lib/command/base.rb +1 -0
  28. data/lib/command/cleanup_stale_apps.rb +53 -14
  29. data/lib/command/delete.rb +3 -1
  30. data/lib/command/deploy_image.rb +5 -2
  31. data/lib/command/generate.rb +7 -3
  32. data/lib/command/generate_github_actions.rb +21 -9
  33. data/lib/command/generator_helpers.rb +5 -1
  34. data/lib/command/info.rb +3 -1
  35. data/lib/command/run.rb +16 -1
  36. data/lib/command/test.rb +1 -3
  37. data/lib/core/controlplane.rb +17 -6
  38. data/lib/core/controlplane_api.rb +3 -1
  39. data/lib/core/controlplane_api_direct.rb +50 -27
  40. data/lib/core/doctor_service.rb +2 -2
  41. data/lib/core/github_flow_readiness_service.rb +26 -2
  42. data/lib/core/repo_introspection.rb +41 -3
  43. data/lib/core/shell.rb +3 -1
  44. data/lib/core/terraform_config/policy.rb +1 -1
  45. data/lib/cpflow/version.rb +1 -1
  46. data/lib/cpflow.rb +27 -13
  47. data/lib/generator_templates/templates/rails.yml +4 -0
  48. data/lib/generator_templates_sqlite/templates/rails.yml +4 -0
  49. data/lib/github_flow_templates/.github/cpflow-help.md +30 -1
  50. data/lib/github_flow_templates/.github/workflows/cpflow-cleanup-stale-review-apps.yml +10 -44
  51. data/lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml +15 -114
  52. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml +10 -413
  53. data/lib/github_flow_templates/.github/workflows/cpflow-deploy-staging.yml +12 -123
  54. data/lib/github_flow_templates/.github/workflows/cpflow-help-command.yml +10 -33
  55. data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +13 -475
  56. data/lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml +12 -30
  57. data/lib/github_flow_templates/bin/pin-cpflow-github-ref +72 -0
  58. data/lib/github_flow_templates/bin/test-cpflow-github-flow +89 -0
  59. data/rakelib/create_release.rake +4 -4
  60. metadata +26 -17
  61. data/lib/github_flow_templates/.github/actions/cpflow-setup-environment/action.yml +0 -98
  62. /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-build-docker-image/action.yml +0 -0
  63. /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-delete-control-plane-app/delete-app.sh +0 -0
  64. /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-validate-config/action.yml +0 -0
  65. /data/{lib/github_flow_templates/.github → .github}/actions/cpflow-wait-for-health/action.yml +0 -0
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ cd "$ROOT"
6
+
7
+ cpflow_cmd=(cpflow)
8
+ if [[ $# -gt 0 ]]; then
9
+ cpflow_cmd=("$@")
10
+ fi
11
+
12
+ echo "==> cpflow github-flow-readiness"
13
+ "${cpflow_cmd[@]}" github-flow-readiness
14
+
15
+ echo "==> parse generated GitHub Actions YAML"
16
+ ruby <<'RUBY'
17
+ require "yaml"
18
+
19
+ Dir[".github/actions/**/action.yml", ".github/workflows/*.yml"].sort.each do |path|
20
+ YAML.load_file(path, aliases: true)
21
+ puts "parsed #{path}"
22
+ end
23
+ RUBY
24
+
25
+ echo "==> check composite action input descriptions"
26
+ ruby <<'RUBY'
27
+ require "yaml"
28
+
29
+ bad = []
30
+ Dir[".github/actions/**/action.yml"].sort.each do |path|
31
+ doc = YAML.load_file(path, aliases: true)
32
+ doc.fetch("inputs", {}).each do |name, spec|
33
+ bad << "#{path}:#{name}" if spec["description"].to_s.include?("${{")
34
+ end
35
+ end
36
+
37
+ abort bad.join("\n") unless bad.empty?
38
+ puts "no action metadata descriptions contain GitHub expressions"
39
+ RUBY
40
+
41
+ echo "==> check cpflow reusable workflow refs"
42
+ ruby <<'RUBY'
43
+ require "yaml"
44
+
45
+ CONTROL_PLANE_FLOW_WORKFLOW = %r{\Ashakacode/control-plane-flow/\.github/workflows/[^@\s]+@([^\s]+)\z}
46
+
47
+ refs = Hash.new { |hash, key| hash[key] = [] }
48
+
49
+ Dir[".github/workflows/cpflow-*.yml"].sort.each do |path|
50
+ doc = YAML.load_file(path, aliases: true)
51
+ doc.fetch("jobs", {}).each do |job_name, job|
52
+ next unless job.is_a?(Hash)
53
+
54
+ with = job["with"].is_a?(Hash) ? job["with"] : {}
55
+ input_ref = with["control_plane_flow_ref"]
56
+ uses_match = job["uses"].to_s.match(CONTROL_PLANE_FLOW_WORKFLOW)
57
+
58
+ unless uses_match
59
+ abort "#{path}:#{job_name} has control_plane_flow_ref but no control-plane-flow reusable workflow" if input_ref
60
+
61
+ next
62
+ end
63
+
64
+ uses_ref = uses_match[1]
65
+ refs[uses_ref] << "#{path}:#{job_name}"
66
+
67
+ if input_ref
68
+ refs[input_ref] << "#{path}:#{job_name}"
69
+ abort "#{path}:#{job_name} mismatched cpflow refs: #{uses_ref}, #{input_ref}" if uses_ref != input_ref
70
+ elsif job.key?("secrets")
71
+ abort "#{path}:#{job_name} inherits secrets but is missing control_plane_flow_ref for #{uses_ref}"
72
+ end
73
+ end
74
+ end
75
+
76
+ if refs.empty?
77
+ puts "no upstream cpflow reusable workflow refs found"
78
+ elsif refs.length > 1
79
+ refs.each do |ref, paths|
80
+ puts "#{ref}: #{paths.uniq.sort.join(', ')}"
81
+ end
82
+ abort "cpflow workflow wrappers use multiple upstream refs: #{refs.keys.sort.join(', ')}"
83
+ else
84
+ puts "cpflow refs: #{refs.keys.sort.join(', ')}"
85
+ end
86
+ RUBY
87
+
88
+ echo "==> actionlint"
89
+ actionlint -ignore "SC2129" .github/workflows/cpflow-*.yml
@@ -45,7 +45,7 @@ desc("Releases the cpflow Ruby gem.
45
45
  task :release, %i[version dry_run override_version_policy] do |_t, args|
46
46
  args_hash = args.to_hash
47
47
  gem_root = Release.gem_root
48
- is_dry_run = Release.object_to_boolean(args_hash[:dry_run])
48
+ is_dry_run = Release.affirmative?(args_hash[:dry_run])
49
49
  allow_version_policy_override = Release.version_policy_override_enabled?(args_hash[:override_version_policy])
50
50
  rubygems_otp = ENV.fetch("RUBYGEMS_OTP", nil)
51
51
  current_branch = Release.current_git_branch(gem_root)
@@ -121,7 +121,7 @@ desc("Creates or updates the GitHub release notes from CHANGELOG.md.
121
121
  task :sync_github_release, %i[gem_version dry_run] do |_t, args|
122
122
  args_hash = args.to_hash
123
123
  gem_root = Release.gem_root
124
- is_dry_run = Release.object_to_boolean(args_hash[:dry_run])
124
+ is_dry_run = Release.affirmative?(args_hash[:dry_run])
125
125
  requested_gem_version = args_hash[:gem_version].to_s.strip
126
126
 
127
127
  if requested_gem_version.empty?
@@ -155,12 +155,12 @@ module Release
155
155
  File.expand_path("..", __dir__)
156
156
  end
157
157
 
158
- def object_to_boolean(value)
158
+ def affirmative?(value)
159
159
  [true, "true", "yes", 1, "1", "t"].include?(value.instance_of?(String) ? value.downcase : value)
160
160
  end
161
161
 
162
162
  def version_policy_override_enabled?(override_flag)
163
- object_to_boolean(override_flag) || object_to_boolean(ENV.fetch("RELEASE_VERSION_POLICY_OVERRIDE", nil))
163
+ affirmative?(override_flag) || affirmative?(ENV.fetch("RELEASE_VERSION_POLICY_OVERRIDE", nil))
164
164
  end
165
165
 
166
166
  def semver_keyword?(value)
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cpflow
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.0.0.rc.1
4
+ version: 5.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Justin Gordon
8
8
  - Sergey Tarasov
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2026-05-12 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: dotenv
@@ -59,14 +58,14 @@ dependencies:
59
58
  requirements:
60
59
  - - "~>"
61
60
  - !ruby/object:Gem::Version
62
- version: '1.4'
61
+ version: '1.3'
63
62
  type: :runtime
64
63
  prerelease: false
65
64
  version_requirements: !ruby/object:Gem::Requirement
66
65
  requirements:
67
66
  - - "~>"
68
67
  - !ruby/object:Gem::Version
69
- version: '1.4'
68
+ version: '1.3'
70
69
  description: CLI for providing Heroku-like platform-as-a-service on Control Plane
71
70
  email:
72
71
  - justin@shakacode.com
@@ -79,14 +78,29 @@ files:
79
78
  - ".agents/workflows/address-review.md"
80
79
  - ".claude/commands/address-review.md"
81
80
  - ".claude/commands/update-changelog.md"
81
+ - ".github/actions/cpflow-build-docker-image/action.yml"
82
+ - ".github/actions/cpflow-delete-control-plane-app/action.yml"
83
+ - ".github/actions/cpflow-delete-control-plane-app/delete-app.sh"
84
+ - ".github/actions/cpflow-detect-release-phase/action.yml"
85
+ - ".github/actions/cpflow-setup-environment/action.yml"
86
+ - ".github/actions/cpflow-validate-config/action.yml"
87
+ - ".github/actions/cpflow-wait-for-health/action.yml"
82
88
  - ".github/workflows/check_cpln_links.yml"
83
89
  - ".github/workflows/claude-code-review.yml"
84
90
  - ".github/workflows/claude.yml"
85
91
  - ".github/workflows/command_docs.yml"
92
+ - ".github/workflows/cpflow-cleanup-stale-review-apps.yml"
93
+ - ".github/workflows/cpflow-delete-review-app.yml"
94
+ - ".github/workflows/cpflow-deploy-review-app.yml"
95
+ - ".github/workflows/cpflow-deploy-staging.yml"
96
+ - ".github/workflows/cpflow-help-command.yml"
97
+ - ".github/workflows/cpflow-promote-staging-to-production.yml"
98
+ - ".github/workflows/cpflow-review-app-help.yml"
86
99
  - ".github/workflows/rspec-shared.yml"
87
100
  - ".github/workflows/rspec-specific.yml"
88
101
  - ".github/workflows/rspec.yml"
89
102
  - ".github/workflows/rubocop.yml"
103
+ - ".github/workflows/trigger-docs-site.yml"
90
104
  - ".gitignore"
91
105
  - ".overcommit.yml"
92
106
  - ".rubocop.yml"
@@ -103,6 +117,7 @@ files:
103
117
  - cpflow
104
118
  - cpflow.gemspec
105
119
  - docs/ai-github-flow-prompt.md
120
+ - docs/assets/cpflow-deploying.svg
106
121
  - docs/assets/grafana-alert.png
107
122
  - docs/assets/memcached.png
108
123
  - docs/assets/sidekiq-pre-stop-hook.png
@@ -120,6 +135,7 @@ files:
120
135
  - docs/terraform/example/.controlplane/templates/postgres.yml
121
136
  - docs/terraform/example/.controlplane/templates/rails.yml
122
137
  - docs/terraform/overview.md
138
+ - docs/thruster.md
123
139
  - docs/tips.md
124
140
  - docs/troubleshooting.md
125
141
  - examples/circleci.yml
@@ -211,13 +227,6 @@ files:
211
227
  - lib/generator_templates_sqlite/templates/db.yml
212
228
  - lib/generator_templates_sqlite/templates/rails.yml
213
229
  - lib/generator_templates_sqlite/templates/storage.yml
214
- - lib/github_flow_templates/.github/actions/cpflow-build-docker-image/action.yml
215
- - lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/action.yml
216
- - lib/github_flow_templates/.github/actions/cpflow-delete-control-plane-app/delete-app.sh
217
- - lib/github_flow_templates/.github/actions/cpflow-detect-release-phase/action.yml
218
- - lib/github_flow_templates/.github/actions/cpflow-setup-environment/action.yml
219
- - lib/github_flow_templates/.github/actions/cpflow-validate-config/action.yml
220
- - lib/github_flow_templates/.github/actions/cpflow-wait-for-health/action.yml
221
230
  - lib/github_flow_templates/.github/cpflow-help.md
222
231
  - lib/github_flow_templates/.github/workflows/cpflow-cleanup-stale-review-apps.yml
223
232
  - lib/github_flow_templates/.github/workflows/cpflow-delete-review-app.yml
@@ -226,6 +235,8 @@ files:
226
235
  - lib/github_flow_templates/.github/workflows/cpflow-help-command.yml
227
236
  - lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml
228
237
  - lib/github_flow_templates/.github/workflows/cpflow-review-app-help.yml
238
+ - lib/github_flow_templates/bin/pin-cpflow-github-ref
239
+ - lib/github_flow_templates/bin/test-cpflow-github-flow
229
240
  - lib/patches/array.rb
230
241
  - lib/patches/hash.rb
231
242
  - lib/patches/string.rb
@@ -256,7 +267,6 @@ licenses:
256
267
  - MIT
257
268
  metadata:
258
269
  rubygems_mfa_required: 'true'
259
- post_install_message:
260
270
  rdoc_options: []
261
271
  require_paths:
262
272
  - lib
@@ -267,12 +277,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
267
277
  version: 3.0.0
268
278
  required_rubygems_version: !ruby/object:Gem::Requirement
269
279
  requirements:
270
- - - ">"
280
+ - - ">="
271
281
  - !ruby/object:Gem::Version
272
- version: 1.3.1
282
+ version: '0'
273
283
  requirements: []
274
- rubygems_version: 3.4.10
275
- signing_key:
284
+ rubygems_version: 4.0.8
276
285
  specification_version: 4
277
286
  summary: Control Plane Flow
278
287
  test_files: []
@@ -1,98 +0,0 @@
1
- name: Setup Control Plane Environment
2
- description: Sets up Ruby, installs the Control Plane CLI and cpflow gem, and configures a default profile
3
-
4
- inputs:
5
- token:
6
- description: Control Plane token
7
- required: true
8
- org:
9
- description: Control Plane organization
10
- required: true
11
- ruby_version:
12
- description: >-
13
- Ruby version used for cpflow. When empty (the default), ruby/setup-ruby auto-detects
14
- from .ruby-version, .tool-versions, or the Gemfile.
15
- required: false
16
- default: ""
17
- cpln_cli_version:
18
- description: >-
19
- @controlplane/cli version. Empty string falls back to the action's pinned default
20
- so callers can pass `${{ vars.CPLN_CLI_VERSION }}` unconditionally.
21
- required: false
22
- default: ""
23
- cpflow_version:
24
- description: >-
25
- cpflow gem version. Empty string falls back to the action's pinned default
26
- so callers can pass `${{ vars.CPFLOW_VERSION }}` unconditionally.
27
- required: false
28
- default: ""
29
-
30
- runs:
31
- using: composite
32
- # Third-party actions are pinned to floating major tags (`@v4`, `@v1`, `@v7`) rather than
33
- # immutable SHAs. SHA pinning is GitHub's stronger security recommendation, but for
34
- # generated templates that ship into many downstream repositories floating tags are
35
- # easier for users to keep current and Dependabot/Renovate already cover the SHA-pinning
36
- # workflow for repositories that opt in. Repositories with stricter supply-chain
37
- # requirements should replace each `uses: actions/...@vN` with the corresponding
38
- # immutable commit SHA.
39
- steps:
40
- - name: Set up Ruby
41
- uses: ruby/setup-ruby@v1
42
- with:
43
- ruby-version: ${{ inputs.ruby_version }}
44
-
45
- - name: Install Control Plane CLI and cpflow gem
46
- shell: bash
47
- env:
48
- CPLN_CLI_VERSION: ${{ inputs.cpln_cli_version }}
49
- CPFLOW_VERSION: ${{ inputs.cpflow_version }}
50
- run: |
51
- set -euo pipefail
52
-
53
- # Bump these defaults when a new release lands that you want to roll out by default.
54
- # Override per-repo by setting `CPLN_CLI_VERSION` / `CPFLOW_VERSION` repo variables;
55
- # an empty input falls back to the action's pinned default below.
56
- default_cpln_cli_version="3.3.1"
57
- default_cpflow_version="__CPFLOW_VERSION__"
58
-
59
- CPLN_CLI_VERSION="${CPLN_CLI_VERSION:-${default_cpln_cli_version}}"
60
- CPFLOW_VERSION="${CPFLOW_VERSION:-${default_cpflow_version}}"
61
-
62
- npm_global_prefix="${HOME}/.npm-global"
63
- mkdir -p "${npm_global_prefix}"
64
- echo "${npm_global_prefix}/bin" >> "$GITHUB_PATH"
65
- export PATH="${npm_global_prefix}/bin:${PATH}"
66
-
67
- npm install --global --prefix "${npm_global_prefix}" "@controlplane/cli@${CPLN_CLI_VERSION}"
68
- cpln --version
69
-
70
- gem install cpflow -v "${CPFLOW_VERSION}" --no-document
71
- cpflow --version
72
-
73
- - name: Setup Control Plane profile and registry login
74
- shell: bash
75
- env:
76
- # Pass the token via CPLN_TOKEN so cpln picks it up from the environment
77
- # rather than `--token`, which would leak it into /proc/<pid>/cmdline and ps output.
78
- CPLN_TOKEN: ${{ inputs.token }}
79
- ORG: ${{ inputs.org }}
80
- run: |
81
- set -euo pipefail
82
-
83
- if [[ -z "$CPLN_TOKEN" ]]; then
84
- echo "Error: Control Plane token not provided" >&2
85
- exit 1
86
- fi
87
-
88
- if [[ -z "$ORG" ]]; then
89
- echo "Error: Control Plane organization not provided" >&2
90
- exit 1
91
- fi
92
-
93
- # `cpln profile update` lists `create` as an alias (cpln profile --help) and is
94
- # idempotent: it creates the profile if missing and updates it otherwise. Calling
95
- # update directly avoids parsing the CLI's "already exists" English error text,
96
- # which would silently swallow a real failure if the wording ever changed.
97
- cpln profile update default --org "$ORG"
98
- cpln image docker-login --org "$ORG"