@dbx-tools/projen 0.9.18 → 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 +72 -88
- 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 +18 -582
- package/src/_task-command.ts +75 -0
- package/src/project-js.ts +2 -42
- package/src/project-py.ts +60 -162
- package/src/project-rs.ts +4 -100
- package/src/release-catalog.ts +37 -203
- package/src/release.ts +96 -775
- 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 +125 -41
- package/tasks/publish-python.ts +79 -106
- package/tasks/publish-uniffi-local.ts +129 -84
- package/tasks/publish.ts +44 -139
- package/tasks/python-registry.ts +2 -9
- package/tasks/release-assets.ts +56 -65
- package/tasks/release-candidate.ts +416 -0
- package/tasks/release-manifest.ts +273 -0
- package/tasks/release-pr.ts +312 -369
- 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
|
@@ -7,21 +7,23 @@ import { BUN_VERSION, bunCacheRestoreSteps, bunCacheSaveStep } from "./bun-workf
|
|
|
7
7
|
import { projectReleaseBranch, type DBXToolsJavaScriptProject } from "./project-js.ts";
|
|
8
8
|
import { applyTasks, taskScript } from "./project.ts";
|
|
9
9
|
import {
|
|
10
|
+
RELEASE_SHA,
|
|
11
|
+
RELEASE_TAG,
|
|
10
12
|
RELEASE_VERSION,
|
|
11
13
|
releaseSourceSteps,
|
|
12
14
|
type ReleaseSummaryProviderName,
|
|
13
15
|
} from "./release-dispatch.ts";
|
|
14
16
|
import { readWorkspaceVersion } from "./workspace-version.ts";
|
|
15
17
|
|
|
16
|
-
const NODE_VERSION = "
|
|
18
|
+
const NODE_VERSION = "24";
|
|
19
|
+
const NPM_VERSION = "11.4.2";
|
|
17
20
|
const NPM_REGISTRY_URL = "https://registry.npmjs.org";
|
|
18
21
|
const nodeReleaseProjects = new WeakSet<DBXToolsJavaScriptProject>();
|
|
19
22
|
const releaseTagPrefixes = new WeakMap<DBXToolsJavaScriptProject, string>();
|
|
20
23
|
const releaseWorkflows = new WeakMap<DBXToolsJavaScriptProject, GithubWorkflow>();
|
|
21
|
-
const independentPublicationJobs = new WeakMap<GithubWorkflow, Set<string>>();
|
|
22
24
|
|
|
23
25
|
/** Independently recoverable portions of the release workflow. */
|
|
24
|
-
export type ReleaseStage = "all" | "node" | "python" | "docs";
|
|
26
|
+
export type ReleaseStage = "all" | "node" | "python" | "cargo" | "docs";
|
|
25
27
|
|
|
26
28
|
/** GitHub Pages configuration included in the unified release workflow. */
|
|
27
29
|
export interface ReleaseDocsOptions {
|
|
@@ -55,14 +57,8 @@ export interface DBXToolsReleaseOptions {
|
|
|
55
57
|
readonly docs?: ReleaseDocsOptions;
|
|
56
58
|
/** Python package root passed to local release preparation. */
|
|
57
59
|
readonly pythonRoot?: string;
|
|
58
|
-
/** Repository task names run
|
|
60
|
+
/** Repository task names run after VERSION generation and before candidate construction. */
|
|
59
61
|
readonly validationTasks?: readonly string[];
|
|
60
|
-
/**
|
|
61
|
-
* Existing source branch safely fast-forwarded after publication.
|
|
62
|
-
*
|
|
63
|
-
* Missing or diverged branches are left untouched.
|
|
64
|
-
*/
|
|
65
|
-
readonly syncBranch?: string | false;
|
|
66
62
|
/**
|
|
67
63
|
* Generate a versioned release summary locally. Defaults to enabled with the
|
|
68
64
|
* standard Cursor, Codex, Claude fallback order.
|
|
@@ -82,13 +78,6 @@ export function tryReleaseWorkflow(project: DBXToolsJavaScriptProject): GithubWo
|
|
|
82
78
|
return releaseWorkflows.get(project);
|
|
83
79
|
}
|
|
84
80
|
|
|
85
|
-
/** Register one publication job for the independent release completion barrier. */
|
|
86
|
-
export function registerIndependentPublicationJob(workflow: GithubWorkflow, jobId: string): void {
|
|
87
|
-
const jobs = independentPublicationJobs.get(workflow) ?? new Set<string>();
|
|
88
|
-
jobs.add(jobId);
|
|
89
|
-
independentPublicationJobs.set(workflow, jobs);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
81
|
/** Whether the unified workflow publishes the normal npm workspace. */
|
|
93
82
|
export function hasNodeRelease(project: DBXToolsJavaScriptProject): boolean {
|
|
94
83
|
return nodeReleaseProjects.has(project);
|
|
@@ -101,48 +90,32 @@ export function releaseTagPattern(project: DBXToolsJavaScriptProject): string {
|
|
|
101
90
|
return `${prefix}*`;
|
|
102
91
|
}
|
|
103
92
|
|
|
104
|
-
/** Run a release stage on
|
|
105
|
-
export function releaseStageCondition(
|
|
106
|
-
|
|
93
|
+
/** Run a release stage on promotion or when selected for manual recovery. */
|
|
94
|
+
export function releaseStageCondition(
|
|
95
|
+
stage: Exclude<ReleaseStage, "all">,
|
|
96
|
+
prerequisites: readonly string[] = [],
|
|
97
|
+
): string {
|
|
98
|
+
if (prerequisites.length === 0) {
|
|
99
|
+
return `\${{ github.event_name == 'release' || inputs.stage == 'all' || inputs.stage == '${stage}' }}`;
|
|
100
|
+
}
|
|
101
|
+
const prefix = prerequisites.length
|
|
102
|
+
? `always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} && `
|
|
103
|
+
: "";
|
|
104
|
+
return `\${{ ${prefix}(github.event_name == 'release' || inputs.stage == 'all' || inputs.stage == '${stage}') }}`;
|
|
107
105
|
}
|
|
108
106
|
|
|
109
107
|
/** Publish a selected stage unless a manual run remains in dry-run mode. */
|
|
110
|
-
export function releasePublishCondition(
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}): readonly JobStep[] {
|
|
122
|
-
const shared = {
|
|
123
|
-
pattern: options.pattern,
|
|
124
|
-
path: options.path,
|
|
125
|
-
"merge-multiple": true,
|
|
126
|
-
};
|
|
127
|
-
return [
|
|
128
|
-
{
|
|
129
|
-
name: options.currentName,
|
|
130
|
-
if: `\${{ ${options.condition ? `${options.condition} && ` : ""}inputs.source_run_id == '' }}`,
|
|
131
|
-
uses: "actions/download-artifact@v8",
|
|
132
|
-
with: shared,
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
name: options.recoveredName,
|
|
136
|
-
if: `\${{ ${options.condition ? `${options.condition} && ` : ""}inputs.source_run_id != '' }}`,
|
|
137
|
-
uses: "actions/download-artifact@v8",
|
|
138
|
-
with: {
|
|
139
|
-
...shared,
|
|
140
|
-
"run-id": "${{ inputs.source_run_id }}",
|
|
141
|
-
"github-token": "${{ github.token }}",
|
|
142
|
-
repository: "${{ github.repository }}",
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
];
|
|
108
|
+
export function releasePublishCondition(
|
|
109
|
+
stage: Exclude<ReleaseStage, "all">,
|
|
110
|
+
prerequisites: readonly string[] = [],
|
|
111
|
+
): string {
|
|
112
|
+
if (prerequisites.length === 0) {
|
|
113
|
+
return `\${{ github.event_name == 'release' || (inputs.dry_run != true && (inputs.stage == 'all' || inputs.stage == '${stage}')) }}`;
|
|
114
|
+
}
|
|
115
|
+
const prefix = prerequisites.length
|
|
116
|
+
? `always() && ${prerequisites.map((condition) => `(${condition})`).join(" && ")} && `
|
|
117
|
+
: "";
|
|
118
|
+
return `\${{ ${prefix}(github.event_name == 'release' || (inputs.dry_run != true && (inputs.stage == 'all' || inputs.stage == '${stage}'))) }}`;
|
|
146
119
|
}
|
|
147
120
|
|
|
148
121
|
/** Shared Bun, Node, cache, and install setup for Node release jobs. */
|
|
@@ -153,20 +126,24 @@ export function nodeReleaseSetupSteps(project: DBXToolsJavaScriptProject): reado
|
|
|
153
126
|
{
|
|
154
127
|
name: "Setup Node.js",
|
|
155
128
|
uses: "actions/setup-node@v6",
|
|
156
|
-
with: {
|
|
129
|
+
with: {
|
|
130
|
+
"node-version": NODE_VERSION,
|
|
131
|
+
"registry-url": NPM_REGISTRY_URL,
|
|
132
|
+
"package-manager-cache": false,
|
|
133
|
+
},
|
|
157
134
|
},
|
|
135
|
+
{ name: "Install npm CLI", run: `npm install --global npm@${NPM_VERSION}` },
|
|
158
136
|
{ name: "Install", run: "bun install" },
|
|
159
137
|
bunCacheSaveStep(),
|
|
160
138
|
];
|
|
161
139
|
}
|
|
162
140
|
|
|
163
|
-
/**
|
|
141
|
+
/** Token authentication, GitHub provenance, and dry-run values shared by npm publishers. */
|
|
164
142
|
export function npmPublishEnvironment(): Record<string, string> {
|
|
165
143
|
return {
|
|
166
|
-
NPM_CONFIG_PROVENANCE:
|
|
167
|
-
"${{ (github.event_name == 'push' || inputs.dry_run == false) && 'true' || 'false' }}",
|
|
168
|
-
NPM_CONFIG_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
169
144
|
NODE_AUTH_TOKEN: "${{ secrets.NPM_TOKEN }}",
|
|
145
|
+
NPM_CONFIG_PROVENANCE:
|
|
146
|
+
"${{ (github.event_name == 'release' || inputs.dry_run != true) && 'true' || 'false' }}",
|
|
170
147
|
DRY_RUN:
|
|
171
148
|
"${{ github.event_name == 'workflow_dispatch' && inputs.dry_run && '--dry-run' || '' }}",
|
|
172
149
|
};
|
|
@@ -175,19 +152,18 @@ export function npmPublishEnvironment(): Record<string, string> {
|
|
|
175
152
|
function verifyContextJob(tagPrefix: string, releaseBranch: string): Job {
|
|
176
153
|
return {
|
|
177
154
|
runsOn: ["ubuntu-latest"],
|
|
178
|
-
permissions: {
|
|
155
|
+
permissions: { contents: JobPermission.READ },
|
|
179
156
|
outputs: {
|
|
180
157
|
release_tag: { stepId: "release", outputName: "release_tag" },
|
|
181
158
|
expected_sha: { stepId: "release", outputName: "expected_sha" },
|
|
182
159
|
release_version: { stepId: "release", outputName: "release_version" },
|
|
183
|
-
build_mode: { stepId: "release", outputName: "build_mode" },
|
|
184
160
|
},
|
|
185
161
|
steps: [
|
|
186
162
|
{
|
|
187
163
|
name: "Checkout release source",
|
|
188
164
|
uses: "actions/checkout@v6",
|
|
189
165
|
with: {
|
|
190
|
-
ref: "${{ github.event_name == '
|
|
166
|
+
ref: "${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}",
|
|
191
167
|
"fetch-depth": 0,
|
|
192
168
|
},
|
|
193
169
|
},
|
|
@@ -203,90 +179,39 @@ function verifyContextJob(tagPrefix: string, releaseBranch: string): Job {
|
|
|
203
179
|
shell: "bash",
|
|
204
180
|
env: {
|
|
205
181
|
RELEASE_TAG:
|
|
206
|
-
"${{ github.event_name == '
|
|
207
|
-
EXPECTED_SHA:
|
|
208
|
-
"${{ github.event_name == 'workflow_dispatch' && inputs.expected_sha || '' }}",
|
|
209
|
-
DRY_RUN: "${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false }}",
|
|
182
|
+
"${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}",
|
|
210
183
|
GH_TOKEN: "${{ github.token }}",
|
|
211
184
|
},
|
|
212
185
|
// prettier-ignore
|
|
213
186
|
run: stringUtils.dedent(
|
|
214
187
|
// ============================================================================
|
|
215
188
|
/*bash*/`
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
git tag -a "$RELEASE_TAG" "$RELEASE_SHA" -m "$RELEASE_TAG"
|
|
236
|
-
git push origin "refs/tags/$RELEASE_TAG"
|
|
237
|
-
fi
|
|
238
|
-
else
|
|
239
|
-
case "$RELEASE_TAG" in ${tagPrefix}*) ;; *) exit 1 ;; esac
|
|
240
|
-
RELEASE_VERSION="\${RELEASE_TAG#${tagPrefix}}"
|
|
241
|
-
bun node_modules/@dbx-tools/projen/tasks/release-version.ts --version "$RELEASE_VERSION"
|
|
242
|
-
git fetch --force origin "+refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG"
|
|
243
|
-
test "$(git cat-file -t "$RELEASE_TAG")" = "tag"
|
|
244
|
-
RELEASE_SHA="$(git rev-parse "$RELEASE_TAG^{commit}")"
|
|
245
|
-
test "$(git rev-parse HEAD)" = "$RELEASE_SHA"
|
|
246
|
-
test "$RELEASE_SHA" = "$EXPECTED_SHA"
|
|
247
|
-
if [ -n "\${{ inputs.source_run_id }}" ]; then
|
|
248
|
-
case "\${{ inputs.stage }}" in node|python) ;; *) exit 1 ;; esac
|
|
249
|
-
case "\${{ inputs.source_run_id }}" in *[!0-9]*|"") exit 1 ;; esac
|
|
250
|
-
fi
|
|
251
|
-
fi
|
|
252
|
-
BUILD_MODE="$(git log -1 --format=%B -- VERSION | sed -n 's/^Release-Build: //p' | tail -1)"
|
|
253
|
-
case "$BUILD_MODE" in local|remote) ;; *) BUILD_MODE="remote" ;; esac
|
|
254
|
-
if [ "$BUILD_MODE" = "local" ] && ! gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
|
|
255
|
-
gh release create "$RELEASE_TAG" --draft --title "$RELEASE_TAG" --target "$RELEASE_SHA"
|
|
256
|
-
fi
|
|
189
|
+
case "$RELEASE_TAG" in ${tagPrefix}*) ;; *) exit 1 ;; esac
|
|
190
|
+
RELEASE_VERSION="\${RELEASE_TAG#${tagPrefix}}"
|
|
191
|
+
bun node_modules/@dbx-tools/projen/tasks/release-version.ts --version "$RELEASE_VERSION"
|
|
192
|
+
git fetch --force origin "+refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG"
|
|
193
|
+
git fetch --force origin "+refs/heads/${releaseBranch}:refs/remotes/origin/${releaseBranch}"
|
|
194
|
+
test "$(git cat-file -t "$RELEASE_TAG")" = "tag"
|
|
195
|
+
RELEASE_SHA="$(git rev-parse "$RELEASE_TAG^{commit}")"
|
|
196
|
+
test "$(git rev-parse HEAD)" = "$RELEASE_SHA"
|
|
197
|
+
git merge-base --is-ancestor "$RELEASE_SHA" "origin/${releaseBranch}"
|
|
198
|
+
test "$(tr -d '\\r\\n' < VERSION)" = "$RELEASE_VERSION"
|
|
199
|
+
test "$(gh release view "$RELEASE_TAG" --json isDraft --jq .isDraft)" = "false"
|
|
200
|
+
rm -rf dist/release-candidate
|
|
201
|
+
mkdir -p dist/release-candidate
|
|
202
|
+
gh release download "$RELEASE_TAG" --dir dist/release-candidate
|
|
203
|
+
bun node_modules/@dbx-tools/projen/tasks/release-manifest.ts verify \
|
|
204
|
+
--directory dist/release-candidate \
|
|
205
|
+
--tag "$RELEASE_TAG" \
|
|
206
|
+
--sha "$RELEASE_SHA" \
|
|
207
|
+
--version "$RELEASE_VERSION"
|
|
257
208
|
echo "release_tag=$RELEASE_TAG" >> "$GITHUB_OUTPUT"
|
|
258
209
|
echo "expected_sha=$RELEASE_SHA" >> "$GITHUB_OUTPUT"
|
|
259
210
|
echo "release_version=$RELEASE_VERSION" >> "$GITHUB_OUTPUT"
|
|
260
|
-
echo "build_mode=$BUILD_MODE" >> "$GITHUB_OUTPUT"
|
|
261
211
|
`
|
|
262
212
|
// ============================================================================
|
|
263
213
|
),
|
|
264
214
|
},
|
|
265
|
-
{
|
|
266
|
-
name: "Verify source artifact run",
|
|
267
|
-
if: "${{ inputs.source_run_id != '' }}",
|
|
268
|
-
uses: "actions/github-script@v8",
|
|
269
|
-
env: {
|
|
270
|
-
EXPECTED_SHA: "${{ steps.release.outputs.expected_sha }}",
|
|
271
|
-
SOURCE_RUN_ID: "${{ inputs.source_run_id }}",
|
|
272
|
-
},
|
|
273
|
-
with: {
|
|
274
|
-
// prettier-ignore
|
|
275
|
-
script: stringUtils.dedent(
|
|
276
|
-
// ============================================================================
|
|
277
|
-
/*js*/`
|
|
278
|
-
const run = await github.rest.actions.getWorkflowRun({
|
|
279
|
-
owner: context.repo.owner,
|
|
280
|
-
repo: context.repo.repo,
|
|
281
|
-
run_id: Number(process.env.SOURCE_RUN_ID),
|
|
282
|
-
});
|
|
283
|
-
if (run.data.path !== ".github/workflows/release.yml") core.setFailed("Source run is not release.yml");
|
|
284
|
-
if (run.data.head_sha !== process.env.EXPECTED_SHA) core.setFailed("Source run commit does not match the release tag");
|
|
285
|
-
`
|
|
286
|
-
// ============================================================================
|
|
287
|
-
),
|
|
288
|
-
},
|
|
289
|
-
},
|
|
290
215
|
],
|
|
291
216
|
};
|
|
292
217
|
}
|
|
@@ -302,13 +227,27 @@ function nodePublishJob(project: DBXToolsJavaScriptProject): Job {
|
|
|
302
227
|
steps: [
|
|
303
228
|
...nodeReleaseSetupSteps(project),
|
|
304
229
|
{
|
|
305
|
-
name: "
|
|
306
|
-
env: {
|
|
230
|
+
name: "Download approved npm archives",
|
|
231
|
+
env: { GH_TOKEN: "${{ github.token }}", RELEASE_SHA, RELEASE_TAG, RELEASE_VERSION },
|
|
232
|
+
shell: "bash",
|
|
307
233
|
run: [
|
|
308
|
-
"
|
|
309
|
-
|
|
234
|
+
"rm -rf dist/release-download dist/npm-release",
|
|
235
|
+
"mkdir -p dist/release-download",
|
|
236
|
+
'gh release download "$RELEASE_TAG" --pattern release-manifest.json --pattern SHA256SUMS --pattern "*.tgz" --dir dist/release-download',
|
|
237
|
+
"bun node_modules/@dbx-tools/projen/tasks/release-manifest.ts verify \\",
|
|
238
|
+
" --directory dist/release-download \\",
|
|
239
|
+
' --tag "$RELEASE_TAG" \\',
|
|
240
|
+
' --sha "$RELEASE_SHA" \\',
|
|
241
|
+
' --version "$RELEASE_VERSION" \\',
|
|
242
|
+
" --kind npm \\",
|
|
243
|
+
" --output dist/npm-release",
|
|
310
244
|
].join("\n"),
|
|
311
245
|
},
|
|
246
|
+
{
|
|
247
|
+
name: "Publish approved npm archives",
|
|
248
|
+
env: { RELEASE_VERSION, ...npmPublishEnvironment() },
|
|
249
|
+
run: 'bun node_modules/@dbx-tools/projen/tasks/publish-npm.ts --directory dist/npm-release --version "$RELEASE_VERSION" $DRY_RUN',
|
|
250
|
+
},
|
|
312
251
|
],
|
|
313
252
|
};
|
|
314
253
|
}
|
|
@@ -366,627 +305,10 @@ function addDocsJobs(
|
|
|
366
305
|
});
|
|
367
306
|
}
|
|
368
307
|
|
|
369
|
-
function independentReleasePleaseJob(project: DBXToolsJavaScriptProject, branch: string): Job {
|
|
370
|
-
return {
|
|
371
|
-
if: "${{ github.event_name == 'push' || inputs.automatic == true }}",
|
|
372
|
-
runsOn: ["ubuntu-latest"],
|
|
373
|
-
permissions: {
|
|
374
|
-
actions: JobPermission.WRITE,
|
|
375
|
-
contents: JobPermission.WRITE,
|
|
376
|
-
pullRequests: JobPermission.WRITE,
|
|
377
|
-
},
|
|
378
|
-
timeoutMinutes: 30,
|
|
379
|
-
env: { BUN_VERSION },
|
|
380
|
-
outputs: {
|
|
381
|
-
releases_created: { stepId: "release", outputName: "releases_created" },
|
|
382
|
-
prs_created: { stepId: "release", outputName: "prs_created" },
|
|
383
|
-
releases: { stepId: "release", outputName: "releases" },
|
|
384
|
-
prs: { stepId: "release", outputName: "prs" },
|
|
385
|
-
docs_changed: { stepId: "changes", outputName: "docs_changed" },
|
|
386
|
-
recovery_requested: { stepId: "recovery", outputName: "requested" },
|
|
387
|
-
recovery_component: { stepId: "recovery", outputName: "component" },
|
|
388
|
-
recovery_version: { stepId: "recovery", outputName: "version" },
|
|
389
|
-
},
|
|
390
|
-
steps: [
|
|
391
|
-
{
|
|
392
|
-
name: "Checkout source",
|
|
393
|
-
uses: "actions/checkout@v6",
|
|
394
|
-
with: { "fetch-depth": 2 },
|
|
395
|
-
},
|
|
396
|
-
...bunCacheRestoreSteps(project, {
|
|
397
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
398
|
-
}),
|
|
399
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
400
|
-
{
|
|
401
|
-
name: "Refresh Release Please state",
|
|
402
|
-
id: "release",
|
|
403
|
-
env: { GITHUB_TOKEN: "${{ github.token }}" },
|
|
404
|
-
run: [
|
|
405
|
-
'OWNER="${GITHUB_REPOSITORY%%/*}"',
|
|
406
|
-
'REPO="${GITHUB_REPOSITORY#*/}"',
|
|
407
|
-
`bun node_modules/@dbx-tools/projen/tasks/release-please.ts --owner "$OWNER" --repo "$REPO" --target-branch ${JSON.stringify(branch)}`,
|
|
408
|
-
].join("\n"),
|
|
409
|
-
},
|
|
410
|
-
{
|
|
411
|
-
name: "Detect documentation changes",
|
|
412
|
-
id: "changes",
|
|
413
|
-
shell: "bash",
|
|
414
|
-
run: [
|
|
415
|
-
"if git diff --quiet HEAD^ HEAD -- README.md AGENTS.md ':(glob)**/README.md' docs ':(exclude)docs/releases/**' ':(exclude).release-notes/**'; then",
|
|
416
|
-
' echo "docs_changed=false" >> "$GITHUB_OUTPUT"',
|
|
417
|
-
"else",
|
|
418
|
-
' echo "docs_changed=true" >> "$GITHUB_OUTPUT"',
|
|
419
|
-
"fi",
|
|
420
|
-
].join("\n"),
|
|
421
|
-
},
|
|
422
|
-
{
|
|
423
|
-
name: "Detect committed recovery request",
|
|
424
|
-
id: "recovery",
|
|
425
|
-
shell: "bash",
|
|
426
|
-
run: [
|
|
427
|
-
"if [ -f .release-recovery.json ]; then",
|
|
428
|
-
' echo "requested=true" >> "$GITHUB_OUTPUT"',
|
|
429
|
-
' echo "component=$(jq -r .component .release-recovery.json)" >> "$GITHUB_OUTPUT"',
|
|
430
|
-
' echo "version=$(jq -r .version .release-recovery.json)" >> "$GITHUB_OUTPUT"',
|
|
431
|
-
"else",
|
|
432
|
-
' echo "requested=false" >> "$GITHUB_OUTPUT"',
|
|
433
|
-
"fi",
|
|
434
|
-
].join("\n"),
|
|
435
|
-
},
|
|
436
|
-
{
|
|
437
|
-
name: "Reconcile generated release PR files",
|
|
438
|
-
if: "${{ steps.release.outputs.prs_created == 'true' }}",
|
|
439
|
-
env: {
|
|
440
|
-
GH_TOKEN: "${{ github.token }}",
|
|
441
|
-
RELEASE_BRANCH: branch,
|
|
442
|
-
RELEASE_PRS: "${{ steps.release.outputs.prs }}",
|
|
443
|
-
},
|
|
444
|
-
shell: "bash",
|
|
445
|
-
// prettier-ignore
|
|
446
|
-
run: stringUtils.dedent(
|
|
447
|
-
// ============================================================================
|
|
448
|
-
/*bash*/`
|
|
449
|
-
BRANCH="$(jq -r '.[0].headBranchName' <<<"$RELEASE_PRS")"
|
|
450
|
-
test -n "$BRANCH" && test "$BRANCH" != "null"
|
|
451
|
-
git fetch origin "$BRANCH"
|
|
452
|
-
git switch --force-create "$BRANCH" "origin/$BRANCH"
|
|
453
|
-
bun install
|
|
454
|
-
bunx projen
|
|
455
|
-
bun node_modules/@dbx-tools/projen/tasks/version-check.ts
|
|
456
|
-
bun node_modules/@dbx-tools/projen/tasks/release-plan.ts --base-ref origin/${branch}
|
|
457
|
-
bun node_modules/@dbx-tools/projen/tasks/release-summary-units.ts --from-ref origin/${branch}
|
|
458
|
-
if ! git diff --quiet || test -n "$(git ls-files --others --exclude-standard)"; then
|
|
459
|
-
git config user.name "github-actions[bot]"
|
|
460
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
461
|
-
git add -A
|
|
462
|
-
git commit -m "chore: reconcile release metadata"
|
|
463
|
-
git push origin "HEAD:$BRANCH"
|
|
464
|
-
fi
|
|
465
|
-
MERGED="false"
|
|
466
|
-
for ATTEMPT in $(seq 1 15); do
|
|
467
|
-
STATE="$(gh pr view "$BRANCH" --json state,mergeable --jq '[.state,.mergeable] | join(" ")')"
|
|
468
|
-
if [[ "$STATE" == MERGED* ]]; then MERGED="true"; break; fi
|
|
469
|
-
if [ "$STATE" = "OPEN CONFLICTING" ]; then
|
|
470
|
-
echo "::error::release pull request has merge conflicts"
|
|
471
|
-
exit 1
|
|
472
|
-
fi
|
|
473
|
-
if [ "$STATE" = "OPEN MERGEABLE" ] && gh pr merge "$BRANCH" --merge; then
|
|
474
|
-
MERGED="true"
|
|
475
|
-
break
|
|
476
|
-
fi
|
|
477
|
-
echo "release pull request is not mergeable yet (attempt $ATTEMPT/15)"
|
|
478
|
-
sleep 2
|
|
479
|
-
done
|
|
480
|
-
if [ "$MERGED" != "true" ]; then
|
|
481
|
-
echo "::error::release pull request did not become mergeable"
|
|
482
|
-
exit 1
|
|
483
|
-
fi
|
|
484
|
-
gh workflow run release.yml --ref "$RELEASE_BRANCH" -f automatic=true
|
|
485
|
-
`
|
|
486
|
-
// ============================================================================
|
|
487
|
-
),
|
|
488
|
-
},
|
|
489
|
-
],
|
|
490
|
-
};
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
function configureReleaseRequestWorkflow(
|
|
494
|
-
project: DBXToolsJavaScriptProject,
|
|
495
|
-
baseBranch: string,
|
|
496
|
-
): void {
|
|
497
|
-
if (!project.github) return;
|
|
498
|
-
const workflow = new GithubWorkflow(project.github, "release-request", {
|
|
499
|
-
fileName: "release-request.yml",
|
|
500
|
-
limitConcurrency: true,
|
|
501
|
-
concurrencyOptions: {
|
|
502
|
-
group: "release-request-${{ github.ref_name }}",
|
|
503
|
-
cancelInProgress: false,
|
|
504
|
-
},
|
|
505
|
-
});
|
|
506
|
-
workflow.runName = "release request ${{ github.ref_name }}";
|
|
507
|
-
workflow.on({ push: {} });
|
|
508
|
-
workflow.file?.addOverride("permissions.contents", "read");
|
|
509
|
-
workflow.addJob("request", {
|
|
510
|
-
if: `\${{ github.ref_name != '${baseBranch}' }}`,
|
|
511
|
-
runsOn: ["ubuntu-latest"],
|
|
512
|
-
permissions: {
|
|
513
|
-
actions: JobPermission.WRITE,
|
|
514
|
-
contents: JobPermission.WRITE,
|
|
515
|
-
pullRequests: JobPermission.WRITE,
|
|
516
|
-
},
|
|
517
|
-
steps: [
|
|
518
|
-
{
|
|
519
|
-
name: "Checkout source branch",
|
|
520
|
-
uses: "actions/checkout@v6",
|
|
521
|
-
with: { "fetch-depth": 2 },
|
|
522
|
-
},
|
|
523
|
-
{
|
|
524
|
-
name: "Read release request",
|
|
525
|
-
id: "request",
|
|
526
|
-
shell: "bash",
|
|
527
|
-
// prettier-ignore
|
|
528
|
-
run: stringUtils.dedent(
|
|
529
|
-
// ============================================================================
|
|
530
|
-
/*bash*/`
|
|
531
|
-
MESSAGE="$(git log -1 --format=%B)"
|
|
532
|
-
if ! grep -q "^Release-Request: true$" <<<"$MESSAGE"; then
|
|
533
|
-
echo "requested=false" >> "$GITHUB_OUTPUT"
|
|
534
|
-
exit 0
|
|
535
|
-
fi
|
|
536
|
-
git fetch origin ${JSON.stringify(baseBranch)}
|
|
537
|
-
if git diff --quiet "origin/${baseBranch}...HEAD"; then
|
|
538
|
-
echo "requested=false" >> "$GITHUB_OUTPUT"
|
|
539
|
-
exit 0
|
|
540
|
-
fi
|
|
541
|
-
echo "requested=true" >> "$GITHUB_OUTPUT"
|
|
542
|
-
echo "branch=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
|
|
543
|
-
echo "notes_path=$(sed -n 's/^Release-Notes-Path: //p' <<<"$MESSAGE" | tail -1)" >> "$GITHUB_OUTPUT"
|
|
544
|
-
echo "title=$(git log -1 --skip=1 --format=%s)" >> "$GITHUB_OUTPUT"
|
|
545
|
-
`
|
|
546
|
-
// ============================================================================
|
|
547
|
-
),
|
|
548
|
-
},
|
|
549
|
-
{
|
|
550
|
-
name: "Create, merge, and release source pull request",
|
|
551
|
-
if: "${{ steps.request.outputs.requested == 'true' }}",
|
|
552
|
-
env: {
|
|
553
|
-
GH_TOKEN: "${{ github.token }}",
|
|
554
|
-
SOURCE_BRANCH: "${{ steps.request.outputs.branch }}",
|
|
555
|
-
BASE_BRANCH: baseBranch,
|
|
556
|
-
TITLE: "${{ steps.request.outputs.title }}",
|
|
557
|
-
NOTES_PATH: "${{ steps.request.outputs.notes_path }}",
|
|
558
|
-
},
|
|
559
|
-
shell: "bash",
|
|
560
|
-
// prettier-ignore
|
|
561
|
-
run: stringUtils.dedent(
|
|
562
|
-
// ============================================================================
|
|
563
|
-
/*bash*/`
|
|
564
|
-
test -f "$NOTES_PATH"
|
|
565
|
-
NOTES="$(cat "$NOTES_PATH")"
|
|
566
|
-
BODY="$(printf '## Release notes\\n\\n%s\\n' "$NOTES")"
|
|
567
|
-
PR="$(gh pr list --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --state open --json number --jq '.[0].number // empty')"
|
|
568
|
-
if [ -n "$PR" ]; then
|
|
569
|
-
gh pr edit "$PR" --title "$TITLE" --body "$BODY"
|
|
570
|
-
else
|
|
571
|
-
gh pr create --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --title "$TITLE" --body "$BODY"
|
|
572
|
-
PR="$(gh pr list --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --state open --json number --jq '.[0].number')"
|
|
573
|
-
fi
|
|
574
|
-
gh pr merge "$PR" --merge
|
|
575
|
-
gh workflow run release.yml --repo "$GITHUB_REPOSITORY" --ref "$BASE_BRANCH" -f automatic=true
|
|
576
|
-
`
|
|
577
|
-
// ============================================================================
|
|
578
|
-
),
|
|
579
|
-
},
|
|
580
|
-
],
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
function independentReleasePlanJob(project: DBXToolsJavaScriptProject): Job {
|
|
585
|
-
return {
|
|
586
|
-
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') }}",
|
|
587
|
-
needs: ["release-please"],
|
|
588
|
-
runsOn: ["ubuntu-latest"],
|
|
589
|
-
permissions: { contents: JobPermission.READ },
|
|
590
|
-
timeoutMinutes: 15,
|
|
591
|
-
env: { BUN_VERSION },
|
|
592
|
-
outputs: {
|
|
593
|
-
release_sha: { stepId: "plan", outputName: "release_sha" },
|
|
594
|
-
rust: { stepId: "plan", outputName: "rust" },
|
|
595
|
-
python: { stepId: "plan", outputName: "python" },
|
|
596
|
-
node: { stepId: "plan", outputName: "node" },
|
|
597
|
-
github: { stepId: "plan", outputName: "github" },
|
|
598
|
-
docs: { stepId: "plan", outputName: "docs" },
|
|
599
|
-
units: { stepId: "plan", outputName: "units" },
|
|
600
|
-
python_packages: { stepId: "plan", outputName: "python_packages" },
|
|
601
|
-
rust_packages: { stepId: "plan", outputName: "rust_packages" },
|
|
602
|
-
artifacts: { stepId: "plan", outputName: "artifacts" },
|
|
603
|
-
rust_targets: { stepId: "plan", outputName: "rust_targets" },
|
|
604
|
-
},
|
|
605
|
-
steps: [
|
|
606
|
-
{
|
|
607
|
-
name: "Checkout release source",
|
|
608
|
-
uses: "actions/checkout@v6",
|
|
609
|
-
with: { "fetch-depth": 2 },
|
|
610
|
-
},
|
|
611
|
-
...bunCacheRestoreSteps(project, {
|
|
612
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
613
|
-
}),
|
|
614
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
615
|
-
{
|
|
616
|
-
name: "Build affected release plan",
|
|
617
|
-
id: "plan",
|
|
618
|
-
shell: "bash",
|
|
619
|
-
env: {
|
|
620
|
-
COMPONENT:
|
|
621
|
-
"${{ inputs.component || needs.release-please.outputs.recovery_component || '' }}",
|
|
622
|
-
VERSION: "${{ inputs.version || needs.release-please.outputs.recovery_version || '' }}",
|
|
623
|
-
DOCS_CHANGED: "${{ needs.release-please.outputs.docs_changed || 'false' }}",
|
|
624
|
-
},
|
|
625
|
-
run: [
|
|
626
|
-
"ARGS=()",
|
|
627
|
-
'if [ -n "$COMPONENT" ]; then ARGS+=(--component "$COMPONENT" --version "$VERSION"); fi',
|
|
628
|
-
'if [ "$DOCS_CHANGED" = "true" ]; then ARGS+=(--docs); fi',
|
|
629
|
-
'bun node_modules/@dbx-tools/projen/tasks/release-plan.ts "${ARGS[@]}"',
|
|
630
|
-
].join("\n"),
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
name: "Upload release plan",
|
|
634
|
-
uses: "actions/upload-artifact@v7",
|
|
635
|
-
with: {
|
|
636
|
-
name: "release-plan",
|
|
637
|
-
path: "dist/release-plan.json",
|
|
638
|
-
"if-no-files-found": "error",
|
|
639
|
-
},
|
|
640
|
-
},
|
|
641
|
-
],
|
|
642
|
-
};
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
/** Checkout and install the immutable source selected by an independent release plan. */
|
|
646
|
-
export function independentReleaseSetupSteps(
|
|
647
|
-
project: DBXToolsJavaScriptProject,
|
|
648
|
-
): readonly JobStep[] {
|
|
649
|
-
return [
|
|
650
|
-
{
|
|
651
|
-
name: "Checkout release source",
|
|
652
|
-
uses: "actions/checkout@v6",
|
|
653
|
-
with: { ref: "${{ needs.release-plan.outputs.release_sha }}", "fetch-depth": 1 },
|
|
654
|
-
},
|
|
655
|
-
...bunCacheRestoreSteps(project, {
|
|
656
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
657
|
-
}),
|
|
658
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
659
|
-
{
|
|
660
|
-
name: "Download release plan",
|
|
661
|
-
uses: "actions/download-artifact@v8",
|
|
662
|
-
with: { name: "release-plan", path: "dist" },
|
|
663
|
-
},
|
|
664
|
-
];
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
function independentNodePublishJob(project: DBXToolsJavaScriptProject): Job {
|
|
668
|
-
return {
|
|
669
|
-
if: "${{ needs.release-plan.outputs.node == 'true' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'node') }}",
|
|
670
|
-
needs: ["release-plan"],
|
|
671
|
-
runsOn: ["ubuntu-latest"],
|
|
672
|
-
permissions: { contents: JobPermission.READ, idToken: JobPermission.WRITE },
|
|
673
|
-
timeoutMinutes: 60,
|
|
674
|
-
env: { BUN_VERSION, CI: "true" },
|
|
675
|
-
steps: [
|
|
676
|
-
...independentReleaseSetupSteps(project),
|
|
677
|
-
{
|
|
678
|
-
name: "Publish affected npm packages",
|
|
679
|
-
env: npmPublishEnvironment(),
|
|
680
|
-
run: "bun node_modules/@dbx-tools/projen/tasks/publish.ts --plan dist/release-plan.json",
|
|
681
|
-
},
|
|
682
|
-
],
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
function independentReleaseNotesJob(project: DBXToolsJavaScriptProject): Job {
|
|
687
|
-
return {
|
|
688
|
-
if: "${{ needs.release-plan.outputs.units != '[]' }}",
|
|
689
|
-
needs: ["release-plan"],
|
|
690
|
-
runsOn: ["ubuntu-latest"],
|
|
691
|
-
permissions: { contents: JobPermission.WRITE },
|
|
692
|
-
env: { BUN_VERSION },
|
|
693
|
-
steps: [
|
|
694
|
-
...independentReleaseSetupSteps(project),
|
|
695
|
-
{
|
|
696
|
-
name: "Publish component release notes",
|
|
697
|
-
env: { GH_TOKEN: "${{ github.token }}" },
|
|
698
|
-
shell: "bash",
|
|
699
|
-
run: [
|
|
700
|
-
"jq -c '.units[]' dist/release-plan.json | while read -r UNIT; do",
|
|
701
|
-
' COMPONENT="$(jq -r .component <<<"$UNIT")"',
|
|
702
|
-
' VERSION="$(jq -r .newVersion <<<"$UNIT")"',
|
|
703
|
-
' gh release edit "$COMPONENT-v$VERSION" --notes-file ".release-notes/final/$COMPONENT-v$VERSION.md"',
|
|
704
|
-
"done",
|
|
705
|
-
].join("\n"),
|
|
706
|
-
},
|
|
707
|
-
{
|
|
708
|
-
name: "Remove consumed release notes",
|
|
709
|
-
shell: "bash",
|
|
710
|
-
// prettier-ignore
|
|
711
|
-
run: stringUtils.dedent(
|
|
712
|
-
// ============================================================================
|
|
713
|
-
/*bash*/`
|
|
714
|
-
git fetch origin ${JSON.stringify(projectReleaseBranch(project))}
|
|
715
|
-
if [ "$(git rev-parse origin/${projectReleaseBranch(project)})" != "$(git rev-parse HEAD)" ]; then
|
|
716
|
-
echo "::warning::main advanced before release-note cleanup; leaving temporary notes for the next release"
|
|
717
|
-
exit 0
|
|
718
|
-
fi
|
|
719
|
-
git rm -r --ignore-unmatch .release-notes
|
|
720
|
-
if ! git diff --cached --quiet; then
|
|
721
|
-
git config user.name "github-actions[bot]"
|
|
722
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
723
|
-
git commit -m "chore: remove consumed release notes"
|
|
724
|
-
git push origin "HEAD:${projectReleaseBranch(project)}"
|
|
725
|
-
fi
|
|
726
|
-
`
|
|
727
|
-
// ============================================================================
|
|
728
|
-
),
|
|
729
|
-
},
|
|
730
|
-
],
|
|
731
|
-
};
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
function addIndependentDocsJobs(
|
|
735
|
-
workflow: GithubWorkflow,
|
|
736
|
-
project: DBXToolsJavaScriptProject,
|
|
737
|
-
options: ReleaseDocsOptions,
|
|
738
|
-
): void {
|
|
739
|
-
workflow.addJob("build-docs", {
|
|
740
|
-
if: "${{ always() && needs['release-plan'].outputs.docs == 'true' && needs['publication-complete'].result == 'success' && (github.event_name == 'push' || inputs.stage == 'all' || inputs.stage == 'docs') }}",
|
|
741
|
-
needs: ["release-plan", "publication-complete"],
|
|
742
|
-
runsOn: ["ubuntu-latest"],
|
|
743
|
-
permissions: {
|
|
744
|
-
contents: JobPermission.READ,
|
|
745
|
-
pages: JobPermission.WRITE,
|
|
746
|
-
idToken: JobPermission.WRITE,
|
|
747
|
-
},
|
|
748
|
-
timeoutMinutes: 30,
|
|
749
|
-
env: {
|
|
750
|
-
BUN_VERSION,
|
|
751
|
-
DOCS_SITE_URL: options.siteUrl,
|
|
752
|
-
DOCS_BASE: options.base ?? "/",
|
|
753
|
-
},
|
|
754
|
-
steps: [
|
|
755
|
-
...independentReleaseSetupSteps(project),
|
|
756
|
-
...options.prepareSteps,
|
|
757
|
-
bunCacheSaveStep(),
|
|
758
|
-
...options.buildSteps,
|
|
759
|
-
{
|
|
760
|
-
name: "Upload Pages artifact",
|
|
761
|
-
uses: "actions/upload-pages-artifact@v4",
|
|
762
|
-
with: { path: options.artifactPath },
|
|
763
|
-
},
|
|
764
|
-
],
|
|
765
|
-
});
|
|
766
|
-
workflow.addJob("deploy-docs", {
|
|
767
|
-
if: "${{ always() && needs['build-docs'].result == 'success' }}",
|
|
768
|
-
needs: ["build-docs"],
|
|
769
|
-
environment: {
|
|
770
|
-
name: "github-pages",
|
|
771
|
-
url: "${{ steps.deployment.outputs.page_url }}",
|
|
772
|
-
},
|
|
773
|
-
runsOn: ["ubuntu-latest"],
|
|
774
|
-
permissions: { pages: JobPermission.WRITE, idToken: JobPermission.WRITE },
|
|
775
|
-
timeoutMinutes: 15,
|
|
776
|
-
steps: [
|
|
777
|
-
{
|
|
778
|
-
name: "Deploy to GitHub Pages",
|
|
779
|
-
id: "deployment",
|
|
780
|
-
uses: "actions/deploy-pages@v4",
|
|
781
|
-
},
|
|
782
|
-
],
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
|
|
786
|
-
function addIndependentBranchSyncJob(
|
|
787
|
-
workflow: GithubWorkflow,
|
|
788
|
-
project: DBXToolsJavaScriptProject,
|
|
789
|
-
branch: string,
|
|
790
|
-
): void {
|
|
791
|
-
const releaseBranch = projectReleaseBranch(project);
|
|
792
|
-
workflow.addJob("sync-release-branch", {
|
|
793
|
-
if: "${{ always() && (github.event_name == 'push' || inputs.automatic == true) && needs['publication-complete'].result == 'success' }}",
|
|
794
|
-
needs: ["publication-complete"],
|
|
795
|
-
runsOn: ["ubuntu-latest"],
|
|
796
|
-
permissions: { contents: JobPermission.WRITE },
|
|
797
|
-
env: { BUN_VERSION },
|
|
798
|
-
steps: [
|
|
799
|
-
{
|
|
800
|
-
name: "Checkout released main",
|
|
801
|
-
uses: "actions/checkout@v6",
|
|
802
|
-
with: { "fetch-depth": 0 },
|
|
803
|
-
},
|
|
804
|
-
...bunCacheRestoreSteps(project, {
|
|
805
|
-
ignorePaths: project.workflowCacheIgnorePaths,
|
|
806
|
-
}),
|
|
807
|
-
{ name: "Install dependencies", run: "bun install" },
|
|
808
|
-
{
|
|
809
|
-
name: `Safely sync ${branch}`,
|
|
810
|
-
shell: "bash",
|
|
811
|
-
env: { SOURCE_BRANCH: branch, RELEASE_BRANCH: releaseBranch },
|
|
812
|
-
// prettier-ignore
|
|
813
|
-
run: stringUtils.dedent(
|
|
814
|
-
// ============================================================================
|
|
815
|
-
/*bash*/`
|
|
816
|
-
if ! git ls-remote --exit-code --heads origin "refs/heads/$SOURCE_BRANCH" >/dev/null 2>&1; then
|
|
817
|
-
echo "source branch $SOURCE_BRANCH no longer exists; nothing to sync"
|
|
818
|
-
exit 0
|
|
819
|
-
fi
|
|
820
|
-
git fetch origin "refs/heads/$SOURCE_BRANCH:refs/remotes/origin/$SOURCE_BRANCH"
|
|
821
|
-
git fetch origin "refs/heads/$RELEASE_BRANCH:refs/remotes/origin/$RELEASE_BRANCH"
|
|
822
|
-
if git merge-base --is-ancestor "origin/$SOURCE_BRANCH" "origin/$RELEASE_BRANCH"; then
|
|
823
|
-
git push origin "refs/remotes/origin/$RELEASE_BRANCH:refs/heads/$SOURCE_BRANCH"
|
|
824
|
-
elif git merge-base --is-ancestor "origin/$RELEASE_BRANCH" "origin/$SOURCE_BRANCH"; then
|
|
825
|
-
echo "source branch $SOURCE_BRANCH already contains released main"
|
|
826
|
-
else
|
|
827
|
-
git config user.name "github-actions[bot]"
|
|
828
|
-
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
829
|
-
git switch --force-create "$SOURCE_BRANCH" "origin/$SOURCE_BRANCH"
|
|
830
|
-
if git merge --no-ff --no-edit "origin/$RELEASE_BRANCH"; then
|
|
831
|
-
git push origin "HEAD:refs/heads/$SOURCE_BRANCH"
|
|
832
|
-
else
|
|
833
|
-
SAFE_GENERATED="true"
|
|
834
|
-
while IFS= read -r FILE; do
|
|
835
|
-
case "$FILE" in
|
|
836
|
-
.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) ;;
|
|
837
|
-
*) SAFE_GENERATED="false" ;;
|
|
838
|
-
esac
|
|
839
|
-
done < <(git diff --name-only --diff-filter=U)
|
|
840
|
-
if [ "$SAFE_GENERATED" = "true" ] && bunx projen; then
|
|
841
|
-
git add -A
|
|
842
|
-
if [ -z "$(git diff --name-only --diff-filter=U)" ]; then
|
|
843
|
-
git commit --no-edit
|
|
844
|
-
git push origin "HEAD:refs/heads/$SOURCE_BRANCH"
|
|
845
|
-
exit 0
|
|
846
|
-
fi
|
|
847
|
-
fi
|
|
848
|
-
git merge --abort
|
|
849
|
-
echo "::warning::source branch $SOURCE_BRANCH has handwritten or unresolved conflicts with released main; leaving it untouched"
|
|
850
|
-
fi
|
|
851
|
-
fi
|
|
852
|
-
`
|
|
853
|
-
// ============================================================================
|
|
854
|
-
),
|
|
855
|
-
},
|
|
856
|
-
],
|
|
857
|
-
});
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
class IndependentReleaseFinalizer extends Component {
|
|
861
|
-
private finalized = false;
|
|
862
|
-
|
|
863
|
-
constructor(
|
|
864
|
-
project: DBXToolsJavaScriptProject,
|
|
865
|
-
private readonly workflow: GithubWorkflow,
|
|
866
|
-
private readonly docs: ReleaseDocsOptions | undefined,
|
|
867
|
-
private readonly syncBranch: string | undefined,
|
|
868
|
-
) {
|
|
869
|
-
super(project);
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
public override preSynthesize(): void {
|
|
873
|
-
if (this.finalized) return;
|
|
874
|
-
this.finalized = true;
|
|
875
|
-
const jobs = [...(independentPublicationJobs.get(this.workflow) ?? [])].sort();
|
|
876
|
-
const successful = jobs
|
|
877
|
-
.map((job) => `needs.${job}.result != 'failure' && needs.${job}.result != 'cancelled'`)
|
|
878
|
-
.join(" && ");
|
|
879
|
-
this.workflow.addJob("publication-complete", {
|
|
880
|
-
if: `\${{ always()${successful ? ` && ${successful}` : ""} }}`,
|
|
881
|
-
needs: jobs,
|
|
882
|
-
runsOn: ["ubuntu-latest"],
|
|
883
|
-
permissions: { contents: JobPermission.READ },
|
|
884
|
-
steps: [{ name: "Confirm publication stages", run: "true" }],
|
|
885
|
-
});
|
|
886
|
-
if (this.docs) {
|
|
887
|
-
addIndependentDocsJobs(this.workflow, this.project as DBXToolsJavaScriptProject, this.docs);
|
|
888
|
-
}
|
|
889
|
-
if (this.syncBranch) {
|
|
890
|
-
addIndependentBranchSyncJob(
|
|
891
|
-
this.workflow,
|
|
892
|
-
this.project as DBXToolsJavaScriptProject,
|
|
893
|
-
this.syncBranch,
|
|
894
|
-
);
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
function configureIndependentRelease(
|
|
900
|
-
project: DBXToolsJavaScriptProject,
|
|
901
|
-
options: DBXToolsReleaseOptions,
|
|
902
|
-
): void {
|
|
903
|
-
const branch = projectReleaseBranch(project);
|
|
904
|
-
if (options.nodeRelease !== false) nodeReleaseProjects.add(project);
|
|
905
|
-
applyTasks(project, {
|
|
906
|
-
"version:check": {
|
|
907
|
-
exec: taskScript(project, "version-check.ts"),
|
|
908
|
-
description: "Verify every package against its release unit",
|
|
909
|
-
},
|
|
910
|
-
"release:plan": {
|
|
911
|
-
exec: taskScript(project, "release-plan.ts"),
|
|
912
|
-
receiveArgs: true,
|
|
913
|
-
description: "Build the affected release plan",
|
|
914
|
-
},
|
|
915
|
-
release: {
|
|
916
|
-
exec: taskScript(project, "release-request.ts", `--base ${JSON.stringify(branch)}`),
|
|
917
|
-
receiveArgs: true,
|
|
918
|
-
description: "Commit, annotate, and push a source release request",
|
|
919
|
-
},
|
|
920
|
-
"release:refresh": {
|
|
921
|
-
exec: taskScript(project, "release-please.ts", `--target-branch ${JSON.stringify(branch)}`),
|
|
922
|
-
receiveArgs: true,
|
|
923
|
-
description: "Refresh Release Please PRs, tags, and GitHub Releases",
|
|
924
|
-
},
|
|
925
|
-
});
|
|
926
|
-
if (!project.github) return;
|
|
927
|
-
const workflow = new GithubWorkflow(project.github, "release", {
|
|
928
|
-
fileName: "release.yml",
|
|
929
|
-
limitConcurrency: true,
|
|
930
|
-
concurrencyOptions: { group: "release", cancelInProgress: false },
|
|
931
|
-
});
|
|
932
|
-
workflow.runName =
|
|
933
|
-
"release units " +
|
|
934
|
-
"${{ github.event_name == 'push' && github.sha || inputs.automatic && 'automatic' || inputs.component }}";
|
|
935
|
-
workflow.on({
|
|
936
|
-
push: { branches: [branch] },
|
|
937
|
-
workflowDispatch: {
|
|
938
|
-
inputs: {
|
|
939
|
-
automatic: {
|
|
940
|
-
description: "Continue an automatically merged Release Please pull request",
|
|
941
|
-
type: "boolean",
|
|
942
|
-
default: "false",
|
|
943
|
-
required: false,
|
|
944
|
-
},
|
|
945
|
-
component: {
|
|
946
|
-
description: "Component to recover",
|
|
947
|
-
type: "string",
|
|
948
|
-
default: "",
|
|
949
|
-
required: false,
|
|
950
|
-
},
|
|
951
|
-
version: {
|
|
952
|
-
description: "Component version to recover",
|
|
953
|
-
type: "string",
|
|
954
|
-
default: "",
|
|
955
|
-
required: false,
|
|
956
|
-
},
|
|
957
|
-
stage: {
|
|
958
|
-
description: "Publication target to recover",
|
|
959
|
-
type: "choice",
|
|
960
|
-
options: ["all", "node", "python", "rust", "github", "docs"],
|
|
961
|
-
default: "all",
|
|
962
|
-
required: true,
|
|
963
|
-
},
|
|
964
|
-
},
|
|
965
|
-
},
|
|
966
|
-
});
|
|
967
|
-
workflow.file?.addOverride("on.workflow_dispatch.inputs.automatic.default", false);
|
|
968
|
-
workflow.file?.addOverride("permissions.contents", "read");
|
|
969
|
-
workflow.addJob("release-please", independentReleasePleaseJob(project, branch));
|
|
970
|
-
workflow.addJob("release-plan", independentReleasePlanJob(project));
|
|
971
|
-
workflow.addJob("publish-release-notes", independentReleaseNotesJob(project));
|
|
972
|
-
registerIndependentPublicationJob(workflow, "publish-release-notes");
|
|
973
|
-
if (options.nodeRelease !== false) {
|
|
974
|
-
workflow.addJob("publish-node", independentNodePublishJob(project));
|
|
975
|
-
registerIndependentPublicationJob(workflow, "publish-node");
|
|
976
|
-
}
|
|
977
|
-
new IndependentReleaseFinalizer(project, workflow, options.docs, options.syncBranch || undefined);
|
|
978
|
-
configureReleaseRequestWorkflow(project, branch);
|
|
979
|
-
releaseWorkflows.set(project, workflow);
|
|
980
|
-
}
|
|
981
|
-
|
|
982
308
|
/** Owns the single release workflow and local release preparation tasks. */
|
|
983
309
|
export class DBXToolsRelease extends Component {
|
|
984
310
|
constructor(project: DBXToolsJavaScriptProject, options: DBXToolsReleaseOptions = {}) {
|
|
985
311
|
super(project);
|
|
986
|
-
if (project.releaseCatalog.mode === "independent") {
|
|
987
|
-
configureIndependentRelease(project, options);
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
312
|
const tagPrefix = options.tagPrefix ?? "v";
|
|
991
313
|
const releaseBranch = projectReleaseBranch(project);
|
|
992
314
|
const summary = options.summary ?? true;
|
|
@@ -1028,12 +350,18 @@ export class DBXToolsRelease extends Component {
|
|
|
1028
350
|
),
|
|
1029
351
|
receiveArgs: true,
|
|
1030
352
|
description:
|
|
1031
|
-
"Prepare, validate, locally publish, and
|
|
353
|
+
"Prepare, validate, locally publish, and upload a draft release candidate",
|
|
1032
354
|
},
|
|
1033
355
|
"release:assets": {
|
|
1034
|
-
exec: taskScript(
|
|
356
|
+
exec: taskScript(
|
|
357
|
+
project,
|
|
358
|
+
"release-candidate.ts",
|
|
359
|
+
options.pythonRoot
|
|
360
|
+
? `--python-root ${JSON.stringify(options.pythonRoot)}`
|
|
361
|
+
: undefined,
|
|
362
|
+
),
|
|
1035
363
|
receiveArgs: true,
|
|
1036
|
-
description: "
|
|
364
|
+
description: "Rebuild and upload a complete draft release candidate",
|
|
1037
365
|
},
|
|
1038
366
|
}
|
|
1039
367
|
: {}),
|
|
@@ -1043,14 +371,18 @@ export class DBXToolsRelease extends Component {
|
|
|
1043
371
|
const workflow = new GithubWorkflow(project.github, "release", {
|
|
1044
372
|
fileName: "release.yml",
|
|
1045
373
|
limitConcurrency: true,
|
|
1046
|
-
concurrencyOptions: {
|
|
374
|
+
concurrencyOptions: {
|
|
375
|
+
group:
|
|
376
|
+
"release-${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}",
|
|
377
|
+
cancelInProgress: false,
|
|
378
|
+
},
|
|
1047
379
|
});
|
|
1048
380
|
const version = readWorkspaceVersion(project.outdir);
|
|
1049
381
|
workflow.runName =
|
|
1050
382
|
`release ${version} ` +
|
|
1051
|
-
"${{ github.event_name == '
|
|
383
|
+
"${{ github.event_name == 'release' && github.event.release.tag_name || inputs.release_tag }}";
|
|
1052
384
|
workflow.on({
|
|
1053
|
-
|
|
385
|
+
release: { types: ["published"] },
|
|
1054
386
|
workflowDispatch: {
|
|
1055
387
|
inputs: {
|
|
1056
388
|
release_tag: {
|
|
@@ -1058,24 +390,13 @@ export class DBXToolsRelease extends Component {
|
|
|
1058
390
|
type: "string",
|
|
1059
391
|
required: true,
|
|
1060
392
|
},
|
|
1061
|
-
expected_sha: {
|
|
1062
|
-
description: "Commit the release tag must reference",
|
|
1063
|
-
type: "string",
|
|
1064
|
-
required: true,
|
|
1065
|
-
},
|
|
1066
393
|
stage: {
|
|
1067
|
-
description: "
|
|
394
|
+
description: "Published release stage to validate or recover",
|
|
1068
395
|
type: "choice",
|
|
1069
|
-
options: ["all", "node", "python", "docs"],
|
|
396
|
+
options: ["all", "node", "python", "cargo", "docs"],
|
|
1070
397
|
default: "all",
|
|
1071
398
|
required: true,
|
|
1072
399
|
},
|
|
1073
|
-
source_run_id: {
|
|
1074
|
-
description: "Earlier release workflow run containing Rust artifacts",
|
|
1075
|
-
type: "string",
|
|
1076
|
-
default: "",
|
|
1077
|
-
required: false,
|
|
1078
|
-
},
|
|
1079
400
|
dry_run: {
|
|
1080
401
|
description: "Build and validate without publishing",
|
|
1081
402
|
type: "boolean",
|