refactor(release): always prune superseded packages
This commit is contained in:
1 parent
3e77454277
commit
cc7e473a58
9 files changed
+50
-85
No files matched your search
@@ -39,12 +39,6 @@ on:
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
keep_old:
|
||||
description: 'Keep superseded R2 version objects while publishing'
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
group: windows-release-${{ inputs.tag }}-${{ inputs.mode }}
|
||||
cancel-in-progress: false
|
||||
@@ -174,7 +168,6 @@ jobs:
|
||||
env:
|
||||
RELEASE_TAG: ${{ inputs.tag }}
|
||||
CANDIDATE_RUN_ID: ${{ inputs.candidate_run_id }}
|
||||
KEEP_OLD: ${{ inputs.keep_old }}
|
||||
NCURATOR_RELEASE_CANDIDATE_ROOT: ${{ github.workspace }}/release-candidates
|
||||
AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
|
||||
@@ -210,10 +203,7 @@ jobs:
|
||||
|
||||
- name: Publish retained candidate without rebuilding
|
||||
shell: bash
|
||||
run: |
|
||||
args=(--tag "$RELEASE_TAG" --publish-only --local-only)
|
||||
if [ "$KEEP_OLD" = "true" ]; then args+=(--keep-old); fi
|
||||
node scripts/release/windows.mjs "${args[@]}"
|
||||
run: node scripts/release/windows.mjs --tag "$RELEASE_TAG" --publish-only --local-only
|
||||
|
||||
- name: Release summary
|
||||
shell: bash
|
||||
|
||||
+1
-1
@@ -224,7 +224,7 @@ RELEASE_REPOSITORY=owner/repo
|
||||
|
||||
publish 会上传候选产物和 fragment,更新对应平台的自动更新 metadata、官网 manifest 与固定下载地址,然后验证公开文件大小、sha512、文件名和 manifest。公开验证成功后才把候选状态标记为 `published`。
|
||||
|
||||
默认会清理该平台的旧 artifacts 与 release-status;发布时使用 `--keep-old` 可以暂时保留旧对象。
|
||||
公开验证成功后会清理该平台更早版本的 artifacts 与 release-status,R2 只保留当前最新版本。
|
||||
|
||||
### 本地保留与清理
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ const valueAfter = (name) => {
|
||||
return index >= 0 ? args[index + 1] : undefined
|
||||
}
|
||||
const releaseTag = valueAfter('--tag') || ''
|
||||
const keepOld = args.includes('--keep-old')
|
||||
const regression = readRegressionSelection(args)
|
||||
const modes = [
|
||||
['prepare', args.includes('--prepare-only')],
|
||||
@@ -45,16 +44,13 @@ try {
|
||||
}
|
||||
if (!releaseVersion || modes.length !== 1) {
|
||||
throw new Error(
|
||||
'usage: node scripts/release/macos.mjs --tag <mac-v1.2.3> (--prepare-only|--test-only|--publish-only) [--keep-old] [--domain <name>] [--suite <name>] [--group <name>] [--case <caseId>] [--fresh-knowledge-cache]'
|
||||
'usage: node scripts/release/macos.mjs --tag <mac-v1.2.3> (--prepare-only|--test-only|--publish-only) [--domain <name>] [--suite <name>] [--group <name>] [--case <caseId>] [--fresh-knowledge-cache]'
|
||||
)
|
||||
}
|
||||
const mode = modes[0][0]
|
||||
if (mode !== 'test' && hasRegressionSelectionArgs(args)) {
|
||||
throw new Error('regression selection options are only valid with --test-only')
|
||||
}
|
||||
if (mode !== 'publish' && keepOld) {
|
||||
throw new Error('--keep-old can only be combined with --publish-only')
|
||||
}
|
||||
|
||||
const run = (command, commandArgs, options = {}) =>
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -361,13 +357,11 @@ for (const candidate of candidates) {
|
||||
candidate.verified.fragmentPath
|
||||
])
|
||||
}
|
||||
const finalizeArgs = [
|
||||
await run(process.execPath, [
|
||||
path.join(ROOT, 'scripts', 'release', 'r2', 'finalize-macos.mjs'),
|
||||
'--tag',
|
||||
releaseTag
|
||||
]
|
||||
if (keepOld) finalizeArgs.push('--keep-old')
|
||||
await run(process.execPath, finalizeArgs)
|
||||
])
|
||||
for (const platform of ['macos-arm64', 'macos-x64']) {
|
||||
await markCandidatePublished({ tag: releaseTag, platform })
|
||||
}
|
||||
|
||||
@@ -15,14 +15,11 @@ const ROOT = process.cwd()
|
||||
const args = process.argv.slice(2)
|
||||
const tagIndex = args.indexOf('--tag')
|
||||
const releaseTag = tagIndex >= 0 ? args[tagIndex + 1] || '' : ''
|
||||
const keepOld = args.includes('--keep-old')
|
||||
let releaseVersion = ''
|
||||
try {
|
||||
releaseVersion = parseReleaseTag(releaseTag, 'mac').version
|
||||
} catch {
|
||||
throw new Error(
|
||||
'usage: node scripts/release/r2/finalize-macos.mjs --tag <mac-v1.2.3> [--keep-old]'
|
||||
)
|
||||
throw new Error('usage: node scripts/release/r2/finalize-macos.mjs --tag <mac-v1.2.3>')
|
||||
}
|
||||
|
||||
const { aws, bucket, publicBaseUrl, listKeys, deleteKeys } = await createR2Client(ROOT)
|
||||
@@ -180,25 +177,23 @@ try {
|
||||
}
|
||||
}
|
||||
|
||||
if (!keepOld) {
|
||||
const removable = (await listKeys('artifacts/macos/')).filter(
|
||||
(key) => !key.startsWith(`artifacts/macos/${releaseTag}/`)
|
||||
const removable = (await listKeys('artifacts/macos/')).filter(
|
||||
(key) => !key.startsWith(`artifacts/macos/${releaseTag}/`)
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/macos/')).filter(
|
||||
(key) => !key.startsWith(`release-status/macos/${releaseTag}/`)
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/macos/')).filter(
|
||||
(key) => !key.startsWith(`release-status/macos/${releaseTag}/`)
|
||||
)
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('artifacts/v')).filter((key) => /\/Ncurator-mac-[^/]+$/u.test(key))
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/v')).filter((key) =>
|
||||
/\/macos-(?:arm64|x64)\.json$/u.test(key)
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('artifacts/v')).filter((key) => /\/Ncurator-mac-[^/]+$/u.test(key))
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/v')).filter((key) =>
|
||||
/\/macos-(?:arm64|x64)\.json$/u.test(key)
|
||||
)
|
||||
)
|
||||
await deleteKeys(removable)
|
||||
}
|
||||
)
|
||||
await deleteKeys(removable)
|
||||
process.stdout.write(
|
||||
`[release] macOS ${releaseTag} is live on independent fixed download channels\n`
|
||||
)
|
||||
|
||||
@@ -12,13 +12,10 @@ const ROOT = process.cwd()
|
||||
const args = process.argv.slice(2)
|
||||
const tagIndex = args.indexOf('--tag')
|
||||
const releaseTag = tagIndex >= 0 ? args[tagIndex + 1] || '' : ''
|
||||
const keepOld = args.includes('--keep-old')
|
||||
try {
|
||||
parseReleaseTag(releaseTag, 'windows')
|
||||
} catch {
|
||||
throw new Error(
|
||||
'usage: node scripts/release/r2/finalize-windows.mjs --tag <windows-v1.2.3> [--keep-old]'
|
||||
)
|
||||
throw new Error('usage: node scripts/release/r2/finalize-windows.mjs --tag <windows-v1.2.3>')
|
||||
}
|
||||
|
||||
const { aws, bucket, publicBaseUrl, listKeys, deleteKeys } = await createR2Client(ROOT)
|
||||
@@ -165,23 +162,21 @@ try {
|
||||
throw new Error('public Windows release manifest verification failed')
|
||||
}
|
||||
|
||||
if (!keepOld) {
|
||||
const removable = (await listKeys('artifacts/windows/')).filter(
|
||||
(key) => !key.startsWith(`artifacts/windows/${releaseTag}/`)
|
||||
const removable = (await listKeys('artifacts/windows/')).filter(
|
||||
(key) => !key.startsWith(`artifacts/windows/${releaseTag}/`)
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/windows/')).filter(
|
||||
(key) => key !== statusKey(releaseTag, 'windows-x64')
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/windows/')).filter(
|
||||
(key) => key !== statusKey(releaseTag, 'windows-x64')
|
||||
)
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('artifacts/v')).filter((key) => /\/Ncurator-windows-[^/]+$/u.test(key))
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/v')).filter((key) => key.endsWith('/windows-x64.json'))
|
||||
)
|
||||
await deleteKeys(removable)
|
||||
}
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('artifacts/v')).filter((key) => /\/Ncurator-windows-[^/]+$/u.test(key))
|
||||
)
|
||||
removable.push(
|
||||
...(await listKeys('release-status/v')).filter((key) => key.endsWith('/windows-x64.json'))
|
||||
)
|
||||
await deleteKeys(removable)
|
||||
process.stdout.write(
|
||||
`[release] Windows ${releaseTag} is live at ${publicBaseUrl}/${downloadKey}\n`
|
||||
)
|
||||
|
||||
@@ -10,9 +10,7 @@ let releaseFamily = ''
|
||||
try {
|
||||
releaseFamily = parseReleaseTag(releaseTag).family
|
||||
} catch {
|
||||
throw new Error(
|
||||
'usage: node scripts/release/r2/finalize.mjs --tag <mac-v1.2.3|windows-v1.2.3> [--keep-old]'
|
||||
)
|
||||
throw new Error('usage: node scripts/release/r2/finalize.mjs --tag <mac-v1.2.3|windows-v1.2.3>')
|
||||
}
|
||||
|
||||
const run = (script) =>
|
||||
@@ -22,7 +20,6 @@ const run = (script) =>
|
||||
'--tag',
|
||||
releaseTag
|
||||
]
|
||||
if (args.includes('--keep-old')) childArgs.push('--keep-old')
|
||||
const child = spawn(process.execPath, childArgs, {
|
||||
cwd: process.cwd(),
|
||||
env: process.env,
|
||||
|
||||
@@ -193,7 +193,7 @@ export const assertWindowsReleaseRouteAvailable = async ({
|
||||
export const dispatchWindowsRelease = async (
|
||||
root,
|
||||
releaseTag,
|
||||
{ mode, candidateRunId = '', regression = {}, keepOld = false }
|
||||
{ mode, candidateRunId = '', regression = {} }
|
||||
) => {
|
||||
await loadReleaseEnvironment(root)
|
||||
const token = String(process.env.NCURATOR_ACTIONS_TOKEN || '').trim()
|
||||
@@ -219,8 +219,7 @@ export const dispatchWindowsRelease = async (
|
||||
test_suite: String(regression.suite || ''),
|
||||
test_groups: Array.isArray(regression.groups) ? regression.groups.join(',') : '',
|
||||
test_case: String(regression.caseId || ''),
|
||||
fresh_knowledge_cache: regression.freshKnowledgeCache ? 'true' : 'false',
|
||||
keep_old: keepOld ? 'true' : 'false'
|
||||
fresh_knowledge_cache: regression.freshKnowledgeCache ? 'true' : 'false'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -35,7 +35,6 @@ const releaseTag = valueAfter('--tag') || ''
|
||||
const forceLocal = args.includes('--local-only')
|
||||
const forceActions = args.includes('--actions')
|
||||
const candidateRunId = valueAfter('--candidate-run-id') || ''
|
||||
const keepOld = args.includes('--keep-old')
|
||||
const regression = readRegressionSelection(args)
|
||||
const modes = [
|
||||
['prepare', args.includes('--prepare-only')],
|
||||
@@ -51,7 +50,7 @@ try {
|
||||
}
|
||||
if (!releaseVersion || modes.length !== 1) {
|
||||
throw new Error(
|
||||
'usage: node scripts/release/windows.mjs --tag <windows-v1.2.3> (--prepare-only|--test-only|--publish-only) [--local-only|--actions] [--candidate-run-id <id>] [--keep-old] [--domain <name>] [--suite <name>] [--group <name>] [--case <caseId>] [--fresh-knowledge-cache]'
|
||||
'usage: node scripts/release/windows.mjs --tag <windows-v1.2.3> (--prepare-only|--test-only|--publish-only) [--local-only|--actions] [--candidate-run-id <id>] [--domain <name>] [--suite <name>] [--group <name>] [--case <caseId>] [--fresh-knowledge-cache]'
|
||||
)
|
||||
}
|
||||
if (forceLocal && forceActions) throw new Error('--local-only and --actions cannot be combined')
|
||||
@@ -59,9 +58,6 @@ const mode = modes[0][0]
|
||||
if (mode !== 'test' && hasRegressionSelectionArgs(args)) {
|
||||
throw new Error('regression selection options are only valid with --test-only')
|
||||
}
|
||||
if (mode !== 'publish' && keepOld) {
|
||||
throw new Error('--keep-old can only be combined with --publish-only')
|
||||
}
|
||||
if (candidateRunId && !['test', 'publish'].includes(mode)) {
|
||||
throw new Error('--candidate-run-id is only valid for Actions test-only or publish-only')
|
||||
}
|
||||
@@ -99,8 +95,7 @@ if (route === 'actions') {
|
||||
await dispatchWindowsRelease(ROOT, releaseTag, {
|
||||
mode,
|
||||
candidateRunId,
|
||||
regression: regression.state,
|
||||
keepOld
|
||||
regression: regression.state
|
||||
})
|
||||
process.exit(0)
|
||||
}
|
||||
@@ -319,13 +314,11 @@ await run(
|
||||
],
|
||||
{ cwd: ROOT, env: process.env }
|
||||
)
|
||||
const finalizeArgs = [
|
||||
path.join(ROOT, 'scripts', 'release', 'r2', 'finalize-windows.mjs'),
|
||||
'--tag',
|
||||
releaseTag
|
||||
]
|
||||
if (keepOld) finalizeArgs.push('--keep-old')
|
||||
await run(process.execPath, finalizeArgs, { cwd: ROOT, env: process.env })
|
||||
await run(
|
||||
process.execPath,
|
||||
[path.join(ROOT, 'scripts', 'release', 'r2', 'finalize-windows.mjs'), '--tag', releaseTag],
|
||||
{ cwd: ROOT, env: process.env }
|
||||
)
|
||||
await verifyPublicReleaseFragment(candidate.verified.fragment, publicBaseUrl)
|
||||
await verifyR2ReleaseFragment(candidate.verified.fragment, inspection.awsExecutable)
|
||||
await markCandidatePublished({ tag: releaseTag, platform: 'windows-x64' })
|
||||
|
||||
@@ -59,7 +59,7 @@ describe('app update publish config', () => {
|
||||
expect(workflow).toContain('- test')
|
||||
expect(workflow).toContain('candidate_run_id:')
|
||||
expect(workflow).toContain('test_domain:')
|
||||
expect(workflow).toContain('keep_old:')
|
||||
expect(workflow).not.toContain('keep_old:')
|
||||
expect(workflow).toContain('test-windows:')
|
||||
expect(workflow).toContain('actions/upload-artifact@v4')
|
||||
expect(workflow).toContain('actions/download-artifact@v4')
|
||||
@@ -69,7 +69,7 @@ describe('app update publish config', () => {
|
||||
expect(windowsRelease).toContain("route === 'actions'")
|
||||
expect(windowsRelease).not.toContain('--package-e2e')
|
||||
expect(windowsRelease).toContain('readRegressionSelection')
|
||||
expect(windowsRelease).toContain("finalizeArgs.push('--keep-old')")
|
||||
expect(windowsRelease).not.toContain('--keep-old')
|
||||
expect(windowsRelease).toContain('--prepare-only')
|
||||
expect(windowsRelease).toContain('--test-only')
|
||||
expect(windowsRelease).toContain('--publish-only')
|
||||
@@ -99,6 +99,8 @@ describe('app update publish config', () => {
|
||||
expect(windowsFinalize).not.toContain('releases/latest/macos.json')
|
||||
expect(macFinalize).toContain('releases/latest/macos.json')
|
||||
expect(macFinalize).not.toContain('releases/latest/windows.json')
|
||||
expect(windowsFinalize).not.toContain('--keep-old')
|
||||
expect(macFinalize).not.toContain('--keep-old')
|
||||
expect(tagContract).toContain('/^(mac|windows)-v')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user