code-foundry 0.32.4 → 0.34.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.
- package/.github/CONTRIBUTING.md +17 -14
- package/.github/workflows/ci.yml +25 -8
- package/.github/workflows/codeql.yml +28 -14
- package/.github/workflows/draft-pr.yml +25 -18
- package/.github/workflows/draft-pr_self-ci.yml +3 -1
- package/.github/workflows/opencode-security_self-ci.yml +4 -2
- package/.github/workflows/release-pr.yml +31 -9
- package/.github/workflows/release-pr_self-ci.yml +4 -7
- package/.github/workflows/release.yml +136 -23
- package/.github/workflows/release_self-ci.yml +5 -1
- package/.github/workflows/security.yml +18 -11
- package/.github/workflows/test.yml +28 -9
- package/.github/workflows/validation.yml +183 -0
- package/.github/workflows/validation_self-ci.yml +82 -0
- package/CHANGELOG.md +25 -0
- package/README.md +7 -4
- package/docs/CONFIGURATION.md +2 -1
- package/docs/RELEASES.md +26 -18
- package/docs/WORKFLOWS.md +56 -4
- package/package.json +1 -1
- package/src/commands/doctor.mjs +53 -3
- package/src/commands/release.mjs +290 -68
- package/src/commands/sync.mjs +88 -4
- package/src/lib/github-doctor.mjs +10 -4
- package/src/lib/release-policy.mjs +88 -19
- package/src/lib/validation-policy.mjs +127 -0
- package/src/runtime.mjs +54 -0
- package/.github/workflows/ci_self-ci.yml +0 -21
- package/.github/workflows/codeql_self-ci.yml +0 -29
- package/.github/workflows/security_self-ci.yml +0 -21
- package/.github/workflows/test_self-ci.yml +0 -22
package/.github/CONTRIBUTING.md
CHANGED
|
@@ -48,7 +48,7 @@ docs/* test/* refactor/* │ │
|
|
|
48
48
|
| `staging` | Integration branch | Target normal pull requests here. Required checks must pass before merge. |
|
|
49
49
|
| `feat/*`, `fix/*`, `chore/*`, `refactor/*`, `docs/*`, `test/*` | Focused work | Branch from `staging`; keep changes small and reviewable. |
|
|
50
50
|
|
|
51
|
-
The
|
|
51
|
+
The Git workflow is `staging-release`: topic branches **squash** into `staging`, a promotion PR **rebases** validated changes into `main` (`merge_strategy: rebase`), and the Release Please version PR **squashes** into `main` (`release_merge_strategy: squash`). Release automation never defaults to a merge method and never merges with `--admin`; `code-foundry doctor` and `code-foundry sync` fail closed on any other merge strategy. Re-align `staging` with `main` after a release when needed.
|
|
52
52
|
|
|
53
53
|
## Before you start
|
|
54
54
|
|
|
@@ -107,7 +107,7 @@ For maintainers, trusted contributors, and automation agents:
|
|
|
107
107
|
|
|
108
108
|
8. Push the branch and open a pull request into `staging`.
|
|
109
109
|
9. Address review feedback and failed checks on the same branch.
|
|
110
|
-
10. Merge
|
|
110
|
+
10. Merge with a squash after required checks pass and the change is ready; feature PRs land on `staging` with squash merges.
|
|
111
111
|
|
|
112
112
|
### Internal agent handoff
|
|
113
113
|
|
|
@@ -153,15 +153,17 @@ Keep pull requests focused and reviewable. Include screenshots or recordings for
|
|
|
153
153
|
|
|
154
154
|
## Workflow and check behavior
|
|
155
155
|
|
|
156
|
-
| Event
|
|
157
|
-
|
|
|
158
|
-
|
|
|
159
|
-
|
|
|
160
|
-
|
|
|
161
|
-
|
|
|
162
|
-
|
|
|
156
|
+
| Event | Expected automation |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| Pull request targeting `staging` | Fast validation: CI plus unit tests, ending in `Validation / Gate` |
|
|
159
|
+
| Ordinary pull request targeting `main` | Audit validation: CI, full tests, Security, and CodeQL, ending in `Validation / Gate` |
|
|
160
|
+
| Exact Release Please pull request targeting `main` | Release-policy validation only, ending in `Validation / Gate` |
|
|
161
|
+
| Scheduled or manual validation | Full audit tier |
|
|
162
|
+
| Push to a working branch | Draft PR workflow |
|
|
163
|
+
| Push to `staging` | Promotion PR workflow; canonical validation waits for the PR event |
|
|
164
|
+
| Push to `main` | Release workflow; canonical validation already ran on the merged PR |
|
|
163
165
|
|
|
164
|
-
The
|
|
166
|
+
The single validation caller keys concurrency by event and pull-request head. A newer update to the same pull request cancels its superseded validation run; scheduled and manual audits remain independent. The mode-aware orchestrator fans out only the jobs required by that event and always concludes with the stable aggregate gate.
|
|
165
167
|
|
|
166
168
|
Required checks are enforced by branch protection rulesets/branch protection. Do not duplicate their checklists in the pull request description; document validation commands and results instead.
|
|
167
169
|
|
|
@@ -173,10 +175,11 @@ Security checks can be skipped when repository visibility or the GitHub plan doe
|
|
|
173
175
|
|
|
174
176
|
## Review and merge protocol
|
|
175
177
|
|
|
176
|
-
| Change
|
|
177
|
-
| ----------------- | --------- | --------------------------------------------------------- |
|
|
178
|
-
| Working branch | `staging` | All applicable required checks pass |
|
|
179
|
-
| `staging`
|
|
178
|
+
| Change | Target | Merge method | Merge gate |
|
|
179
|
+
| ----------------- | --------- | ------------------------------------------------------- | --------------------------------------------------------- |
|
|
180
|
+
| Working branch | `staging` | Squash | All applicable required checks pass |
|
|
181
|
+
| `staging` → `main` promotion | `main` | Rebase (`merge_strategy`) | Current staging checks, release review, and rollout notes |
|
|
182
|
+
| Release Please version PR | `main` | Squash (`release_merge_strategy`, fails closed) | Validation gate and release policy pass |
|
|
180
183
|
|
|
181
184
|
Reviewers focus on correctness, security, maintainability, test coverage, operational impact, and compatibility. Authors remain responsible for responding to feedback and verifying the final commit.
|
|
182
185
|
|
package/.github/workflows/ci.yml
CHANGED
|
@@ -18,6 +18,11 @@ on:
|
|
|
18
18
|
required: false
|
|
19
19
|
type: string
|
|
20
20
|
default: ubuntu-latest
|
|
21
|
+
secrets:
|
|
22
|
+
TURBO_TOKEN:
|
|
23
|
+
required: false
|
|
24
|
+
NEXTAUTH_SECRET:
|
|
25
|
+
required: false
|
|
21
26
|
|
|
22
27
|
permissions:
|
|
23
28
|
contents: read
|
|
@@ -44,10 +49,13 @@ jobs:
|
|
|
44
49
|
runs-on: ${{ inputs.runner }}
|
|
45
50
|
steps:
|
|
46
51
|
- name: Checkout
|
|
47
|
-
uses: actions/checkout@v7
|
|
52
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
53
|
+
with:
|
|
54
|
+
persist-credentials: false
|
|
48
55
|
- name: Runtime
|
|
49
|
-
uses: actions/checkout@v7
|
|
56
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
50
57
|
with:
|
|
58
|
+
persist-credentials: false
|
|
51
59
|
repository: ${{ inputs.runtime-repository }}
|
|
52
60
|
ref: ${{ inputs.runtime-ref }}
|
|
53
61
|
path: .github/.code-foundry
|
|
@@ -84,10 +92,13 @@ jobs:
|
|
|
84
92
|
runs-on: ${{ inputs.runner }}
|
|
85
93
|
steps:
|
|
86
94
|
- name: Checkout
|
|
87
|
-
uses: actions/checkout@v7
|
|
95
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
96
|
+
with:
|
|
97
|
+
persist-credentials: false
|
|
88
98
|
- name: Runtime
|
|
89
|
-
uses: actions/checkout@v7
|
|
99
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
90
100
|
with:
|
|
101
|
+
persist-credentials: false
|
|
91
102
|
repository: ${{ inputs.runtime-repository }}
|
|
92
103
|
ref: ${{ inputs.runtime-ref }}
|
|
93
104
|
path: .github/.code-foundry
|
|
@@ -119,10 +130,13 @@ jobs:
|
|
|
119
130
|
runs-on: ${{ inputs.runner }}
|
|
120
131
|
steps:
|
|
121
132
|
- name: Checkout
|
|
122
|
-
uses: actions/checkout@v7
|
|
133
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
134
|
+
with:
|
|
135
|
+
persist-credentials: false
|
|
123
136
|
- name: Runtime
|
|
124
|
-
uses: actions/checkout@v7
|
|
137
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
125
138
|
with:
|
|
139
|
+
persist-credentials: false
|
|
126
140
|
repository: ${{ inputs.runtime-repository }}
|
|
127
141
|
ref: ${{ inputs.runtime-ref }}
|
|
128
142
|
path: .github/.code-foundry
|
|
@@ -159,10 +173,13 @@ jobs:
|
|
|
159
173
|
NEXTAUTH_SECRET: ${{ secrets.NEXTAUTH_SECRET || 'code-foundry-ci-placeholder-0123456789' }}
|
|
160
174
|
steps:
|
|
161
175
|
- name: Checkout
|
|
162
|
-
uses: actions/checkout@v7
|
|
176
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
177
|
+
with:
|
|
178
|
+
persist-credentials: false
|
|
163
179
|
- name: Runtime
|
|
164
|
-
uses: actions/checkout@v7
|
|
180
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
165
181
|
with:
|
|
182
|
+
persist-credentials: false
|
|
166
183
|
repository: ${{ inputs.runtime-repository }}
|
|
167
184
|
ref: ${{ inputs.runtime-ref }}
|
|
168
185
|
path: .github/.code-foundry
|
|
@@ -33,7 +33,6 @@ on:
|
|
|
33
33
|
required: false
|
|
34
34
|
type: number
|
|
35
35
|
default: 1
|
|
36
|
-
|
|
37
36
|
permissions:
|
|
38
37
|
actions: read
|
|
39
38
|
contents: read
|
|
@@ -76,17 +75,19 @@ jobs:
|
|
|
76
75
|
id: security
|
|
77
76
|
env:
|
|
78
77
|
GH_TOKEN: ${{ github.token }}
|
|
78
|
+
REPOSITORY_VISIBILITY: ${{ github.event.repository.visibility }}
|
|
79
79
|
run: |
|
|
80
80
|
status="disabled"
|
|
81
|
-
if [ "$
|
|
81
|
+
if [ "$REPOSITORY_VISIBILITY" = "public" ]; then
|
|
82
82
|
status="enabled"
|
|
83
83
|
else
|
|
84
84
|
status="$(gh api "repos/${GITHUB_REPOSITORY}" --jq '.security_and_analysis.code_security.status // "disabled"' 2>/dev/null || printf 'disabled')"
|
|
85
85
|
fi
|
|
86
86
|
printf 'status=%s\n' "$status" >> "$GITHUB_OUTPUT"
|
|
87
87
|
- name: Checkout
|
|
88
|
-
uses: actions/checkout@v7
|
|
88
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
89
89
|
with:
|
|
90
|
+
persist-credentials: false
|
|
90
91
|
fetch-depth: 2
|
|
91
92
|
filter: blob:none
|
|
92
93
|
sparse-checkout: |
|
|
@@ -101,8 +102,9 @@ jobs:
|
|
|
101
102
|
package-lock.json
|
|
102
103
|
sparse-checkout-cone-mode: false
|
|
103
104
|
- name: Runtime
|
|
104
|
-
uses: actions/checkout@v7
|
|
105
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
105
106
|
with:
|
|
107
|
+
persist-credentials: false
|
|
106
108
|
repository: ${{ inputs.runtime-repository }}
|
|
107
109
|
ref: ${{ inputs.runtime-ref }}
|
|
108
110
|
path: .github/.code-foundry
|
|
@@ -138,14 +140,17 @@ jobs:
|
|
|
138
140
|
needs.detect.outputs.enabled == 'true' &&
|
|
139
141
|
needs.detect.outputs.actions_available == 'true' &&
|
|
140
142
|
needs.detect.outputs.actions_changed == 'true'
|
|
141
|
-
uses: actions/checkout@v7
|
|
143
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
144
|
+
with:
|
|
145
|
+
persist-credentials: false
|
|
142
146
|
- name: Runtime
|
|
143
147
|
if: >-
|
|
144
148
|
needs.detect.outputs.enabled == 'true' &&
|
|
145
149
|
needs.detect.outputs.actions_available == 'true' &&
|
|
146
150
|
needs.detect.outputs.actions_changed == 'true'
|
|
147
|
-
uses: actions/checkout@v7
|
|
151
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
148
152
|
with:
|
|
153
|
+
persist-credentials: false
|
|
149
154
|
repository: ${{ inputs.runtime-repository }}
|
|
150
155
|
ref: ${{ inputs.runtime-ref }}
|
|
151
156
|
path: .github/.code-foundry
|
|
@@ -193,14 +198,17 @@ jobs:
|
|
|
193
198
|
needs.detect.outputs.enabled == 'true' &&
|
|
194
199
|
needs.detect.outputs.javascript_available == 'true' &&
|
|
195
200
|
needs.detect.outputs.javascript_changed == 'true'
|
|
196
|
-
uses: actions/checkout@v7
|
|
201
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
202
|
+
with:
|
|
203
|
+
persist-credentials: false
|
|
197
204
|
- name: Runtime
|
|
198
205
|
if: >-
|
|
199
206
|
needs.detect.outputs.enabled == 'true' &&
|
|
200
207
|
needs.detect.outputs.javascript_available == 'true' &&
|
|
201
208
|
needs.detect.outputs.javascript_changed == 'true'
|
|
202
|
-
uses: actions/checkout@v7
|
|
209
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
203
210
|
with:
|
|
211
|
+
persist-credentials: false
|
|
204
212
|
repository: ${{ inputs.runtime-repository }}
|
|
205
213
|
ref: ${{ inputs.runtime-ref }}
|
|
206
214
|
path: .github/.code-foundry
|
|
@@ -248,14 +256,17 @@ jobs:
|
|
|
248
256
|
needs.detect.outputs.enabled == 'true' &&
|
|
249
257
|
needs.detect.outputs.python_available == 'true' &&
|
|
250
258
|
needs.detect.outputs.python_changed == 'true'
|
|
251
|
-
uses: actions/checkout@v7
|
|
259
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
260
|
+
with:
|
|
261
|
+
persist-credentials: false
|
|
252
262
|
- name: Runtime
|
|
253
263
|
if: >-
|
|
254
264
|
needs.detect.outputs.enabled == 'true' &&
|
|
255
265
|
needs.detect.outputs.python_available == 'true' &&
|
|
256
266
|
needs.detect.outputs.python_changed == 'true'
|
|
257
|
-
uses: actions/checkout@v7
|
|
267
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
258
268
|
with:
|
|
269
|
+
persist-credentials: false
|
|
259
270
|
repository: ${{ inputs.runtime-repository }}
|
|
260
271
|
ref: ${{ inputs.runtime-ref }}
|
|
261
272
|
path: .github/.code-foundry
|
|
@@ -308,14 +319,17 @@ jobs:
|
|
|
308
319
|
needs.detect.outputs.enabled == 'true' &&
|
|
309
320
|
needs.detect.outputs.rust_available == 'true' &&
|
|
310
321
|
needs.detect.outputs.rust_changed == 'true'
|
|
311
|
-
uses: actions/checkout@v7
|
|
322
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
323
|
+
with:
|
|
324
|
+
persist-credentials: false
|
|
312
325
|
- name: Runtime
|
|
313
326
|
if: >-
|
|
314
327
|
needs.detect.outputs.enabled == 'true' &&
|
|
315
328
|
needs.detect.outputs.rust_available == 'true' &&
|
|
316
329
|
needs.detect.outputs.rust_changed == 'true'
|
|
317
|
-
uses: actions/checkout@v7
|
|
330
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
318
331
|
with:
|
|
332
|
+
persist-credentials: false
|
|
319
333
|
repository: ${{ inputs.runtime-repository }}
|
|
320
334
|
ref: ${{ inputs.runtime-ref }}
|
|
321
335
|
path: .github/.code-foundry
|
|
@@ -388,7 +402,7 @@ jobs:
|
|
|
388
402
|
needs.detect.outputs.enabled == 'true' &&
|
|
389
403
|
needs.detect.outputs.rust_available == 'true' &&
|
|
390
404
|
needs.detect.outputs.rust_changed == 'true'
|
|
391
|
-
uses: github/codeql-action/init@v4
|
|
405
|
+
uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4
|
|
392
406
|
with:
|
|
393
407
|
languages: rust
|
|
394
408
|
build-mode: ${{ needs.detect.outputs.rust_build_mode }}
|
|
@@ -399,7 +413,7 @@ jobs:
|
|
|
399
413
|
needs.detect.outputs.enabled == 'true' &&
|
|
400
414
|
needs.detect.outputs.rust_available == 'true' &&
|
|
401
415
|
needs.detect.outputs.rust_changed == 'true'
|
|
402
|
-
uses: github/codeql-action/analyze@v4
|
|
416
|
+
uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4
|
|
403
417
|
with:
|
|
404
418
|
category: /language:rust/${{ steps.scope.outputs.scope_id }}
|
|
405
419
|
upload-database: false
|
|
@@ -8,13 +8,18 @@ on:
|
|
|
8
8
|
required: false
|
|
9
9
|
type: string
|
|
10
10
|
default: ubuntu-slim
|
|
11
|
+
secrets:
|
|
12
|
+
CODE_FOUNDRY_TOKEN:
|
|
13
|
+
required: false
|
|
14
|
+
RELEASE_PLEASE_TOKEN:
|
|
15
|
+
required: false
|
|
11
16
|
|
|
12
17
|
permissions:
|
|
13
18
|
contents: read
|
|
14
19
|
pull-requests: write
|
|
15
20
|
|
|
16
21
|
env:
|
|
17
|
-
|
|
22
|
+
HAS_AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN != '' || secrets.RELEASE_PLEASE_TOKEN != '' }}
|
|
18
23
|
|
|
19
24
|
jobs:
|
|
20
25
|
create-draft-pr:
|
|
@@ -27,15 +32,21 @@ jobs:
|
|
|
27
32
|
steps:
|
|
28
33
|
- name: Check
|
|
29
34
|
id: check-pr
|
|
35
|
+
env:
|
|
36
|
+
HEAD_REF: ${{ github.ref_name }}
|
|
37
|
+
GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
|
|
30
38
|
run: |
|
|
31
|
-
BRANCH="$
|
|
39
|
+
BRANCH="$HEAD_REF"
|
|
32
40
|
EXISTING=$(gh pr list --repo "$GITHUB_REPOSITORY" --limit 1 --base staging --head "$BRANCH" --state open --json number,title 2>/dev/null | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]").length))')
|
|
33
41
|
echo "existing=$EXISTING" >> "$GITHUB_OUTPUT"
|
|
34
42
|
|
|
35
43
|
- name: Create
|
|
36
44
|
if: steps.check-pr.outputs.existing == '0'
|
|
45
|
+
env:
|
|
46
|
+
HEAD_REF: ${{ github.ref_name }}
|
|
47
|
+
GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
|
|
37
48
|
run: |
|
|
38
|
-
BRANCH="$
|
|
49
|
+
BRANCH="$HEAD_REF"
|
|
39
50
|
PREFIX="${BRANCH%%/*}"
|
|
40
51
|
SUFFIX="${BRANCH#*/}"
|
|
41
52
|
PR_TITLE=""
|
|
@@ -60,23 +71,19 @@ jobs:
|
|
|
60
71
|
PR_TITLE="$BRANCH"
|
|
61
72
|
fi
|
|
62
73
|
|
|
74
|
+
DRAFT_ARGS=()
|
|
75
|
+
if [ "$HAS_AUTOMATION_TOKEN" = true ]; then
|
|
76
|
+
BODY_NOTICE="This PR is ready for review and merging once required validation passes."
|
|
77
|
+
else
|
|
78
|
+
DRAFT_ARGS+=(--draft)
|
|
79
|
+
BODY_NOTICE="This PR was created automatically and is currently in draft mode."
|
|
80
|
+
echo "::notice title=Manual PR readiness required::No automation token is configured; this PR may remain draft until manually marked ready for validation and merge."
|
|
81
|
+
fi
|
|
82
|
+
|
|
63
83
|
gh pr create \
|
|
64
84
|
--repo "$GITHUB_REPOSITORY" \
|
|
65
85
|
--base staging \
|
|
66
86
|
--head "$BRANCH" \
|
|
67
|
-
|
|
87
|
+
"${DRAFT_ARGS[@]}" \
|
|
68
88
|
--title "$PR_TITLE" \
|
|
69
|
-
--body "
|
|
70
|
-
|
|
71
|
-
This PR is a draft and should not be merged until CI passes and a reviewer (or the Daily Review agent) marks it ready.
|
|
72
|
-
|
|
73
|
-
**CI Status:** Pending — this workflow triggered on push to \`$BRANCH\`."
|
|
74
|
-
|
|
75
|
-
- name: Mark ready
|
|
76
|
-
if: steps.check-pr.outputs.existing == '0'
|
|
77
|
-
run: |
|
|
78
|
-
BRANCH="${{ github.ref_name }}"
|
|
79
|
-
PR_NUMBER=$(gh pr list --repo "$GITHUB_REPOSITORY" --limit 1 --base staging --head "$BRANCH" --state open --json number 2>/dev/null | node -e 'let d=""; process.stdin.on("data", c => d += c).on("end", () => console.log(JSON.parse(d || "[]")[0]?.number || ""))')
|
|
80
|
-
if [ -n "$PR_NUMBER" ]; then
|
|
81
|
-
gh pr ready "$PR_NUMBER" --repo "$GITHUB_REPOSITORY"
|
|
82
|
-
fi
|
|
89
|
+
--body "CI PR created automatically by this workflow.\n\n $BODY_NOTICE\n\n **CI Status:** Pending \u2014 this workflow triggered on push to \`$BRANCH\`."
|
|
@@ -20,7 +20,9 @@ jobs:
|
|
|
20
20
|
token: ${{ steps.detect.outputs.token }}
|
|
21
21
|
steps:
|
|
22
22
|
- name: Checkout
|
|
23
|
-
uses: actions/checkout@v7
|
|
23
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
24
26
|
- name: Detect configuration and token
|
|
25
27
|
id: detect
|
|
26
28
|
env:
|
|
@@ -37,7 +39,7 @@ jobs:
|
|
|
37
39
|
name: OpenCode Security / Scan
|
|
38
40
|
needs: detect
|
|
39
41
|
if: needs.detect.outputs.enabled == 'true' && needs.detect.outputs.token == 'true'
|
|
40
|
-
uses: 0xPlayerOne/opencode-security/.github/workflows/opencode-security.yml@main
|
|
42
|
+
uses: 0xPlayerOne/opencode-security/.github/workflows/opencode-security.yml@b3dce823322672b285fbe99b870ea984c01826cb # main
|
|
41
43
|
with:
|
|
42
44
|
source_ref: ${{ github.event.pull_request.head.ref || 'main' }}
|
|
43
45
|
runner: ubuntu-latest
|
|
@@ -8,13 +8,18 @@ on:
|
|
|
8
8
|
required: false
|
|
9
9
|
type: string
|
|
10
10
|
default: ubuntu-slim
|
|
11
|
+
secrets:
|
|
12
|
+
CODE_FOUNDRY_TOKEN:
|
|
13
|
+
required: false
|
|
14
|
+
RELEASE_PLEASE_TOKEN:
|
|
15
|
+
required: false
|
|
11
16
|
|
|
12
17
|
permissions:
|
|
13
18
|
contents: read
|
|
14
19
|
pull-requests: write
|
|
15
20
|
|
|
16
21
|
env:
|
|
17
|
-
|
|
22
|
+
HAS_AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN != '' || secrets.RELEASE_PLEASE_TOKEN != '' }}
|
|
18
23
|
|
|
19
24
|
jobs:
|
|
20
25
|
create-release-pr:
|
|
@@ -26,13 +31,16 @@ jobs:
|
|
|
26
31
|
cancel-in-progress: true
|
|
27
32
|
steps:
|
|
28
33
|
- name: Checkout
|
|
29
|
-
uses: actions/checkout@v6
|
|
34
|
+
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6
|
|
30
35
|
with:
|
|
36
|
+
persist-credentials: false
|
|
31
37
|
fetch-depth: 0
|
|
32
38
|
filter: blob:none
|
|
33
39
|
|
|
34
40
|
- name: Check
|
|
35
41
|
id: check-pr
|
|
42
|
+
env:
|
|
43
|
+
GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
|
|
36
44
|
run: |
|
|
37
45
|
set -euo pipefail
|
|
38
46
|
EXISTING=$(gh pr list \
|
|
@@ -101,15 +109,19 @@ jobs:
|
|
|
101
109
|
RELEASE_ONLY=true
|
|
102
110
|
fi
|
|
103
111
|
fi
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
112
|
+
{
|
|
113
|
+
echo "existing=$EXISTING"
|
|
114
|
+
echo "commits=$TOTAL_COMMITS"
|
|
115
|
+
echo "tree_equal=$TREE_EQUAL"
|
|
116
|
+
echo "release_only=$RELEASE_ONLY"
|
|
117
|
+
} >> "$GITHUB_OUTPUT"
|
|
108
118
|
|
|
109
119
|
- name: No changes
|
|
110
120
|
if: steps.check-pr.outputs.existing == '0' && (steps.check-pr.outputs.commits == '0' || steps.check-pr.outputs.tree_equal == 'true' || steps.check-pr.outputs.release_only == 'true')
|
|
121
|
+
env:
|
|
122
|
+
RELEASE_ONLY: ${{ steps.check-pr.outputs.release_only }}
|
|
111
123
|
run: |
|
|
112
|
-
if [ "$
|
|
124
|
+
if [ "$RELEASE_ONLY" = true ]; then
|
|
113
125
|
echo 'Only approved release metadata differs between rebased branch histories; reconciliation from main to staging is pending, so no promotion PR is needed.'
|
|
114
126
|
else
|
|
115
127
|
echo 'staging is already aligned with main; no promotion PR is needed.'
|
|
@@ -117,6 +129,8 @@ jobs:
|
|
|
117
129
|
|
|
118
130
|
- name: Create
|
|
119
131
|
if: steps.check-pr.outputs.existing == '0' && steps.check-pr.outputs.commits != '0' && steps.check-pr.outputs.tree_equal != 'true' && steps.check-pr.outputs.release_only != 'true'
|
|
132
|
+
env:
|
|
133
|
+
GH_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN || github.token }}
|
|
120
134
|
run: |
|
|
121
135
|
DATE=$(date +%Y-%m-%d)
|
|
122
136
|
BODY_FILE="$RUNNER_TEMP/release-pr.md"
|
|
@@ -128,7 +142,7 @@ jobs:
|
|
|
128
142
|
LAST_PAGE=$(( (TOTAL_COMMITS + 99) / 100 ))
|
|
129
143
|
gh api "$COMPARE_URL?per_page=100&page=$LAST_PAGE" > "$COMPARE_FILE"
|
|
130
144
|
fi
|
|
131
|
-
COMMITS=$(node -e
|
|
145
|
+
COMMITS=$(node -e "const d=require(process.argv[1]); for (const c of d.commits || []) console.log('- ' + c.commit.message.split('\\n')[0] + ' (' + c.sha.slice(0, 7) + ')')" "$COMPARE_FILE")
|
|
132
146
|
if [ -z "$COMMITS" ]; then
|
|
133
147
|
COMMITS='- No commits found since main.'
|
|
134
148
|
fi
|
|
@@ -157,14 +171,22 @@ jobs:
|
|
|
157
171
|
### Validation
|
|
158
172
|
|
|
159
173
|
- Required CI, test, security, and CodeQL checks must pass before merge.
|
|
160
|
-
- Merge using the repository's configured \`merge_strategy\` (
|
|
174
|
+
- Merge using the repository's configured \`merge_strategy\` (**rebase**).
|
|
175
|
+
- The promotion topology requires rebase; never merge a promotion PR with a merge commit.
|
|
161
176
|
- After merge, Release Please opens a separate versioned release PR with the changelog.
|
|
162
177
|
EOF
|
|
163
178
|
|
|
179
|
+
DRAFT_ARGS=()
|
|
180
|
+
if [ "$HAS_AUTOMATION_TOKEN" != true ]; then
|
|
181
|
+
DRAFT_ARGS+=(--draft)
|
|
182
|
+
echo "::notice title=Manual PR readiness required::Created draft promotion PR because no automation token is configured. Configure CODE_FOUNDRY_TOKEN or RELEASE_PLEASE_TOKEN, or mark this PR ready manually to trigger validation."
|
|
183
|
+
fi
|
|
184
|
+
|
|
164
185
|
if ! gh pr create \
|
|
165
186
|
--repo "$GITHUB_REPOSITORY" \
|
|
166
187
|
--base main \
|
|
167
188
|
--head staging \
|
|
189
|
+
"${DRAFT_ARGS[@]}" \
|
|
168
190
|
--title "Promote staging -> main ($DATE)" \
|
|
169
191
|
--body-file "$BODY_FILE"; then
|
|
170
192
|
EXISTING_NUMBER=$(gh pr list \
|
|
@@ -3,8 +3,6 @@ name: Code Foundry
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches: [staging]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [main]
|
|
8
6
|
workflow_dispatch:
|
|
9
7
|
|
|
10
8
|
permissions:
|
|
@@ -13,12 +11,11 @@ permissions:
|
|
|
13
11
|
|
|
14
12
|
jobs:
|
|
15
13
|
release-pr:
|
|
16
|
-
if:
|
|
17
|
-
github.event_name == 'push' ||
|
|
18
|
-
github.event_name == 'workflow_dispatch' ||
|
|
19
|
-
startsWith(github.head_ref, 'release-please--branches--main')
|
|
14
|
+
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
|
|
20
15
|
name: Release PR
|
|
21
16
|
uses: ./.github/workflows/release-pr.yml
|
|
22
17
|
with:
|
|
23
18
|
runner: ubuntu-slim
|
|
24
|
-
secrets:
|
|
19
|
+
secrets:
|
|
20
|
+
CODE_FOUNDRY_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN }}
|
|
21
|
+
RELEASE_PLEASE_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|