@dbx-tools/projen 0.9.19 → 0.9.21
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/._LICENSE +0 -0
- package/._README.md +0 -0
- package/._index.ts +0 -0
- package/._package.json +0 -0
- package/README.md +67 -83
- package/index.ts +2 -7
- package/package.json +9 -5
- package/src/.__lazy-require.ts +0 -0
- package/src/.__release-platform.ts +0 -0
- package/src/.__rust-project.ts +0 -0
- package/src/.__rust-release-workflow.ts +0 -0
- package/src/.__task-command.ts +0 -0
- package/src/._barrels.ts +0 -0
- package/src/._bun-app.ts +0 -0
- package/src/._bun-workflow.ts +0 -0
- package/src/._clean.ts +0 -0
- package/src/._codegen.ts +0 -0
- package/src/._dbx-tools-config.ts +0 -0
- package/src/._engine-root.ts +0 -0
- package/src/._generated.ts +0 -0
- package/src/._mixin.ts +0 -0
- package/src/._module-exports.ts +0 -0
- package/src/._openapi.ts +0 -0
- package/src/._packages.ts +0 -0
- package/src/._pnpm-workspace.ts +0 -0
- package/src/._project-js.ts +0 -0
- package/src/._project-predicate.ts +0 -0
- package/src/._project-py.ts +0 -0
- package/src/._project-rs.ts +0 -0
- package/src/._project.ts +0 -0
- package/src/._projen-version.ts +0 -0
- package/src/._publish.ts +0 -0
- package/src/._release-catalog.ts +0 -0
- package/src/._release-dispatch.ts +0 -0
- package/src/._release-github.ts +0 -0
- package/src/._release.ts +0 -0
- package/src/._scaffold.ts +0 -0
- package/src/._tags.ts +0 -0
- package/src/._tsconfig.ts +0 -0
- package/src/._uniffi.ts +0 -0
- package/src/._vscode.ts +0 -0
- package/src/._watch.ts +0 -0
- package/src/._workspace-lock.ts +0 -0
- package/src/._workspace-version.ts +0 -0
- package/src/_rust-release-workflow.ts +4 -391
- package/src/_task-command.ts +75 -0
- package/src/project-js.ts +2 -42
- package/src/project-py.ts +5 -96
- package/src/project-rs.ts +3 -76
- package/src/release-catalog.ts +37 -203
- package/src/release.ts +12 -634
- package/src/scaffold.ts +2 -6
- package/src/workspace-version.ts +9 -121
- package/tasks/._barrels.ts +0 -0
- package/tasks/._bump.ts +0 -0
- package/tasks/._clean.ts +0 -0
- package/tasks/._compile-workspace.ts +0 -0
- package/tasks/._local-publish.ts +0 -0
- package/tasks/._openapi.ts +0 -0
- package/tasks/._projenrc.ts +0 -0
- package/tasks/._publish-npm.ts +0 -0
- package/tasks/._publish-python.ts +0 -0
- package/tasks/._publish-uniffi-local.ts +0 -0
- package/tasks/._publish.ts +0 -0
- package/tasks/._python-registry.ts +0 -0
- package/tasks/._release-assets.ts +0 -0
- package/tasks/._release-candidate.ts +0 -0
- package/tasks/._release-manifest.ts +0 -0
- package/tasks/._release-pr.ts +0 -0
- package/tasks/._release-summary.ts +0 -0
- package/tasks/._release-version.ts +0 -0
- package/tasks/._rust.ts +0 -0
- package/tasks/._sync.ts +0 -0
- package/tasks/._uniffi-python.d.ts +0 -0
- package/tasks/._uniffi-python.js +0 -0
- package/tasks/._uniffi-release.mjs +0 -0
- package/tasks/._uniffi.ts +0 -0
- package/tasks/._version-check.ts +0 -0
- package/tasks/bump.ts +17 -34
- package/tasks/local-publish.ts +124 -117
- package/tasks/publish-npm.ts +62 -30
- package/tasks/publish-python.ts +38 -140
- package/tasks/publish-uniffi-local.ts +129 -84
- package/tasks/publish.ts +25 -139
- package/tasks/python-registry.ts +2 -9
- package/tasks/release-assets.ts +56 -65
- package/tasks/release-candidate.ts +123 -90
- package/tasks/release-pr.ts +266 -240
- package/tasks/release-summary.ts +8 -10
- package/tasks/release-version.ts +23 -2
- package/tasks/rust.ts +8 -13
- package/tasks/uniffi-python.d.ts +2 -3
- package/tasks/uniffi-python.js +7 -20
- package/tasks/uniffi-release.mjs +19 -13
- package/tasks/uniffi.ts +15 -24
- package/tasks/version-check.ts +24 -56
- package/src/release-plan.ts +0 -269
- package/src/release-please.ts +0 -242
- package/tasks/release-bootstrap.ts +0 -59
- package/tasks/release-plan.ts +0 -89
- package/tasks/release-please.ts +0 -162
- package/tasks/release-request.ts +0 -166
- package/tasks/release-summary-units.ts +0 -75
- package/tasks/stamp-python.ts +0 -13
package/src/release.ts
CHANGED
|
@@ -16,11 +16,11 @@ import {
|
|
|
16
16
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
17
17
|
|
|
18
18
|
const NODE_VERSION = "24";
|
|
19
|
+
const NPM_VERSION = "11.4.2";
|
|
19
20
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
20
21
|
const nodeReleaseProjects = new WeakSet<DBXToolsJavaScriptProject>();
|
|
21
22
|
const releaseTagPrefixes = new WeakMap<DBXToolsJavaScriptProject, string>();
|
|
22
23
|
const releaseWorkflows = new WeakMap<DBXToolsJavaScriptProject, GithubWorkflow>();
|
|
23
|
-
const independentPublicationJobs = new WeakMap<GithubWorkflow, Set<string>>();
|
|
24
24
|
|
|
25
25
|
/** Independently recoverable portions of the release workflow. */
|
|
26
26
|
export type ReleaseStage = "all" | "node" | "python" | "cargo" | "docs";
|
|
@@ -57,14 +57,8 @@ export interface DBXToolsReleaseOptions {
|
|
|
57
57
|
readonly docs?: ReleaseDocsOptions;
|
|
58
58
|
/** Python package root passed to local release preparation. */
|
|
59
59
|
readonly pythonRoot?: string;
|
|
60
|
-
/** Repository task names run
|
|
60
|
+
/** Repository task names run after VERSION generation and before candidate construction. */
|
|
61
61
|
readonly validationTasks?: readonly string[];
|
|
62
|
-
/**
|
|
63
|
-
* Existing source branch safely fast-forwarded after publication.
|
|
64
|
-
*
|
|
65
|
-
* Missing or diverged branches are left untouched.
|
|
66
|
-
*/
|
|
67
|
-
readonly syncBranch?: string | false;
|
|
68
62
|
/**
|
|
69
63
|
* Generate a versioned release summary locally. Defaults to enabled with the
|
|
70
64
|
* standard Cursor, Codex, Claude fallback order.
|
|
@@ -84,13 +78,6 @@ export function tryReleaseWorkflow(project: DBXToolsJavaScriptProject): GithubWo
|
|
|
84
78
|
return releaseWorkflows.get(project);
|
|
85
79
|
}
|
|
86
80
|
|
|
87
|
-
/** Register one publication job for the independent release completion barrier. */
|
|
88
|
-
export function registerIndependentPublicationJob(workflow: GithubWorkflow, jobId: string): void {
|
|
89
|
-
const jobs = independentPublicationJobs.get(workflow) ?? new Set<string>();
|
|
90
|
-
jobs.add(jobId);
|
|
91
|
-
independentPublicationJobs.set(workflow, jobs);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
81
|
/** Whether the unified workflow publishes the normal npm workspace. */
|
|
95
82
|
export function hasNodeRelease(project: DBXToolsJavaScriptProject): boolean {
|
|
96
83
|
return nodeReleaseProjects.has(project);
|
|
@@ -145,14 +132,16 @@ export function nodeReleaseSetupSteps(project: DBXToolsJavaScriptProject): reado
|
|
|
145
132
|
"package-manager-cache": false,
|
|
146
133
|
},
|
|
147
134
|
},
|
|
135
|
+
{ name: "Install npm CLI", run: `npm install --global npm@${NPM_VERSION}` },
|
|
148
136
|
{ name: "Install", run: "bun install" },
|
|
149
137
|
bunCacheSaveStep(),
|
|
150
138
|
];
|
|
151
139
|
}
|
|
152
140
|
|
|
153
|
-
/**
|
|
141
|
+
/** Token authentication, GitHub provenance, and dry-run values shared by npm publishers. */
|
|
154
142
|
export function npmPublishEnvironment(): Record<string, string> {
|
|
155
143
|
return {
|
|
144
|
+
NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
156
145
|
NPM_CONFIG_PROVENANCE:
|
|
157
146
|
"${{ (github.event_name == 'release' || inputs.dry_run != true) && 'true' || 'false' }}",
|
|
158
147
|
DRY_RUN:
|
|
@@ -316,627 +305,10 @@ function addDocsJobs(
|
|
|
316
305
|
});
|
|
317
306
|
}
|
|
318
307
|
|
|
319
|
-
function independentReleasePleaseJob(project: DBXToolsJavaScriptProject, branch: string): Job {
|
|
320
|
-
return {
|
|
321
|
-
if: "${{ github.event_name == 'push' || inputs.automatic == true }}",
|
|
322
|
-
runsOn: ["ubuntu-latest"],
|
|
323
|
-
permissions: {
|
|
324
|
-
actions: JobPermission.WRITE,
|
|
325
|
-
contents: JobPermission.WRITE,
|
|
326
|
-
pullRequests: JobPermission.WRITE,
|
|
327
|
-
},
|
|
328
|
-
timeoutMinutes: 30,
|
|
329
|
-
env: { BUN_VERSION },
|
|
330
|
-
outputs: {
|
|
331
|
-
releases_created: { stepId: "release", outputName: "releases_created" },
|
|
332
|
-
prs_created: { stepId: "release", outputName: "prs_created" },
|
|
333
|
-
releases: { stepId: "release", outputName: "releases" },
|
|
334
|
-
prs: { stepId: "release", outputName: "prs" },
|
|
335
|
-
docs_changed: { stepId: "changes", outputName: "docs_changed" },
|
|
336
|
-
recovery_requested: { stepId: "recovery", outputName: "requested" },
|
|
337
|
-
recovery_component: { stepId: "recovery", outputName: "component" },
|
|
338
|
-
recovery_version: { stepId: "recovery", outputName: "version" },
|
|
339
|
-
},
|
|
340
|
-
steps: [
|
|
341
|
-
{
|
|
342
|
-
name: "Checkout source",
|
|
343
|
-
uses: "actions/checkout@v6",
|
|
344
|
-
with: { "fetch-depth": 2 },
|
|
345
|
-
},
|
|
346
|
-
...bunCacheRestoreSteps(project, {
|
|
347
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
348
|
-
}),
|
|
349
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
350
|
-
{
|
|
351
|
-
name: "Refresh Release Please state",
|
|
352
|
-
id: "release",
|
|
353
|
-
env: { GITHUB_TOKEN: "${{ github.token }}" },
|
|
354
|
-
run: [
|
|
355
|
-
'OWNER="${GITHUB_REPOSITORY%%/*}"',
|
|
356
|
-
'REPO="${GITHUB_REPOSITORY#*/}"',
|
|
357
|
-
`bun node_modules/@dbx-tools/projen/tasks/release-please.ts --owner "$OWNER" --repo "$REPO" --target-branch ${JSON.stringify(branch)}`,
|
|
358
|
-
].join("\n"),
|
|
359
|
-
},
|
|
360
|
-
{
|
|
361
|
-
name: "Detect documentation changes",
|
|
362
|
-
id: "changes",
|
|
363
|
-
shell: "bash",
|
|
364
|
-
run: [
|
|
365
|
-
"if git diff --quiet HEAD^ HEAD -- README.md AGENTS.md ':(glob)**/README.md' docs ':(exclude)docs/releases/**' ':(exclude).release-notes/**'; then",
|
|
366
|
-
' echo "docs_changed=false" >> "$GITHUB_OUTPUT"',
|
|
367
|
-
"else",
|
|
368
|
-
' echo "docs_changed=true" >> "$GITHUB_OUTPUT"',
|
|
369
|
-
"fi",
|
|
370
|
-
].join("\n"),
|
|
371
|
-
},
|
|
372
|
-
{
|
|
373
|
-
name: "Detect committed recovery request",
|
|
374
|
-
id: "recovery",
|
|
375
|
-
shell: "bash",
|
|
376
|
-
run: [
|
|
377
|
-
"if [ -f .release-recovery.json ]; then",
|
|
378
|
-
' echo "requested=true" >> "$GITHUB_OUTPUT"',
|
|
379
|
-
' echo "component=$(jq -r .component .release-recovery.json)" >> "$GITHUB_OUTPUT"',
|
|
380
|
-
' echo "version=$(jq -r .version .release-recovery.json)" >> "$GITHUB_OUTPUT"',
|
|
381
|
-
"else",
|
|
382
|
-
' echo "requested=false" >> "$GITHUB_OUTPUT"',
|
|
383
|
-
"fi",
|
|
384
|
-
].join("\n"),
|
|
385
|
-
},
|
|
386
|
-
{
|
|
387
|
-
name: "Reconcile generated release PR files",
|
|
388
|
-
if: "${{ steps.release.outputs.prs_created == 'true' }}",
|
|
389
|
-
env: {
|
|
390
|
-
GH_TOKEN: "${{ github.token }}",
|
|
391
|
-
RELEASE_BRANCH: branch,
|
|
392
|
-
RELEASE_PRS: "${{ steps.release.outputs.prs }}",
|
|
393
|
-
},
|
|
394
|
-
shell: "bash",
|
|
395
|
-
// prettier-ignore
|
|
396
|
-
run: stringUtils.dedent(
|
|
397
|
-
// ============================================================================
|
|
398
|
-
/*bash*/`
|
|
399
|
-
BRANCH="$(jq -r '.[0].headBranchName' <<<"$RELEASE_PRS")"
|
|
400
|
-
test -n "$BRANCH" && test "$BRANCH" != "null"
|
|
401
|
-
git fetch origin "$BRANCH"
|
|
402
|
-
git switch --force-create "$BRANCH" "origin/$BRANCH"
|
|
403
|
-
bun install
|
|
404
|
-
bunx projen
|
|
405
|
-
bun node_modules/@dbx-tools/projen/tasks/version-check.ts
|
|
406
|
-
bun node_modules/@dbx-tools/projen/tasks/release-plan.ts --base-ref origin/${branch}
|
|
407
|
-
bun node_modules/@dbx-tools/projen/tasks/release-summary-units.ts --from-ref origin/${branch}
|
|
408
|
-
if ! git diff --quiet || test -n "$(git ls-files --others --exclude-standard)"; then
|
|
409
|
-
git config user.name "github-actions[bot]"
|
|
410
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
411
|
-
git add -A
|
|
412
|
-
git commit -m "chore: reconcile release metadata"
|
|
413
|
-
git push origin "HEAD:$BRANCH"
|
|
414
|
-
fi
|
|
415
|
-
MERGED="false"
|
|
416
|
-
for ATTEMPT in $(seq 1 15); do
|
|
417
|
-
STATE="$(gh pr view "$BRANCH" --json state,mergeable --jq '[.state,.mergeable] | join(" ")')"
|
|
418
|
-
if [[ "$STATE" == MERGED* ]]; then MERGED="true"; break; fi
|
|
419
|
-
if [ "$STATE" = "OPEN CONFLICTING" ]; then
|
|
420
|
-
echo "::error::release pull request has merge conflicts"
|
|
421
|
-
exit 1
|
|
422
|
-
fi
|
|
423
|
-
if [ "$STATE" = "OPEN MERGEABLE" ] && gh pr merge "$BRANCH" --merge; then
|
|
424
|
-
MERGED="true"
|
|
425
|
-
break
|
|
426
|
-
fi
|
|
427
|
-
echo "release pull request is not mergeable yet (attempt $ATTEMPT/15)"
|
|
428
|
-
sleep 2
|
|
429
|
-
done
|
|
430
|
-
if [ "$MERGED" != "true" ]; then
|
|
431
|
-
echo "::error::release pull request did not become mergeable"
|
|
432
|
-
exit 1
|
|
433
|
-
fi
|
|
434
|
-
gh workflow run release.yml --ref "$RELEASE_BRANCH" -f automatic=true
|
|
435
|
-
`
|
|
436
|
-
// ============================================================================
|
|
437
|
-
),
|
|
438
|
-
},
|
|
439
|
-
],
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
function configureReleaseRequestWorkflow(
|
|
444
|
-
project: DBXToolsJavaScriptProject,
|
|
445
|
-
baseBranch: string,
|
|
446
|
-
): void {
|
|
447
|
-
if (!project.github) return;
|
|
448
|
-
const workflow = new GithubWorkflow(project.github, "release-request", {
|
|
449
|
-
fileName: "release-request.yml",
|
|
450
|
-
limitConcurrency: true,
|
|
451
|
-
concurrencyOptions: {
|
|
452
|
-
group: "release-request-${{ github.ref_name }}",
|
|
453
|
-
cancelInProgress: false,
|
|
454
|
-
},
|
|
455
|
-
});
|
|
456
|
-
workflow.runName = "release request ${{ github.ref_name }}";
|
|
457
|
-
workflow.on({ push: {} });
|
|
458
|
-
workflow.file?.addOverride("permissions.contents", "read");
|
|
459
|
-
workflow.addJob("request", {
|
|
460
|
-
if: `\${{ github.ref_name != '${baseBranch}' }}`,
|
|
461
|
-
runsOn: ["ubuntu-latest"],
|
|
462
|
-
permissions: {
|
|
463
|
-
actions: JobPermission.WRITE,
|
|
464
|
-
contents: JobPermission.WRITE,
|
|
465
|
-
pullRequests: JobPermission.WRITE,
|
|
466
|
-
},
|
|
467
|
-
steps: [
|
|
468
|
-
{
|
|
469
|
-
name: "Checkout source branch",
|
|
470
|
-
uses: "actions/checkout@v6",
|
|
471
|
-
with: { "fetch-depth": 2 },
|
|
472
|
-
},
|
|
473
|
-
{
|
|
474
|
-
name: "Read release request",
|
|
475
|
-
id: "request",
|
|
476
|
-
shell: "bash",
|
|
477
|
-
// prettier-ignore
|
|
478
|
-
run: stringUtils.dedent(
|
|
479
|
-
// ============================================================================
|
|
480
|
-
/*bash*/`
|
|
481
|
-
MESSAGE="$(git log -1 --format=%B)"
|
|
482
|
-
if ! grep -q "^Release-Request: true$" <<<"$MESSAGE"; then
|
|
483
|
-
echo "requested=false" >> "$GITHUB_OUTPUT"
|
|
484
|
-
exit 0
|
|
485
|
-
fi
|
|
486
|
-
git fetch origin ${JSON.stringify(baseBranch)}
|
|
487
|
-
if git diff --quiet "origin/${baseBranch}...HEAD"; then
|
|
488
|
-
echo "requested=false" >> "$GITHUB_OUTPUT"
|
|
489
|
-
exit 0
|
|
490
|
-
fi
|
|
491
|
-
echo "requested=true" >> "$GITHUB_OUTPUT"
|
|
492
|
-
echo "branch=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
|
|
493
|
-
echo "notes_path=$(sed -n 's/^Release-Notes-Path: //p' <<<"$MESSAGE" | tail -1)" >> "$GITHUB_OUTPUT"
|
|
494
|
-
echo "title=$(git log -1 --skip=1 --format=%s)" >> "$GITHUB_OUTPUT"
|
|
495
|
-
`
|
|
496
|
-
// ============================================================================
|
|
497
|
-
),
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
name: "Create, merge, and release source pull request",
|
|
501
|
-
if: "${{ steps.request.outputs.requested == 'true' }}",
|
|
502
|
-
env: {
|
|
503
|
-
GH_TOKEN: "${{ github.token }}",
|
|
504
|
-
SOURCE_BRANCH: "${{ steps.request.outputs.branch }}",
|
|
505
|
-
BASE_BRANCH: baseBranch,
|
|
506
|
-
TITLE: "${{ steps.request.outputs.title }}",
|
|
507
|
-
NOTES_PATH: "${{ steps.request.outputs.notes_path }}",
|
|
508
|
-
},
|
|
509
|
-
shell: "bash",
|
|
510
|
-
// prettier-ignore
|
|
511
|
-
run: stringUtils.dedent(
|
|
512
|
-
// ============================================================================
|
|
513
|
-
/*bash*/`
|
|
514
|
-
test -f "$NOTES_PATH"
|
|
515
|
-
NOTES="$(cat "$NOTES_PATH")"
|
|
516
|
-
BODY="$(printf '## Release notes\\n\\n%s\\n' "$NOTES")"
|
|
517
|
-
PR="$(gh pr list --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --state open --json number --jq '.[0].number // empty')"
|
|
518
|
-
if [ -n "$PR" ]; then
|
|
519
|
-
gh pr edit "$PR" --title "$TITLE" --body "$BODY"
|
|
520
|
-
else
|
|
521
|
-
gh pr create --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --title "$TITLE" --body "$BODY"
|
|
522
|
-
PR="$(gh pr list --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --state open --json number --jq '.[0].number')"
|
|
523
|
-
fi
|
|
524
|
-
gh pr merge "$PR" --merge
|
|
525
|
-
gh workflow run release.yml --repo "$GITHUB_REPOSITORY" --ref "$BASE_BRANCH" -f automatic=true
|
|
526
|
-
`
|
|
527
|
-
// ============================================================================
|
|
528
|
-
),
|
|
529
|
-
},
|
|
530
|
-
],
|
|
531
|
-
});
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
function independentReleasePlanJob(project: DBXToolsJavaScriptProject): Job {
|
|
535
|
-
return {
|
|
536
|
-
if: "${{ always() && ((github.event_name == 'workflow_dispatch' && inputs.automatic != true) || needs.release-please.outputs.releases_created == 'true' || (needs.release-please.outputs.docs_changed == 'true' && needs.release-please.outputs.prs_created != 'true') || needs.release-please.outputs.recovery_requested == 'true') }}",
|
|
537
|
-
needs: ["release-please"],
|
|
538
|
-
runsOn: ["ubuntu-latest"],
|
|
539
|
-
permissions: { contents: JobPermission.READ },
|
|
540
|
-
timeoutMinutes: 15,
|
|
541
|
-
env: { BUN_VERSION },
|
|
542
|
-
outputs: {
|
|
543
|
-
release_sha: { stepId: "plan", outputName: "release_sha" },
|
|
544
|
-
rust: { stepId: "plan", outputName: "rust" },
|
|
545
|
-
python: { stepId: "plan", outputName: "python" },
|
|
546
|
-
node: { stepId: "plan", outputName: "node" },
|
|
547
|
-
github: { stepId: "plan", outputName: "github" },
|
|
548
|
-
docs: { stepId: "plan", outputName: "docs" },
|
|
549
|
-
units: { stepId: "plan", outputName: "units" },
|
|
550
|
-
python_packages: { stepId: "plan", outputName: "python_packages" },
|
|
551
|
-
rust_packages: { stepId: "plan", outputName: "rust_packages" },
|
|
552
|
-
artifacts: { stepId: "plan", outputName: "artifacts" },
|
|
553
|
-
rust_targets: { stepId: "plan", outputName: "rust_targets" },
|
|
554
|
-
},
|
|
555
|
-
steps: [
|
|
556
|
-
{
|
|
557
|
-
name: "Checkout release source",
|
|
558
|
-
uses: "actions/checkout@v6",
|
|
559
|
-
with: { "fetch-depth": 2 },
|
|
560
|
-
},
|
|
561
|
-
...bunCacheRestoreSteps(project, {
|
|
562
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
563
|
-
}),
|
|
564
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
565
|
-
{
|
|
566
|
-
name: "Build affected release plan",
|
|
567
|
-
id: "plan",
|
|
568
|
-
shell: "bash",
|
|
569
|
-
env: {
|
|
570
|
-
COMPONENT:
|
|
571
|
-
"${{ inputs.component || needs.release-please.outputs.recovery_component || '' }}",
|
|
572
|
-
VERSION: "${{ inputs.version || needs.release-please.outputs.recovery_version || '' }}",
|
|
573
|
-
DOCS_CHANGED: "${{ needs.release-please.outputs.docs_changed || 'false' }}",
|
|
574
|
-
},
|
|
575
|
-
run: [
|
|
576
|
-
"ARGS=()",
|
|
577
|
-
'if [ -n "$COMPONENT" ]; then ARGS+=(--component "$COMPONENT" --version "$VERSION"); fi',
|
|
578
|
-
'if [ "$DOCS_CHANGED" = "true" ]; then ARGS+=(--docs); fi',
|
|
579
|
-
'bun node_modules/@dbx-tools/projen/tasks/release-plan.ts "${ARGS[@]}"',
|
|
580
|
-
].join("\n"),
|
|
581
|
-
},
|
|
582
|
-
{
|
|
583
|
-
name: "Upload release plan",
|
|
584
|
-
uses: "actions/upload-artifact@v7",
|
|
585
|
-
with: {
|
|
586
|
-
name: "release-plan",
|
|
587
|
-
path: "dist/release-plan.json",
|
|
588
|
-
"if-no-files-found": "error",
|
|
589
|
-
},
|
|
590
|
-
},
|
|
591
|
-
],
|
|
592
|
-
};
|
|
593
|
-
}
|
|
594
|
-
|
|
595
|
-
/** Checkout and install the immutable source selected by an independent release plan. */
|
|
596
|
-
export function independentReleaseSetupSteps(
|
|
597
|
-
project: DBXToolsJavaScriptProject,
|
|
598
|
-
): readonly JobStep[] {
|
|
599
|
-
return [
|
|
600
|
-
{
|
|
601
|
-
name: "Checkout release source",
|
|
602
|
-
uses: "actions/checkout@v6",
|
|
603
|
-
with: { ref: "${{ needs.release-plan.outputs.release_sha }}", "fetch-depth": 1 },
|
|
604
|
-
},
|
|
605
|
-
...bunCacheRestoreSteps(project, {
|
|
606
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
607
|
-
}),
|
|
608
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
609
|
-
{
|
|
610
|
-
name: "Download release plan",
|
|
611
|
-
uses: "actions/download-artifact@v8",
|
|
612
|
-
with: { name: "release-plan", path: "dist" },
|
|
613
|
-
},
|
|
614
|
-
];
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
function independentNodePublishJob(project: DBXToolsJavaScriptProject): Job {
|
|
618
|
-
return {
|
|
619
|
-
if: "${{ needs.release-plan.outputs.node == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
620
|
-
needs: ["release-plan"],
|
|
621
|
-
runsOn: ["ubuntu-latest"],
|
|
622
|
-
permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
|
|
623
|
-
timeoutMinutes: 60,
|
|
624
|
-
env: { BUN_VERSION, CI: "true" },
|
|
625
|
-
steps: [
|
|
626
|
-
...independentReleaseSetupSteps(project),
|
|
627
|
-
{
|
|
628
|
-
name: "Publish affected npm packages",
|
|
629
|
-
env: npmPublishEnvironment(),
|
|
630
|
-
run: "bun node_modules/@dbx-tools/projen/tasks/publish.ts --plan dist/release-plan.json",
|
|
631
|
-
},
|
|
632
|
-
],
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
|
|
636
|
-
function independentReleaseNotesJob(project: DBXToolsJavaScriptProject): Job {
|
|
637
|
-
return {
|
|
638
|
-
if: "${{ needs.release-plan.outputs.units != '[]' }}",
|
|
639
|
-
needs: ["release-plan"],
|
|
640
|
-
runsOn: ["ubuntu-latest"],
|
|
641
|
-
permissions: { contents: JobPermission.WRITE },
|
|
642
|
-
env: { BUN_VERSION },
|
|
643
|
-
steps: [
|
|
644
|
-
...independentReleaseSetupSteps(project),
|
|
645
|
-
{
|
|
646
|
-
name: "Publish component release notes",
|
|
647
|
-
env: { GH_TOKEN: "${{ github.token }}" },
|
|
648
|
-
shell: "bash",
|
|
649
|
-
run: [
|
|
650
|
-
"jq -c '.units[]' dist/release-plan.json | while read -r UNIT; do",
|
|
651
|
-
' COMPONENT="$(jq -r .component <<<"$UNIT")"',
|
|
652
|
-
' VERSION="$(jq -r .newVersion <<<"$UNIT")"',
|
|
653
|
-
' gh release edit "$COMPONENT-v$VERSION" --notes-file ".release-notes/final/$COMPONENT-v$VERSION.md"',
|
|
654
|
-
"done",
|
|
655
|
-
].join("\n"),
|
|
656
|
-
},
|
|
657
|
-
{
|
|
658
|
-
name: "Remove consumed release notes",
|
|
659
|
-
shell: "bash",
|
|
660
|
-
// prettier-ignore
|
|
661
|
-
run: stringUtils.dedent(
|
|
662
|
-
// ============================================================================
|
|
663
|
-
/*bash*/`
|
|
664
|
-
git fetch origin ${JSON.stringify(projectReleaseBranch(project))}
|
|
665
|
-
if [ "$(git rev-parse origin/${projectReleaseBranch(project)})" != "$(git rev-parse HEAD)" ]; then
|
|
666
|
-
echo "::warning::main advanced before release-note cleanup; leaving temporary notes for the next release"
|
|
667
|
-
exit 0
|
|
668
|
-
fi
|
|
669
|
-
git rm -r --ignore-unmatch .release-notes
|
|
670
|
-
if ! git diff --cached --quiet; then
|
|
671
|
-
git config user.name "github-actions[bot]"
|
|
672
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
673
|
-
git commit -m "chore: remove consumed release notes"
|
|
674
|
-
git push origin "HEAD:${projectReleaseBranch(project)}"
|
|
675
|
-
fi
|
|
676
|
-
`
|
|
677
|
-
// ============================================================================
|
|
678
|
-
),
|
|
679
|
-
},
|
|
680
|
-
],
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
function addIndependentDocsJobs(
|
|
685
|
-
workflow: GithubWorkflow,
|
|
686
|
-
project: DBXToolsJavaScriptProject,
|
|
687
|
-
options: ReleaseDocsOptions,
|
|
688
|
-
): void {
|
|
689
|
-
workflow.addJob("build-docs", {
|
|
690
|
-
if: "${{ always() && needs['release-plan'].outputs.docs == 'true' && needs['publication-complete'].result == 'success' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'docs') }}",
|
|
691
|
-
needs: ["release-plan", "publication-complete"],
|
|
692
|
-
runsOn: ["ubuntu-latest"],
|
|
693
|
-
permissions: {
|
|
694
|
-
contents: JobPermission.READ,
|
|
695
|
-
pages: JobPermission.WRITE,
|
|
696
|
-
idToken: JobPermission.WRITE,
|
|
697
|
-
},
|
|
698
|
-
timeoutMinutes: 30,
|
|
699
|
-
env: {
|
|
700
|
-
BUN_VERSION,
|
|
701
|
-
DOCS_SITE_URL: options.siteUrl,
|
|
702
|
-
DOCS_BASE: options.base ?? "/",
|
|
703
|
-
},
|
|
704
|
-
steps: [
|
|
705
|
-
...independentReleaseSetupSteps(project),
|
|
706
|
-
...options.prepareSteps,
|
|
707
|
-
bunCacheSaveStep(),
|
|
708
|
-
...options.buildSteps,
|
|
709
|
-
{
|
|
710
|
-
name: "Upload Pages artifact",
|
|
711
|
-
uses: "actions/upload-pages-artifact@v4",
|
|
712
|
-
with: { path: options.artifactPath },
|
|
713
|
-
},
|
|
714
|
-
],
|
|
715
|
-
});
|
|
716
|
-
workflow.addJob("deploy-docs", {
|
|
717
|
-
if: "${{ always() && needs['build-docs'].result == 'success' }}",
|
|
718
|
-
needs: ["build-docs"],
|
|
719
|
-
environment: {
|
|
720
|
-
name: "github-pages",
|
|
721
|
-
url: "${{ steps.deployment.outputs.page_url }}",
|
|
722
|
-
},
|
|
723
|
-
runsOn: ["ubuntu-latest"],
|
|
724
|
-
permissions: { pages: JobPermission.WRITE, idToken: JobPermission.WRITE },
|
|
725
|
-
timeoutMinutes: 15,
|
|
726
|
-
steps: [
|
|
727
|
-
{
|
|
728
|
-
name: "Deploy to GitHub Pages",
|
|
729
|
-
id: "deployment",
|
|
730
|
-
uses: "actions/deploy-pages@v4",
|
|
731
|
-
},
|
|
732
|
-
],
|
|
733
|
-
});
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
function addIndependentBranchSyncJob(
|
|
737
|
-
workflow: GithubWorkflow,
|
|
738
|
-
project: DBXToolsJavaScriptProject,
|
|
739
|
-
branch: string,
|
|
740
|
-
): void {
|
|
741
|
-
const releaseBranch = projectReleaseBranch(project);
|
|
742
|
-
workflow.addJob("sync-release-branch", {
|
|
743
|
-
if: "${{ always() && (github.event_name == 'push' || inputs.automatic == true) && needs['publication-complete'].result == 'success' }}",
|
|
744
|
-
needs: ["publication-complete"],
|
|
745
|
-
runsOn: ["ubuntu-latest"],
|
|
746
|
-
permissions: { contents: JobPermission.WRITE },
|
|
747
|
-
env: { BUN_VERSION },
|
|
748
|
-
steps: [
|
|
749
|
-
{
|
|
750
|
-
name: "Checkout released main",
|
|
751
|
-
uses: "actions/checkout@v6",
|
|
752
|
-
with: { "fetch-depth": 0 },
|
|
753
|
-
},
|
|
754
|
-
...bunCacheRestoreSteps(project, {
|
|
755
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
756
|
-
}),
|
|
757
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
758
|
-
{
|
|
759
|
-
name: `Safely sync ${branch}`,
|
|
760
|
-
shell: "bash",
|
|
761
|
-
env: { SOURCE_BRANCH: branch, RELEASE_BRANCH: releaseBranch },
|
|
762
|
-
// prettier-ignore
|
|
763
|
-
run: stringUtils.dedent(
|
|
764
|
-
// ============================================================================
|
|
765
|
-
/*bash*/`
|
|
766
|
-
if ! git ls-remote --exit-code --heads origin "refs/heads/$SOURCE_BRANCH" >/dev/null 2>&1; then
|
|
767
|
-
echo "source branch $SOURCE_BRANCH no longer exists; nothing to sync"
|
|
768
|
-
exit 0
|
|
769
|
-
fi
|
|
770
|
-
git fetch origin "refs/heads/$SOURCE_BRANCH:refs/remotes/origin/$SOURCE_BRANCH"
|
|
771
|
-
git fetch origin "refs/heads/$RELEASE_BRANCH:refs/remotes/origin/$RELEASE_BRANCH"
|
|
772
|
-
if git merge-base --is-ancestor "origin/$SOURCE_BRANCH" "origin/$RELEASE_BRANCH"; then
|
|
773
|
-
git push origin "refs/remotes/origin/$RELEASE_BRANCH:refs/heads/$SOURCE_BRANCH"
|
|
774
|
-
elif git merge-base --is-ancestor "origin/$RELEASE_BRANCH" "origin/$SOURCE_BRANCH"; then
|
|
775
|
-
echo "source branch $SOURCE_BRANCH already contains released main"
|
|
776
|
-
else
|
|
777
|
-
git config user.name "github-actions[bot]"
|
|
778
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
779
|
-
git switch --force-create "$SOURCE_BRANCH" "origin/$SOURCE_BRANCH"
|
|
780
|
-
if git merge --no-ff --no-edit "origin/$RELEASE_BRANCH"; then
|
|
781
|
-
git push origin "HEAD:refs/heads/$SOURCE_BRANCH"
|
|
782
|
-
else
|
|
783
|
-
SAFE_GENERATED="true"
|
|
784
|
-
while IFS= read -r FILE; do
|
|
785
|
-
case "$FILE" in
|
|
786
|
-
.projen/release-units.json|.release-please-manifest.json|.release-units/*/source.json|.release-units/*/version.txt|.release-units/*/CHANGELOG.md|Cargo.lock|*/Cargo.toml|*/package.json|*/pyproject.toml|*/index.ts) ;;
|
|
787
|
-
*) SAFE_GENERATED="false" ;;
|
|
788
|
-
esac
|
|
789
|
-
done < <(git diff --name-only --diff-filter=U)
|
|
790
|
-
if [ "$SAFE_GENERATED" = "true" ] && bunx projen; then
|
|
791
|
-
git add -A
|
|
792
|
-
if [ -z "$(git diff --name-only --diff-filter=U)" ]; then
|
|
793
|
-
git commit --no-edit
|
|
794
|
-
git push origin "HEAD:refs/heads/$SOURCE_BRANCH"
|
|
795
|
-
exit 0
|
|
796
|
-
fi
|
|
797
|
-
fi
|
|
798
|
-
git merge --abort
|
|
799
|
-
echo "::warning::source branch $SOURCE_BRANCH has handwritten or unresolved conflicts with released main; leaving it untouched"
|
|
800
|
-
fi
|
|
801
|
-
fi
|
|
802
|
-
`
|
|
803
|
-
// ============================================================================
|
|
804
|
-
),
|
|
805
|
-
},
|
|
806
|
-
],
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
class IndependentReleaseFinalizer extends Component {
|
|
811
|
-
private finalized = false;
|
|
812
|
-
|
|
813
|
-
constructor(
|
|
814
|
-
project: DBXToolsJavaScriptProject,
|
|
815
|
-
private readonly workflow: GithubWorkflow,
|
|
816
|
-
private readonly docs: ReleaseDocsOptions | undefined,
|
|
817
|
-
private readonly syncBranch: string | undefined,
|
|
818
|
-
) {
|
|
819
|
-
super(project);
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
public override preSynthesize(): void {
|
|
823
|
-
if (this.finalized) return;
|
|
824
|
-
this.finalized = true;
|
|
825
|
-
const jobs = [...(independentPublicationJobs.get(this.workflow) ?? [])].sort();
|
|
826
|
-
const successful = jobs
|
|
827
|
-
.map((job) => `needs.${job}.result != 'failure' && needs.${job}.result != 'cancelled'`)
|
|
828
|
-
.join(" && ");
|
|
829
|
-
this.workflow.addJob("publication-complete", {
|
|
830
|
-
if: `\${{ always()${successful ? ` && ${successful}` : ""} }}`,
|
|
831
|
-
needs: jobs,
|
|
832
|
-
runsOn: ["ubuntu-latest"],
|
|
833
|
-
permissions: { contents: JobPermission.READ },
|
|
834
|
-
steps: [{ name: "Confirm publication stages", run: "true" }],
|
|
835
|
-
});
|
|
836
|
-
if (this.docs) {
|
|
837
|
-
addIndependentDocsJobs(this.workflow, this.project as DBXToolsJavaScriptProject, this.docs);
|
|
838
|
-
}
|
|
839
|
-
if (this.syncBranch) {
|
|
840
|
-
addIndependentBranchSyncJob(
|
|
841
|
-
this.workflow,
|
|
842
|
-
this.project as DBXToolsJavaScriptProject,
|
|
843
|
-
this.syncBranch,
|
|
844
|
-
);
|
|
845
|
-
}
|
|
846
|
-
}
|
|
847
|
-
}
|
|
848
|
-
|
|
849
|
-
function configureIndependentRelease(
|
|
850
|
-
project: DBXToolsJavaScriptProject,
|
|
851
|
-
options: DBXToolsReleaseOptions,
|
|
852
|
-
): void {
|
|
853
|
-
const branch = projectReleaseBranch(project);
|
|
854
|
-
if (options.nodeRelease !== false) nodeReleaseProjects.add(project);
|
|
855
|
-
applyTasks(project, {
|
|
856
|
-
"version:check": {
|
|
857
|
-
exec: taskScript(project, "version-check.ts"),
|
|
858
|
-
description: "Verify every package against its release unit",
|
|
859
|
-
},
|
|
860
|
-
"release:plan": {
|
|
861
|
-
exec: taskScript(project, "release-plan.ts"),
|
|
862
|
-
receiveArgs: true,
|
|
863
|
-
description: "Build the affected release plan",
|
|
864
|
-
},
|
|
865
|
-
release: {
|
|
866
|
-
exec: taskScript(project, "release-request.ts", `--base ${JSON.stringify(branch)}`),
|
|
867
|
-
receiveArgs: true,
|
|
868
|
-
description: "Commit, annotate, and push a source release request",
|
|
869
|
-
},
|
|
870
|
-
"release:refresh": {
|
|
871
|
-
exec: taskScript(project, "release-please.ts", `--target-branch ${JSON.stringify(branch)}`),
|
|
872
|
-
receiveArgs: true,
|
|
873
|
-
description: "Refresh Release Please PRs, tags, and GitHub Releases",
|
|
874
|
-
},
|
|
875
|
-
});
|
|
876
|
-
if (!project.github) return;
|
|
877
|
-
const workflow = new GithubWorkflow(project.github, "release", {
|
|
878
|
-
fileName: "release.yml",
|
|
879
|
-
limitConcurrency: true,
|
|
880
|
-
concurrencyOptions: { group: "release", cancelInProgress: false },
|
|
881
|
-
});
|
|
882
|
-
workflow.runName =
|
|
883
|
-
"release units " +
|
|
884
|
-
"${{ github.event_name == 'push' && github.sha || inputs.automatic && 'automatic' || inputs.component }}";
|
|
885
|
-
workflow.on({
|
|
886
|
-
push: { branches: [branch] },
|
|
887
|
-
workflowDispatch: {
|
|
888
|
-
inputs: {
|
|
889
|
-
automatic: {
|
|
890
|
-
description: "Continue an automatically merged Release Please pull request",
|
|
891
|
-
type: "boolean",
|
|
892
|
-
default: "false",
|
|
893
|
-
required: false,
|
|
894
|
-
},
|
|
895
|
-
component: {
|
|
896
|
-
description: "Component to recover",
|
|
897
|
-
type: "string",
|
|
898
|
-
default: "",
|
|
899
|
-
required: false,
|
|
900
|
-
},
|
|
901
|
-
version: {
|
|
902
|
-
description: "Component version to recover",
|
|
903
|
-
type: "string",
|
|
904
|
-
default: "",
|
|
905
|
-
required: false,
|
|
906
|
-
},
|
|
907
|
-
stage: {
|
|
908
|
-
description: "Publication target to recover",
|
|
909
|
-
type: "choice",
|
|
910
|
-
options: ["all", "node", "python", "rust", "github", "docs"],
|
|
911
|
-
default: "all",
|
|
912
|
-
required: true,
|
|
913
|
-
},
|
|
914
|
-
},
|
|
915
|
-
},
|
|
916
|
-
});
|
|
917
|
-
workflow.file?.addOverride("on.workflow_dispatch.inputs.automatic.default", false);
|
|
918
|
-
workflow.file?.addOverride("permissions.contents", "read");
|
|
919
|
-
workflow.addJob("release-please", independentReleasePleaseJob(project, branch));
|
|
920
|
-
workflow.addJob("release-plan", independentReleasePlanJob(project));
|
|
921
|
-
workflow.addJob("publish-release-notes", independentReleaseNotesJob(project));
|
|
922
|
-
registerIndependentPublicationJob(workflow, "publish-release-notes");
|
|
923
|
-
if (options.nodeRelease !== false) {
|
|
924
|
-
workflow.addJob("publish-node", independentNodePublishJob(project));
|
|
925
|
-
registerIndependentPublicationJob(workflow, "publish-node");
|
|
926
|
-
}
|
|
927
|
-
new IndependentReleaseFinalizer(project, workflow, options.docs, options.syncBranch || undefined);
|
|
928
|
-
configureReleaseRequestWorkflow(project, branch);
|
|
929
|
-
releaseWorkflows.set(project, workflow);
|
|
930
|
-
}
|
|
931
|
-
|
|
932
308
|
/** Owns the single release workflow and local release preparation tasks. */
|
|
933
309
|
export class DBXToolsRelease extends Component {
|
|
934
310
|
constructor(project: DBXToolsJavaScriptProject, options: DBXToolsReleaseOptions = {}) {
|
|
935
311
|
super(project);
|
|
936
|
-
if (project.releaseCatalog.mode === "independent") {
|
|
937
|
-
configureIndependentRelease(project, options);
|
|
938
|
-
return;
|
|
939
|
-
}
|
|
940
312
|
const tagPrefix = options.tagPrefix ?? "v";
|
|
941
313
|
const releaseBranch = projectReleaseBranch(project);
|
|
942
314
|
const summary = options.summary ?? true;
|
|
@@ -981,7 +353,13 @@ export class DBXToolsRelease extends Component {
|
|
|
981
353
|
"Prepare, validate, locally publish, and upload a draft release candidate",
|
|
982
354
|
},
|
|
983
355
|
"release:assets": {
|
|
984
|
-
exec: taskScript(
|
|
356
|
+
exec: taskScript(
|
|
357
|
+
project,
|
|
358
|
+
"release-candidate.ts",
|
|
359
|
+
options.pythonRoot
|
|
360
|
+
? `--python-root ${JSON.stringify(options.pythonRoot)}`
|
|
361
|
+
: undefined,
|
|
362
|
+
),
|
|
985
363
|
receiveArgs: true,
|
|
986
364
|
description: "Rebuild and upload a complete draft release candidate",
|
|
987
365
|
},
|