@dbx-tools/projen 0.9.19 → 0.9.28

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.
Files changed (56) hide show
  1. package/README.md +83 -229
  2. package/index.ts +11 -18
  3. package/package.json +9 -5
  4. package/src/_task-command.ts +75 -0
  5. package/src/barrels.ts +1 -74
  6. package/src/module-exports.ts +175 -1
  7. package/src/openapi.ts +5 -72
  8. package/src/packages.ts +45 -0
  9. package/src/project-js.ts +5 -48
  10. package/src/project-predicate.ts +1 -2
  11. package/src/project-py.ts +87 -199
  12. package/src/project.ts +2 -2
  13. package/src/python-node-bindings.ts +138 -0
  14. package/src/python-node-bundle.ts +92 -0
  15. package/src/release-catalog.ts +40 -208
  16. package/src/{release-dispatch.ts → release-context.ts} +0 -11
  17. package/src/release.ts +74 -778
  18. package/src/scaffold.ts +2 -6
  19. package/src/workspace-version.ts +9 -121
  20. package/tasks/bump.ts +17 -34
  21. package/tasks/databricks-cli-assets.ts +129 -0
  22. package/tasks/local-publish.ts +61 -138
  23. package/tasks/publish-npm.ts +71 -30
  24. package/tasks/publish-python.ts +61 -148
  25. package/tasks/publish.ts +32 -182
  26. package/tasks/python-node-bindings-watch.ts +47 -0
  27. package/tasks/python-node-bindings.ts +1017 -0
  28. package/tasks/python-registry.ts +2 -9
  29. package/tasks/python-release.ts +74 -0
  30. package/tasks/release-version.ts +23 -2
  31. package/tasks/release.ts +99 -0
  32. package/tasks/sync.ts +13 -18
  33. package/tasks/version-check.ts +13 -72
  34. package/src/_rust-project.ts +0 -429
  35. package/src/_rust-release-workflow.ts +0 -698
  36. package/src/project-rs.ts +0 -1127
  37. package/src/release-plan.ts +0 -269
  38. package/src/release-please.ts +0 -242
  39. package/src/uniffi.ts +0 -65
  40. package/tasks/publish-uniffi-local.ts +0 -314
  41. package/tasks/release-assets.ts +0 -476
  42. package/tasks/release-bootstrap.ts +0 -59
  43. package/tasks/release-candidate.ts +0 -383
  44. package/tasks/release-manifest.ts +0 -273
  45. package/tasks/release-plan.ts +0 -89
  46. package/tasks/release-please.ts +0 -162
  47. package/tasks/release-pr.ts +0 -563
  48. package/tasks/release-request.ts +0 -166
  49. package/tasks/release-summary-units.ts +0 -75
  50. package/tasks/release-summary.ts +0 -381
  51. package/tasks/rust.ts +0 -178
  52. package/tasks/stamp-python.ts +0 -13
  53. package/tasks/uniffi-python.d.ts +0 -61
  54. package/tasks/uniffi-python.js +0 -191
  55. package/tasks/uniffi-release.mjs +0 -573
  56. package/tasks/uniffi.ts +0 -271
package/src/release.ts CHANGED
@@ -6,24 +6,17 @@ import { JobPermission, type Job, type JobStep } from "projen/lib/github/workflo
6
6
  import { BUN_VERSION, bunCacheRestoreSteps, bunCacheSaveStep } from "./bun-workflow.ts";
7
7
  import { projectReleaseBranch, type DBXToolsJavaScriptProject } from "./project-js.ts";
8
8
  import { applyTasks, taskScript } from "./project.ts";
9
- import {
10
- RELEASE_SHA,
11
- RELEASE_TAG,
12
- RELEASE_VERSION,
13
- releaseSourceSteps,
14
- type ReleaseSummaryProviderName,
15
- } from "./release-dispatch.ts";
16
- import { readWorkspaceVersion } from "./workspace-version.ts";
9
+ import { RELEASE_VERSION, releaseSourceSteps } from "./release-context.ts";
17
10
 
18
11
  const NODE_VERSION = "24";
12
+ const NPM_VERSION = "11.4.2";
19
13
  const NPM_REGISTRY_URL = "https://registry.npmjs.org";
20
14
  const nodeReleaseProjects = new WeakSet<DBXToolsJavaScriptProject>();
21
15
  const releaseTagPrefixes = new WeakMap<DBXToolsJavaScriptProject, string>();
22
16
  const releaseWorkflows = new WeakMap<DBXToolsJavaScriptProject, GithubWorkflow>();
