@dbx-tools/projen 0.6.223 → 0.6.225
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 +55 -8
- package/index.ts +7 -4
- package/package.json +5 -5
- package/src/barrels.ts +10 -4
- package/src/bun-workflow.ts +36 -17
- package/src/clean.ts +3 -3
- package/src/codegen.ts +16 -8
- package/src/packages.ts +14 -13
- package/src/project-js.ts +320 -148
- package/src/project-py.ts +8 -25
- package/src/project-rs.ts +100 -71
- package/src/release-dispatch.ts +10 -0
- package/src/release-github.ts +37 -0
- package/src/release.ts +57 -38
- package/src/tsconfig.ts +17 -17
- package/tasks/local-publish.ts +3 -3
- package/tasks/publish-npm.ts +75 -4
- package/tasks/publish-python.ts +13 -29
- package/tasks/publish-uniffi-local.ts +12 -9
- package/tasks/publish.ts +2 -2
- package/tasks/release-pr.ts +64 -10
- package/tasks/release-summary.ts +270 -0
- package/tasks/uniffi-python.d.ts +56 -0
- package/tasks/uniffi-python.js +160 -0
- package/tasks/uniffi-release.mjs +25 -49
- package/tasks/uniffi.ts +11 -45
package/src/project-js.ts
CHANGED
|
@@ -13,8 +13,10 @@ import { ignore, match } from "@dbx-tools/path";
|
|
|
13
13
|
import { object, string, type OneOrMany } from "@dbx-tools/shared-core";
|
|
14
14
|
import { type IConstruct } from "constructs";
|
|
15
15
|
import { Component, IgnoreFile, Project, type TaskOptions, javascript, typescript } from "projen";
|
|
16
|
+
import { BuildWorkflow } from "projen/lib/build";
|
|
17
|
+
import { AutoMerge } from "projen/lib/github";
|
|
16
18
|
import { JobPermission, type JobStep } from "projen/lib/github/workflows-model";
|
|
17
|
-
import {
|
|
19
|
+
import type { ReleaseProjectOptions } from "projen/lib/release";
|
|
18
20
|
import { mixin } from "..";
|
|
19
21
|
import { generateBarrels } from "./barrels.ts";
|
|
20
22
|
import {
|
|
@@ -33,14 +35,13 @@ import {
|
|
|
33
35
|
type DiscoveredPackage,
|
|
34
36
|
projectName,
|
|
35
37
|
readPackageManifest,
|
|
36
|
-
repoRoot,
|
|
37
38
|
scanPackages,
|
|
38
39
|
toPosix,
|
|
39
40
|
} from "./packages.ts";
|
|
40
41
|
import { PnpmWorkspaceState, type DBXToolsPNPMWorkspaceOptions } from "./pnpm-workspace.ts";
|
|
41
42
|
import type { DBXToolsProject, DBXToolsProjectOptions as CommonProjectOptions } from "./project.ts";
|
|
42
43
|
import { applyCompiledPublish } from "./publish.ts";
|
|
43
|
-
import { DBXToolsRelease, type ReleaseDocsOptions } from "./release.ts";
|
|
44
|
+
import { DBXToolsRelease, type ReleaseDocsOptions, type ReleaseSummaryOptions } from "./release.ts";
|
|
44
45
|
import { AGNOSTIC_COMPILER_OPTIONS, PACKAGE_TAG_MIXINS, type PackageTag } from "./tags.ts";
|
|
45
46
|
import { DBXToolsRootTsconfig } from "./tsconfig.ts";
|
|
46
47
|
import { DBXToolsVsCode } from "./vscode.ts";
|
|
@@ -67,6 +68,8 @@ export interface DBXToolsJavaScriptProject extends DBXToolsProject, javascript.N
|
|
|
67
68
|
rootTsconfig?: DBXToolsRootTsconfig;
|
|
68
69
|
/** Root `.vscode/*` - only a tree ROOT has one. */
|
|
69
70
|
vsCode?: DBXToolsVsCode;
|
|
71
|
+
/** Repository outputs excluded from generated workflow dependency-cache hashing. */
|
|
72
|
+
readonly workflowCacheIgnorePaths: readonly string[];
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
/** Parsed npm package identifier: optional scope plus the unscoped package name. */
|
|
@@ -146,10 +149,11 @@ function configureRootPackage(project: javascript.NodeProject): void {
|
|
|
146
149
|
* a normalized git remote), in npm's `git+https://.../repo.git` form.
|
|
147
150
|
*/
|
|
148
151
|
function applyRepository(project: javascript.NodeProject, override?: string): void {
|
|
149
|
-
const
|
|
152
|
+
const workspaceRoot = resolve(project.root.outdir);
|
|
153
|
+
const url =
|
|
154
|
+
override && override.length ? override : coreProject.repositoryUrl(workspaceRoot, "npm");
|
|
150
155
|
if (!url) return;
|
|
151
|
-
const
|
|
152
|
-
const directory = toPosix(relative(resolve(root.outdir), resolve(project.outdir)));
|
|
156
|
+
const directory = toPosix(relative(workspaceRoot, resolve(project.outdir)));
|
|
153
157
|
project.package.addField("repository", {
|
|
154
158
|
type: "git",
|
|
155
159
|
url,
|
|
@@ -389,9 +393,7 @@ export const DBX_TOOLS_LICENSE = "Apache-2.0";
|
|
|
389
393
|
* inherits the root's config rather than emitting its own. `name`/`defaultReleaseBranch`
|
|
390
394
|
* are resolved/applied by the caller.
|
|
391
395
|
*/
|
|
392
|
-
function defaultProjectOptions(
|
|
393
|
-
options: DBXToolsJavaScriptProjectOptions,
|
|
394
|
-
): DBXToolsJavaScriptProjectOptions {
|
|
396
|
+
function defaultProjectOptions(options: DBXToolsJavaScriptProjectOptions) {
|
|
395
397
|
const isRoot = options.parent === undefined;
|
|
396
398
|
return {
|
|
397
399
|
// Bun owns install/run/build/test locally and in CI. projen renders
|
|
@@ -423,9 +425,7 @@ function defaultProjectOptions(
|
|
|
423
425
|
// to Verdaccio still work without a CI OIDC provider. See
|
|
424
426
|
// {@link DBXToolsRelease}.
|
|
425
427
|
...(isRoot ? {} : { npmAccess: javascript.NpmAccess.PUBLIC }),
|
|
426
|
-
buildWorkflow: false,
|
|
427
428
|
workflowPackageCache: false,
|
|
428
|
-
release: false,
|
|
429
429
|
// The root build validates the whole workspace and must not also pack every
|
|
430
430
|
// member into unused `dist/js` tarballs. Child projects keep projen's package
|
|
431
431
|
// task so `bun run build` in ONE package remains a complete compile/test/pack
|
|
@@ -460,6 +460,8 @@ function defaultProjectOptions(
|
|
|
460
460
|
}
|
|
461
461
|
: {}),
|
|
462
462
|
...options,
|
|
463
|
+
buildWorkflow: false,
|
|
464
|
+
release: false,
|
|
463
465
|
githubOptions: {
|
|
464
466
|
...options.githubOptions,
|
|
465
467
|
pullRequestLint: false,
|
|
@@ -493,9 +495,7 @@ function copiedGitIgnoreOptions(
|
|
|
493
495
|
* same parent-based root/child logic applies; this just layers on typescript +
|
|
494
496
|
* bun types and disables sample code. No `tsx`: bun runs `.ts` directly.
|
|
495
497
|
*/
|
|
496
|
-
function defaultTypeScriptProjectOptions(
|
|
497
|
-
options: DBXToolsTypeScriptProjectOptions,
|
|
498
|
-
): DBXToolsTypeScriptProjectOptions {
|
|
498
|
+
function defaultTypeScriptProjectOptions(options: DBXToolsTypeScriptProjectOptions) {
|
|
499
499
|
const base = defaultProjectOptions(options);
|
|
500
500
|
return {
|
|
501
501
|
...base,
|
|
@@ -513,84 +513,154 @@ function defaultTypeScriptProjectOptions(
|
|
|
513
513
|
// Pinned to match the subproject defaults so bun resolves one TypeScript and
|
|
514
514
|
// one runtime-compatible set of Bun globals across the workspace.
|
|
515
515
|
const DEV_DEPS_ROOT: string[] = ["typescript@^5.9.3", `@types/bun@${BUN_VERSION}`];
|
|
516
|
+
const NATIVE_RELEASE_OPTIONS = [
|
|
517
|
+
"jsiiReleaseVersion",
|
|
518
|
+
"majorVersion",
|
|
519
|
+
"minMajorVersion",
|
|
520
|
+
"npmDistTag",
|
|
521
|
+
"prerelease",
|
|
522
|
+
"publishDryRun",
|
|
523
|
+
"publishTasks",
|
|
524
|
+
"releasableCommits",
|
|
525
|
+
"release",
|
|
526
|
+
"releaseBranches",
|
|
527
|
+
"releaseEnvironment",
|
|
528
|
+
"releaseEveryCommit",
|
|
529
|
+
"releaseFailureIssue",
|
|
530
|
+
"releaseFailureIssueLabel",
|
|
531
|
+
"releaseToNpm",
|
|
532
|
+
"releaseTrigger",
|
|
533
|
+
"releaseWorkflowName",
|
|
534
|
+
"releaseWorkflowSetupSteps",
|
|
535
|
+
"versionrcOptions",
|
|
536
|
+
] as const;
|
|
537
|
+
|
|
538
|
+
function validateReleaseOptions(options: DBXToolsJavaScriptProjectOptions): void {
|
|
539
|
+
for (const key of NATIVE_RELEASE_OPTIONS) {
|
|
540
|
+
if ((options as Record<string, unknown>)[key] !== undefined) {
|
|
541
|
+
throw new Error(
|
|
542
|
+
`${key} is a native Projen release option; use dbx-tools release options instead`,
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
if (
|
|
547
|
+
options.releaseMode === "disabled" &&
|
|
548
|
+
(options.releaseDocs !== undefined || options.nodeRelease !== undefined)
|
|
549
|
+
) {
|
|
550
|
+
throw new Error("releaseMode disabled cannot be combined with releaseDocs or nodeRelease");
|
|
551
|
+
}
|
|
552
|
+
}
|
|
516
553
|
|
|
517
554
|
/** Options for {@link DBXToolsNodeProject} (the monorepo root). */
|
|
518
|
-
export
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
/**
|
|
525
|
-
|
|
526
|
-
* the (resolved) project name; a leading `@` is optional.
|
|
527
|
-
*/
|
|
528
|
-
readonly scope?: string;
|
|
529
|
-
/**
|
|
530
|
-
* Roots scanned for packages (each `src`-bearing folder under a root is one).
|
|
531
|
-
* Only a ROOT scans. Defaults to {@link DEFAULT_PACKAGE_ROOTS}.
|
|
532
|
-
*/
|
|
533
|
-
readonly packageRoots?: readonly string[];
|
|
534
|
-
/**
|
|
535
|
-
* Descriptions for published packages, keyed by repository-relative package
|
|
536
|
-
* directory. When configured, synthesis rejects every public JavaScript
|
|
537
|
-
* package whose final manifest has no non-empty description.
|
|
538
|
-
*/
|
|
539
|
-
readonly packageDescriptions?: Readonly<Record<string, string>>;
|
|
540
|
-
/**
|
|
541
|
-
* Leading path segment(s) dropped from a discovered package's relative path
|
|
542
|
-
* before its npm name is derived, so a tier folder doesn't become a name
|
|
543
|
-
* prefix. E.g. with the default `"node"`, `packages/node/path` names as
|
|
544
|
-
* `@<scope>/path` instead of `@<scope>/node-path` (its `node` TAG still
|
|
545
|
-
* derives from the path). One or many segment names; a segment is only
|
|
546
|
-
* stripped when it is the FIRST segment of the relative path. Pass `[]` to
|
|
547
|
-
* disable. Defaults to `"node"`.
|
|
548
|
-
*/
|
|
549
|
-
readonly omitRelativePrefix?: OneOrMany<string>;
|
|
550
|
-
/**
|
|
551
|
-
* Maps a path token / relPath / glob to tag(s), unioned into a package's
|
|
552
|
-
* path-derived tags. Defaults to an identity map over the known tag names; a
|
|
553
|
-
* `""`/`"."` key tags the root.
|
|
554
|
-
*/
|
|
555
|
-
readonly packageTagPaths?: Record<string, string[]>;
|
|
556
|
-
/**
|
|
557
|
-
* Which built-in {@link PACKAGE_TAG_MIXINS} to apply and seed
|
|
558
|
-
* `packageTagPaths` identity entries for. Omitted = all; `false` = none;
|
|
559
|
-
* a list = only those tags.
|
|
560
|
-
*/
|
|
561
|
-
readonly defaultTagMixins?: false | PackageTag[];
|
|
562
|
-
/**
|
|
563
|
-
* Extra repo-root paths that trigger a full re-synth during `sync --watch`
|
|
564
|
-
* (alongside `.projenrc.ts`). Repo-relative, e.g. `".example.projenrc.ts"`.
|
|
565
|
-
*/
|
|
566
|
-
readonly syncResynthPaths?: readonly string[];
|
|
567
|
-
/** GitHub Pages documentation included in the unified release workflow. */
|
|
568
|
-
readonly releaseDocs?: ReleaseDocsOptions;
|
|
569
|
-
/** Set to `false` to omit normal npm workspace publication. */
|
|
570
|
-
readonly nodeRelease?: boolean;
|
|
571
|
-
/**
|
|
572
|
-
* Extra workspace member paths (repo-relative, POSIX) to list in the workspace
|
|
573
|
-
* config ALONGSIDE the discovered `packageRoots` members - for a package that
|
|
574
|
-
* is synthesized by its OWN `.projenrc.ts` (so it isn't a root subproject) but
|
|
575
|
-
* should still resolve as a workspace sibling. The `@dbx-tools/projen` engine in
|
|
576
|
-
* `projen/` is the case: it synthesizes itself (avoiding a dogfooding cycle) yet
|
|
577
|
-
* is a member of the single bun workspace, so the root links it from source.
|
|
578
|
-
*/
|
|
579
|
-
readonly extraWorkspaceMembers?: readonly string[];
|
|
580
|
-
/**
|
|
581
|
-
* Install workspace dependencies once from the custom root instead of once
|
|
582
|
-
* per child project during post-synthesis. Defaults to `true`; set `false` to
|
|
583
|
-
* preserve projen's native per-project install tasks.
|
|
584
|
-
*/
|
|
585
|
-
readonly rootInstallOnly?: boolean;
|
|
555
|
+
export type DBXToolsReleaseMode = "dbx-tools" | "disabled";
|
|
556
|
+
|
|
557
|
+
/** Optional semantic pull request title policy for the generated build workflow. */
|
|
558
|
+
export interface PullRequestTitlePolicyOptions {
|
|
559
|
+
/** Allowed semantic title types. */
|
|
560
|
+
readonly types: readonly string[];
|
|
561
|
+
/** Require a semantic title scope. Defaults to `false`. */
|
|
562
|
+
readonly requireScope?: boolean;
|
|
586
563
|
}
|
|
587
564
|
|
|
565
|
+
type SupportedWorkflowOptions = Pick<
|
|
566
|
+
ReleaseProjectOptions,
|
|
567
|
+
"postBuildSteps" | "workflowContainerImage" | "workflowRunsOn" | "workflowRunsOnGroup"
|
|
568
|
+
>;
|
|
569
|
+
|
|
570
|
+
export type DBXToolsJavaScriptProjectOptions = CommonProjectOptions &
|
|
571
|
+
Partial<
|
|
572
|
+
Omit<javascript.NodeProjectOptions, keyof ReleaseProjectOptions | "release" | "releaseToNpm">
|
|
573
|
+
> &
|
|
574
|
+
Partial<SupportedWorkflowOptions> &
|
|
575
|
+
DBXToolsConfigOptions &
|
|
576
|
+
DBXToolsPNPMWorkspaceOptions & {
|
|
577
|
+
/**
|
|
578
|
+
* The npm scope for generated package names (`@<scope>/<seg-...>`). Defaults to
|
|
579
|
+
* the (resolved) project name; a leading `@` is optional.
|
|
580
|
+
*/
|
|
581
|
+
readonly scope?: string;
|
|
582
|
+
/**
|
|
583
|
+
* Roots scanned for packages (each `src`-bearing folder under a root is one).
|
|
584
|
+
* Only a ROOT scans. Defaults to {@link DEFAULT_PACKAGE_ROOTS}.
|
|
585
|
+
*/
|
|
586
|
+
readonly packageRoots?: readonly string[];
|
|
587
|
+
/**
|
|
588
|
+
* Descriptions for published packages, keyed by repository-relative package
|
|
589
|
+
* directory. When configured, synthesis rejects every public JavaScript
|
|
590
|
+
* package whose final manifest has no non-empty description.
|
|
591
|
+
*/
|
|
592
|
+
readonly packageDescriptions?: Readonly<Record<string, string>>;
|
|
593
|
+
/**
|
|
594
|
+
* Leading path segment(s) dropped from a discovered package's relative path
|
|
595
|
+
* before its npm name is derived, so a tier folder doesn't become a name
|
|
596
|
+
* prefix. E.g. with the default `"node"`, `packages/node/path` names as
|
|
597
|
+
* `@<scope>/path` instead of `@<scope>/node-path` (its `node` TAG still
|
|
598
|
+
* derives from the path). One or many segment names; a segment is only
|
|
599
|
+
* stripped when it is the FIRST segment of the relative path. Pass `[]` to
|
|
600
|
+
* disable. Defaults to `"node"`.
|
|
601
|
+
*/
|
|
602
|
+
readonly omitRelativePrefix?: OneOrMany<string>;
|
|
603
|
+
/**
|
|
604
|
+
* Maps a path token / relPath / glob to tag(s), unioned into a package's
|
|
605
|
+
* path-derived tags. Defaults to an identity map over the known tag names; a
|
|
606
|
+
* `""`/`"."` key tags the root.
|
|
607
|
+
*/
|
|
608
|
+
readonly packageTagPaths?: Record<string, string[]>;
|
|
609
|
+
/**
|
|
610
|
+
* Which built-in {@link PACKAGE_TAG_MIXINS} to apply and seed
|
|
611
|
+
* `packageTagPaths` identity entries for. Omitted = all; `false` = none;
|
|
612
|
+
* a list = only those tags.
|
|
613
|
+
*/
|
|
614
|
+
readonly defaultTagMixins?: false | PackageTag[];
|
|
615
|
+
/**
|
|
616
|
+
* Extra repo-root paths that trigger a full re-synth during `sync --watch`
|
|
617
|
+
* (alongside `.projenrc.ts`). Repo-relative, e.g. `".example.projenrc.ts"`.
|
|
618
|
+
*/
|
|
619
|
+
readonly syncResynthPaths?: readonly string[];
|
|
620
|
+
/** GitHub Pages documentation included in the unified release workflow. */
|
|
621
|
+
readonly releaseDocs?: ReleaseDocsOptions;
|
|
622
|
+
/** Python package root passed to local release preparation when configured. */
|
|
623
|
+
readonly releasePythonRoot?: string;
|
|
624
|
+
/** Optional AI-generated release summary. Defaults to enabled. */
|
|
625
|
+
readonly releaseSummary?: boolean | ReleaseSummaryOptions;
|
|
626
|
+
/** Set to `false` to omit normal npm workspace publication. */
|
|
627
|
+
readonly nodeRelease?: boolean;
|
|
628
|
+
/** Unified dbx-tools release workflow, or no release surface. Defaults to `dbx-tools`. */
|
|
629
|
+
readonly releaseMode?: DBXToolsReleaseMode;
|
|
630
|
+
/** Prefix for generated release tags. Defaults to `v`. */
|
|
631
|
+
readonly releaseTagPrefix?: string;
|
|
632
|
+
/** Semantic PR title validation policy. Omitted or `false` disables title validation. */
|
|
633
|
+
readonly pullRequestTitlePolicy?: false | PullRequestTitlePolicyOptions;
|
|
634
|
+
/** Repository output paths excluded from generated workflow dependency-cache hashing. */
|
|
635
|
+
readonly workflowCacheIgnorePaths?: readonly string[];
|
|
636
|
+
/**
|
|
637
|
+
* Extra workspace member paths (repo-relative, POSIX) to list in the workspace
|
|
638
|
+
* config ALONGSIDE the discovered `packageRoots` members - for a package that
|
|
639
|
+
* is synthesized by its OWN `.projenrc.ts` (so it isn't a root subproject) but
|
|
640
|
+
* should still resolve as a workspace sibling. The `@dbx-tools/projen` engine in
|
|
641
|
+
* `projen/` is the case: it synthesizes itself (avoiding a dogfooding cycle) yet
|
|
642
|
+
* is a member of the single bun workspace, so the root links it from source.
|
|
643
|
+
*/
|
|
644
|
+
readonly extraWorkspaceMembers?: readonly string[];
|
|
645
|
+
/**
|
|
646
|
+
* Install workspace dependencies once from the custom root instead of once
|
|
647
|
+
* per child project during post-synthesis. Defaults to `true`; set `false` to
|
|
648
|
+
* preserve projen's native per-project install tasks.
|
|
649
|
+
*/
|
|
650
|
+
readonly rootInstallOnly?: boolean;
|
|
651
|
+
};
|
|
652
|
+
|
|
588
653
|
/** Options for {@link DBXToolsTypeScriptProject} (a package, or a compiling root). */
|
|
589
|
-
export
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
654
|
+
export type DBXToolsTypeScriptProjectOptions = Partial<
|
|
655
|
+
Omit<
|
|
656
|
+
typescript.TypeScriptProjectOptions,
|
|
657
|
+
keyof ReleaseProjectOptions | "release" | "releaseToNpm"
|
|
658
|
+
>
|
|
659
|
+
> &
|
|
660
|
+
DBXToolsJavaScriptProjectOptions & {
|
|
661
|
+
/** Emit the projen-owned bun app scaffolding (`bunfig.toml`/`dev.ts`/`build.ts`). */
|
|
662
|
+
readonly bunApp?: boolean;
|
|
663
|
+
};
|
|
594
664
|
|
|
595
665
|
/**
|
|
596
666
|
* A monorepo root. Scans `packageRoots` and appends a
|
|
@@ -609,14 +679,12 @@ export class DBXToolsNodeProject
|
|
|
609
679
|
vsCode?: DBXToolsVsCode;
|
|
610
680
|
readonly extraWorkspaceMembers: readonly string[];
|
|
611
681
|
readonly releaseBranch: string;
|
|
682
|
+
readonly workflowCacheIgnorePaths: readonly string[];
|
|
612
683
|
private readonly rootInstallOnly: boolean;
|
|
613
684
|
|
|
614
685
|
constructor(options: DBXToolsJavaScriptProjectOptions = {}) {
|
|
686
|
+
validateReleaseOptions(options);
|
|
615
687
|
const { name, scope } = resolveIdentity(options);
|
|
616
|
-
const releaseDefaults =
|
|
617
|
-
options.release && options.releaseTrigger === undefined
|
|
618
|
-
? { releaseTrigger: ReleaseTrigger.tagged({ tags: ["v*"] }) }
|
|
619
|
-
: {};
|
|
620
688
|
// Holds the workspace state (members/catalog/allowBuilds/overrides). Under
|
|
621
689
|
// bun, projen's base constructor does NOT create the `PnpmWorkspaceYaml`
|
|
622
690
|
// component (its `configurePnpm` call site is gated to pnpm), so this state's
|
|
@@ -626,7 +694,6 @@ export class DBXToolsNodeProject
|
|
|
626
694
|
const pnpmWorkspace = new PnpmWorkspaceState(options);
|
|
627
695
|
super({
|
|
628
696
|
...defaultProjectOptions(options),
|
|
629
|
-
...releaseDefaults,
|
|
630
697
|
pnpmOptions: {
|
|
631
698
|
...options.pnpmOptions,
|
|
632
699
|
workspaceYamlOptions: pnpmWorkspace.options,
|
|
@@ -645,8 +712,10 @@ export class DBXToolsNodeProject
|
|
|
645
712
|
this.scope = scope;
|
|
646
713
|
this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
|
|
647
714
|
this.releaseBranch = options.defaultReleaseBranch ?? "main";
|
|
715
|
+
this.workflowCacheIgnorePaths = options.workflowCacheIgnorePaths ?? [];
|
|
648
716
|
this.rootInstallOnly = options.rootInstallOnly !== false;
|
|
649
717
|
this.dbxToolsConfig = new DBXToolsConfig(this, options);
|
|
718
|
+
configureBuildWorkflow(this, options);
|
|
650
719
|
initProject(this, options);
|
|
651
720
|
}
|
|
652
721
|
|
|
@@ -654,7 +723,9 @@ export class DBXToolsNodeProject
|
|
|
654
723
|
const steps = super.renderWorkflowSetup(options);
|
|
655
724
|
if (this.parent) return steps;
|
|
656
725
|
return steps.flatMap((step) => {
|
|
657
|
-
if (step.uses === "oven-sh/setup-bun@v2")
|
|
726
|
+
if (step.uses === "oven-sh/setup-bun@v2") {
|
|
727
|
+
return [...bunCacheRestoreSteps(this, { ignorePaths: this.workflowCacheIgnorePaths })];
|
|
728
|
+
}
|
|
658
729
|
if (step.run === "bun install") {
|
|
659
730
|
return [
|
|
660
731
|
step,
|
|
@@ -669,16 +740,9 @@ export class DBXToolsNodeProject
|
|
|
669
740
|
}
|
|
670
741
|
|
|
671
742
|
public override preSynthesize(): void {
|
|
672
|
-
|
|
743
|
+
prepareRootSynthesis(this, this.rootInstallOnly);
|
|
673
744
|
super.preSynthesize();
|
|
674
|
-
|
|
675
|
-
for (const member of this.extraWorkspaceMembers) {
|
|
676
|
-
syncWorkspaceManifestVersion(join(this.outdir, member, "package.json"), version);
|
|
677
|
-
}
|
|
678
|
-
// Members come from the attached subprojects, which the root's scan appends
|
|
679
|
-
// after construction - so the list is filled here, not in the constructor.
|
|
680
|
-
// `extraWorkspaceMembers` adds self-synthesizing siblings (e.g. `projen/`).
|
|
681
|
-
this.pnpmWorkspace?.resolveMembers(this, this.extraWorkspaceMembers);
|
|
745
|
+
resolveRootWorkspace(this, this.extraWorkspaceMembers);
|
|
682
746
|
preSynthesizeProject(this);
|
|
683
747
|
}
|
|
684
748
|
}
|
|
@@ -726,10 +790,16 @@ export class DBXToolsTypeScriptProject
|
|
|
726
790
|
pnpmWorkspace?: PnpmWorkspaceState;
|
|
727
791
|
rootTsconfig?: DBXToolsRootTsconfig;
|
|
728
792
|
vsCode?: DBXToolsVsCode;
|
|
793
|
+
readonly extraWorkspaceMembers: readonly string[];
|
|
794
|
+
readonly releaseBranch: string;
|
|
795
|
+
readonly workflowCacheIgnorePaths: readonly string[];
|
|
796
|
+
private readonly rootInstallOnly: boolean;
|
|
729
797
|
|
|
730
798
|
constructor(options: DBXToolsTypeScriptProjectOptions) {
|
|
799
|
+
validateReleaseOptions(options);
|
|
731
800
|
const { name, scope } = resolveIdentity(options);
|
|
732
801
|
const parent = options?.parent;
|
|
802
|
+
const pnpmWorkspace = parent ? undefined : new PnpmWorkspaceState(options);
|
|
733
803
|
const packageManager =
|
|
734
804
|
options.packageManager ??
|
|
735
805
|
inheritedPackageManager(parent instanceof javascript.NodeProject ? parent : undefined);
|
|
@@ -738,6 +808,14 @@ export class DBXToolsTypeScriptProject
|
|
|
738
808
|
...defaultTypeScriptProjectOptions(options),
|
|
739
809
|
name: options.name ?? name,
|
|
740
810
|
packageManager,
|
|
811
|
+
...(pnpmWorkspace
|
|
812
|
+
? {
|
|
813
|
+
pnpmOptions: {
|
|
814
|
+
...options.pnpmOptions,
|
|
815
|
+
workspaceYamlOptions: pnpmWorkspace.options,
|
|
816
|
+
},
|
|
817
|
+
}
|
|
818
|
+
: {}),
|
|
741
819
|
tsconfig: {
|
|
742
820
|
...options.tsconfig,
|
|
743
821
|
include: options.tsconfig?.include,
|
|
@@ -750,7 +828,13 @@ export class DBXToolsTypeScriptProject
|
|
|
750
828
|
},
|
|
751
829
|
},
|
|
752
830
|
});
|
|
831
|
+
this.pnpmWorkspace = pnpmWorkspace;
|
|
832
|
+
pnpmWorkspace?.attachWorkspaceFile(this);
|
|
753
833
|
this.scope = scope;
|
|
834
|
+
this.extraWorkspaceMembers = options.extraWorkspaceMembers ?? [];
|
|
835
|
+
this.releaseBranch = options.defaultReleaseBranch ?? "main";
|
|
836
|
+
this.workflowCacheIgnorePaths = options.workflowCacheIgnorePaths ?? [];
|
|
837
|
+
this.rootInstallOnly = options.rootInstallOnly !== false;
|
|
754
838
|
// Pairs with `jsx` in SHARED_COMPILER_OPTIONS: projen's default `include` is
|
|
755
839
|
// `src/**/*.ts` only, which silently omits a `.tsx` file from the program
|
|
756
840
|
// instead of failing, so authoring a React component would otherwise need
|
|
@@ -772,27 +856,106 @@ export class DBXToolsTypeScriptProject
|
|
|
772
856
|
this.package.addField("version", readWorkspaceVersion(this.root.outdir));
|
|
773
857
|
addPackageFiles(this, "index.ts", "src");
|
|
774
858
|
// `bun test` intercepts `node:test` (the suites keep using node:test) and
|
|
775
|
-
// runs it with bun's own fast runner.
|
|
776
|
-
//
|
|
777
|
-
|
|
778
|
-
// exists, else succeed.
|
|
779
|
-
this.testTask.exec("bun test test", {
|
|
780
|
-
condition: 'find test -name "*.test.ts" 2>/dev/null | grep -q .',
|
|
781
|
-
});
|
|
859
|
+
// runs it with bun's own fast runner. The native no-tests option is portable
|
|
860
|
+
// across Windows and Unix and lets packages without tests remain a no-op.
|
|
861
|
+
this.testTask.exec("bun test test --pass-with-no-tests");
|
|
782
862
|
if (options.bunApp ?? false) {
|
|
783
863
|
new BunfigFile(this);
|
|
784
864
|
new BunDevServerFile(this);
|
|
785
865
|
new BunBuildFile(this);
|
|
786
866
|
}
|
|
867
|
+
configureBuildWorkflow(this, options);
|
|
787
868
|
initProject(this, options);
|
|
788
869
|
}
|
|
789
870
|
|
|
790
871
|
public override preSynthesize(): void {
|
|
872
|
+
prepareRootSynthesis(this, this.rootInstallOnly);
|
|
791
873
|
super.preSynthesize();
|
|
874
|
+
resolveRootWorkspace(this, this.extraWorkspaceMembers);
|
|
792
875
|
preSynthesizeProject(this);
|
|
793
876
|
}
|
|
794
877
|
}
|
|
795
878
|
|
|
879
|
+
function configureBuildWorkflow(
|
|
880
|
+
project: DBXToolsNodeProject | DBXToolsTypeScriptProject,
|
|
881
|
+
options: DBXToolsJavaScriptProjectOptions,
|
|
882
|
+
): void {
|
|
883
|
+
if (project.parent || !options.buildWorkflow || !project.github) return;
|
|
884
|
+
const validation = project.addTask("pr:validate", {
|
|
885
|
+
description: "Validate generated files and TypeScript packages",
|
|
886
|
+
});
|
|
887
|
+
validation.exec("bunx projen default");
|
|
888
|
+
validation.exec("bun run compile");
|
|
889
|
+
const configured = options.buildWorkflowOptions ?? {};
|
|
890
|
+
const compatibility = nodeWorkflowCompatibility(project);
|
|
891
|
+
const configuredRunner = configured.runsOn !== undefined || configured.runsOnGroup !== undefined;
|
|
892
|
+
const workflow = new BuildWorkflow(project, {
|
|
893
|
+
buildTask: validation,
|
|
894
|
+
artifactsDirectory: project.artifactsDirectory,
|
|
895
|
+
containerImage: options.workflowContainerImage,
|
|
896
|
+
gitIdentity: options.workflowGitIdentity,
|
|
897
|
+
permissions: { idToken: compatibility.determineIdTokenPermissions(options) },
|
|
898
|
+
...configured,
|
|
899
|
+
preBuildSteps: [
|
|
900
|
+
...project.renderWorkflowSetup({
|
|
901
|
+
installStepConfiguration: {
|
|
902
|
+
workingDirectory: compatibility.determineInstallWorkingDirectory(),
|
|
903
|
+
},
|
|
904
|
+
mutable: configured.mutableInstall ?? configured.mutableBuild ?? true,
|
|
905
|
+
}),
|
|
906
|
+
...(configured.preBuildSteps ?? []),
|
|
907
|
+
],
|
|
908
|
+
postBuildSteps: [...(options.postBuildSteps ?? [])],
|
|
909
|
+
runsOn: configuredRunner ? configured.runsOn : options.workflowRunsOn,
|
|
910
|
+
runsOnGroup: configuredRunner ? configured.runsOnGroup : options.workflowRunsOnGroup,
|
|
911
|
+
});
|
|
912
|
+
workflow.addPostBuildSteps(...compatibility.renderUploadCoverageJobStep(options));
|
|
913
|
+
compatibility.buildWorkflow = workflow;
|
|
914
|
+
|
|
915
|
+
if ((options.autoMerge ?? true) && project.github.mergify) {
|
|
916
|
+
const autoMerge = new AutoMerge(project.github, options.autoMergeOptions);
|
|
917
|
+
autoMerge.addConditionsLater({
|
|
918
|
+
render: () => workflow.buildJobIds.map((id) => `status-success=${id}`),
|
|
919
|
+
});
|
|
920
|
+
compatibility.autoMerge = autoMerge;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
interface NodeWorkflowCompatibility {
|
|
925
|
+
autoMerge?: AutoMerge;
|
|
926
|
+
buildWorkflow?: BuildWorkflow;
|
|
927
|
+
determineIdTokenPermissions(options: DBXToolsJavaScriptProjectOptions): JobPermission | undefined;
|
|
928
|
+
determineInstallWorkingDirectory(): string | undefined;
|
|
929
|
+
renderUploadCoverageJobStep(options: DBXToolsJavaScriptProjectOptions): JobStep[];
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Access the narrow NodeProject workflow hooks that have no public equivalent.
|
|
934
|
+
* BuildWorkflow itself is created exclusively through its public constructor.
|
|
935
|
+
*/
|
|
936
|
+
function nodeWorkflowCompatibility(project: javascript.NodeProject): NodeWorkflowCompatibility {
|
|
937
|
+
return project as unknown as NodeWorkflowCompatibility;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
function prepareRootSynthesis(
|
|
941
|
+
project: DBXToolsNodeProject | DBXToolsTypeScriptProject,
|
|
942
|
+
rootInstallOnly: boolean,
|
|
943
|
+
): void {
|
|
944
|
+
if (!project.parent && rootInstallOnly) project.with(ROOT_INSTALL_ONLY_MIXIN);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
function resolveRootWorkspace(
|
|
948
|
+
project: DBXToolsNodeProject | DBXToolsTypeScriptProject,
|
|
949
|
+
extraWorkspaceMembers: readonly string[],
|
|
950
|
+
): void {
|
|
951
|
+
if (project.parent) return;
|
|
952
|
+
const version = readWorkspaceVersion(project.outdir);
|
|
953
|
+
for (const member of extraWorkspaceMembers) {
|
|
954
|
+
syncWorkspaceManifestVersion(join(project.outdir, member, "package.json"), version);
|
|
955
|
+
}
|
|
956
|
+
project.pnpmWorkspace?.resolveMembers(project, extraWorkspaceMembers);
|
|
957
|
+
}
|
|
958
|
+
|
|
796
959
|
/**
|
|
797
960
|
* Regenerates the repo's generated source after synth: first the codegen
|
|
798
961
|
* modules (ts-to-zod schemas from each `codegen`-declaring package's upstream
|
|
@@ -808,8 +971,10 @@ export class DBXToolsTypeScriptProject
|
|
|
808
971
|
*/
|
|
809
972
|
class GeneratedSource extends Component {
|
|
810
973
|
public override postSynthesize(): void {
|
|
811
|
-
|
|
812
|
-
|
|
974
|
+
const projectRoot = this.project.outdir;
|
|
975
|
+
const includeRoot = this.project instanceof DBXToolsTypeScriptProject;
|
|
976
|
+
generateCodegen(projectRoot, { includeRoot });
|
|
977
|
+
generateBarrels({ projectRoot, includeRoot });
|
|
813
978
|
}
|
|
814
979
|
}
|
|
815
980
|
|
|
@@ -837,7 +1002,10 @@ class WorkspaceValidationTasks extends Component {
|
|
|
837
1002
|
public override preSynthesize(): void {
|
|
838
1003
|
if (this.configured) return;
|
|
839
1004
|
this.configured = true;
|
|
840
|
-
const project = this.project as
|
|
1005
|
+
const project = this.project as DBXToolsNodeProject | DBXToolsTypeScriptProject;
|
|
1006
|
+
if (project.subprojects.length === 0 && project.extraWorkspaceMembers.length === 0) {
|
|
1007
|
+
return;
|
|
1008
|
+
}
|
|
841
1009
|
for (const task of [project.compileTask, project.testTask]) {
|
|
842
1010
|
task.exec(`bun run --filter '*' ${task.name}`);
|
|
843
1011
|
}
|
|
@@ -852,29 +1020,17 @@ class WorkspaceValidationTasks extends Component {
|
|
|
852
1020
|
* off) do not gain new files.
|
|
853
1021
|
*/
|
|
854
1022
|
class WorkflowDefaults extends Component {
|
|
1023
|
+
constructor(
|
|
1024
|
+
project: javascript.NodeProject,
|
|
1025
|
+
private readonly pullRequestTitlePolicy: false | PullRequestTitlePolicyOptions | undefined,
|
|
1026
|
+
) {
|
|
1027
|
+
super(project);
|
|
1028
|
+
}
|
|
1029
|
+
|
|
855
1030
|
public override preSynthesize(): void {
|
|
856
1031
|
const project = this.project as javascript.NodeProject;
|
|
857
1032
|
const workflow = project.buildWorkflow?.workflow;
|
|
858
|
-
if (workflow) {
|
|
859
|
-
const job = workflow.getJob("build");
|
|
860
|
-
if ("steps" in job) {
|
|
861
|
-
const mutableJob = job as unknown as { steps: JobStep[] | (() => JobStep[]) };
|
|
862
|
-
const configuredSteps = mutableJob.steps;
|
|
863
|
-
const rewrite = (steps: JobStep[]): JobStep[] =>
|
|
864
|
-
steps.map((step) =>
|
|
865
|
-
step.name === "build"
|
|
866
|
-
? {
|
|
867
|
-
...step,
|
|
868
|
-
name: "Validate generated files and types",
|
|
869
|
-
run: "bunx projen default\nbun run compile",
|
|
870
|
-
}
|
|
871
|
-
: step,
|
|
872
|
-
);
|
|
873
|
-
mutableJob.steps =
|
|
874
|
-
typeof configuredSteps === "function"
|
|
875
|
-
? () => rewrite(configuredSteps())
|
|
876
|
-
: rewrite(configuredSteps);
|
|
877
|
-
}
|
|
1033
|
+
if (workflow && this.pullRequestTitlePolicy) {
|
|
878
1034
|
workflow.addJob("pr-title", {
|
|
879
1035
|
name: "Validate PR title",
|
|
880
1036
|
runsOn: ["ubuntu-latest"],
|
|
@@ -886,8 +1042,8 @@ class WorkflowDefaults extends Component {
|
|
|
886
1042
|
uses: "amannn/action-semantic-pull-request@v6",
|
|
887
1043
|
env: { GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}" },
|
|
888
1044
|
with: {
|
|
889
|
-
types:
|
|
890
|
-
requireScope: false,
|
|
1045
|
+
types: this.pullRequestTitlePolicy.types.join("\n"),
|
|
1046
|
+
requireScope: this.pullRequestTitlePolicy.requireScope ?? false,
|
|
891
1047
|
},
|
|
892
1048
|
},
|
|
893
1049
|
],
|
|
@@ -995,11 +1151,19 @@ function packageNameFor(scope: string, relPath: string, omitPrefixes: string[]):
|
|
|
995
1151
|
* either way it is parsed through {@link PackageIdentifier} so a scoped value
|
|
996
1152
|
* (`@dbx-tools` or a full `@dbx-tools/root` name) yields the bare scope `dbx-tools`.
|
|
997
1153
|
*/
|
|
998
|
-
function resolveIdentity(options: {
|
|
1154
|
+
function resolveIdentity(options: {
|
|
1155
|
+
name?: string;
|
|
1156
|
+
scope?: string;
|
|
1157
|
+
outdir?: string;
|
|
1158
|
+
parent?: Project;
|
|
1159
|
+
}): {
|
|
999
1160
|
name: string;
|
|
1000
1161
|
scope: string;
|
|
1001
1162
|
} {
|
|
1002
|
-
const
|
|
1163
|
+
const projectRoot = options.parent
|
|
1164
|
+
? resolve(options.parent.outdir, options.outdir ?? ".")
|
|
1165
|
+
: resolve(options.outdir ?? process.cwd());
|
|
1166
|
+
const name = options.name && options.name.length ? options.name : projectName(projectRoot);
|
|
1003
1167
|
const rawScope = options.scope && options.scope.length ? options.scope : name;
|
|
1004
1168
|
const identifier = PackageIdentifier.parse(rawScope);
|
|
1005
1169
|
return { name, scope: identifier?.scope ?? identifier?.name ?? rawScope };
|
|
@@ -1227,9 +1391,7 @@ function initProject(
|
|
|
1227
1391
|
project.annotateGenerated(`/${root}/**/index.ts`);
|
|
1228
1392
|
project.annotateGenerated(`/${root}/openapi/**`);
|
|
1229
1393
|
}
|
|
1230
|
-
const extraWorkspaceMembers
|
|
1231
|
-
project instanceof DBXToolsNodeProject ? project.extraWorkspaceMembers : [];
|
|
1232
|
-
for (const member of extraWorkspaceMembers) {
|
|
1394
|
+
for (const member of project.extraWorkspaceMembers) {
|
|
1233
1395
|
project.annotateGenerated(`/${member}/index.ts`);
|
|
1234
1396
|
}
|
|
1235
1397
|
|
|
@@ -1241,13 +1403,17 @@ function initProject(
|
|
|
1241
1403
|
// repairs the worktree it is meant to validate; `eslint:fix` is the explicit
|
|
1242
1404
|
// local mutation path.
|
|
1243
1405
|
const eslint = new javascript.Eslint(project, {
|
|
1244
|
-
dirs: [...roots,
|
|
1406
|
+
dirs: [...roots, ...project.extraWorkspaceMembers],
|
|
1245
1407
|
fileExtensions: [".ts", ".tsx"],
|
|
1246
1408
|
projectService: true,
|
|
1247
1409
|
prettier: Boolean(project.prettier),
|
|
1248
|
-
tsconfigPath:
|
|
1410
|
+
tsconfigPath:
|
|
1411
|
+
project instanceof typescript.TypeScriptProject
|
|
1412
|
+
? (project.tsconfig?.fileName ?? "./tsconfig.json")
|
|
1413
|
+
: "./tsconfig.json",
|
|
1249
1414
|
commandOptions: { fix: false },
|
|
1250
1415
|
});
|
|
1416
|
+
eslint.allowDefaultProjectFiles(".projenrc.ts");
|
|
1251
1417
|
project.addTask("eslint:fix", {
|
|
1252
1418
|
description: "Fix ESLint issues across the codebase",
|
|
1253
1419
|
exec: "bun run eslint -- --fix",
|
|
@@ -1260,7 +1426,9 @@ function initProject(
|
|
|
1260
1426
|
eslint.addIgnorePattern(`${root}/**/index.ts`);
|
|
1261
1427
|
}
|
|
1262
1428
|
eslint.addIgnorePattern("**/src/generated/**");
|
|
1263
|
-
|
|
1429
|
+
for (const member of project.extraWorkspaceMembers) {
|
|
1430
|
+
eslint.addIgnorePattern(`${member}/index.ts`);
|
|
1431
|
+
}
|
|
1264
1432
|
// The generated bun app scripts + unmanaged overrides live at the package root,
|
|
1265
1433
|
// outside any `src/**` tsconfig include, so the type-aware parser cannot resolve
|
|
1266
1434
|
// them to a project. ESLint still cannot parse them.
|
|
@@ -1362,17 +1530,21 @@ function initProject(
|
|
|
1362
1530
|
}
|
|
1363
1531
|
|
|
1364
1532
|
new WorkspaceValidationTasks(project);
|
|
1365
|
-
new WorkflowDefaults(project);
|
|
1533
|
+
new WorkflowDefaults(project, options.pullRequestTitlePolicy);
|
|
1366
1534
|
new PrettierIgnoreGenerated(project);
|
|
1367
1535
|
|
|
1368
1536
|
new GeneratedSource(project);
|
|
1369
1537
|
// Version mutation, reviewed release preparation, and public publication are
|
|
1370
1538
|
// separate surfaces owned by one release component.
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1539
|
+
if (options.releaseMode !== "disabled") {
|
|
1540
|
+
new DBXToolsRelease(project, {
|
|
1541
|
+
tagPrefix: options.releaseTagPrefix,
|
|
1542
|
+
nodeRelease: options.nodeRelease,
|
|
1543
|
+
docs: options.releaseDocs,
|
|
1544
|
+
pythonRoot: options.releasePythonRoot,
|
|
1545
|
+
summary: options.releaseSummary,
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1376
1548
|
}
|
|
1377
1549
|
|
|
1378
1550
|
/**
|