cpflow 5.3.0 → 6.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.
- checksums.yaml +4 -4
- data/.agents/agent-workflow.yml +13 -0
- data/.agents/bin/README.md +12 -1
- data/.agents/bin/docs +1 -1
- data/.agents/bin/lint +1 -1
- data/.agents/bin/setup +1 -1
- data/.agents/bin/test +1 -1
- data/.agents/bin/validate +2 -1
- data/.coderabbit.yaml +13 -0
- data/.github/actions/cpflow-delete-control-plane-app/action.yml +2 -1
- data/.github/actions/cpflow-setup-environment/action.yml +8 -6
- data/.github/dependabot.yml +10 -0
- data/.github/workflows/check_cpln_links.yml +6 -1
- data/.github/workflows/claude-code-review.yml +5 -2
- data/.github/workflows/claude.yml +6 -4
- data/.github/workflows/coderabbit-lifecycle-review.yml +29 -0
- data/.github/workflows/command_docs.yml +7 -2
- data/.github/workflows/cpflow-cleanup-stale-review-apps.yml +12 -5
- data/.github/workflows/cpflow-delete-review-app.yml +18 -11
- data/.github/workflows/cpflow-deploy-review-app.yml +25 -16
- data/.github/workflows/cpflow-deploy-staging.yml +16 -10
- data/.github/workflows/cpflow-help-command.yml +3 -3
- data/.github/workflows/cpflow-promote-staging-to-production.yml +7 -7
- data/.github/workflows/cpflow-review-app-help.yml +1 -1
- data/.github/workflows/rspec-shared.yml +34 -26
- data/.github/workflows/rspec-specific.yml +10 -2
- data/.github/workflows/rspec.yml +71 -4
- data/.github/workflows/rubocop.yml +9 -2
- data/.github/workflows/trigger-docs-site.yml +2 -0
- data/.rubocop.yml +6 -1
- data/CHANGELOG.md +24 -1
- data/CONTRIBUTING.md +39 -2
- data/Gemfile.lock +1 -1
- data/README.md +6 -1
- data/cpflow.gemspec +3 -15
- data/docs/ai-github-flow-prompt.md +2 -2
- data/docs/ci-automation.md +112 -60
- data/docs/commands.md +18 -8
- data/docs/rds-private-networking.md +12 -12
- data/docs/releasing.md +15 -4
- data/examples/controlplane.yml +5 -0
- data/lib/command/ai_github_flow_prompt.rb +1 -1
- data/lib/command/cleanup_stale_apps.rb +28 -4
- data/lib/command/copy_image_from_upstream.rb +3 -0
- data/lib/command/deploy_image.rb +38 -1
- data/lib/command/generate_github_actions.rb +36 -12
- data/lib/command/run.rb +224 -34
- data/lib/command/update_github_actions.rb +7 -6
- data/lib/core/controlplane.rb +145 -78
- data/lib/core/shell.rb +35 -10
- data/lib/core/timed_command.rb +111 -0
- data/lib/cpflow/version.rb +1 -1
- data/lib/cpflow.rb +1 -1
- data/lib/github_flow_templates/.github/workflows/cpflow-promote-staging-to-production.yml +7 -7
- data/lib/github_flow_templates/bin/test-cpflow-github-flow +63 -3
- data/lib/patches/hash.rb +2 -2
- data/rakelib/create_release.rake +14 -14
- data/script/check_shell_scripts +66 -0
- metadata +11 -18
|
@@ -60,9 +60,15 @@ jobs:
|
|
|
60
60
|
echo "is_deployable=false" >> "$GITHUB_OUTPUT"
|
|
61
61
|
fi
|
|
62
62
|
|
|
63
|
+
- name: Checkout generated cpflow actions
|
|
64
|
+
if: steps.check-branch.outputs.is_deployable == 'true'
|
|
65
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
66
|
+
with:
|
|
67
|
+
persist-credentials: false
|
|
68
|
+
|
|
63
69
|
- name: Checkout control-plane-flow actions
|
|
64
70
|
if: steps.check-branch.outputs.is_deployable == 'true'
|
|
65
|
-
uses: actions/checkout@
|
|
71
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
66
72
|
with:
|
|
67
73
|
repository: ${{ job.workflow_repository }}
|
|
68
74
|
ref: ${{ job.workflow_sha }}
|
|
@@ -71,7 +77,7 @@ jobs:
|
|
|
71
77
|
|
|
72
78
|
- name: Validate required secrets and variables
|
|
73
79
|
if: steps.check-branch.outputs.is_deployable == 'true'
|
|
74
|
-
uses: ./.
|
|
80
|
+
uses: ./.github/actions/cpflow-validate-config
|
|
75
81
|
env:
|
|
76
82
|
CPLN_TOKEN_STAGING: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
77
83
|
CPLN_ORG_STAGING: ${{ vars.CPLN_ORG_STAGING }}
|
|
@@ -89,12 +95,12 @@ jobs:
|
|
|
89
95
|
timeout-minutes: 30
|
|
90
96
|
steps:
|
|
91
97
|
- name: Checkout repository
|
|
92
|
-
uses: actions/checkout@
|
|
98
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
93
99
|
with:
|
|
94
100
|
persist-credentials: false
|
|
95
101
|
|
|
96
102
|
- name: Checkout control-plane-flow actions
|
|
97
|
-
uses: actions/checkout@
|
|
103
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
98
104
|
with:
|
|
99
105
|
repository: ${{ job.workflow_repository }}
|
|
100
106
|
ref: ${{ job.workflow_sha }}
|
|
@@ -102,7 +108,7 @@ jobs:
|
|
|
102
108
|
persist-credentials: false
|
|
103
109
|
|
|
104
110
|
- name: Setup environment
|
|
105
|
-
uses: ./.
|
|
111
|
+
uses: ./.github/actions/cpflow-setup-environment
|
|
106
112
|
with:
|
|
107
113
|
token: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
108
114
|
org: ${{ vars.CPLN_ORG_STAGING }}
|
|
@@ -112,7 +118,7 @@ jobs:
|
|
|
112
118
|
control_plane_flow_ref: ${{ job.workflow_ref }}
|
|
113
119
|
|
|
114
120
|
- name: Build Docker image
|
|
115
|
-
uses: ./.
|
|
121
|
+
uses: ./.github/actions/cpflow-build-docker-image
|
|
116
122
|
with:
|
|
117
123
|
app_name: ${{ env.APP_NAME }}
|
|
118
124
|
org: ${{ vars.CPLN_ORG_STAGING }}
|
|
@@ -128,12 +134,12 @@ jobs:
|
|
|
128
134
|
timeout-minutes: 30
|
|
129
135
|
steps:
|
|
130
136
|
- name: Checkout repository
|
|
131
|
-
uses: actions/checkout@
|
|
137
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
132
138
|
with:
|
|
133
139
|
persist-credentials: false
|
|
134
140
|
|
|
135
141
|
- name: Checkout control-plane-flow actions
|
|
136
|
-
uses: actions/checkout@
|
|
142
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
137
143
|
with:
|
|
138
144
|
repository: ${{ job.workflow_repository }}
|
|
139
145
|
ref: ${{ job.workflow_sha }}
|
|
@@ -141,7 +147,7 @@ jobs:
|
|
|
141
147
|
persist-credentials: false
|
|
142
148
|
|
|
143
149
|
- name: Setup environment
|
|
144
|
-
uses: ./.
|
|
150
|
+
uses: ./.github/actions/cpflow-setup-environment
|
|
145
151
|
with:
|
|
146
152
|
token: ${{ secrets.CPLN_TOKEN_STAGING }}
|
|
147
153
|
org: ${{ vars.CPLN_ORG_STAGING }}
|
|
@@ -152,7 +158,7 @@ jobs:
|
|
|
152
158
|
|
|
153
159
|
- name: Detect release phase support
|
|
154
160
|
id: release-phase
|
|
155
|
-
uses: ./.
|
|
161
|
+
uses: ./.github/actions/cpflow-detect-release-phase
|
|
156
162
|
with:
|
|
157
163
|
app_name: ${{ env.APP_NAME }}
|
|
158
164
|
|
|
@@ -28,7 +28,7 @@ jobs:
|
|
|
28
28
|
- name: React to help command
|
|
29
29
|
if: github.event_name == 'issue_comment'
|
|
30
30
|
continue-on-error: true
|
|
31
|
-
uses: actions/github-script@
|
|
31
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
32
32
|
with:
|
|
33
33
|
script: |
|
|
34
34
|
try {
|
|
@@ -47,14 +47,14 @@ jobs:
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
- name: Checkout repository
|
|
50
|
-
uses: actions/checkout@
|
|
50
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
51
51
|
with:
|
|
52
52
|
# Help only reads `.github/cpflow-help.md`; no git push happens, so drop the
|
|
53
53
|
# GITHUB_TOKEN credential helper to keep the token out of .git/config.
|
|
54
54
|
persist-credentials: false
|
|
55
55
|
|
|
56
56
|
- name: Post help message
|
|
57
|
-
uses: actions/github-script@
|
|
57
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
58
58
|
with:
|
|
59
59
|
script: |
|
|
60
60
|
const fs = require("fs");
|
|
@@ -65,12 +65,12 @@ jobs:
|
|
|
65
65
|
|
|
66
66
|
steps:
|
|
67
67
|
- name: Checkout repository
|
|
68
|
-
uses: actions/checkout@
|
|
68
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
69
69
|
with:
|
|
70
70
|
persist-credentials: false
|
|
71
71
|
|
|
72
72
|
- name: Checkout control-plane-flow actions
|
|
73
|
-
uses: actions/checkout@
|
|
73
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
74
74
|
with:
|
|
75
75
|
repository: ${{ job.workflow_repository }}
|
|
76
76
|
ref: ${{ job.workflow_sha }}
|
|
@@ -91,7 +91,7 @@ jobs:
|
|
|
91
91
|
fi
|
|
92
92
|
|
|
93
93
|
- name: Validate required secrets and variables
|
|
94
|
-
uses: ./.
|
|
94
|
+
uses: ./.github/actions/cpflow-validate-config
|
|
95
95
|
# Pass secrets via env so the composite action checks indirect shell
|
|
96
96
|
# variables instead of interpolating secret values into a run script.
|
|
97
97
|
env:
|
|
@@ -158,7 +158,7 @@ jobs:
|
|
|
158
158
|
} >> "$GITHUB_OUTPUT"
|
|
159
159
|
|
|
160
160
|
- name: Setup production environment
|
|
161
|
-
uses: ./.
|
|
161
|
+
uses: ./.github/actions/cpflow-setup-environment
|
|
162
162
|
with:
|
|
163
163
|
token: ${{ secrets.CPLN_TOKEN_PRODUCTION }}
|
|
164
164
|
org: ${{ steps.cpln-orgs.outputs.production }}
|
|
@@ -220,7 +220,7 @@ jobs:
|
|
|
220
220
|
|
|
221
221
|
- name: Detect release phase support
|
|
222
222
|
id: release-phase
|
|
223
|
-
uses: ./.
|
|
223
|
+
uses: ./.github/actions/cpflow-detect-release-phase
|
|
224
224
|
with:
|
|
225
225
|
app_name: ${{ vars.PRODUCTION_APP_NAME }}
|
|
226
226
|
|
|
@@ -422,7 +422,7 @@ jobs:
|
|
|
422
422
|
echo "image=${staging_image}" >> "$GITHUB_OUTPUT"
|
|
423
423
|
|
|
424
424
|
- name: Set up Docker Buildx
|
|
425
|
-
uses: docker/setup-buildx-action@
|
|
425
|
+
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
|
|
426
426
|
|
|
427
427
|
- name: Copy image from staging
|
|
428
428
|
id: copy-image
|
|
@@ -570,7 +570,7 @@ jobs:
|
|
|
570
570
|
|
|
571
571
|
- name: Wait for deployment health
|
|
572
572
|
id: health-check
|
|
573
|
-
uses: ./.
|
|
573
|
+
uses: ./.github/actions/cpflow-wait-for-health
|
|
574
574
|
with:
|
|
575
575
|
workload_name: ${{ steps.workloads.outputs.primary }}
|
|
576
576
|
app_name: ${{ vars.PRODUCTION_APP_NAME }}
|
|
@@ -13,7 +13,7 @@ jobs:
|
|
|
13
13
|
timeout-minutes: 5
|
|
14
14
|
steps:
|
|
15
15
|
- name: Post quick reference
|
|
16
|
-
uses: actions/github-script@
|
|
16
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
17
17
|
with:
|
|
18
18
|
script: |
|
|
19
19
|
const body = [
|
|
@@ -15,38 +15,27 @@ on:
|
|
|
15
15
|
spec_paths:
|
|
16
16
|
required: false
|
|
17
17
|
type: string
|
|
18
|
-
|
|
18
|
+
secrets:
|
|
19
|
+
CPLN_TOKEN:
|
|
20
|
+
description: Control Plane token used by integration specs
|
|
19
21
|
required: false
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
22
25
|
|
|
23
26
|
jobs:
|
|
24
27
|
rspec:
|
|
25
28
|
runs-on: ${{ inputs.os_version }}
|
|
26
|
-
# Scope the live Control Plane org queue per PR (or ref) instead of globally:
|
|
27
|
-
# each run uses its own random app suffix (SecureRandom.hex(2)) on a fresh
|
|
28
|
-
# runner, so concurrent PRs don't collide on app names or CLI profiles. PRs
|
|
29
|
-
# run only the fast (~slow) suite, which doesn't switch the shared domain's
|
|
30
|
-
# route; domain-mutating specs are :slow and dispatched manually, keyed by
|
|
31
|
-
# github.ref so same-ref fast dispatches still serialize. Callers that may
|
|
32
|
-
# touch the shared domain use one ref-independent queue, covering scheduled,
|
|
33
|
-
# manual slow, and manual specific runs. Fall back to the repository rather
|
|
34
|
-
# than a unique run ID so missing CPLN_ORG cannot bypass serialization.
|
|
35
|
-
# cancel-in-progress is false, so queued runs wait rather than cancel.
|
|
36
|
-
concurrency:
|
|
37
|
-
group: cpln-shared-org-${{ vars.CPLN_ORG || github.repository }}-${{ inputs.uses_shared_org && 'shared-org' || github.event.pull_request.number || github.ref }}
|
|
38
|
-
cancel-in-progress: false
|
|
39
29
|
env:
|
|
40
30
|
RAILS_ENV: test
|
|
41
|
-
# We have to add "_CI" to the end, otherwise it messes with tests where we switch profiles,
|
|
42
|
-
# as Control Plane will try to use this token's profile instead.
|
|
43
|
-
CPLN_TOKEN_CI: ${{ secrets.CPLN_TOKEN }}
|
|
44
31
|
CPLN_ORG: ${{ vars.CPLN_ORG }}
|
|
45
32
|
steps:
|
|
46
33
|
- name: Checkout code
|
|
47
|
-
uses: actions/checkout@
|
|
34
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
35
|
+
with:
|
|
36
|
+
persist-credentials: false
|
|
48
37
|
- name: Set up Ruby
|
|
49
|
-
uses: ruby/setup-ruby@v1
|
|
38
|
+
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
50
39
|
with:
|
|
51
40
|
ruby-version: ${{ inputs.ruby_version }}
|
|
52
41
|
bundler-cache: true
|
|
@@ -54,22 +43,41 @@ jobs:
|
|
|
54
43
|
run: bundle install
|
|
55
44
|
- name: Install Control Plane tools
|
|
56
45
|
run: |
|
|
57
|
-
sudo npm install -g @controlplane/cli
|
|
46
|
+
sudo npm install -g @controlplane/cli@3.11.0
|
|
58
47
|
cpln --version
|
|
59
48
|
- name: Setup Control Plane tools
|
|
49
|
+
env:
|
|
50
|
+
# Keep the _CI suffix so tests that switch profiles do not use this token's profile.
|
|
51
|
+
CPLN_TOKEN_CI: ${{ secrets.CPLN_TOKEN }}
|
|
60
52
|
run: |
|
|
61
|
-
cpln profile create default --token $CPLN_TOKEN_CI --org $CPLN_ORG
|
|
53
|
+
cpln profile create default --token "$CPLN_TOKEN_CI" --org "$CPLN_ORG"
|
|
62
54
|
cpln image docker-login
|
|
63
55
|
- name: Run tests
|
|
64
|
-
|
|
56
|
+
env:
|
|
57
|
+
CPLN_TOKEN_CI: ${{ secrets.CPLN_TOKEN }}
|
|
58
|
+
RSPEC_SPEC_PATHS: ${{ inputs.spec_paths }}
|
|
59
|
+
RSPEC_TEST_TAG: ${{ inputs.test_tag }}
|
|
60
|
+
run: |
|
|
61
|
+
set -euo pipefail
|
|
62
|
+
|
|
63
|
+
rspec_args=(--format documentation)
|
|
64
|
+
if [[ -n "${RSPEC_TEST_TAG}" ]]; then
|
|
65
|
+
rspec_args+=(--tag "${RSPEC_TEST_TAG}")
|
|
66
|
+
fi
|
|
67
|
+
if [[ -n "${RSPEC_SPEC_PATHS}" ]]; then
|
|
68
|
+
read -r -a requested_paths <<< "${RSPEC_SPEC_PATHS}"
|
|
69
|
+
rspec_args+=("${requested_paths[@]}")
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
bundle exec rspec "${rspec_args[@]}"
|
|
65
73
|
- name: Upload spec log
|
|
66
|
-
uses: actions/upload-artifact@
|
|
74
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
67
75
|
if: always()
|
|
68
76
|
with:
|
|
69
77
|
name: spec-${{ inputs.test_tag }}-${{ github.run_id }}-${{ inputs.os_version }}-${{ inputs.ruby_version }}.log
|
|
70
78
|
path: spec.log
|
|
71
79
|
- name: Upload coverage results
|
|
72
|
-
uses: actions/upload-artifact@
|
|
80
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
73
81
|
if: always()
|
|
74
82
|
with:
|
|
75
83
|
name: coverage-report-${{ inputs.test_tag }}-${{ github.run_id }}-${{ inputs.os_version }}-${{ inputs.ruby_version }}
|
|
@@ -7,13 +7,21 @@ on:
|
|
|
7
7
|
description: "Test files or directories that should be run"
|
|
8
8
|
required: true
|
|
9
9
|
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
|
|
10
13
|
jobs:
|
|
11
14
|
rspec-specific:
|
|
12
15
|
name: RSpec (Specific)
|
|
13
16
|
uses: ./.github/workflows/rspec-shared.yml
|
|
17
|
+
# Share the no-drop queue with scheduled and manually dispatched Slow runs.
|
|
18
|
+
concurrency:
|
|
19
|
+
group: cpln-shared-org-${{ vars.CPLN_ORG || github.repository }}-shared-org
|
|
20
|
+
cancel-in-progress: false
|
|
21
|
+
queue: max
|
|
14
22
|
with:
|
|
15
23
|
os_version: ubuntu-latest
|
|
16
24
|
ruby_version: "3.2"
|
|
17
25
|
spec_paths: ${{ inputs.spec_paths }}
|
|
18
|
-
|
|
19
|
-
|
|
26
|
+
secrets:
|
|
27
|
+
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
|
data/.github/workflows/rspec.yml
CHANGED
|
@@ -19,27 +19,94 @@ on:
|
|
|
19
19
|
schedule:
|
|
20
20
|
- cron: "0 2 * * *"
|
|
21
21
|
|
|
22
|
+
permissions:
|
|
23
|
+
contents: read
|
|
24
|
+
|
|
22
25
|
jobs:
|
|
23
26
|
rspec-fast:
|
|
24
27
|
name: RSpec (Fast)
|
|
25
28
|
uses: ./.github/workflows/rspec-shared.yml
|
|
26
29
|
if: github.event_name != 'schedule'
|
|
30
|
+
# Fast runs use isolated random app suffixes, so only serialize the same PR
|
|
31
|
+
# or ref. Keep the default single pending slot so obsolete heads are
|
|
32
|
+
# replaced instead of accumulating behind the current run.
|
|
33
|
+
concurrency:
|
|
34
|
+
group: cpln-shared-org-${{ vars.CPLN_ORG || github.repository }}-${{ github.event.pull_request.number || github.ref }}
|
|
35
|
+
cancel-in-progress: false
|
|
27
36
|
with:
|
|
28
37
|
os_version: ubuntu-latest
|
|
29
38
|
ruby_version: "3.2"
|
|
30
39
|
test_tag: ~slow
|
|
31
|
-
secrets:
|
|
40
|
+
secrets:
|
|
41
|
+
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
|
|
42
|
+
|
|
43
|
+
ruby-compatibility:
|
|
44
|
+
name: Ruby ${{ matrix.ruby-version }} compatibility
|
|
45
|
+
if: github.event_name != 'schedule'
|
|
46
|
+
runs-on: ubuntu-latest
|
|
47
|
+
permissions:
|
|
48
|
+
contents: read
|
|
49
|
+
strategy:
|
|
50
|
+
fail-fast: false
|
|
51
|
+
matrix:
|
|
52
|
+
ruby-version:
|
|
53
|
+
- "3.3"
|
|
54
|
+
- "3.4"
|
|
55
|
+
steps:
|
|
56
|
+
- name: Checkout code
|
|
57
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
58
|
+
with:
|
|
59
|
+
persist-credentials: false
|
|
60
|
+
- name: Set up Ruby
|
|
61
|
+
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
62
|
+
with:
|
|
63
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
64
|
+
bundler-cache: true
|
|
65
|
+
- name: Run credential-free offline suite
|
|
66
|
+
env:
|
|
67
|
+
CPLN_ORG: ""
|
|
68
|
+
run: |
|
|
69
|
+
bundle exec rspec \
|
|
70
|
+
spec/cpflow_spec.rb \
|
|
71
|
+
spec/github_actions_dependency_policy_spec.rb \
|
|
72
|
+
spec/github_workflows_spec.rb \
|
|
73
|
+
spec/patches \
|
|
74
|
+
spec/support_specs \
|
|
75
|
+
spec/core/controlplane_api_direct_spec.rb \
|
|
76
|
+
spec/core/controlplane_api_spec.rb \
|
|
77
|
+
spec/core/doctor_service_spec.rb \
|
|
78
|
+
spec/core/github_flow_readiness/checks_spec.rb \
|
|
79
|
+
spec/core/github_flow_readiness_service_spec.rb \
|
|
80
|
+
spec/core/helpers_spec.rb \
|
|
81
|
+
spec/core/repo_introspection_spec.rb \
|
|
82
|
+
spec/core/shell_spec.rb \
|
|
83
|
+
spec/rakelib/create_release_spec.rb \
|
|
84
|
+
spec/command/no_command_spec.rb \
|
|
85
|
+
spec/command/staging_branch_validation_spec.rb \
|
|
86
|
+
spec/command/test_spec.rb \
|
|
87
|
+
spec/command/update_github_actions_spec.rb \
|
|
88
|
+
spec/command/version_spec.rb \
|
|
89
|
+
spec/command/deploy_image_unit_spec.rb \
|
|
90
|
+
spec/command/promote_app_from_upstream_unit_spec.rb
|
|
91
|
+
- name: Analyze code
|
|
92
|
+
run: bundle exec rubocop
|
|
32
93
|
|
|
33
94
|
rspec-slow:
|
|
34
95
|
name: RSpec (Slow)
|
|
35
96
|
uses: ./.github/workflows/rspec-shared.yml
|
|
36
97
|
if: github.event_name == 'workflow_dispatch' || github.event_name == 'schedule'
|
|
98
|
+
# Slow and Specific runs can mutate the shared domain. Retain every waiter
|
|
99
|
+
# in one repository-wide queue instead of replacing an earlier pending run.
|
|
100
|
+
concurrency:
|
|
101
|
+
group: cpln-shared-org-${{ vars.CPLN_ORG || github.repository }}-shared-org
|
|
102
|
+
cancel-in-progress: false
|
|
103
|
+
queue: max
|
|
37
104
|
with:
|
|
38
105
|
os_version: ubuntu-latest
|
|
39
106
|
ruby_version: "3.2"
|
|
40
107
|
test_tag: slow
|
|
41
|
-
|
|
42
|
-
|
|
108
|
+
secrets:
|
|
109
|
+
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
|
|
43
110
|
|
|
44
111
|
report-scheduled-slow-suite-failure:
|
|
45
112
|
name: Report scheduled slow suite failure
|
|
@@ -50,7 +117,7 @@ jobs:
|
|
|
50
117
|
issues: write
|
|
51
118
|
steps:
|
|
52
119
|
- name: Create or update the scheduled slow suite failure issue
|
|
53
|
-
uses: actions/github-script@
|
|
120
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
54
121
|
with:
|
|
55
122
|
script: |
|
|
56
123
|
const title = "Scheduled slow suite failing";
|
|
@@ -16,15 +16,22 @@ on:
|
|
|
16
16
|
- 'LICENSE'
|
|
17
17
|
- 'COMM-LICENSE.txt'
|
|
18
18
|
|
|
19
|
+
permissions:
|
|
20
|
+
contents: read
|
|
21
|
+
|
|
19
22
|
jobs:
|
|
20
23
|
rubocop:
|
|
21
24
|
runs-on: ubuntu-latest
|
|
22
25
|
name: Rubocop
|
|
23
26
|
steps:
|
|
24
27
|
- name: Checkout code
|
|
25
|
-
uses: actions/checkout@
|
|
28
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
29
|
+
with:
|
|
30
|
+
persist-credentials: false
|
|
31
|
+
- name: Analyze shell scripts
|
|
32
|
+
run: script/check_shell_scripts
|
|
26
33
|
- name: Set up Ruby
|
|
27
|
-
uses: ruby/setup-ruby@v1
|
|
34
|
+
uses: ruby/setup-ruby@95ef2b042f9d7a56d8268cba8559e2842e2ad01b # v1.321.0
|
|
28
35
|
with:
|
|
29
36
|
ruby-version: "3.2"
|
|
30
37
|
bundler-cache: true
|
|
@@ -18,6 +18,8 @@ on:
|
|
|
18
18
|
# Non-main manual dispatches are skipped by the job guard below.
|
|
19
19
|
# Only use this for forcing a rebuild from main.
|
|
20
20
|
|
|
21
|
+
permissions: {}
|
|
22
|
+
|
|
21
23
|
concurrency:
|
|
22
24
|
# Include the ref so accidental non-main manual runs cannot cancel a main dispatch
|
|
23
25
|
# before the job guard skips them.
|
data/.rubocop.yml
CHANGED
|
@@ -3,7 +3,7 @@ plugins:
|
|
|
3
3
|
- rubocop-rspec
|
|
4
4
|
|
|
5
5
|
AllCops:
|
|
6
|
-
TargetRubyVersion: 3.
|
|
6
|
+
TargetRubyVersion: 3.2
|
|
7
7
|
NewCops: enable
|
|
8
8
|
|
|
9
9
|
Metrics/AbcSize:
|
|
@@ -12,6 +12,11 @@ Metrics/AbcSize:
|
|
|
12
12
|
Style/Documentation:
|
|
13
13
|
Enabled: false
|
|
14
14
|
|
|
15
|
+
# These value objects intentionally reject positional construction. Retaining
|
|
16
|
+
# keyword-only initialization is part of their API contract, not redundant.
|
|
17
|
+
Style/RedundantStructKeywordInit:
|
|
18
|
+
Enabled: false
|
|
19
|
+
|
|
15
20
|
Style/StringLiterals:
|
|
16
21
|
EnforcedStyle: double_quotes
|
|
17
22
|
|
data/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,28 @@ In addition to the standard keepachangelog.com categories, this project uses a l
|
|
|
12
12
|
|
|
13
13
|
## [Unreleased]
|
|
14
14
|
|
|
15
|
+
## [6.0.0.rc.0] - 2026-09-06
|
|
16
|
+
|
|
17
|
+
### Breaking Changes
|
|
18
|
+
|
|
19
|
+
- BREAKING CHANGE: Raised the minimum supported Ruby version from 3.0 to 3.2. Users on Ruby 3.0 or 3.1 must upgrade Ruby before installing the next major cpflow release. CI now tests each supported Ruby minor from 3.2 through 3.4. [PR 464](https://github.com/shakacode/control-plane-flow/pull/464) by [Justin Gordon](https://github.com/justin808).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **Bumped the pinned GitHub Actions in the generated production-promotion workflow and this repository's reusable workflows to `actions/checkout` 7.0.1, `actions/github-script` 9.0.0, and `docker/setup-buildx-action` 4.3.0.** Downstream repositories pick up the template change with `cpflow update-github-actions`. [PR 460](https://github.com/shakacode/control-plane-flow/pull/460) by [Justin Gordon](https://github.com/justin808). Fixes [issue 459](https://github.com/shakacode/control-plane-flow/issues/459).
|
|
24
|
+
- **Changed generated GitHub Actions to check in cpflow's composite actions under `.github/actions/cpflow-*` and refresh them with `cpflow update-github-actions`.** Reusable workflows now load those local actions from the caller repository's trusted event revision, while the separately pinned checkout at `.cpflow` supplies the cpflow runtime source. Downstream repositories must commit generated workflows and local actions together when upgrading. [PR 451](https://github.com/shakacode/control-plane-flow/pull/451) by [Justin Gordon](https://github.com/justin808). Part of [issue 375](https://github.com/shakacode/control-plane-flow/issues/375).
|
|
25
|
+
- **Trimmed the RubyGems post-install message to a three-line generated-workflow reminder with a link to the full update and validation instructions.** [PR 447](https://github.com/shakacode/control-plane-flow/pull/447) by [Justin Gordon](https://github.com/justin808). Fixes [issue 377](https://github.com/shakacode/control-plane-flow/issues/377).
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- **Kept no-argument releases pinned to the latest changelog version during retries, and blocked implicit prerelease-to-stable promotion.** If an interrupted release already bumped the gem version or created its tag, rerunning `bundle exec rake release` no longer falls through to a stable release that is absent from the changelog. [PR 472](https://github.com/shakacode/control-plane-flow/pull/472) by [Justin Gordon](https://github.com/justin808).
|
|
30
|
+
- **Loaded the caller's generated `.github/actions/cpflow-*` through `actions/checkout`'s trusted default in the reusable review-app deploy, delete, and stale-cleanup workflows.** Dropping the explicit `ref:` still resolves to the revision GitHub already recorded for the triggering event (`GITHUB_SHA`, the base-branch tip under `pull_request_target`), and a default checkout is never inspected by the fork-PR checkout guard added in `actions/checkout` 7.0.0. The previous explicit `github.event.pull_request.base.sha` pin in the delete workflow could trip that guard, and fail teardown, when a fork PR was closed by a manual fast-forward that left the recorded base SHA equal to the PR head. Review-app teardown consequently runs the base-tip copy of the generated actions rather than the pull request's recorded pre-merge base, which matters only if the merge itself changed those actions. Downstream repositories pick up the change when `cpflow update-github-actions` bumps the reusable-workflow ref. [PR 467](https://github.com/shakacode/control-plane-flow/pull/467) by [Justin Gordon](https://github.com/justin808). Fixes [issue 463](https://github.com/shakacode/control-plane-flow/issues/463).
|
|
31
|
+
- **Gave `pull_request_target` an explicit branch in the reusable review-app deploy source validator.** The reusable workflow's event allowlist admits `pull_request_target`, but the deploy source validator handled only `pull_request` and `issue_comment`. It now treats `pull_request_target` exactly like `pull_request`, skipping fork pull requests with the documented deploy-skipped summary, as defence-in-depth for callers that rewire the deploy trigger. The shipped caller templates never send that event, so no existing deployment behavior changes and same-repository pull requests are unaffected. [PR 467](https://github.com/shakacode/control-plane-flow/pull/467) by [Justin Gordon](https://github.com/justin808). Fixes [issue 462](https://github.com/shakacode/control-plane-flow/issues/462).
|
|
32
|
+
- **Prevented shell interpretation of dynamic Control Plane CLI and Docker arguments.** Resource names, image references, container names, locations, and other dynamic values now remain literal argv elements; output suppression and stderr capture use process redirection options without rebuilding a shell command. Fixes [issue 452](https://github.com/shakacode/control-plane-flow/issues/452). [PR 458](https://github.com/shakacode/control-plane-flow/pull/458) by [Justin Gordon](https://github.com/justin808).
|
|
33
|
+
- **Fixed scheduled slow-suite regressions in stale-app workload suspension, invalid upstream-token handling, transient workload image deployment, and delayed one-off job output.** `cleanup-stale-apps --mode=stop` now skips configured workloads absent from a stale app, upstream authorization failures cleanly remove their temporary profile and stderr capture, workload image updates retry for a bounded window before failing, and non-interactive `cpflow run` commands drain logs for a bounded post-terminal window so delayed ingestion does not drop completed job output. Slow-suite command logs and failure artifacts now redact token options and explicitly supplied sensitive values. [PR 413](https://github.com/shakacode/control-plane-flow/pull/413) by [Justin Gordon](https://github.com/justin808). Addresses [issue 409](https://github.com/shakacode/control-plane-flow/issues/409).
|
|
34
|
+
- **Queued every pending shared-org Slow and Specific RSpec run instead of letting GitHub replace an older waiter.** Fast runs keep their per-PR or per-ref queue, while the domain-mutating suites use GitHub's bounded `queue: max` behavior in one repository-wide concurrency group. [PR 457](https://github.com/shakacode/control-plane-flow/pull/457) by [Justin Gordon](https://github.com/justin808). Fixes [issue 403](https://github.com/shakacode/control-plane-flow/issues/403).
|
|
35
|
+
- **Bounded `cpflow run` status reconciliation after a non-interactive command finishes.** When Control Plane keeps reporting a cron job as active or pending after the command completion marker, `cpflow run` now waits up to a configurable 20-minute grace period and then exits nonzero with the job, replica, and last observed status instead of polling forever. Addresses the bounded-reconciliation portion of [HiChee issue 10375](https://github.com/shakacode/hichee/issues/10375). [PR 453](https://github.com/shakacode/control-plane-flow/pull/453) by [Justin Gordon](https://github.com/justin808).
|
|
36
|
+
|
|
15
37
|
## [5.3.0] - 2026-09-02
|
|
16
38
|
|
|
17
39
|
### Added
|
|
@@ -474,7 +496,8 @@ Deprecated `cpl` gem. New gem is `cpflow`.
|
|
|
474
496
|
|
|
475
497
|
First release.
|
|
476
498
|
|
|
477
|
-
[Unreleased]: https://github.com/shakacode/control-plane-flow/compare/
|
|
499
|
+
[Unreleased]: https://github.com/shakacode/control-plane-flow/compare/v6.0.0.rc.0...main
|
|
500
|
+
[6.0.0.rc.0]: https://github.com/shakacode/control-plane-flow/compare/v5.3.0...v6.0.0.rc.0
|
|
478
501
|
[5.3.0]: https://github.com/shakacode/control-plane-flow/compare/v5.2.0...v5.3.0
|
|
479
502
|
[5.2.0]: https://github.com/shakacode/control-plane-flow/compare/v5.1.1...v5.2.0
|
|
480
503
|
[5.1.1]: https://github.com/shakacode/control-plane-flow/compare/v5.1.0...v5.1.1
|
data/CONTRIBUTING.md
CHANGED
|
@@ -35,6 +35,43 @@ gem install overcommit
|
|
|
35
35
|
overcommit --install
|
|
36
36
|
```
|
|
37
37
|
|
|
38
|
+
## GitHub Actions Dependencies
|
|
39
|
+
|
|
40
|
+
Every repository-based external `uses:` entry under `.github/workflows/` or `.github/actions/` must use an immutable,
|
|
41
|
+
lowercase 40-character commit SHA followed by the exact release tag in a same-line comment. Do not use moving
|
|
42
|
+
major-version tags or branch names. New action repositories also require explicit review before they are added to
|
|
43
|
+
`trusted_actions` in `.agents/agent-workflow.yml`. Docker actions must use an exact `sha256:` image digest; manually
|
|
44
|
+
review the registry, image, and digest because Docker references are outside the repository allowlist.
|
|
45
|
+
Generated downstream calls to Control Plane Flow's cross-repository reusable workflows are the deliberate exception:
|
|
46
|
+
they use an exact `vX.Y.Z` release tag so the workflow source stays aligned with the released `cpflow` gem.
|
|
47
|
+
|
|
48
|
+
Dependabot checks GitHub Actions dependencies weekly. For each proposed update, verify that the release tag resolves to
|
|
49
|
+
the proposed commit, review the upstream release and diff, and keep the version comment synchronized with the pin.
|
|
50
|
+
Dependabot-authored runs receive no repository secrets, so `RSpec (Fast)` fails at `Setup Control Plane tools`. The
|
|
51
|
+
credential-free `Ruby 3.3 compatibility` and `Ruby 3.4 compatibility` jobs do run
|
|
52
|
+
`spec/github_actions_dependency_policy_spec.rb`, so a bump that leaves the generated templates or the
|
|
53
|
+
`EXPECTED_CPFLOW_CHECKOUT_ACTION` constant behind still fails there, even on a Dependabot-authored pull request that
|
|
54
|
+
cannot run the credentialed suite. A Dependabot bump is therefore never merged directly: a maintainer opens a pull
|
|
55
|
+
request that supersedes it and lands the same pin. That maintainer pull request must update the pin in all four places,
|
|
56
|
+
or CI fails:
|
|
57
|
+
|
|
58
|
+
- `.github/workflows/**` and `.github/actions/**` — the workflows that actually run in this repository.
|
|
59
|
+
- `lib/github_flow_templates/.github/workflows/**` — the workflows generated into downstream repositories.
|
|
60
|
+
- `lib/github_flow_templates/bin/test-cpflow-github-flow` — the `EXPECTED_CPFLOW_CHECKOUT_ACTION` constant.
|
|
61
|
+
- `spec/command/generate_github_actions_spec.rb` and `spec/github_workflows_spec.rb` — the assertions that hard-code
|
|
62
|
+
the expected SHA.
|
|
63
|
+
|
|
64
|
+
`spec/github_actions_dependency_policy_spec.rb` guards the first three. It fails when a template occurrence's commit
|
|
65
|
+
SHA or version comment drifts from the repository pin for the same action, when a template `uses:` entry is left on a
|
|
66
|
+
mutable ref such as `@v7` or `@main`, or when a template pins an external action that the repository workflows do not
|
|
67
|
+
use. Only script constants such as `EXPECTED_CPFLOW_CHECKOUT_ACTION` and `docker://` image references may omit the
|
|
68
|
+
version comment, because neither is a workflow step with somewhere to hang a same-line release tag. Calls to cpflow's
|
|
69
|
+
own reusable workflows under `.github/workflows/` are the one exception to the commit-pin rule, and only for the
|
|
70
|
+
`@__CPFLOW_GITHUB_ACTIONS_REF__` generator placeholder or an exact release tag. `@main` and `@v5` fail, and so does any
|
|
71
|
+
other `shakacode/control-plane-flow` reference, such as `shakacode/control-plane-flow/some-action@v6.0.0` or the bare
|
|
72
|
+
repository, which must be commit-pinned like any external action. The literal `vX.Y.Z` is accepted only in the verifier
|
|
73
|
+
script's `EXPECTED_PROMOTE_WORKFLOW_REF_FORMAT` constant, never in a workflow step.
|
|
74
|
+
|
|
38
75
|
## Docs Site Dispatch
|
|
39
76
|
|
|
40
77
|
The `trigger-docs-site.yml` workflow notifies `shakacode/controlplaneflow-com` when docs-related files change on `main`.
|
|
@@ -113,9 +150,9 @@ cpflow test
|
|
|
113
150
|
|
|
114
151
|
## Developing the GitHub flow generator
|
|
115
152
|
|
|
116
|
-
`cpflow generate-github-actions` copies templates
|
|
153
|
+
`cpflow generate-github-actions` copies workflow templates in `lib/github_flow_templates/` and canonical composite actions in `.github/actions/cpflow-*` into a target repo's `.github/` directory. To work on this feature:
|
|
117
154
|
|
|
118
|
-
- **Edit
|
|
155
|
+
- **Edit each canonical source in place.** The generator does no string-mangling beyond a small set of substitutions handled in `lib/command/generate_github_actions.rb`; what you put in `lib/github_flow_templates/.github/` is (almost) exactly what ships into a generated repo. Edit composite actions in the root `.github/actions/cpflow-*` directories. Make changes in those canonical sources, not in a generated copy.
|
|
119
156
|
- **Surface area to keep consistent.** A change to a PR command (e.g. `+review-app-deploy`) usually touches three places: the trigger workflow (`lib/github_flow_templates/.github/workflows/cpflow-deploy-review-app.yml`), the PR-open quick reference (`cpflow-review-app-help.yml`), and the long-form help (`lib/github_flow_templates/.github/cpflow-help.md`). The AI flow prompt (`lib/command/ai_github_flow_prompt.rb`) also names commands and should be kept in sync.
|
|
120
157
|
- **Run the generator spec on every change:**
|
|
121
158
|
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -307,6 +307,11 @@ aliases:
|
|
|
307
307
|
# If not specified, defaults to 21600 (6 hours).
|
|
308
308
|
runner_job_timeout: 1000
|
|
309
309
|
|
|
310
|
+
# Sets how long `cpflow run` waits for Control Plane to reconcile a cron job status
|
|
311
|
+
# after the non-interactive command prints its completion marker.
|
|
312
|
+
# If not specified, defaults to 1200 (20 minutes).
|
|
313
|
+
runner_job_status_reconciliation_timeout: 1200
|
|
314
|
+
|
|
310
315
|
# Apps with a deployed image, or an image-less GVC, created before this amount of days
|
|
311
316
|
# will be listed for deletion when running the command `cpflow cleanup-stale-apps`.
|
|
312
317
|
stale_app_image_deployed_days: 5
|
|
@@ -393,7 +398,7 @@ cpflow generate-github-actions
|
|
|
393
398
|
bin/test-cpflow-github-flow
|
|
394
399
|
```
|
|
395
400
|
|
|
396
|
-
`cpflow github-flow-readiness` exits non-zero when it finds blockers such as unpublished exact-pinned packages or a missing production Dockerfile, so use it as the gate before generation. Then review the generated `.controlplane/controlplane.yml` entries, adjust any app-specific workloads, and configure the GitHub repository variables and secrets described in [CI automation](./docs/ci-automation.md), including the optional Docker build settings for private GitHub dependencies and custom SSH known hosts. `cpflow generate-github-actions` also writes `bin/test-cpflow-github-flow` for local validation and `bin/pin-cpflow-github-ref` for temporarily pinning downstream wrappers to an upstream commit SHA during pre-release testing. `cpflow generate` already switches to persistent `db` and `storage` volumes when `config/database.yml` shows SQLite in production and preserves detected frontend precompile hooks, but you should still confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement and that the emitted workload set matches the real app. If you want an AI agent to do this end to end, give it the [AI rollout prompt](./docs/ai-github-flow-prompt.md) rather than a vague "set up CI" request.
|
|
401
|
+
`cpflow github-flow-readiness` exits non-zero when it finds blockers such as unpublished exact-pinned packages or a missing production Dockerfile, so use it as the gate before generation. Then review the generated `.controlplane/controlplane.yml` entries, adjust any app-specific workloads, and configure the GitHub repository variables and secrets described in [CI automation](./docs/ci-automation.md), including the optional Docker build settings for private GitHub dependencies and custom SSH known hosts. `cpflow generate-github-actions` checks in the local `.github/actions/cpflow-*` implementations alongside the workflows, and also writes `bin/test-cpflow-github-flow` for local validation and `bin/pin-cpflow-github-ref` for temporarily pinning downstream wrappers to an upstream commit SHA during pre-release testing. `cpflow generate` already switches to persistent `db` and `storage` volumes when `config/database.yml` shows SQLite in production and preserves detected frontend precompile hooks, but you should still confirm that the generated Dockerfile picked a Ruby base image compatible with the app's declared Ruby requirement and that the emitted workload set matches the real app. If you want an AI agent to do this end to end, give it the [AI rollout prompt](./docs/ai-github-flow-prompt.md) rather than a vague "set up CI" request.
|
|
397
402
|
|
|
398
403
|
For a live example, see the [react-webpack-rails-tutorial](https://github.com/shakacode/react-webpack-rails-tutorial/blob/master/.controlplane/readme.md) repository.
|
|
399
404
|
|
data/cpflow.gemspec
CHANGED
|
@@ -14,23 +14,11 @@ Gem::Specification.new do |spec|
|
|
|
14
14
|
spec.license = "MIT"
|
|
15
15
|
spec.post_install_message = <<~MESSAGE
|
|
16
16
|
cpflow #{Cpflow::VERSION} installed.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
checked-in wrappers so GitHub loads the matching control-plane-flow release tag:
|
|
20
|
-
|
|
21
|
-
cpflow update-github-actions
|
|
22
|
-
bin/test-cpflow-github-flow
|
|
23
|
-
|
|
24
|
-
If you run cpflow through Bundler:
|
|
25
|
-
|
|
26
|
-
bundle exec cpflow update-github-actions
|
|
27
|
-
bin/test-cpflow-github-flow bundle exec cpflow
|
|
28
|
-
|
|
29
|
-
New repository? Run `cpflow generate-github-actions` first to create the
|
|
30
|
-
wrappers (and the `bin/test-cpflow-github-flow` script referenced above).
|
|
17
|
+
Generated GitHub Actions users: run `cpflow update-github-actions` after upgrading.
|
|
18
|
+
Docs: https://github.com/shakacode/control-plane-flow/blob/main/docs/ci-automation.md#updating-generated-github-actions-after-gem-updates
|
|
31
19
|
MESSAGE
|
|
32
20
|
|
|
33
|
-
spec.required_ruby_version = ">= 3.
|
|
21
|
+
spec.required_ruby_version = ">= 3.2"
|
|
34
22
|
|
|
35
23
|
spec.add_dependency "dotenv", "~> 3.1"
|
|
36
24
|
spec.add_dependency "jwt", "~> 3.1"
|