Skip to content

Commit 46542d3

Browse files
committed
ci(install): close Bun migration validation gaps
1. Keep the version bump at HEAD on release proposal branches by preventing license auto-commits there. 2. Keep scoped package identities slash-delimited so Windows sandbox setup patches their peers. 3. Regenerate license attribution when any source input changes instead of only on lock updates.
1 parent 56ffcec commit 46542d3

4 files changed

Lines changed: 96 additions & 8 deletions

File tree

.github/workflows/update-3rdparty-licenses.yml

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,15 @@ on:
1313
pull_request:
1414
paths:
1515
- ".github/vendored-dependencies.csv"
16+
- ".github/workflows/update-3rdparty-licenses.yml"
17+
- "LICENSE-3rdparty.csv"
1618
- "bun.lock"
19+
- "package.json"
20+
- "scripts/generate-3rdparty-licenses.js"
21+
- "scripts/helpers/concurrency.js"
22+
- "scripts/third-party-dependencies.js"
1723
- "vendor/bun.lock"
24+
- "vendor/package.json"
1825

1926
jobs:
2027
check-licenses:
@@ -24,6 +31,7 @@ jobs:
2431
outputs:
2532
needs_update: ${{ steps.check.outputs.needs_update }}
2633
is_bot_same_repo: ${{ steps.check.outputs.is_bot_same_repo }}
34+
is_release_proposal: ${{ steps.check.outputs.is_release_proposal }}
2735
head_oid: ${{ steps.check.outputs.head_oid }}
2836
steps:
2937
- name: Check out PR branch
@@ -40,6 +48,7 @@ jobs:
4048
PR_USER_TYPE: ${{ github.event.pull_request.user.type }}
4149
PR_HEAD_REPO: ${{ github.event.pull_request.head.repo.full_name }}
4250
BASE_REPO: ${{ github.repository }}
51+
HEAD_REF: ${{ github.head_ref }}
4352
run: |
4453
set -e
4554
echo "head_oid=${{ github.event.pull_request.head.sha }}" >> "$GITHUB_OUTPUT"
@@ -58,16 +67,28 @@ jobs:
5867
echo "is_bot_same_repo=false" >> "$GITHUB_OUTPUT"
5968
fi
6069
70+
# Release tooling requires the version bump to stay at HEAD.
71+
if [[ "$HEAD_REF" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-proposal$ ]]; then
72+
echo "is_release_proposal=true" >> "$GITHUB_OUTPUT"
73+
else
74+
echo "is_release_proposal=false" >> "$GITHUB_OUTPUT"
75+
fi
76+
6177
- name: Upload updated LICENSE-3rdparty.csv
62-
if: steps.check.outputs.needs_update == 'true' && steps.check.outputs.is_bot_same_repo == 'true'
78+
if: >-
79+
steps.check.outputs.needs_update == 'true' &&
80+
steps.check.outputs.is_bot_same_repo == 'true' &&
81+
steps.check.outputs.is_release_proposal != 'true'
6382
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
6483
with:
6584
name: license-csv
6685
path: LICENSE-3rdparty.csv
6786
if-no-files-found: error
6887

6988
- name: Fail for PRs with outdated licenses
70-
if: steps.check.outputs.needs_update == 'true' && steps.check.outputs.is_bot_same_repo != 'true'
89+
if: >-
90+
steps.check.outputs.needs_update == 'true' &&
91+
(steps.check.outputs.is_bot_same_repo != 'true' || steps.check.outputs.is_release_proposal == 'true')
7192
run: |
7293
echo "❌ The LICENSE-3rdparty.csv file needs to be updated!"
7394
echo ""
@@ -76,7 +97,10 @@ jobs:
7697
7798
auto-commit-licenses:
7899
needs: check-licenses
79-
if: needs.check-licenses.outputs.needs_update == 'true' && needs.check-licenses.outputs.is_bot_same_repo == 'true'
100+
if: >-
101+
needs.check-licenses.outputs.needs_update == 'true' &&
102+
needs.check-licenses.outputs.is_bot_same_repo == 'true' &&
103+
needs.check-licenses.outputs.is_release_proposal != 'true'
80104
runs-on: ubuntu-latest
81105
permissions:
82106
contents: read

scripts/install_plugin_modules.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync
55
const { lstat, mkdir, readdir, readFile, writeFile } = require('fs/promises')
66
const { createRequire } = require('module')
77
const { arch } = require('os')
8-
const { join } = require('path')
8+
const { join, posix } = require('path')
99

1010
// eslint-disable-next-line n/no-restricted-require
1111
const semver = require('semver')
@@ -357,11 +357,11 @@ async function collectPeerDependencyFolders (rootFolder, parent = '') {
357357
if (!isGeneratedWorkspace(entry, parent)) continue
358358
if (entry.startsWith('@')) {
359359
// eslint-disable-next-line no-await-in-loop
360-
folders.push(...await collectPeerDependencyFolders(current, parent ? join(parent, entry) : entry))
360+
folders.push(...await collectPeerDependencyFolders(current, posix.join(parent, entry)))
361361
continue
362362
}
363363

364-
const externalName = join(parent, entry.split('@', 1)[0])
364+
const externalName = posix.join(parent, entry.split('@', 1)[0])
365365
if (externalDeps.has(externalName)) folders.push({ folder: current, externalName })
366366
}
367367