23
- const independentPublicationJobs = new WeakMap<GithubWorkflow, Set<string>>();
24
17
 
25
18
  /** Independently recoverable portions of the release workflow. */
26
- export type ReleaseStage = "all" | "node" | "python" | "cargo" | "docs";
19
+ export type ReleaseStage = "all" | "node" | "python" | "docs";
27
20
 
28
21
  /** GitHub Pages configuration included in the unified release workflow. */
29
22
  export interface ReleaseDocsOptions {
@@ -37,16 +30,6 @@ export interface ReleaseDocsOptions {
37
30
  readonly artifactPath: string;
38
31
  }
39
32
 
40
- /** Optional local AI summary generation during reviewed release preparation. */
41
- export interface ReleaseSummaryOptions {
42
- /**
43
- * Provider fallback order.
44
- *
45
- * @default ["cursor", "codex", "claude"]
46
- */
47
- readonly providers?: readonly ReleaseSummaryProviderName[];
48
- }
49
-
50
33
  /** Options for {@link DBXToolsRelease}. */
51
34
  export interface DBXToolsReleaseOptions {
52
35
  /** Git tag prefix. Defaults to `v`. */
@@ -55,21 +38,10 @@ export interface DBXToolsReleaseOptions {
55
38
  readonly nodeRelease?: boolean;
56
39
  /** Build and deploy generated documentation through GitHub Pages. */
57
40
  readonly docs?: ReleaseDocsOptions;
58
- /** Python package root passed to local release preparation. */
41
+ /** Python package root used by attached Python publication jobs. */
59
42
  readonly pythonRoot?: string;
60
- /** Repository task names run in the release worktree before expensive validation and publication. */
43
+ /** Repository task names run after VERSION verification and before publication. */
61
44
  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
- /**
69
- * Generate a versioned release summary locally. Defaults to enabled with the
70
- * standard Cursor, Codex, Claude fallback order.
71
- */
72
- readonly summary?: boolean | ReleaseSummaryOptions;
73
45
  }
74
46
 
75
47
  /** Locate the unified workflow so attached language workspaces can add jobs. */
@@ -84,13 +56,6 @@ export function tryReleaseWorkflow(project: DBXToolsJavaScriptProject): GithubWo
84
56
  return releaseWorkflows.get(project);
85
57
  }
86
58
 
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
59
  /** Whether the unified workflow publishes the normal npm workspace. */
95
60
  export function hasNodeRelease(project: DBXToolsJavaScriptProject): boolean {
96
61
  return nodeReleaseProjects.has(project);
@@ -103,32 +68,22 @@ export function releaseTagPattern(project: DBXToolsJavaScriptProject): string {
103
68
  return `${prefix}*`;
104
69
  }
105
70
 
106
- /** Run a release stage on promotion or when selected for manual recovery. */
71
+ /** Run a release stage after its prerequisite tag-build jobs succeed. */
107
72
  export function releaseStageCondition(
108
- stage: Exclude<ReleaseStage, "all">,
73
+ _stage: Exclude<ReleaseStage, "all">,
109
74
  prerequisites: readonly string[] = [],
110
75
  ): string {
111
- if (prerequisites.length === 0) {
112
- return `\${{ github.event_name == 'release' || inputs.stage == 'all' || inputs.stage == '${stage}' }}`;
113
- }
114
- const prefix = prerequisites.length
115
- ? `always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} && `
116
- : "";
117
- return `\${{ ${prefix}(github.event_name == 'release' || inputs.stage == 'all' || inputs.stage == '${stage}') }}`;
76
+ if (prerequisites.length === 0) return "${{ success() }}";
77
+ return `\${{ always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} }}`;
118
78
  }
119
79
 
120
- /** Publish a selected stage unless a manual run remains in dry-run mode. */
80
+ /** Publish a release stage after its prerequisite tag-build jobs succeed. */
121
81
  export function releasePublishCondition(
122
- stage: Exclude<ReleaseStage, "all">,
82
+ _stage: Exclude<ReleaseStage, "all">,
123
83
  prerequisites: readonly string[] = [],
124
84
  ): string {
125
- if (prerequisites.length === 0) {
126
- return `\${{ github.event_name == 'release' || (inputs.dry_run != true && (inputs.stage == 'all' || inputs.stage == '${stage}')) }}`;
127
- }
128
- const prefix = prerequisites.length
129
- ? `always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} && `
130
- : "";
131
- return `\${{ ${prefix}(github.event_name == 'release' || (inputs.dry_run != true && (inputs.stage == 'all' || inputs.stage == '${stage}'))) }}`;
85
+ if (prerequisites.length === 0) return "${{ success() }}";
86
+ return `\${{ always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} }}`;
132
87
  }
133
88
 
134
89
  /** Shared Bun, Node, cache, and install setup for Node release jobs. */
@@ -145,25 +100,59 @@ export function nodeReleaseSetupSteps(project: DBXToolsJavaScriptProject): reado
145
100
  "package-manager-cache": false,
146
101
  },
147
102
  },
