cpflow 5.0.4 → 5.1.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/.github/actions/cpflow-wait-for-health/action.yml +11 -4
- data/.github/workflows/cpflow-promote-staging-to-production.yml +269 -43
- data/.github/workflows/rspec-shared.yml +8 -1
- data/CHANGELOG.md +28 -1
- data/Gemfile.lock +1 -1
- data/README.md +36 -11
- data/docs/ai-github-flow-prompt.md +1 -1
- data/docs/assets/logo/favicon.ico +0 -0
- data/docs/assets/logo/icon-1024.png +0 -0
- data/docs/assets/logo/icon-128.png +0 -0
- data/docs/assets/logo/icon-16.png +0 -0
- data/docs/assets/logo/icon-192.png +0 -0
- data/docs/assets/logo/icon-24.png +0 -0
- data/docs/assets/logo/icon-32.png +0 -0
- data/docs/assets/logo/icon-48.png +0 -0
- data/docs/assets/logo/icon-512.png +0 -0
- data/docs/assets/logo/icon-64.png +0 -0
- data/docs/assets/logo/icon-tile.svg +17 -0
- data/docs/assets/logo/mark-transparent.svg +16 -0
- data/docs/ci-automation.md +137 -47
- data/docs/commands.md +13 -3
- data/docs/postgres.md +6 -0
- data/docs/rds-private-networking.md +649 -0
- data/docs/secrets-and-env-values.md +49 -0
- data/docs/tips.md +256 -10
- data/examples/controlplane.yml +8 -0
- data/lib/command/ai_github_flow_prompt.rb +1 -1
- data/lib/command/apply_template.rb +3 -0
- data/lib/command/base.rb +69 -0
- data/lib/command/cleanup_stale_apps.rb +1 -1
- data/lib/command/delete.rb +85 -10
- data/lib/command/deploy_image.rb +30 -8
- data/lib/command/generate_github_actions.rb +6 -0
- data/lib/command/maintenance_off.rb +1 -0
- data/lib/command/maintenance_on.rb +1 -0
- data/lib/command/run.rb +25 -5
- data/lib/command/setup_app.rb +11 -2
- data/lib/core/config.rb +81 -0
- data/lib/core/controlplane.rb +15 -5
- data/lib/core/maintenance_mode.rb +93 -6
- data/lib/core/template_parser.rb +4 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/generator_templates/controlplane.yml +7 -0
- data/lib/generator_templates_sqlite/controlplane.yml +7 -0
- data/lib/github_flow_templates/.github/cpflow-help.md +48 -13
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +768 -15
- data/lib/github_flow_templates/bin/pin-cpflow-github-ref +17 -3
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +61 -9
- metadata +15 -2
|
@@ -8,15 +8,25 @@ USAGE = <<~USAGE
|
|
|
8
8
|
|
|
9
9
|
Use a release tag for normal operation, e.g. v5.0.0.
|
|
10
10
|
Use a full 40-character commit SHA for temporary unreleased upstream testing.
|
|
11
|
-
This
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
This updates generated reusable-workflow `uses:` refs plus the production
|
|
12
|
+
workflow's pinned control-plane-flow checkout and setup validation ref.
|
|
13
|
+
Regenerate from the cpflow gem when templates changed.
|
|
14
14
|
Use --allow-moving-ref only for short-lived local branch/ref experiments.
|
|
15
15
|
USAGE
|
|
16
16
|
|
|
17
17
|
ALLOWED_OPTIONS = ["--allow-moving-ref"].freeze
|
|
18
18
|
FULL_COMMIT_SHA = /\A[0-9a-f]{40}\z/i
|
|
19
19
|
RELEASE_TAG = /\Av\d+\.\d+\.\d+(?:[-.][0-9A-Za-z][0-9A-Za-z.-]*)?\z/
|
|
20
|
+
PRODUCTION_WORKFLOW_REF = "shakacode/control-plane-flow/.github/workflows/" \
|
|
21
|
+
"cpflow-promote-staging-to-production.yml"
|
|
22
|
+
CPFLOW_CHECKOUT_REF_PATTERN = %r{
|
|
23
|
+
(^\s*-\s+name:\s+Checkout\ control-plane-flow\ actions\s*\n
|
|
24
|
+
(?:(?!^\s*-\s+name:).)*?
|
|
25
|
+
^\s+repository:\s+shakacode/control-plane-flow\s*\n
|
|
26
|
+
(?:(?!^\s*-\s+name:).)*?
|
|
27
|
+
^\s+ref:\s+)
|
|
28
|
+
[^\s]+
|
|
29
|
+
}mx
|
|
20
30
|
|
|
21
31
|
options, positional = ARGV.partition { |arg| arg.start_with?("--") }
|
|
22
32
|
unknown_options = options - ALLOWED_OPTIONS
|
|
@@ -57,8 +67,12 @@ end
|
|
|
57
67
|
changed = []
|
|
58
68
|
workflow_paths.each do |path|
|
|
59
69
|
text = File.read(path)
|
|
70
|
+
production_setup_ref_pattern =
|
|
71
|
+
/(control_plane_flow_ref:\s+#{Regexp.escape(PRODUCTION_WORKFLOW_REF)}@)[^\s]+/
|
|
60
72
|
updated = text
|
|
61
73
|
.gsub(%r{(uses:\s+shakacode/control-plane-flow/\.github/workflows/[^@\s]+@)[^\s]+}, "\\1#{ref}")
|
|
74
|
+
.gsub(production_setup_ref_pattern, "\\1#{ref}")
|
|
75
|
+
.gsub(CPFLOW_CHECKOUT_REF_PATTERN, "\\1#{ref}")
|
|
62
76
|
|
|
63
77
|
next if updated == text
|
|
64
78
|
|
|
@@ -43,7 +43,10 @@ ruby <<'RUBY'
|
|
|
43
43
|
require "yaml"
|
|
44
44
|
|
|
45
45
|
CONTROL_PLANE_FLOW_WORKFLOW = %r{\Ashakacode/control-plane-flow/\.github/workflows/[^@\s]+@([^\s]+)\z}
|
|
46
|
-
PROMOTE_WORKFLOW = %r{\Ashakacode/control-plane-flow/\.github/workflows/cpflow-promote-staging-to-production\.yml@[^\s]
|
|
46
|
+
PROMOTE_WORKFLOW = %r{\Ashakacode/control-plane-flow/\.github/workflows/cpflow-promote-staging-to-production\.yml@([^\s]+)\z}
|
|
47
|
+
EXPECTED_PROMOTE_WORKFLOW_REF_FORMAT = "shakacode/control-plane-flow/.github/workflows/cpflow-promote-staging-to-production.yml@vX.Y.Z"
|
|
48
|
+
EXPECTED_CPFLOW_CHECKOUT_ACTION = "actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd"
|
|
49
|
+
EXPECTED_CPFLOW_CHECKOUT_REPOSITORY = "shakacode/control-plane-flow"
|
|
47
50
|
|
|
48
51
|
refs = Hash.new { |hash, key| hash[key] = [] }
|
|
49
52
|
|
|
@@ -72,19 +75,68 @@ Dir[".github/workflows/cpflow-*.yml"].sort.each do |path|
|
|
|
72
75
|
refs[uses_ref] << "#{path}:#{job_name}"
|
|
73
76
|
|
|
74
77
|
if job["uses"].to_s.match?(PROMOTE_WORKFLOW)
|
|
75
|
-
|
|
76
|
-
abort "#{path}:#{job_name} must set production_environment so GitHub can expose production environment secrets after approval"
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
secrets = job["secrets"].is_a?(Hash) ? job["secrets"] : {}
|
|
80
|
-
if secrets.key?("CPLN_TOKEN_PRODUCTION")
|
|
81
|
-
abort "#{path}:#{job_name} must not pass CPLN_TOKEN_PRODUCTION as a caller secret; store it on the protected production environment"
|
|
82
|
-
end
|
|
78
|
+
abort "#{path}:#{job_name} must not call the cross-repo production reusable workflow; use a normal caller-repo job with environment: production"
|
|
83
79
|
end
|
|
84
80
|
|
|
85
81
|
end
|
|
86
82
|
end
|
|
87
83
|
|
|
84
|
+
promote_path = ".github/workflows/cpflow-promote-staging-to-production.yml"
|
|
85
|
+
promote_doc = YAML.load_file(promote_path, aliases: true)
|
|
86
|
+
promote_job = promote_doc.fetch("jobs", {})["promote-to-production"]
|
|
87
|
+
|
|
88
|
+
unless promote_job
|
|
89
|
+
abort "#{promote_path}:promote-to-production job is missing"
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if promote_job.key?("uses")
|
|
93
|
+
abort "#{promote_path}:promote-to-production must run as a normal caller-repo job, not a reusable workflow, so GitHub can expose production environment secrets"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
unless promote_job["environment"].to_s == "production"
|
|
97
|
+
abort "#{promote_path}:promote-to-production must declare environment: production"
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
checkout_step = Array(promote_job["steps"]).find { |step| step["name"] == "Checkout control-plane-flow actions" }
|
|
101
|
+
|
|
102
|
+
unless checkout_step
|
|
103
|
+
abort "#{promote_path}:promote-to-production must include a Checkout control-plane-flow actions step"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
unless checkout_step["uses"] == EXPECTED_CPFLOW_CHECKOUT_ACTION
|
|
107
|
+
abort "#{promote_path}:promote-to-production must use #{EXPECTED_CPFLOW_CHECKOUT_ACTION} for the Checkout control-plane-flow actions step"
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
checkout_with = checkout_step.fetch("with", {})
|
|
111
|
+
checkout_repository = checkout_with["repository"]
|
|
112
|
+
checkout_ref = checkout_with["ref"]
|
|
113
|
+
|
|
114
|
+
unless checkout_repository == EXPECTED_CPFLOW_CHECKOUT_REPOSITORY
|
|
115
|
+
abort "#{promote_path}:promote-to-production must check out #{EXPECTED_CPFLOW_CHECKOUT_REPOSITORY}"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
if checkout_ref.to_s.strip.empty?
|
|
119
|
+
abort "#{promote_path}:promote-to-production must pin the Checkout control-plane-flow actions step"
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
refs[checkout_ref] << "#{promote_path}:promote-to-production"
|
|
123
|
+
|
|
124
|
+
setup_step = Array(promote_job["steps"]).find { |step| step["name"] == "Setup production environment" }
|
|
125
|
+
|
|
126
|
+
unless setup_step
|
|
127
|
+
abort "#{promote_path}:promote-to-production must include a Setup production environment step"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
setup_ref = setup_step.fetch("with", {})["control_plane_flow_ref"]
|
|
131
|
+
setup_match = setup_ref.to_s.match(PROMOTE_WORKFLOW)
|
|
132
|
+
|
|
133
|
+
unless setup_match
|
|
134
|
+
abort "#{promote_path}:promote-to-production must pass a pinned production control_plane_flow_ref to setup, " \
|
|
135
|
+
"for example #{EXPECTED_PROMOTE_WORKFLOW_REF_FORMAT}"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
refs[setup_match[1]] << "#{promote_path}:promote-to-production setup"
|
|
139
|
+
|
|
88
140
|
if refs.empty?
|
|
89
141
|
puts "no upstream cpflow reusable workflow refs found"
|
|
90
142
|
elsif refs.length > 1
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cpflow
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.
|
|
4
|
+
version: 5.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Justin Gordon
|
|
@@ -120,6 +120,18 @@ files:
|
|
|
120
120
|
- docs/ai-github-flow-prompt.md
|
|
121
121
|
- docs/assets/cpflow-deploying.svg
|
|
122
122
|
- docs/assets/grafana-alert.png
|
|
123
|
+
- docs/assets/logo/favicon.ico
|
|
124
|
+
- docs/assets/logo/icon-1024.png
|
|
125
|
+
- docs/assets/logo/icon-128.png
|
|
126
|
+
- docs/assets/logo/icon-16.png
|
|
127
|
+
- docs/assets/logo/icon-192.png
|
|
128
|
+
- docs/assets/logo/icon-24.png
|
|
129
|
+
- docs/assets/logo/icon-32.png
|
|
130
|
+
- docs/assets/logo/icon-48.png
|
|
131
|
+
- docs/assets/logo/icon-512.png
|
|
132
|
+
- docs/assets/logo/icon-64.png
|
|
133
|
+
- docs/assets/logo/icon-tile.svg
|
|
134
|
+
- docs/assets/logo/mark-transparent.svg
|
|
123
135
|
- docs/assets/memcached.png
|
|
124
136
|
- docs/assets/sidekiq-pre-stop-hook.png
|
|
125
137
|
- docs/ci-automation.md
|
|
@@ -127,6 +139,7 @@ files:
|
|
|
127
139
|
- docs/dns.md
|
|
128
140
|
- docs/migrating-heroku-to-control-plane.md
|
|
129
141
|
- docs/postgres.md
|
|
142
|
+
- docs/rds-private-networking.md
|
|
130
143
|
- docs/redis.md
|
|
131
144
|
- docs/releasing.md
|
|
132
145
|
- docs/secrets-and-env-values.md
|
|
@@ -271,7 +284,7 @@ licenses:
|
|
|
271
284
|
metadata:
|
|
272
285
|
rubygems_mfa_required: 'true'
|
|
273
286
|
post_install_message: |
|
|
274
|
-
cpflow 5.
|
|
287
|
+
cpflow 5.1.1 installed.
|
|
275
288
|
|
|
276
289
|
If this repository already uses generated cpflow GitHub Actions, update the
|
|
277
290
|
checked-in wrappers so GitHub loads the matching control-plane-flow release tag:
|