code-foundry 0.38.1 → 0.39.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/code-foundry.yml +1 -1
- package/.github/workflows/draft-pr_self-ci.yml +1 -1
- package/.github/workflows/opencode-security_self-ci.yml +1 -0
- package/.github/workflows/release-pr.yml +55 -6
- package/.github/workflows/release-pr_self-ci.yml +1 -1
- package/CHANGELOG.md +19 -0
- package/docs/RELEASES.md +8 -0
- package/docs/WORKFLOWS.md +1 -1
- package/package.json +1 -1
- package/src/commands/sync.mjs +5 -1
package/.github/code-foundry.yml
CHANGED
|
@@ -46,6 +46,7 @@ jobs:
|
|
|
46
46
|
# reusable workflow already checks out the consumer repository.
|
|
47
47
|
source_ref: b3dce823322672b285fbe99b870ea984c01826cb
|
|
48
48
|
runner: ubuntu-latest
|
|
49
|
+
model: opencode-go/muse-spark-1.2-contributor
|
|
49
50
|
mode: standard
|
|
50
51
|
fail_on_severity: high
|
|
51
52
|
max_cost_usd: 1
|
|
@@ -15,11 +15,12 @@ on:
|
|
|
15
15
|
required: false
|
|
16
16
|
|
|
17
17
|
permissions:
|
|
18
|
-
contents:
|
|
18
|
+
contents: write
|
|
19
19
|
pull-requests: write
|
|
20
20
|
|
|
21
21
|
env:
|
|
22
22
|
HAS_AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN != '' || secrets.RELEASE_PLEASE_TOKEN != '' }}
|
|
23
|
+
PROMOTION_BRANCH: code-foundry/promote/staging-to-main
|
|
23
24
|
|
|
24
25
|
jobs:
|
|
25
26
|
create-release-pr:
|
|
@@ -44,8 +45,11 @@ jobs:
|
|
|
44
45
|
# persist-credentials disabled, git has no auth for that fetch; configure
|
|
45
46
|
# the credential helper with the short-lived workflow token. NiftyLeague
|
|
46
47
|
# rejects long-lived fine-grained automation tokens with HTTP 403 even
|
|
47
|
-
# on REST, so all read-only operations use github.token
|
|
48
|
-
#
|
|
48
|
+
# on REST, so all read-only operations use github.token. It is used
|
|
49
|
+
# only for GitHub operations owned by this workflow. The job's
|
|
50
|
+
# contents: write permission is required later for the isolated,
|
|
51
|
+
# deterministic promotion ref; protected main and staging are never
|
|
52
|
+
# written by this workflow.
|
|
49
53
|
env:
|
|
50
54
|
GH_TOKEN: ${{ github.token }}
|
|
51
55
|
run: gh auth setup-git
|
|
@@ -65,7 +69,7 @@ jobs:
|
|
|
65
69
|
# REST query keeps the exact base/head/state filter and the per_page=1
|
|
66
70
|
# cap (existing is 0 or 1) and fails closed on any API error.
|
|
67
71
|
EXISTING=$(gh api \
|
|
68
|
-
"repos/${GITHUB_REPOSITORY}/pulls?base=main&head
|
|
72
|
+
"repos/${GITHUB_REPOSITORY}/pulls?base=main&head=${PROMOTION_BRANCH}&state=open&per_page=1" \
|
|
69
73
|
--jq 'length')
|
|
70
74
|
MAIN_TREE=$(gh api "repos/${GITHUB_REPOSITORY}/commits/main" --jq '.commit.tree.sha')
|
|
71
75
|
STAGING_TREE=$(gh api "repos/${GITHUB_REPOSITORY}/commits/staging" --jq '.commit.tree.sha')
|
|
@@ -144,6 +148,51 @@ jobs:
|
|
|
144
148
|
echo 'staging is already aligned with main; no promotion PR is needed.'
|
|
145
149
|
fi
|
|
146
150
|
|
|
151
|
+
- name: Prepare exact-tree promotion head
|
|
152
|
+
if: steps.check-pr.outputs.commits != '0' && steps.check-pr.outputs.tree_equal != 'true' && steps.check-pr.outputs.release_only != 'true'
|
|
153
|
+
env:
|
|
154
|
+
GH_TOKEN: ${{ github.token }}
|
|
155
|
+
AUTOMATION_TOKEN: ${{ secrets.CODE_FOUNDRY_TOKEN || secrets.RELEASE_PLEASE_TOKEN }}
|
|
156
|
+
run: |
|
|
157
|
+
set -euo pipefail
|
|
158
|
+
MAIN_SHA=$(git rev-parse origin/main)
|
|
159
|
+
STAGING_SHA=$(git rev-parse origin/staging)
|
|
160
|
+
STAGING_TREE=$(git rev-parse 'origin/staging^{tree}')
|
|
161
|
+
STAGING_SUBJECT=$(git log -1 --format=%s origin/staging)
|
|
162
|
+
COMMIT_FILE="$RUNNER_TEMP/promotion-commit.json"
|
|
163
|
+
node - "$MAIN_SHA" "$STAGING_SHA" "$STAGING_TREE" "$STAGING_SUBJECT" <<'NODE' > "$COMMIT_FILE"
|
|
164
|
+
const [main, staging, tree, subject] = process.argv.slice(2)
|
|
165
|
+
process.stdout.write(JSON.stringify({
|
|
166
|
+
message: `${subject}\n\nPromoted from staging snapshot ${staging.slice(0, 12)}.`,
|
|
167
|
+
tree,
|
|
168
|
+
parents: [main],
|
|
169
|
+
}))
|
|
170
|
+
NODE
|
|
171
|
+
PROMOTION_SHA=$(gh api \
|
|
172
|
+
--method POST \
|
|
173
|
+
"repos/${GITHUB_REPOSITORY}/git/commits" \
|
|
174
|
+
--input "$COMMIT_FILE" \
|
|
175
|
+
--jq '.sha')
|
|
176
|
+
REF_ENDPOINT="repos/${GITHUB_REPOSITORY}/git/refs/heads/${PROMOTION_BRANCH}"
|
|
177
|
+
if gh api "$REF_ENDPOINT" >/dev/null 2>&1; then
|
|
178
|
+
UPDATED=false
|
|
179
|
+
if [ "$HAS_AUTOMATION_TOKEN" = true ] && GH_TOKEN="$AUTOMATION_TOKEN" gh api --method PATCH "$REF_ENDPOINT" --field sha="$PROMOTION_SHA" --field force=true >/dev/null; then
|
|
180
|
+
UPDATED=true
|
|
181
|
+
fi
|
|
182
|
+
if [ "$UPDATED" != true ]; then
|
|
183
|
+
if [ "$HAS_AUTOMATION_TOKEN" = true ]; then
|
|
184
|
+
echo "::warning title=Promotion token fallback::Automation token could not refresh the promotion ref; using the workflow token. GitHub may require a manual check rerun for an already-open pull request."
|
|
185
|
+
fi
|
|
186
|
+
gh api --method PATCH "$REF_ENDPOINT" --field sha="$PROMOTION_SHA" --field force=true >/dev/null
|
|
187
|
+
fi
|
|
188
|
+
else
|
|
189
|
+
gh api --method POST \
|
|
190
|
+
"repos/${GITHUB_REPOSITORY}/git/refs" \
|
|
191
|
+
--field ref="refs/heads/${PROMOTION_BRANCH}" \
|
|
192
|
+
--field sha="$PROMOTION_SHA" >/dev/null
|
|
193
|
+
fi
|
|
194
|
+
echo "Prepared ${PROMOTION_BRANCH} at ${PROMOTION_SHA} with parent ${MAIN_SHA} and the exact staging tree ${STAGING_TREE}."
|
|
195
|
+
|
|
147
196
|
- name: Create
|
|
148
197
|
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'
|
|
149
198
|
env:
|
|
@@ -203,7 +252,7 @@ jobs:
|
|
|
203
252
|
"repos/${GITHUB_REPOSITORY}/pulls"
|
|
204
253
|
--method POST
|
|
205
254
|
--field base=main
|
|
206
|
-
--field head=
|
|
255
|
+
--field head="$PROMOTION_BRANCH"
|
|
207
256
|
--field title="Promote staging -> main ($DATE)"
|
|
208
257
|
--field body=@"$BODY_FILE"
|
|
209
258
|
)
|
|
@@ -237,7 +286,7 @@ jobs:
|
|
|
237
286
|
# the short-lived workflow token; gh pr list issues a GraphQL query
|
|
238
287
|
# that NiftyLeague's long-lived fine-grained token policy rejects.
|
|
239
288
|
EXISTING_NUMBER=$(GH_TOKEN="${{ github.token }}" gh api \
|
|
240
|
-
"repos/${GITHUB_REPOSITORY}/pulls?base=main&head
|
|
289
|
+
"repos/${GITHUB_REPOSITORY}/pulls?base=main&head=${PROMOTION_BRANCH}&state=open&per_page=1" \
|
|
241
290
|
--jq '.[0].number // empty')
|
|
242
291
|
if [ -z "$EXISTING_NUMBER" ]; then
|
|
243
292
|
echo 'Pull request creation failed and no existing promotion PR was found.' >&2
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.39.0](https://github.com/0xPlayerOne/code-foundry/compare/v0.38.2...v0.39.0) (2026-08-29)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* code-foundry 0.38.3 — direct workflow default, muse spark model, opencode_security_model override ([436da59](https://github.com/0xPlayerOne/code-foundry/commit/436da5947098039642cb961987e962cd88960db8))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* draft-pr base main for direct workflow (staging deleted) ([b1c063f](https://github.com/0xPlayerOne/code-foundry/commit/b1c063fa8e967800b85ffb9ae42df5d62e9a4e1e))
|
|
14
|
+
|
|
15
|
+
## [0.38.2](https://github.com/0xPlayerOne/code-foundry/compare/v0.38.1...v0.38.2) (2026-08-29)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* **release:** preserve promotion release semantics ([#418](https://github.com/0xPlayerOne/code-foundry/issues/418)) ([b1702a7](https://github.com/0xPlayerOne/code-foundry/commit/b1702a756cc6d7297f98b529b0bca178a1cdc3d1))
|
|
21
|
+
|
|
3
22
|
## [0.38.1](https://github.com/0xPlayerOne/code-foundry/compare/v0.38.0...v0.38.1) (2026-08-29)
|
|
4
23
|
|
|
5
24
|
|
package/docs/RELEASES.md
CHANGED
|
@@ -61,6 +61,14 @@ possible. The final branch trees are inspected before mutation; validated
|
|
|
61
61
|
main-only changes are inherited by `staging`, while unpromoted staging work is
|
|
62
62
|
replayed on top of `main`.
|
|
63
63
|
|
|
64
|
+
Promotion never opens a pull request directly from a divergent `staging`
|
|
65
|
+
history. The workflow creates or refreshes a deterministic promotion branch
|
|
66
|
+
whose single commit has the current `main` tip as its parent and the exact
|
|
67
|
+
validated `staging` tree. This keeps the review diff limited to the actual
|
|
68
|
+
environment delta even after squash or rebase merges have changed ancestry.
|
|
69
|
+
The generated commit preserves the staged tip's conventional subject so
|
|
70
|
+
Release Please still detects the appropriate release type after promotion.
|
|
71
|
+
|
|
64
72
|
The `staging` → `main` reconciliation exists only in the `staging-release`
|
|
65
73
|
topology. Patch-equivalent divergence between `main` and `staging` is treated
|
|
66
74
|
as aligned. When `staging` has pending commits that are not yet represented on
|
package/docs/WORKFLOWS.md
CHANGED
|
@@ -95,7 +95,7 @@ workflow refuses to run unless its strategy is exactly `rebase`.
|
|
|
95
95
|
| --- | --- | --- |
|
|
96
96
|
| Feature/fix PR into `main` (direct topology) | Squash | Contribution policy; see `CONTRIBUTING.md` |
|
|
97
97
|
| Feature/fix PR into `staging` (staging-release topology) | Squash | Contribution policy; see `CONTRIBUTING.md` |
|
|
98
|
-
| `staging` → `main` promotion PR (staging-release topology) | Rebase (`merge_strategy: rebase`) | `merge_strategy` must be `rebase
|
|
98
|
+
| `staging` → `main` promotion PR (staging-release topology) | Rebase (`merge_strategy: rebase`) | Code Foundry creates a one-commit head with `main` as its parent and the exact validated `staging` tree; `merge_strategy` must be `rebase`, and merge commits are rejected |
|
|
99
99
|
| Release Please version PR into `main` | Rebase (`release_merge_strategy: rebase`) | Release automation fails closed unless `rebase`; never defaults to `merge`, never uses `--admin` |
|
|
100
100
|
|
|
101
101
|
The promotion rows above apply only to `staging-release`; `direct`
|
package/package.json
CHANGED
package/src/commands/sync.mjs
CHANGED
|
@@ -388,6 +388,10 @@ function renderWorkflow(content, config, repository, ref, rustCodeql) {
|
|
|
388
388
|
rendered = rendered.replace(/^(\s+rust-threads:)\s+.*$/m, `$1 '${rustCodeql.threads}'`)
|
|
389
389
|
rendered = rendered.replace(/^(\s+rust-max-parallel:)\s+.*$/m, `$1 ${rustCodeql.maxParallel}`)
|
|
390
390
|
}
|
|
391
|
+
if (workflow === 'opencode-security') {
|
|
392
|
+
const model = configured(config.opencode_security_model, '').trim()
|
|
393
|
+
if (model) rendered = rendered.replace(/^(\s+model:)\s+.*$/m, `$1 ${model}`)
|
|
394
|
+
}
|
|
391
395
|
return rendered
|
|
392
396
|
}
|
|
393
397
|
|
|
@@ -645,7 +649,7 @@ function createDefaultConfig(root, source) {
|
|
|
645
649
|
prune_standard: 'false', cache_packages: 'auto', cache_build: 'auto', coverage_minimum: '80', turbo_remote: 'auto',
|
|
646
650
|
release_type: detectPackageManager(root) === 'none' ? 'auto' : 'node', npm_publish: 'false',
|
|
647
651
|
post_release: 'false', post_release_workflow: '', post_release_mode: 'auto',
|
|
648
|
-
opencode_security: 'false',
|
|
652
|
+
opencode_security: 'false', opencode_security_model: '',
|
|
649
653
|
sync_mode: 'overlay', custom_workflows: 'preserve',
|
|
650
654
|
license: existsSync(join(root, 'LICENSE')) ? 'preserve' : 'gpl-3.0-or-later', git_workflow: 'direct', merge_strategy: 'rebase', release_merge_strategy: 'rebase',
|
|
651
655
|
}
|