103
+ { name: "Install npm CLI", run: `npm install --global npm@${NPM_VERSION}` },
148
104
  { name: "Install", run: "bun install" },
149
105
  bunCacheSaveStep(),
150
106
  ];
151
107
  }
152
108
 
153
- /** Authentication, provenance, and dry-run values shared by npm publishers. */
109
+ /** Token authentication, GitHub provenance, and dry-run values shared by npm publishers. */
154
110
  export function npmPublishEnvironment(): Record<string, string> {
155
111
  return {
156
- NPM_CONFIG_PROVENANCE:
157
- "${{ (github.event_name == 'release' || inputs.dry_run != true) && 'true' || 'false' }}",
158
- DRY_RUN:
159
- "${{ github.event_name == 'workflow_dispatch' && inputs.dry_run && '--dry-run' || '' }}",
112
+ NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
113
+ NPM_CONFIG_PROVENANCE: "true",
114
+ DRY_RUN: "",
160
115
  };
161
116
  }
162
117
 
163
- function verifyContextJob(tagPrefix: string, releaseBranch: string): Job {
118
+ /** Install uv and restore its download/build cache using Python manifests. */
119
+ export function uvSetupStep(): JobStep {
120
+ return {
121
+ name: "Setup uv",
122
+ uses: "astral-sh/setup-uv@v7",
123
+ with: {
124
+ "enable-cache": true,
125
+ "cache-dependency-glob": "**/pyproject.toml",
126
+ },
127
+ };
128
+ }
129
+
130
+ function refreshDocsRegistryDependencies(workflow: GithubWorkflow): void {
131
+ const docs = workflow.getJob("build-docs") as Job | undefined;
132
+ if (!docs) return;
133
+ const registryJobs = Object.keys(workflow.jobs).filter(
134
+ (name) => name === "publish-node" || name.startsWith("publish-pypi-"),
135
+ );
136
+ if (registryJobs.length > 0) workflow.updateJob("build-docs", { ...docs, needs: registryJobs });
137
+ }
138
+
139
+ /** Keep documentation publication behind every configured package registry. */
140
+ export function refreshReleaseDocsDependencies(project: DBXToolsJavaScriptProject): void {
141
+ const workflow = releaseWorkflows.get(project);
142
+ if (workflow) refreshDocsRegistryDependencies(workflow);
143
+ }
144
+
145
+ function verifyContextJob(
146
+ project: DBXToolsJavaScriptProject,
147
+ tagPrefix: string,
148
+ releaseBranch: string,
149
+ options: DBXToolsReleaseOptions,
150
+ ): Job {
164
151
  return {
165
152
  runsOn: ["ubuntu-latest"],
166
153
  permissions: { contents: JobPermission.READ },
154
+ timeoutMinutes: 30,
155
+ env: { BUN_VERSION, CI: "true" },
167
156
  outputs: {
168
157
  release_tag: { stepId: "release", outputName: "release_tag" },
169
158
  expected_sha: { stepId: "release", outputName: "expected_sha" },
@@ -174,24 +163,19 @@ function verifyContextJob(tagPrefix: string, releaseBranch: string): Job {
174
163
  name: "Checkout release source",
175
164
  uses: "actions/checkout@v6",
176
165
  with: {
177
- ref: "${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}",
166
+ ref: "${{ github.ref_name }}",
178
167
  "fetch-depth": 0,
179
168
  },
180
169
  },
181
- {
182
- name: "Setup Bun",
183
- uses: "oven-sh/setup-bun@v2",
184
- with: { "bun-version": BUN_VERSION },
185
- },
170
+ ...bunCacheRestoreSteps(project, { ignorePaths: project.workflowCacheIgnorePaths }),
186
171
  { name: "Install release validation dependencies", run: "bun install --frozen-lockfile" },
172
+ bunCacheSaveStep(),
187
173
  {
188
174
  name: "Verify release context",
189
175
  id: "release",
190
176
  shell: "bash",
191
177
  env: {
192
- RELEASE_TAG:
193
- "${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}",
194
- GH_TOKEN: "${{ github.token }}",
178
+ RELEASE_TAG: "${{ github.ref_name }}",
195
179
  },
196
180
  // prettier-ignore
197
181
  run: stringUtils.dedent(
@@ -205,17 +189,8 @@ function verifyContextJob(tagPrefix: string, releaseBranch: string): Job {
205
189
  test "$(git cat-file -t "$RELEASE_TAG")" = "tag"
206
190
  RELEASE_SHA="$(git rev-parse "$RELEASE_TAG^{commit}")"
207
191
  test "$(git rev-parse HEAD)" = "$RELEASE_SHA"
208
- git merge-base --is-ancestor "$RELEASE_SHA" "origin/${releaseBranch}"
192
+ test "$(git rev-parse "origin/${releaseBranch}")" = "$RELEASE_SHA"
209
193
  test "$(tr -d '\\r\\n' < VERSION)" = "$RELEASE_VERSION"
210
- test "$(gh release view "$RELEASE_TAG" --json isDraft --jq .isDraft)" = "false"
211
- rm -rf dist/release-candidate
212
- mkdir -p dist/release-candidate
213
- gh release download "$RELEASE_TAG" --dir dist/release-candidate
214
- bun node_modules/@dbx-tools/projen/tasks/release-manifest.ts verify \
215
- --directory dist/release-candidate \
216
- --tag "$RELEASE_TAG" \
217
- --sha "$RELEASE_SHA" \
218
- --version "$RELEASE_VERSION"
219
194
  echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
220
195
  echo "expected_sha=$RELEASE_SHA" >> "$GITHUB_OUTPUT"
221
196
  echo "release_version=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"
@@ -223,6 +198,10 @@ function verifyContextJob(tagPrefix: string, releaseBranch: string): Job {
223
198
  // ============================================================================
224
199
  ),
225
200
  },
201
+ ...(options.validationTasks ?? []).map((task) => ({
202
+ name: `Validate ${task}`,
203
+ run: `bun run ${task}`,
204
+ })),
226
205
  ],
227
206
  };
228
207
  }
@@ -238,26 +217,9 @@ function nodePublishJob(project: DBXToolsJavaScriptProject): Job {
238
217
  steps: [
239
218
  ...nodeReleaseSetupSteps(project),
240
219
  {
241
- name: "Download approved npm archives",
242
- env: { GH_TOKEN: "${{ github.token }}", RELEASE_SHA, RELEASE_TAG, RELEASE_VERSION },
243
- shell: "bash",
244
- run: [
245
- "rm -rf dist/release-download dist/npm-release",
246
- "mkdir -p dist/release-download",
247
- 'gh release download "$RELEASE_TAG" --pattern release-manifest.json --pattern SHA256SUMS --pattern "*.tgz" --dir dist/release-download',
248
- "bun node_modules/@dbx-tools/projen/tasks/release-manifest.ts verify \\",
249
- " --directory dist/release-download \\",
250
- ' --tag "$RELEASE_TAG" \\',
251
- ' --sha "$RELEASE_SHA" \\',
252
- ' --version "$RELEASE_VERSION" \\',
253
- " --kind npm \\",
254
- " --output dist/npm-release",
255
- ].join("\n"),
256
- },
257
- {
258
- name: "Publish approved npm archives",
220
+ name: "Publish npm workspace",
259
221
  env: { RELEASE_VERSION, ...npmPublishEnvironment() },
260
- run: 'bun node_modules/@dbx-tools/projen/tasks/publish-npm.ts --directory dist/npm-release --version "$RELEASE_VERSION" $DRY_RUN',
222
+ run: 'bun node_modules/@dbx-tools/projen/tasks/publish.ts "$RELEASE_VERSION" $DRY_RUN',
261
223
  },
262
224
  ],
263
225
  };
@@ -314,643 +276,20 @@ function addDocsJobs(
314
276
  },
315
277
  ],
316
278
  });