@@ -433,7 +433,7 @@ async function patchPeerDependencies ({ folder, externalName }) {
433433
* @returns {boolean}
434434
*/
435435
function isGeneratedWorkspace (entry, parent = '') {
436-
const workspaceName = parent ? join(parent, entry) : entry
436+
const workspaceName = parent ? posix.join(parent, entry) : entry
437437

438438
if (entry.startsWith('@')) {
439439
for (const workspace of workspaces) {

scripts/test/install-plugin-modules.spec.js

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,29 @@ externals.express.push(
197197
assert.strictEqual(semver.subset(manifest.dependencies.zod, '^4.0.0'), true)
198198
})
199199

200+
it('keeps scoped package identities portable across path separators', () => {
201+
const preload = path.join(wrapperDirectory, 'windows-package-separators.js')
202+
fs.writeFileSync(preload, `
203+
const path = require('node:path')
204+
const nativeJoin = path.join
205+
path.posix = { ...path.posix, join: nativeJoin }
206+
/**
207+
* @param {...string} parts
208+
*/
209+
path.join = function join (...parts) {
210+
return parts[0].startsWith('@') ? path.win32.join(...parts) : nativeJoin(...parts)
211+
}
212+
`)
213+
214+
runInstall('claude-agent-sdk', undefined, undefined, {
215+
NODE_OPTIONS: `--require=${preload}`,
216+
})
217+
218+
const manifest = require(path.join(versionsDir, '@anthropic-ai', 'claude-agent-sdk', 'package.json'))
219+
assert.ok(manifest.dependencies.zod, 'expected the scoped workspace to receive its peer dependency')
220+
assert.strictEqual(semver.subset(manifest.dependencies.zod, '^4.0.0'), true)
221+
})
222+
200223
it('trusts the transitive native builder required by pg-native', () => {
201224
runInstall('pg')
202225

@@ -253,12 +276,14 @@ function readVersionsManifest () {
253276
* @param {string} plugin
254277
* @param {string} [binDirectory]
255278
* @param {string} [traceFile]
279+
* @param {NodeJS.ProcessEnv} [env]
256280
* @returns {import('node:child_process').SpawnSyncReturns<string>}
257281
*/
258-
function runInstall (plugin, binDirectory, traceFile) {
282+
function runInstall (plugin, binDirectory, traceFile, env) {
259283
const result = spawnInstall(plugin, {
260284
PATH: `${binDirectory ?? wrapperDirectory}:/usr/bin:/bin`,
261285
...(traceFile && { DD_TEST_PACKAGE_MANAGER_TRACE_FILE: traceFile }),
286+
...env,
262287
})
263288

264289
assert.strictEqual(

scripts/test/no-yarn-dev-references.spec.js

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,4 +438,43 @@ describe('no yarn dev references', function () {
438438
]
439439
)
440440
})
441+
442+
it('regenerates licenses when any generator input changes', () => {
443+
const workflow = yaml.parse(fs.readFileSync(
444+
path.join(repoRoot, '.github/workflows/update-3rdparty-licenses.yml'),
445+
'utf8'
446+
))
447+
448+
assert.deepStrictEqual(workflow.on.pull_request.paths.sort(), [
449+
'.github/vendored-dependencies.csv',
450+
'.github/workflows/update-3rdparty-licenses.yml',
451+
'LICENSE-3rdparty.csv',
452+
'bun.lock',
453+
'package.json',
454+
'scripts/generate-3rdparty-licenses.js',
455+
'scripts/helpers/concurrency.js',
456+
'scripts/third-party-dependencies.js',
457+
'vendor/bun.lock',
458+
'vendor/package.json',
459+
])
460+
})
461+
462+
it('keeps automated license updates off release proposal branches', () => {
463+
const workflow = yaml.parse(fs.readFileSync(
464+
path.join(repoRoot, '.github/workflows/update-3rdparty-licenses.yml'),
465+
'utf8'
466+
))
467+
const checkJob = workflow.jobs['check-licenses']
468+
const checkScript = checkJob.steps.find(step => step.id === 'check').run
469+
const uploadStep = checkJob.steps.find(step => step.name === 'Upload updated LICENSE-3rdparty.csv')
470+
const failStep = checkJob.steps.find(step => step.name === 'Fail for PRs with outdated licenses')
471+
472+
assert.strictEqual(checkJob.outputs.is_release_proposal, '$' + '{{ steps.check.outputs.is_release_proposal }}')
473+
assert.match(checkScript, /\^v\[0-9\]\+\\\.\[0-9\]\+\\\.\[0-9\]\+-proposal\$/)
474+
assert.match(checkScript, /is_release_proposal=true/)
475+
assert.match(checkScript, /is_release_proposal=false/)
476+
assert.match(uploadStep.if, /is_release_proposal != 'true'/)
477+
assert.match(failStep.if, /is_release_proposal == 'true'/)
478+
assert.match(workflow.jobs['auto-commit-licenses'].if, /is_release_proposal != 'true'/)
479+
})
441480
})

0 commit comments

Comments
 (0)