@dbx-tools/projen 0.8.0 → 0.9.0
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/README.md +9 -5
- package/index.ts +1 -1
- package/package.json +1 -1
- package/src/codegen.ts +18 -6
- package/src/project-js.ts +30 -2
- package/src/release-catalog.ts +14 -0
- package/src/release.ts +84 -20
- package/tasks/release-please.ts +0 -1
- package/tasks/release-request.ts +12 -12
package/README.md
CHANGED
|
@@ -454,16 +454,20 @@ a new package is covered without a re-synth. Work from the root:
|
|
|
454
454
|
before notes, AI, commits, pushes, or PR creation. It commits dirty source,
|
|
455
455
|
writes custom `--notes` / `--notes-file` content or a bounded Cursor, Codex,
|
|
456
456
|
Claude, then Git fallback to `.release-notes/requests/<branch>.md`, adds one
|
|
457
|
-
request commit, and pushes. The generated
|
|
458
|
-
|
|
457
|
+
request commit, and pushes. The generated workflow creates or updates the source
|
|
458
|
+
PR, merges it directly with `GITHUB_TOKEN`, and dispatches release planning, so
|
|
459
|
+
no UI approval or merge is required. GitHub may briefly record
|
|
460
|
+
`action_required` for the bot-authored PR validation; it is not a required gate.
|
|
459
461
|
|
|
460
462
|
After the source PR merges, Release Please retains direct conventional semantic
|
|
461
463
|
increments and applies required dependent patches. Reconciliation copies the
|
|
462
464
|
readable request Markdown into one temporary
|
|
463
465
|
`.release-notes/final/<component>-v<version>.md` per affected component and
|
|
464
|
-
deletes the consumed request file in the release PR
|
|
465
|
-
|
|
466
|
-
|
|
466
|
+
deletes the consumed request file in the release PR, then merges that generated
|
|
467
|
+
PR and explicitly dispatches publication. A source merge with no affected
|
|
468
|
+
release units creates no release PR or publication work. Publication applies
|
|
469
|
+
each file to its matching GitHub Release, then removes the temporary notes tree
|
|
470
|
+
in a cleanup commit. Request and final notes never count as source changes.
|
|
467
471
|
|
|
468
472
|
The GitHub PR workflow runs the explicit `pr:validate` task through Projen's
|
|
469
473
|
public `BuildWorkflow` `buildTask` option. That task runs synth plus the
|
package/index.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Hand edits are overwritten on the next watch; this file is read-only.
|
|
4
4
|
|
|
5
5
|
export const PACKAGE_IDENTIFIER = "@dbx-tools/projen";
|
|
6
|
-
export const PACKAGE_VERSION = "0.
|
|
6
|
+
export const PACKAGE_VERSION = "0.9.0";
|
|
7
7
|
export * as barrels from "./src/barrels.ts";
|
|
8
8
|
export * as bunApp from "./src/bun-app.ts";
|
|
9
9
|
export * as bunWorkflow from "./src/bun-workflow.ts";
|
package/package.json
CHANGED
package/src/codegen.ts
CHANGED
|
@@ -67,6 +67,16 @@ interface CodegenInput {
|
|
|
67
67
|
name: string;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
function packageName(dir: string): string {
|
|
71
|
+
const name = readPackageManifest(dir)?.name;
|
|
72
|
+
return typeof name === "string" && name.length > 0 ? name : basename(dir);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function sourceLabel(source: string): string {
|
|
76
|
+
const nodeModulesPrefix = "node_modules/";
|
|
77
|
+
return source.startsWith(nodeModulesPrefix) ? source.slice(nodeModulesPrefix.length) : source;
|
|
78
|
+
}
|
|
79
|
+
|
|
70
80
|
/** Read a package's `package.json` `codegen.inputs`, or `undefined` if absent. */
|
|
71
81
|
function codegenInputs(dir: string): string[] | undefined {
|
|
72
82
|
const codegen = readPackageManifest(dir)?.codegen;
|
|
@@ -282,6 +292,7 @@ function generatePackage(
|
|
|
282
292
|
): string {
|
|
283
293
|
const parsed = inputs.map(parseInputArg);
|
|
284
294
|
const srcDir = resolve(dir, "src");
|
|
295
|
+
const destinationPackage = packageName(dir);
|
|
285
296
|
mkdirSync(srcDir, { recursive: true });
|
|
286
297
|
|
|
287
298
|
// Remove prior generated modules (read-only + our header) so a dropped input
|
|
@@ -295,12 +306,13 @@ function generatePackage(
|
|
|
295
306
|
}
|
|
296
307
|
}
|
|
297
308
|
|
|
298
|
-
let warnings = 0;
|
|
299
309
|
for (const input of parsed) {
|
|
300
310
|
const sourcePath = resolveInputSource(input.source, dir, projectRoot);
|
|
301
311
|
if (!existsSync(sourcePath)) {
|
|
302
312
|
throw new Error(`codegen input not found: ${input.source}`);
|
|
303
313
|
}
|
|
314
|
+
const destination = `${destinationPackage}/src/${input.name}.ts`;
|
|
315
|
+
const source = sourceLabel(input.source);
|
|
304
316
|
|
|
305
317
|
const sourceText = preprocess(stripImports(tsRuntime, sourcePath));
|
|
306
318
|
const { getZodSchemasFile, getInferredTypes, errors } = generate({
|
|
@@ -310,8 +322,7 @@ function generatePackage(
|
|
|
310
322
|
keepComments: true,
|
|
311
323
|
});
|
|
312
324
|
if (errors.length) {
|
|
313
|
-
|
|
314
|
-
for (const err of errors) logger.warn(` ! ${err}`);
|
|
325
|
+
for (const err of errors) logger.warn(`${destination} from ${source}: ${err}`);
|
|
315
326
|
}
|
|
316
327
|
|
|
317
328
|
// ts-to-zod adds an import line only when the source references external
|
|
@@ -324,11 +335,12 @@ function generatePackage(
|
|
|
324
335
|
makeWritable(outPath);
|
|
325
336
|
writeFileSync(outPath, content);
|
|
326
337
|
makeReadonly(outPath);
|
|
338
|
+
logger.success(
|
|
339
|
+
`generated ${destination} from ${source}` +
|
|
340
|
+
(errors.length ? ` (${errors.length} warning(s))` : ""),
|
|
341
|
+
);
|
|
327
342
|
}
|
|
328
343
|
|
|
329
|
-
logger.success(
|
|
330
|
-
`${basename(dir)}: ${parsed.length} module(s)` + (warnings ? ` (${warnings} warning(s))` : ""),
|
|
331
|
-
);
|
|
332
344
|
return dir;
|
|
333
345
|
}
|
|
334
346
|
|
package/src/project-js.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { type IConstruct } from "constructs";
|
|
|
15
15
|
import { Component, IgnoreFile, Project, type TaskOptions, javascript, typescript } from "projen";
|
|
16
16
|
import { BuildWorkflow } from "projen/lib/build";
|
|
17
17
|
import { AutoMerge } from "projen/lib/github";
|
|
18
|
-
import { JobPermission, type JobStep } from "projen/lib/github/workflows-model";
|
|
18
|
+
import { JobPermission, type JobStep, type Triggers } from "projen/lib/github/workflows-model";
|
|
19
19
|
import type { ReleaseProjectOptions } from "projen/lib/release";
|
|
20
20
|
import { mixin } from "..";
|
|
21
21
|
import { generateBarrels } from "./barrels.ts";
|
|
@@ -943,7 +943,35 @@ function configureBuildWorkflow(
|
|
|
943
943
|
});
|
|
944
944
|
validation.exec("bunx projen default");
|
|
945
945
|
validation.exec("bun run compile");
|
|
946
|
-
const configured =
|
|
946
|
+
const configured = {
|
|
947
|
+
...options.buildWorkflowOptions,
|
|
948
|
+
...(!options.buildWorkflowOptions?.workflowTriggers &&
|
|
949
|
+
project.releaseCatalog.mode === "independent"
|
|
950
|
+
? {
|
|
951
|
+
workflowTriggers: {
|
|
952
|
+
pullRequest: {
|
|
953
|
+
types: ["opened", "synchronize", "reopened", "closed"],
|
|
954
|
+
paths: [
|
|
955
|
+
"**",
|
|
956
|
+
"!.projen/release-units.json",
|
|
957
|
+
"!.release-please-manifest.json",
|
|
958
|
+
"!.release-units/**",
|
|
959
|
+
"!.release-notes/**",
|
|
960
|
+
"!docs/releases/**",
|
|
961
|
+
"!Cargo.lock",
|
|
962
|
+
"!**/Cargo.toml",
|
|
963
|
+
"!**/package.json",
|
|
964
|
+
"!**/pyproject.toml",
|
|
965
|
+
"!**/index.ts",
|
|
966
|
+
"!packages/js/node/rust-binary/src/_rust-release-binaries.ts",
|
|
967
|
+
"!packages/js/node/appkit-graphiti/src/_python-runtime.ts",
|
|
968
|
+
],
|
|
969
|
+
},
|
|
970
|
+
workflowDispatch: {},
|
|
971
|
+
} satisfies Triggers,
|
|
972
|
+
}
|
|
973
|
+
: {}),
|
|
974
|
+
};
|
|
947
975
|
const compatibility = nodeWorkflowCompatibility(project);
|
|
948
976
|
const configuredRunner = configured.runsOn !== undefined || configured.runsOnGroup !== undefined;
|
|
949
977
|
const workflow = new BuildWorkflow(project, {
|
package/src/release-catalog.ts
CHANGED
|
@@ -800,12 +800,26 @@ function gitReleaseFiles(root: string, paths: readonly string[]): string[] | und
|
|
|
800
800
|
.filter(Boolean)
|
|
801
801
|
.map((path) => resolve(root, path))
|
|
802
802
|
.filter((path) => existsSync(path))
|
|
803
|
+
.filter((path) => paths.some((sourcePath) => trackedReleaseFile(sourcePath, path)))
|
|
803
804
|
.sort();
|
|
804
805
|
} catch {
|
|
805
806
|
return undefined;
|
|
806
807
|
}
|
|
807
808
|
}
|
|
808
809
|
|
|
810
|
+
function trackedReleaseFile(sourcePath: string, path: string): boolean {
|
|
811
|
+
const sourceRelative = toPosix(relative(sourcePath, path));
|
|
812
|
+
if (sourceRelative.startsWith("../") || sourceRelative === "..") return false;
|
|
813
|
+
const parts = sourceRelative.split("/");
|
|
814
|
+
const file = parts.pop();
|
|
815
|
+
if (!file) return false;
|
|
816
|
+
if (parts.some((part) => IGNORED_DIRECTORIES.has(part))) return false;
|
|
817
|
+
if (IGNORED_FILES.has(file) || file.endsWith(".lock") || file.startsWith("tsconfig")) {
|
|
818
|
+
return false;
|
|
819
|
+
}
|
|
820
|
+
return sourceRelative !== "index.ts";
|
|
821
|
+
}
|
|
822
|
+
|
|
809
823
|
function releaseFiles(path: string): string[] {
|
|
810
824
|
if (!existsSync(path)) return [];
|
|
811
825
|
const entries = readdirSync(path, { withFileTypes: true });
|
package/src/release.ts
CHANGED
|
@@ -352,9 +352,10 @@ function addDocsJobs(
|
|
|
352
352
|
|
|
353
353
|
function independentReleasePleaseJob(project: DBXToolsJavaScriptProject, branch: string): Job {
|
|
354
354
|
return {
|
|
355
|
-
if: "${{ github.event_name == 'push' }}",
|
|
355
|
+
if: "${{ github.event_name == 'push' || inputs.automatic == true }}",
|
|
356
356
|
runsOn: ["ubuntu-latest"],
|
|
357
357
|
permissions: {
|
|
358
|
+
actions: JobPermission.WRITE,
|
|
358
359
|
contents: JobPermission.WRITE,
|
|
359
360
|
pullRequests: JobPermission.WRITE,
|
|
360
361
|
},
|
|
@@ -419,7 +420,11 @@ function independentReleasePleaseJob(project: DBXToolsJavaScriptProject, branch:
|
|
|
419
420
|
{
|
|
420
421
|
name: "Reconcile generated release PR files",
|
|
421
422
|
if: "${{ steps.release.outputs.prs_created == 'true' }}",
|
|
422
|
-
env: {
|
|
423
|
+
env: {
|
|
424
|
+
GH_TOKEN: "${{ github.token }}",
|
|
425
|
+
RELEASE_BRANCH: branch,
|
|
426
|
+
RELEASE_PRS: "${{ steps.release.outputs.prs }}",
|
|
427
|
+
},
|
|
423
428
|
shell: "bash",
|
|
424
429
|
run: [
|
|
425
430
|
'BRANCH="$(jq -r \'.[0].headBranchName\' <<<"$RELEASE_PRS")"',
|
|
@@ -438,6 +443,26 @@ function independentReleasePleaseJob(project: DBXToolsJavaScriptProject, branch:
|
|
|
438
443
|
' git commit -m "chore: reconcile release metadata"',
|
|
439
444
|
' git push origin "HEAD:$BRANCH"',
|
|
440
445
|
"fi",
|
|
446
|
+
'MERGED="false"',
|
|
447
|
+
"for ATTEMPT in $(seq 1 15); do",
|
|
448
|
+
' STATE="$(gh pr view "$BRANCH" --json state,mergeable --jq \'[.state,.mergeable] | join(" ")\')"',
|
|
449
|
+
' if [[ "$STATE" == MERGED* ]]; then MERGED="true"; break; fi',
|
|
450
|
+
' if [ "$STATE" = "OPEN CONFLICTING" ]; then',
|
|
451
|
+
' echo "::error::release pull request has merge conflicts"',
|
|
452
|
+
" exit 1",
|
|
453
|
+
" fi",
|
|
454
|
+
' if [ "$STATE" = "OPEN MERGEABLE" ] && gh pr merge "$BRANCH" --merge; then',
|
|
455
|
+
' MERGED="true"',
|
|
456
|
+
" break",
|
|
457
|
+
" fi",
|
|
458
|
+
' echo "release pull request is not mergeable yet (attempt $ATTEMPT/15)"',
|
|
459
|
+
" sleep 2",
|
|
460
|
+
"done",
|
|
461
|
+
'if [ "$MERGED" != "true" ]; then',
|
|
462
|
+
' echo "::error::release pull request did not become mergeable"',
|
|
463
|
+
" exit 1",
|
|
464
|
+
"fi",
|
|
465
|
+
'gh workflow run release.yml --ref "$RELEASE_BRANCH" -f automatic=true',
|
|
441
466
|
].join("\n"),
|
|
442
467
|
},
|
|
443
468
|
],
|
|
@@ -464,7 +489,8 @@ function configureReleaseRequestWorkflow(
|
|
|
464
489
|
if: `\${{ github.ref_name != '${baseBranch}' }}`,
|
|
465
490
|
runsOn: ["ubuntu-latest"],
|
|
466
491
|
permissions: {
|
|
467
|
-
|
|
492
|
+
actions: JobPermission.WRITE,
|
|
493
|
+
contents: JobPermission.WRITE,
|
|
468
494
|
pullRequests: JobPermission.WRITE,
|
|
469
495
|
},
|
|
470
496
|
steps: [
|
|
@@ -489,14 +515,13 @@ function configureReleaseRequestWorkflow(
|
|
|
489
515
|
" exit 0",
|
|
490
516
|
"fi",
|
|
491
517
|
'echo "requested=true" >> "$GITHUB_OUTPUT"',
|
|
492
|
-
'echo "branch=$
|
|
493
|
-
'echo "approve=$(sed -n \'s/^Release-Approve: //p\' <<<"$MESSAGE" | tail -1)" >> "$GITHUB_OUTPUT"',
|
|
518
|
+
'echo "branch=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"',
|
|
494
519
|
'echo "notes_path=$(sed -n \'s/^Release-Notes-Path: //p\' <<<"$MESSAGE" | tail -1)" >> "$GITHUB_OUTPUT"',
|
|
495
520
|
'echo "title=$(git log -1 --skip=1 --format=%s)" >> "$GITHUB_OUTPUT"',
|
|
496
521
|
].join("\n"),
|
|
497
522
|
},
|
|
498
523
|
{
|
|
499
|
-
name: "Create
|
|
524
|
+
name: "Create, merge, and release source pull request",
|
|
500
525
|
if: "${{ steps.request.outputs.requested == 'true' }}",
|
|
501
526
|
env: {
|
|
502
527
|
GH_TOKEN: "${{ github.token }}",
|
|
@@ -504,7 +529,6 @@ function configureReleaseRequestWorkflow(
|
|
|
504
529
|
BASE_BRANCH: baseBranch,
|
|
505
530
|
TITLE: "${{ steps.request.outputs.title }}",
|
|
506
531
|
NOTES_PATH: "${{ steps.request.outputs.notes_path }}",
|
|
507
|
-
APPROVE: "${{ steps.request.outputs.approve }}",
|
|
508
532
|
},
|
|
509
533
|
shell: "bash",
|
|
510
534
|
run: [
|
|
@@ -515,9 +539,11 @@ function configureReleaseRequestWorkflow(
|
|
|
515
539
|
'if [ -n "$PR" ]; then',
|
|
516
540
|
' gh pr edit "$PR" --title "$TITLE" --body "$BODY"',
|
|
517
541
|
"else",
|
|
518
|
-
'
|
|
542
|
+
' gh pr create --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --title "$TITLE" --body "$BODY"',
|
|
543
|
+
' PR="$(gh pr list --head "$SOURCE_BRANCH" --base "$BASE_BRANCH" --state open --json number --jq \'.[0].number\')"',
|
|
519
544
|
"fi",
|
|
520
|
-
'
|
|
545
|
+
'gh pr merge "$PR" --merge',
|
|
546
|
+
'gh workflow run release.yml --repo "$GITHUB_REPOSITORY" --ref "$BASE_BRANCH" -f automatic=true',
|
|
521
547
|
].join("\n"),
|
|
522
548
|
},
|
|
523
549
|
],
|
|
@@ -526,7 +552,7 @@ function configureReleaseRequestWorkflow(
|
|
|
526
552
|
|
|
527
553
|
function independentReleasePlanJob(project: DBXToolsJavaScriptProject): Job {
|
|
528
554
|
return {
|
|
529
|
-
if: "${{ always() && (github.event_name == 'workflow_dispatch' || needs.release-please.outputs.releases_created == 'true' || needs.release-please.outputs.docs_changed == 'true' || needs.release-please.outputs.recovery_requested == 'true') }}",
|
|
555
|
+
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') }}",
|
|
530
556
|
needs: ["release-please"],
|
|
531
557
|
runsOn: ["ubuntu-latest"],
|
|
532
558
|
permissions: { contents: JobPermission.READ },
|
|
@@ -721,41 +747,67 @@ function addIndependentDocsJobs(
|
|
|
721
747
|
});
|
|
722
748
|
}
|
|
723
749
|
|
|
724
|
-
function addIndependentBranchSyncJob(
|
|
750
|
+
function addIndependentBranchSyncJob(
|
|
751
|
+
workflow: GithubWorkflow,
|
|
752
|
+
project: DBXToolsJavaScriptProject,
|
|
753
|
+
branch: string,
|
|
754
|
+
): void {
|
|
755
|
+
const releaseBranch = projectReleaseBranch(project);
|
|
725
756
|
workflow.addJob("sync-release-branch", {
|
|
726
|
-
if: "${{ always() && github.event_name == 'push' && needs['publication-complete'].result == 'success' }}",
|
|
757
|
+
if: "${{ always() && (github.event_name == 'push' || inputs.automatic == true) && needs['publication-complete'].result == 'success' }}",
|
|
727
758
|
needs: ["publication-complete"],
|
|
728
759
|
runsOn: ["ubuntu-latest"],
|
|
729
760
|
permissions: { contents: JobPermission.WRITE },
|
|
761
|
+
env: { BUN_VERSION },
|
|
730
762
|
steps: [
|
|
731
763
|
{
|
|
732
764
|
name: "Checkout released main",
|
|
733
765
|
uses: "actions/checkout@v6",
|
|
734
766
|
with: { "fetch-depth": 0 },
|
|
735
767
|
},
|
|
768
|
+
...bunCacheRestoreSteps(project, {
|
|
769
|
+
ignorePaths: project.workflowCacheIgnorePaths,
|
|
770
|
+
}),
|
|
771
|
+
{ name: "Install dependencies", run: "bun install" },
|
|
736
772
|
{
|
|
737
773
|
name: `Safely sync ${branch}`,
|
|
738
774
|
shell: "bash",
|
|
739
|
-
env: { SOURCE_BRANCH: branch },
|
|
775
|
+
env: { SOURCE_BRANCH: branch, RELEASE_BRANCH: releaseBranch },
|
|
740
776
|
run: [
|
|
741
777
|
'if ! git ls-remote --exit-code --heads origin "refs/heads/$SOURCE_BRANCH" >/dev/null 2>&1; then',
|
|
742
778
|
' echo "source branch $SOURCE_BRANCH no longer exists; nothing to sync"',
|
|
743
779
|
" exit 0",
|
|
744
780
|
"fi",
|
|
745
781
|
'git fetch origin "refs/heads/$SOURCE_BRANCH:refs/remotes/origin/$SOURCE_BRANCH"',
|
|
746
|
-
'
|
|
747
|
-
'
|
|
748
|
-
'
|
|
782
|
+
'git fetch origin "refs/heads/$RELEASE_BRANCH:refs/remotes/origin/$RELEASE_BRANCH"',
|
|
783
|
+
'if git merge-base --is-ancestor "origin/$SOURCE_BRANCH" "origin/$RELEASE_BRANCH"; then',
|
|
784
|
+
' git push origin "refs/remotes/origin/$RELEASE_BRANCH:refs/heads/$SOURCE_BRANCH"',
|
|
785
|
+
'elif git merge-base --is-ancestor "origin/$RELEASE_BRANCH" "origin/$SOURCE_BRANCH"; then',
|
|
749
786
|
' echo "source branch $SOURCE_BRANCH already contains released main"',
|
|
750
787
|
"else",
|
|
751
788
|
' git config user.name "github-actions[bot]"',
|
|
752
789
|
' git config user.email "41898282+github-actions[bot]@users.noreply.github.com"',
|
|
753
790
|
' git switch --force-create "$SOURCE_BRANCH" "origin/$SOURCE_BRANCH"',
|
|
754
|
-
' if git merge --no-ff --no-edit "
|
|
791
|
+
' if git merge --no-ff --no-edit "origin/$RELEASE_BRANCH"; then',
|
|
755
792
|
' git push origin "HEAD:refs/heads/$SOURCE_BRANCH"',
|
|
756
793
|
" else",
|
|
794
|
+
' SAFE_GENERATED="true"',
|
|
795
|
+
" while IFS= read -r FILE; do",
|
|
796
|
+
' case "$FILE" in',
|
|
797
|
+
" .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) ;;",
|
|
798
|
+
' *) SAFE_GENERATED="false" ;;',
|
|
799
|
+
" esac",
|
|
800
|
+
" done < <(git diff --name-only --diff-filter=U)",
|
|
801
|
+
' if [ "$SAFE_GENERATED" = "true" ] && bunx projen; then',
|
|
802
|
+
" git add -A",
|
|
803
|
+
' if [ -z "$(git diff --name-only --diff-filter=U)" ]; then',
|
|
804
|
+
" git commit --no-edit",
|
|
805
|
+
' git push origin "HEAD:refs/heads/$SOURCE_BRANCH"',
|
|
806
|
+
" exit 0",
|
|
807
|
+
" fi",
|
|
808
|
+
" fi",
|
|
757
809
|
" git merge --abort",
|
|
758
|
-
' echo "::warning::source branch $SOURCE_BRANCH has
|
|
810
|
+
' echo "::warning::source branch $SOURCE_BRANCH has handwritten or unresolved conflicts with released main; leaving it untouched"',
|
|
759
811
|
" fi",
|
|
760
812
|
"fi",
|
|
761
813
|
].join("\n"),
|
|
@@ -794,7 +846,11 @@ class IndependentReleaseFinalizer extends Component {
|
|
|
794
846
|
addIndependentDocsJobs(this.workflow, this.project as DBXToolsJavaScriptProject, this.docs);
|
|
795
847
|
}
|
|
796
848
|
if (this.syncBranch) {
|
|
797
|
-
addIndependentBranchSyncJob(
|
|
849
|
+
addIndependentBranchSyncJob(
|
|
850
|
+
this.workflow,
|
|
851
|
+
this.project as DBXToolsJavaScriptProject,
|
|
852
|
+
this.syncBranch,
|
|
853
|
+
);
|
|
798
854
|
}
|
|
799
855
|
}
|
|
800
856
|
}
|
|
@@ -833,11 +889,18 @@ function configureIndependentRelease(
|
|
|
833
889
|
concurrencyOptions: { group: "release", cancelInProgress: false },
|
|
834
890
|
});
|
|
835
891
|
workflow.runName =
|
|
836
|
-
"release units " +
|
|
892
|
+
"release units " +
|
|
893
|
+
"${{ github.event_name == 'push' && github.sha || inputs.automatic && 'automatic' || inputs.component }}";
|
|
837
894
|
workflow.on({
|
|
838
895
|
push: { branches: [branch] },
|
|
839
896
|
workflowDispatch: {
|
|
840
897
|
inputs: {
|
|
898
|
+
automatic: {
|
|
899
|
+
description: "Continue an automatically merged Release Please pull request",
|
|
900
|
+
type: "boolean",
|
|
901
|
+
default: "false",
|
|
902
|
+
required: false,
|
|
903
|
+
},
|
|
841
904
|
component: {
|
|
842
905
|
description: "Component to recover",
|
|
843
906
|
type: "string",
|
|
@@ -860,6 +923,7 @@ function configureIndependentRelease(
|
|
|
860
923
|
},
|
|
861
924
|
},
|
|
862
925
|
});
|
|
926
|
+
workflow.file?.addOverride("on.workflow_dispatch.inputs.automatic.default", false);
|
|
863
927
|
workflow.file?.addOverride("permissions.contents", "read");
|
|
864
928
|
workflow.addJob("release-please", independentReleasePleaseJob(project, branch));
|
|
865
929
|
workflow.addJob("release-plan", independentReleasePlanJob(project));
|
package/tasks/release-please.ts
CHANGED
package/tasks/release-request.ts
CHANGED
|
@@ -13,7 +13,6 @@ const logger = log.logger("projen:release-request");
|
|
|
13
13
|
export interface PrepareReleaseRequestOptions {
|
|
14
14
|
readonly root: string;
|
|
15
15
|
readonly baseBranch: string;
|
|
16
|
-
readonly approve?: boolean;
|
|
17
16
|
readonly message?: string;
|
|
18
17
|
readonly notes?: string;
|
|
19
18
|
readonly notesFile?: string;
|
|
@@ -94,12 +93,11 @@ export async function prepareReleaseRequest(
|
|
|
94
93
|
[
|
|
95
94
|
"Release-Request: true",
|
|
96
95
|
`Release-Source-Branch: ${branch}`,
|
|
97
|
-
`Release-Approve: ${options.approve === true}`,
|
|
98
96
|
`Release-Notes-Path: ${notesPath}`,
|
|
99
97
|
].join("\n"),
|
|
100
98
|
]);
|
|
101
99
|
if (options.push !== false) run(root, ["push", "--set-upstream", "origin", branch]);
|
|
102
|
-
logger.success("release request pushed", { branch
|
|
100
|
+
logger.success("release request pushed", { branch });
|
|
103
101
|
return true;
|
|
104
102
|
}
|
|
105
103
|
|
|
@@ -155,19 +153,22 @@ function run(root: string, args: string[]): void {
|
|
|
155
153
|
});
|
|
156
154
|
}
|
|
157
155
|
|
|
156
|
+
/** Restore option text after Projen forwards task arguments without shell quoting. */
|
|
157
|
+
function optionText(values?: readonly string[]): string | undefined {
|
|
158
|
+
return values?.join(" ");
|
|
159
|
+
}
|
|
160
|
+
|
|
158
161
|
if (import.meta.main) {
|
|
159
162
|
await new Command()
|
|
160
163
|
.option("--base <branch>", "release target branch", "main")
|
|
161
|
-
.option("--
|
|
162
|
-
.option("--
|
|
163
|
-
.option("--notes <notes>", "custom release notes")
|
|
164
|
+
.option("--message <message...>", "commit message for uncommitted source changes")
|
|
165
|
+
.option("--notes <notes...>", "custom release notes")
|
|
164
166
|
.option("--notes-file <path>", "read custom release notes from a file")
|
|
165
167
|
.action(
|
|
166
168
|
async (options: {
|
|
167
169
|
base: string;
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
notes?: string;
|
|
170
|
+
message?: string[];
|
|
171
|
+
notes?: string[];
|
|
171
172
|
notesFile?: string;
|
|
172
173
|
}) => {
|
|
173
174
|
if (options.notes && options.notesFile) {
|
|
@@ -176,9 +177,8 @@ if (import.meta.main) {
|
|
|
176
177
|
await prepareReleaseRequest({
|
|
177
178
|
root: project.root() ?? process.cwd(),
|
|
178
179
|
baseBranch: options.base,
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
notes: options.notes,
|
|
180
|
+
message: optionText(options.message),
|
|
181
|
+
notes: optionText(options.notes),
|
|
182
182
|
notesFile: options.notesFile,
|
|
183
183
|
});
|
|
184
184
|
},
|