317
- }
318
-
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);
279
+ refreshDocsRegistryDependencies(workflow);
930
280
  }
931
281
 
932
282
  /** Owns the single release workflow and local release preparation tasks. */
933
283
  export class DBXToolsRelease extends Component {
934
284
  constructor(project: DBXToolsJavaScriptProject, options: DBXToolsReleaseOptions = {}) {
935
285
  super(project);
936
- if (project.releaseCatalog.mode === "independent") {
937
- configureIndependentRelease(project, options);
938
- return;
939
- }
940
286
  const tagPrefix = options.tagPrefix ?? "v";
941
287
  const releaseBranch = projectReleaseBranch(project);
942
- const summary = options.summary ?? true;
943
- const summaryArgs =
944
- summary === false || (typeof summary === "object" && summary.providers?.length === 0)
945
- ? ["--no-release-summary"]
946
- : typeof summary === "object" && summary.providers
947
- ? [`--release-summary-providers ${summary.providers.join(",")}`]
948
- : [];
949
288
  releaseTagPrefixes.set(project, tagPrefix);
950
289
  if (options.nodeRelease !== false) nodeReleaseProjects.add(project);
951
290
  applyTasks(project, {
952
291
  bump: {
953
- exec: taskScript(project, "bump.ts", `--prefix ${tagPrefix}`),
292
+ exec: taskScript(project, "bump.ts"),
954
293
  receiveArgs: true,
955
294
  description: "Increment VERSION and synchronize generated workspace versions",
956
295
  },
@@ -963,27 +302,11 @@ export class DBXToolsRelease extends Component {
963
302
  release: {
964
303
  exec: taskScript(
965
304
  project,
966
- "release-pr.ts",
967
- [
968
- `--prefix ${tagPrefix}`,
969
- `--base ${releaseBranch}`,
970
- ...(options.pythonRoot
971
- ? [`--python-root ${JSON.stringify(options.pythonRoot)}`]
972
- : []),
973
- ...(options.validationTasks ?? []).map(
974
- (task) => `--validate-task ${JSON.stringify(task)}`,
975
- ),
976
- ...summaryArgs,
977
- ].join(" "),
305
+ "release.ts",
306
+ `--prefix ${tagPrefix} --branch ${releaseBranch}`,
978
307
  ),
979
308
  receiveArgs: true,
980
- description:
981
- "Prepare, validate, locally publish, and upload a draft release candidate",
982
- },
983
- "release:assets": {
984
- exec: taskScript(project, "release-candidate.ts"),
985
- receiveArgs: true,
986
- description: "Rebuild and upload a complete draft release candidate",
309
+ description: "Run bump, commit it, and push an annotated release tag",
987
310
  },
988
311
  }
989
312
  : {}),
@@ -994,49 +317,22 @@ export class DBXToolsRelease extends Component {
994
317
  fileName: "release.yml",
995
318
  limitConcurrency: true,
996
319
  concurrencyOptions: {
997
- group:
998
- "release-${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}",
320
+ group: "release-${{ github.ref_name }}",
999
321
  cancelInProgress: false,
1000
322
  },
1001
323
  });
1002
- const version = readWorkspaceVersion(project.outdir);
1003
- workflow.runName =
1004
- `release ${version} ` +
1005
- "${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}";
324
+ releaseWorkflows.set(project, workflow);
325
+ workflow.runName = "release ${{ github.ref_name }}";
1006
326
  workflow.on({
1007
- release: { types: ["published"] },
1008
- workflowDispatch: {
1009
- inputs: {
1010
- release_tag: {
1011
- description: "Annotated release tag to validate",
1012
- type: "string",
1013
- required: true,
1014
- },
1015
- stage: {
1016
- description: "Published release stage to validate or recover",
1017
- type: "choice",
1018
- options: ["all", "node", "python", "cargo", "docs"],
1019
- default: "all",
1020
- required: true,
1021
- },
1022
- dry_run: {
1023
- description: "Build and validate without publishing",
1024
- type: "boolean",
1025
- default: "true",
1026
- required: true,
1027
- },
1028
- },
1029
- },
327
+ push: { tags: [`${tagPrefix}*`] },
1030
328
  });
1031
329
  workflow.file?.addOverride("permissions.contents", "read");
1032
- workflow.file?.addOverride("on.workflow_dispatch.inputs.dry_run.default", true);
1033
- workflow.addJob("verify-context", verifyContextJob(tagPrefix, releaseBranch));
330
+ workflow.addJob("verify-context", verifyContextJob(project, tagPrefix, releaseBranch, options));
1034
331
  if (options.nodeRelease !== false) {
1035
332
  workflow.addJob("publish-node", nodePublishJob(project));
1036
333
  }
1037
334
  if (options.docs) {
1038
335
  addDocsJobs(workflow, project, options.docs);
1039
336
  }
1040
- releaseWorkflows.set(project, workflow);
1041
337
  }
1042
338
  }