@smoothbricks/cli 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +208 -83
  2. package/dist/cli.js +50 -20
  3. package/dist/lib/devenv.d.ts +6 -0
  4. package/dist/lib/devenv.d.ts.map +1 -0
  5. package/dist/lib/devenv.js +82 -0
  6. package/dist/lib/workspace.d.ts +5 -0
  7. package/dist/lib/workspace.d.ts.map +1 -1
  8. package/dist/lib/workspace.js +62 -5
  9. package/dist/monorepo/index.d.ts +6 -1
  10. package/dist/monorepo/index.d.ts.map +1 -1
  11. package/dist/monorepo/index.js +38 -5
  12. package/dist/monorepo/lockfile.d.ts +5 -1
  13. package/dist/monorepo/lockfile.d.ts.map +1 -1
  14. package/dist/monorepo/lockfile.js +45 -5
  15. package/dist/monorepo/managed-files.d.ts +1 -1
  16. package/dist/monorepo/managed-files.d.ts.map +1 -1
  17. package/dist/monorepo/managed-files.js +27 -10
  18. package/dist/monorepo/package-hygiene.js +1 -1
  19. package/dist/monorepo/package-policy.d.ts +3 -0
  20. package/dist/monorepo/package-policy.d.ts.map +1 -1
  21. package/dist/monorepo/package-policy.js +122 -19
  22. package/dist/monorepo/packed-manifest.d.ts +4 -0
  23. package/dist/monorepo/packed-manifest.d.ts.map +1 -0
  24. package/dist/monorepo/packed-manifest.js +51 -0
  25. package/dist/monorepo/packed-package.d.ts.map +1 -1
  26. package/dist/monorepo/packed-package.js +6 -0
  27. package/dist/monorepo/packs/index.d.ts.map +1 -1
  28. package/dist/monorepo/packs/index.js +4 -1
  29. package/dist/monorepo/publish-workflow.d.ts +86 -0
  30. package/dist/monorepo/publish-workflow.d.ts.map +1 -0
  31. package/dist/monorepo/publish-workflow.js +343 -0
  32. package/dist/nx-version-actions.cjs +25 -0
  33. package/dist/nx-version-actions.d.cts +6 -0
  34. package/dist/nx-version-actions.d.cts.map +1 -0
  35. package/dist/release/core.d.ts +50 -0
  36. package/dist/release/core.d.ts.map +1 -0
  37. package/dist/release/core.js +97 -0
  38. package/dist/release/github-release.d.ts +46 -0
  39. package/dist/release/github-release.d.ts.map +1 -0
  40. package/dist/release/github-release.js +97 -0
  41. package/dist/release/index.d.ts +14 -5
  42. package/dist/release/index.d.ts.map +1 -1
  43. package/dist/release/index.js +544 -109
  44. package/dist/release/npm-auth.d.ts +17 -0
  45. package/dist/release/npm-auth.d.ts.map +1 -0
  46. package/dist/release/npm-auth.js +51 -0
  47. package/dist/release/orchestration.d.ts +48 -0
  48. package/dist/release/orchestration.d.ts.map +1 -0
  49. package/dist/release/orchestration.js +105 -0
  50. package/dist/release/publish-plan.d.ts +17 -0
  51. package/dist/release/publish-plan.d.ts.map +1 -0
  52. package/dist/release/publish-plan.js +15 -0
  53. package/dist/release/retag-unpublished.d.ts +34 -0
  54. package/dist/release/retag-unpublished.d.ts.map +1 -0
  55. package/dist/release/retag-unpublished.js +77 -0
  56. package/managed/raw/tooling/git-hooks/pre-commit.sh +2 -7
  57. package/managed/templates/github/workflows/ci.yml +2 -0
  58. package/package.json +24 -3
  59. package/src/cli.ts +64 -25
  60. package/src/lib/devenv.test.ts +28 -0
  61. package/src/lib/devenv.ts +89 -0
  62. package/src/lib/workspace.ts +76 -5
  63. package/src/monorepo/__tests__/nx-version-actions.test.ts +75 -0
  64. package/src/monorepo/__tests__/publish-workflow.test.ts +315 -0
  65. package/src/monorepo/index.ts +45 -5
  66. package/src/monorepo/lockfile.ts +52 -7
  67. package/src/monorepo/managed-files.ts +42 -12
  68. package/src/monorepo/package-hygiene.ts +1 -1
  69. package/src/monorepo/package-policy.ts +134 -18
  70. package/src/monorepo/packed-manifest.ts +67 -0
  71. package/src/monorepo/packed-package.ts +7 -0
  72. package/src/monorepo/packs/index.ts +4 -0
  73. package/src/monorepo/publish-workflow.ts +430 -0
  74. package/src/nx-version-actions.cts +36 -0
  75. package/src/release/__tests__/core-properties.test.ts +149 -0
  76. package/src/release/__tests__/core-scenarios.test.ts +177 -0
  77. package/src/release/__tests__/core.test.ts +73 -0
  78. package/src/release/__tests__/fixture-repo.test.ts +305 -0
  79. package/src/release/__tests__/github-release.test.ts +144 -0
  80. package/src/release/__tests__/helpers/fixture-repo.ts +113 -0
  81. package/src/release/__tests__/npm-auth.test.ts +129 -0
  82. package/src/release/__tests__/orchestration.test.ts +202 -0
  83. package/src/release/__tests__/publish-plan.test.ts +61 -0
  84. package/src/release/__tests__/retag-unpublished.test.ts +160 -0
  85. package/src/release/core.ts +170 -0
  86. package/src/release/github-release.ts +134 -0
  87. package/src/release/index.ts +662 -116
  88. package/src/release/npm-auth.ts +122 -0
  89. package/src/release/orchestration.ts +186 -0
  90. package/src/release/publish-plan.ts +37 -0
  91. package/src/release/retag-unpublished.ts +122 -0
  92. package/managed/templates/github/workflows/publish.yml +0 -136
@@ -0,0 +1,343 @@
1
+ export var PublishWorkflowStepKind;
2
+ (function (PublishWorkflowStepKind) {
3
+ PublishWorkflowStepKind["Checkout"] = "checkout";
4
+ PublishWorkflowStepKind["SetupDevenv"] = "setup-devenv";
5
+ PublishWorkflowStepKind["ConfigureReleaseAuthor"] = "configure-release-author";
6
+ PublishWorkflowStepKind["BuildSelfHostedCli"] = "build-self-hosted-cli";
7
+ PublishWorkflowStepKind["RepairPendingReleases"] = "repair-pending-releases";
8
+ PublishWorkflowStepKind["VersionRelease"] = "version-release";
9
+ PublishWorkflowStepKind["CheckManagedMonorepoFiles"] = "check-managed-monorepo-files";
10
+ PublishWorkflowStepKind["Build"] = "build";
11
+ PublishWorkflowStepKind["Lint"] = "lint";
12
+ PublishWorkflowStepKind["UnitTests"] = "unit-tests";
13
+ PublishWorkflowStepKind["UploadTraceDbs"] = "upload-trace-dbs";
14
+ PublishWorkflowStepKind["ValidateMonorepoConfig"] = "validate-monorepo-config";
15
+ PublishWorkflowStepKind["PublishRelease"] = "publish-release";
16
+ PublishWorkflowStepKind["SaveNixDevenv"] = "save-nix-devenv";
17
+ })(PublishWorkflowStepKind || (PublishWorkflowStepKind = {}));
18
+ export function definePublishWorkflow(options = {}) {
19
+ const versionMode = githubExpression('steps.version.outputs.mode');
20
+ const setupSteps = [
21
+ { kind: PublishWorkflowStepKind.Checkout, name: '📥 Checkout' },
22
+ { kind: PublishWorkflowStepKind.SetupDevenv, name: '🧱 Setup Nix/devenv', id: 'setup' },
23
+ { kind: PublishWorkflowStepKind.ConfigureReleaseAuthor, name: '🤖 Configure release author' },
24
+ ];
25
+ if (options.repoName === '@smoothbricks/codebase') {
26
+ setupSteps.push({ kind: PublishWorkflowStepKind.BuildSelfHostedCli, name: '🏗️ Build self-hosted smoo' });
27
+ }
28
+ return {
29
+ steps: numberWorkflowSteps([
30
+ ...setupSteps,
31
+ {
32
+ kind: PublishWorkflowStepKind.RepairPendingReleases,
33
+ name: '🧯 Repair pending releases',
34
+ needsNodeAuthToken: true,
35
+ },
36
+ { kind: PublishWorkflowStepKind.VersionRelease, name: '🏷️ Version release', id: 'version' },
37
+ {
38
+ kind: PublishWorkflowStepKind.CheckManagedMonorepoFiles,
39
+ name: `✅ Check managed monorepo files (${versionMode})`,
40
+ condition: 'version-mode-not-none',
41
+ },
42
+ {
43
+ kind: PublishWorkflowStepKind.Build,
44
+ name: `🔨 Build (${versionMode})`,
45
+ condition: 'version-mode-not-none',
46
+ nxTarget: 'build',
47
+ },
48
+ {
49
+ kind: PublishWorkflowStepKind.Lint,
50
+ name: `🔍 Lint (${versionMode})`,
51
+ condition: 'version-mode-not-none',
52
+ nxTarget: 'lint',
53
+ },
54
+ {
55
+ kind: PublishWorkflowStepKind.UnitTests,
56
+ name: `🧪 Unit Tests (${versionMode})`,
57
+ condition: 'version-mode-not-none',
58
+ nxTarget: 'test',
59
+ },
60
+ { kind: PublishWorkflowStepKind.UploadTraceDbs, name: '📎 Upload trace DBs', condition: 'failure' },
61
+ {
62
+ kind: PublishWorkflowStepKind.ValidateMonorepoConfig,
63
+ name: `✅ Validate monorepo config (${versionMode})`,
64
+ condition: 'version-mode-not-none',
65
+ },
66
+ {
67
+ kind: PublishWorkflowStepKind.PublishRelease,
68
+ name: `📦 Publish release (${versionMode})`,
69
+ needsNodeAuthToken: true,
70
+ },
71
+ {
72
+ kind: PublishWorkflowStepKind.SaveNixDevenv,
73
+ name: '🧹 Cleanup and cache Nix/devenv',
74
+ condition: 'always',
75
+ },
76
+ ]),
77
+ };
78
+ }
79
+ function numberWorkflowSteps(steps) {
80
+ return steps.map((step, index) => ({ ...step, number: index + 2 }));
81
+ }
82
+ export async function runPublishWorkflow(workflow, context) {
83
+ let setupOutputs = { nixCacheHit: '', devenvCacheHit: '' };
84
+ let version = { mode: 'none', projects: [] };
85
+ let failed = false;
86
+ let failure;
87
+ for (const step of workflow.steps) {
88
+ if (!shouldRunStep(step, version, failed)) {
89
+ continue;
90
+ }
91
+ try {
92
+ switch (step.kind) {
93
+ case PublishWorkflowStepKind.Checkout:
94
+ await context.callbacks.checkout();
95
+ break;
96
+ case PublishWorkflowStepKind.SetupDevenv:
97
+ setupOutputs = await context.callbacks.setupDevenv();
98
+ break;
99
+ case PublishWorkflowStepKind.ConfigureReleaseAuthor:
100
+ await context.callbacks.configureReleaseAuthor();
101
+ break;
102
+ case PublishWorkflowStepKind.BuildSelfHostedCli:
103
+ await context.callbacks.buildSelfHostedCli();
104
+ break;
105
+ case PublishWorkflowStepKind.RepairPendingReleases:
106
+ await context.callbacks.repairPendingReleases({
107
+ dryRun: context.inputs.dryRun,
108
+ nodeAuthToken: context.nodeAuthToken,
109
+ });
110
+ break;
111
+ case PublishWorkflowStepKind.VersionRelease:
112
+ version = await context.callbacks.versionRelease(context.inputs);
113
+ break;
114
+ case PublishWorkflowStepKind.CheckManagedMonorepoFiles:
115
+ await context.callbacks.checkManagedMonorepoFiles();
116
+ break;
117
+ case PublishWorkflowStepKind.Build:
118
+ case PublishWorkflowStepKind.Lint:
119
+ case PublishWorkflowStepKind.UnitTests:
120
+ if (!step.nxTarget) {
121
+ throw new Error(`Workflow step ${step.kind} is missing an Nx target.`);
122
+ }
123
+ await context.callbacks.nxRunMany({ target: step.nxTarget, projects: version.projects });
124
+ break;
125
+ case PublishWorkflowStepKind.UploadTraceDbs:
126
+ await context.callbacks.uploadTraceDbs();
127
+ break;
128
+ case PublishWorkflowStepKind.ValidateMonorepoConfig:
129
+ await context.callbacks.validateMonorepoConfig();
130
+ break;
131
+ case PublishWorkflowStepKind.PublishRelease:
132
+ await context.callbacks.publishRelease({
133
+ bump: context.inputs.bump,
134
+ dryRun: context.inputs.dryRun,
135
+ nodeAuthToken: context.nodeAuthToken,
136
+ });
137
+ break;
138
+ case PublishWorkflowStepKind.SaveNixDevenv:
139
+ await context.callbacks.saveNixDevenv(setupOutputs);
140
+ break;
141
+ }
142
+ }
143
+ catch (error) {
144
+ failed = true;
145
+ failure = error;
146
+ }
147
+ }
148
+ if (failure) {
149
+ throw failure;
150
+ }
151
+ return { version, failed };
152
+ }
153
+ function shouldRunStep(step, version, failed) {
154
+ if (step.condition === 'version-mode-not-none') {
155
+ return version.mode !== 'none';
156
+ }
157
+ if (step.condition === 'failure') {
158
+ return failed;
159
+ }
160
+ return true;
161
+ }
162
+ export function renderPublishWorkflowYaml(options = {}) {
163
+ const steps = definePublishWorkflow(options).steps;
164
+ return `${renderPublishWorkflowHeader()}${renderPublishWorkflowSteps(steps)}`;
165
+ }
166
+ function renderPublishWorkflowHeader() {
167
+ return `name: Publish
168
+
169
+ on:
170
+ workflow_dispatch:
171
+ inputs:
172
+ bump:
173
+ type: choice
174
+ description:
175
+ Use auto for conventional commits, or force a semver bump. Prerelease publishes to next; all others publish to
176
+ latest.
177
+ options: [auto, patch, minor, major, prerelease]
178
+ default: auto
179
+ dry_run:
180
+ type: boolean
181
+ description: Run release commands without writing versions, tags, publishes, or GitHub Releases.
182
+ default: false
183
+
184
+ permissions:
185
+ contents: write
186
+ id-token: write
187
+
188
+ concurrency:
189
+ group: release-${githubExpression('github.ref')}
190
+ cancel-in-progress: false
191
+
192
+ defaults:
193
+ run:
194
+ working-directory: tooling/direnv
195
+
196
+ jobs:
197
+ publish:
198
+ runs-on: ubuntu-latest
199
+ env:
200
+ NIX_STORE_NAR: ${githubExpression('github.workspace')}/nix-store.nar
201
+ GH_TOKEN: ${githubExpression('github.token')}
202
+ steps:
203
+ `;
204
+ }
205
+ function renderPublishWorkflowSteps(steps) {
206
+ const lines = [];
207
+ for (const step of steps) {
208
+ lines.push(...sectionLinesBefore(step));
209
+ lines.push(...commentLinesForStep(step));
210
+ lines.push(...yamlLinesForStep(step));
211
+ lines.push('');
212
+ }
213
+ return `${lines.join('\n').trimEnd()}\n`;
214
+ }
215
+ function sectionLinesBefore(step) {
216
+ if (step.kind === PublishWorkflowStepKind.Checkout) {
217
+ return [' # --- Setup --------------------------------------------------------------', ''];
218
+ }
219
+ if (step.kind === PublishWorkflowStepKind.CheckManagedMonorepoFiles) {
220
+ return [
221
+ ' # --- Validation ---------------------------------------------------------',
222
+ '',
223
+ ' # Release validation intentionally does not restore persisted Nx task',
224
+ ' # cache. Nx may reuse tasks produced earlier in this same job, but publish',
225
+ ' # never relies on task outputs restored from CI cache. version runs before',
226
+ ' # validation so the commit completed below is the commit that was checked.',
227
+ '',
228
+ ];
229
+ }
230
+ if (step.kind === PublishWorkflowStepKind.PublishRelease) {
231
+ return [' # --- Release ------------------------------------------------------------', ''];
232
+ }
233
+ if (step.kind === PublishWorkflowStepKind.SaveNixDevenv) {
234
+ return [' # --- Cleanup ------------------------------------------------------------', ''];
235
+ }
236
+ return [];
237
+ }
238
+ function commentLinesForStep(step) {
239
+ if (step.kind === PublishWorkflowStepKind.Checkout) {
240
+ return [' # Step 1: GitHub adds "Set up job" automatically', ' # Step 2'];
241
+ }
242
+ if (step.kind === PublishWorkflowStepKind.SetupDevenv) {
243
+ return [
244
+ ' # Step 3. Composite action internals do not affect top-level job step',
245
+ ' # anchors; update these comments if top-level steps move.',
246
+ ];
247
+ }
248
+ return [` # Step ${step.number}`];
249
+ }
250
+ function yamlLinesForStep(step) {
251
+ switch (step.kind) {
252
+ case PublishWorkflowStepKind.Checkout:
253
+ return [
254
+ ` - name: ${step.name}`,
255
+ ' uses: actions/checkout@v6.0.2',
256
+ ' with:',
257
+ ' filter: blob:none',
258
+ ' fetch-depth: 0',
259
+ ];
260
+ case PublishWorkflowStepKind.SetupDevenv:
261
+ return [` - name: ${step.name}`, ' id: setup', ' uses: ./.github/actions/setup-devenv'];
262
+ case PublishWorkflowStepKind.ConfigureReleaseAuthor:
263
+ return [
264
+ ` - name: ${step.name}`,
265
+ ' run:',
266
+ ' git config user.name "github-actions[bot]" && git config user.email',
267
+ ' "41898282+github-actions[bot]@users.noreply.github.com"',
268
+ ];
269
+ case PublishWorkflowStepKind.BuildSelfHostedCli:
270
+ return [
271
+ ` - name: ${step.name}`,
272
+ ' # SmoothBricks self-hosts smoo from source, but Nx release loads',
273
+ ' # @smoothbricks/cli/nx-version-actions through the built package export.',
274
+ ' run: nx build @smoothbricks/cli',
275
+ ];
276
+ case PublishWorkflowStepKind.RepairPendingReleases:
277
+ return [
278
+ ` - name: ${step.name}`,
279
+ ' env:',
280
+ ` NODE_AUTH_TOKEN: ${githubExpression('secrets.NPM_TOKEN')}`,
281
+ ` run: smoo release repair-pending --dry-run "${githubExpression('inputs.dry_run')}"`,
282
+ ];
283
+ case PublishWorkflowStepKind.VersionRelease:
284
+ return [
285
+ ` - name: ${step.name}`,
286
+ ' id: version',
287
+ ' run:',
288
+ ` smoo release version --bump "${githubExpression('inputs.bump')}" --dry-run "${githubExpression('inputs.dry_run')}" --github-output`,
289
+ ' "$GITHUB_OUTPUT"',
290
+ ];
291
+ case PublishWorkflowStepKind.CheckManagedMonorepoFiles:
292
+ return conditionalRunStep(step, 'smoo monorepo check');
293
+ case PublishWorkflowStepKind.Build:
294
+ return conditionalRunStep(step, `smoo github-ci nx-run-many --targets build --projects "${githubExpression('steps.version.outputs.projects')}"`);
295
+ case PublishWorkflowStepKind.Lint:
296
+ return conditionalRunStep(step, `smoo github-ci nx-run-many --targets lint --projects "${githubExpression('steps.version.outputs.projects')}"`);
297
+ case PublishWorkflowStepKind.UnitTests:
298
+ return conditionalRunStep(step, `smoo github-ci nx-run-many --targets test --projects "${githubExpression('steps.version.outputs.projects')}"`);
299
+ case PublishWorkflowStepKind.UploadTraceDbs:
300
+ return [
301
+ ` - name: ${step.name}`,
302
+ ` if: ${githubExpression('failure()')}`,
303
+ ' uses: actions/upload-artifact@v4',
304
+ ' with:',
305
+ ` name: trace-results-${githubExpression('github.run_id')}`,
306
+ ' path: packages/*/.trace-results.db',
307
+ ' if-no-files-found: ignore',
308
+ ' retention-days: 14',
309
+ ' include-hidden-files: true',
310
+ ];
311
+ case PublishWorkflowStepKind.ValidateMonorepoConfig:
312
+ return conditionalRunStep(step, 'smoo monorepo validate');
313
+ case PublishWorkflowStepKind.PublishRelease:
314
+ return [
315
+ ` - name: ${step.name}`,
316
+ ' # smoo packs with Bun, then publishes tarballs with npm. Existing',
317
+ ' # packages use trusted publishing/OIDC; first publishes use NODE_AUTH_TOKEN',
318
+ ' # because npm trust can only be configured after a package exists.',
319
+ ' env:',
320
+ ` NODE_AUTH_TOKEN: ${githubExpression('secrets.NPM_TOKEN')}`,
321
+ ` run: smoo release publish --bump "${githubExpression('inputs.bump')}" --dry-run "${githubExpression('inputs.dry_run')}"`,
322
+ ];
323
+ case PublishWorkflowStepKind.SaveNixDevenv:
324
+ return [
325
+ ` - name: ${step.name}`,
326
+ ` if: ${githubExpression('always()')}`,
327
+ ' uses: ./.github/actions/save-nix-devenv',
328
+ ' with:',
329
+ ` nix-cache-hit: ${githubExpression('steps.setup.outputs.nix-cache-hit')}`,
330
+ ` devenv-cache-hit: ${githubExpression('steps.setup.outputs.devenv-cache-hit')}`,
331
+ ];
332
+ }
333
+ }
334
+ function conditionalRunStep(step, run) {
335
+ return [
336
+ ` - name: ${step.name}`,
337
+ ` if: ${githubExpression("steps.version.outputs.mode != 'none'")}`,
338
+ ` run: ${run}`,
339
+ ];
340
+ }
341
+ function githubExpression(expression) {
342
+ return ['$', '{{ ', expression, ' }}'].join('');
343
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ const nxJsVersionActions = require('@nx/js/src/release/version-actions');
3
+ const baseVersionActions = nxJsVersionActions.default ?? nxJsVersionActions;
4
+ const afterAllProjectsVersioned = async (cwd, options) => {
5
+ const result = await nxJsVersionActions.afterAllProjectsVersioned(cwd, options);
6
+ // Temporary Bun workaround. Remove this hook only after all three issues are
7
+ // fixed in supported Bun versions:
8
+ // - https://github.com/oven-sh/bun/issues/18906
9
+ // - https://github.com/oven-sh/bun/issues/20477
10
+ // - https://github.com/oven-sh/bun/issues/20829
11
+ // Nx runs `bun install --lockfile-only`, but Bun currently leaves workspace
12
+ // versions stale in bun.lock. `bun pm pack` then rewrites `workspace:*` using
13
+ // those stale lockfile versions instead of the current package.json versions.
14
+ const { syncBunLockfileVersions } = await import('./monorepo/lockfile.js');
15
+ const updated = syncBunLockfileVersions(cwd);
16
+ if (updated === 0) {
17
+ return result;
18
+ }
19
+ return {
20
+ changedFiles: Array.from(new Set([...result.changedFiles, 'bun.lock'])),
21
+ deletedFiles: result.deletedFiles,
22
+ };
23
+ };
24
+ baseVersionActions.afterAllProjectsVersioned = afterAllProjectsVersioned;
25
+ module.exports = baseVersionActions;
@@ -0,0 +1,6 @@
1
+ import type { AfterAllProjectsVersioned, VersionActions } from 'nx/release';
2
+ declare const baseVersionActions: typeof VersionActions & {
3
+ afterAllProjectsVersioned: AfterAllProjectsVersioned;
4
+ };
5
+ export = baseVersionActions;
6
+ //# sourceMappingURL=nx-version-actions.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nx-version-actions.d.cts","sourceRoot":"","sources":["../src/nx-version-actions.cts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAQ5E,QAAA,MAAM,kBAAkB;+BALyC,yBAAyB;CAKf,CAAC;AA2B5E,SAAS,kBAAkB,CAAC"}
@@ -0,0 +1,50 @@
1
+ export interface ReleasePackageInfo {
2
+ name: string;
3
+ path: string;
4
+ version: string;
5
+ }
6
+ export interface GitReleaseTagInfo {
7
+ name: string;
8
+ sha: string;
9
+ timestamp: number;
10
+ }
11
+ export interface MatchedReleaseTag<Package extends ReleasePackageInfo = ReleasePackageInfo> {
12
+ tag: string;
13
+ sha: string;
14
+ timestamp: number;
15
+ pkg: Package;
16
+ }
17
+ export interface ReleaseTagRecord<Package extends ReleasePackageInfo = ReleasePackageInfo> extends MatchedReleaseTag<Package> {
18
+ needsNpmPublish: boolean;
19
+ needsGithubRelease: boolean;
20
+ }
21
+ export interface ReleaseTarget<Package extends ReleasePackageInfo = ReleasePackageInfo> {
22
+ sha: string;
23
+ timestamp: number;
24
+ packages: Package[];
25
+ npmPackages: Package[];
26
+ githubPackages: Package[];
27
+ }
28
+ export interface DurableTagState {
29
+ npmPublished: boolean;
30
+ githubReleaseExists: boolean;
31
+ }
32
+ export interface ReleasePlanningShell {
33
+ listReleaseTagsByCreatorDate(): Promise<GitReleaseTagInfo[]>;
34
+ isAncestor(ancestor: string, descendant: string): Promise<boolean>;
35
+ packageVersionAtRef(packagePath: string, ref: string): Promise<string | null>;
36
+ durableTagState(pkg: ReleasePackageInfo, tag: string): Promise<DurableTagState>;
37
+ }
38
+ export declare function releaseTag(pkg: Pick<ReleasePackageInfo, 'name' | 'version'>): string;
39
+ export declare function npmDistTagForVersion(version: string): string;
40
+ export declare function releasePackageForTag<Package extends Omit<ReleasePackageInfo, 'version'>>(packages: Package[], tag: string): {
41
+ pkg: Package;
42
+ version: string;
43
+ } | null;
44
+ export declare function classifyReleaseTag<Package extends ReleasePackageInfo>(tag: MatchedReleaseTag<Package>, state: DurableTagState): ReleaseTagRecord<Package>;
45
+ export declare function collectOwnedReleaseTagRecords<Package extends Omit<ReleasePackageInfo, 'version'>>(packages: Package[], ref: string, shell: ReleasePlanningShell): Promise<Array<ReleaseTagRecord<Package & {
46
+ version: string;
47
+ }>>>;
48
+ export declare function groupReleaseTargets<Package extends ReleasePackageInfo>(records: ReleaseTagRecord<Package>[]): ReleaseTarget<Package>[];
49
+ export declare function pendingReleaseTargets<Package extends ReleasePackageInfo>(records: ReleaseTagRecord<Package>[], headSha: string): ReleaseTarget<Package>[];
50
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/release/core.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,97 @@
1
+ export function releaseTag(pkg) {
2
+ return `${pkg.name}@${pkg.version}`;
3
+ }
4
+ export function npmDistTagForVersion(version) {
5
+ return version.includes('-') ? 'next' : 'latest';
6
+ }
7
+ export function releasePackageForTag(packages, tag) {
8
+ for (const pkg of packages) {
9
+ const prefix = `${pkg.name}@`;
10
+ if (tag.startsWith(prefix)) {
11
+ const version = tag.slice(prefix.length);
12
+ if (!version) {
13
+ throw new Error(`Release tag ${tag} does not include a version.`);
14
+ }
15
+ return { pkg, version };
16
+ }
17
+ }
18
+ return null;
19
+ }
20
+ export function classifyReleaseTag(tag, state) {
21
+ return {
22
+ ...tag,
23
+ needsNpmPublish: !state.npmPublished,
24
+ needsGithubRelease: !state.githubReleaseExists,
25
+ };
26
+ }
27
+ export async function collectOwnedReleaseTagRecords(packages, ref, shell) {
28
+ const records = [];
29
+ const completedPackages = new Set();
30
+ for (const tag of await shell.listReleaseTagsByCreatorDate()) {
31
+ const match = releasePackageForTag(packages, tag.name);
32
+ if (match && completedPackages.has(match.pkg.name)) {
33
+ continue;
34
+ }
35
+ if (!match || !(await shell.isAncestor(tag.sha, ref))) {
36
+ continue;
37
+ }
38
+ const versionAtTag = await shell.packageVersionAtRef(match.pkg.path, tag.sha);
39
+ if (versionAtTag !== match.version) {
40
+ throw new Error(`Release tag ${tag.name} points at ${tag.sha.slice(0, 12)}, but ${match.pkg.path}/package.json has version ${versionAtTag ?? 'missing'}.`);
41
+ }
42
+ const pkg = { ...match.pkg, version: match.version };
43
+ const state = await shell.durableTagState(pkg, tag.name);
44
+ records.push(classifyReleaseTag({ tag: tag.name, sha: tag.sha, timestamp: tag.timestamp, pkg }, state));
45
+ if (state.npmPublished && state.githubReleaseExists) {
46
+ completedPackages.add(pkg.name);
47
+ }
48
+ }
49
+ return records;
50
+ }
51
+ export function groupReleaseTargets(records) {
52
+ const targets = new Map();
53
+ const packageNamesByTarget = new Map();
54
+ for (const record of records) {
55
+ let target = targets.get(record.sha);
56
+ let packageNames = packageNamesByTarget.get(record.sha);
57
+ if (!target) {
58
+ target = { sha: record.sha, timestamp: record.timestamp, packages: [], npmPackages: [], githubPackages: [] };
59
+ targets.set(record.sha, target);
60
+ packageNames = new Set();
61
+ packageNamesByTarget.set(record.sha, packageNames);
62
+ }
63
+ else if (record.timestamp > target.timestamp) {
64
+ target.timestamp = record.timestamp;
65
+ }
66
+ if (!packageNames) {
67
+ throw new Error(`Release target ${record.sha.slice(0, 12)} lost package tracking state.`);
68
+ }
69
+ if (packageNames.has(record.pkg.name)) {
70
+ throw new Error(`Release target ${record.sha.slice(0, 12)} has more than one release tag for ${record.pkg.name}.`);
71
+ }
72
+ packageNames.add(record.pkg.name);
73
+ if (record.needsNpmPublish || record.needsGithubRelease) {
74
+ target.packages.push(record.pkg);
75
+ }
76
+ if (record.needsNpmPublish) {
77
+ target.npmPackages.push(record.pkg);
78
+ }
79
+ if (record.needsGithubRelease) {
80
+ target.githubPackages.push(record.pkg);
81
+ }
82
+ }
83
+ return [...targets.values()].sort((left, right) => right.timestamp - left.timestamp || right.sha.localeCompare(left.sha));
84
+ }
85
+ export function pendingReleaseTargets(records, headSha) {
86
+ const pending = [];
87
+ for (const target of groupReleaseTargets(records)) {
88
+ if (target.sha === headSha) {
89
+ continue;
90
+ }
91
+ if (target.npmPackages.length === 0 && target.githubPackages.length === 0) {
92
+ break;
93
+ }
94
+ pending.push(target);
95
+ }
96
+ return pending.reverse();
97
+ }
@@ -0,0 +1,46 @@
1
+ import { type ReleasePackageInfo } from './core.js';
2
+ interface ProjectChangelogLookupResult {
3
+ projectChangelogs?: Record<string, {
4
+ contents: string;
5
+ }>;
6
+ }
7
+ export interface RenderNxProjectChangelogInput<Package extends ReleasePackageInfo = ReleasePackageInfo> {
8
+ root: string;
9
+ pkg: Package;
10
+ previousTag: string | null;
11
+ dryRun: boolean;
12
+ }
13
+ export interface GithubReleaseWriteShell {
14
+ githubReleaseExists(tag: string): Promise<boolean>;
15
+ runGhRelease(args: string[]): Promise<void>;
16
+ log(message: string): void;
17
+ }
18
+ export declare function renderNxProjectChangelogContents(input: RenderNxProjectChangelogInput): Promise<string>;
19
+ export declare function createOrUpdateGithubRelease(pkg: ReleasePackageInfo, contents: string, shell: GithubReleaseWriteShell): Promise<void>;
20
+ export declare function nxProjectChangelogArgs(pkg: ReleasePackageInfo, previousTag: string | null, dryRun: boolean): {
21
+ from: string;
22
+ version: string;
23
+ projects: string[];
24
+ gitCommit: false;
25
+ gitTag: false;
26
+ gitPush: false;
27
+ stageChanges: false;
28
+ createRelease: false;
29
+ deleteVersionPlans: false;
30
+ dryRun: boolean;
31
+ } | {
32
+ firstRelease: boolean;
33
+ version: string;
34
+ projects: string[];
35
+ gitCommit: false;
36
+ gitTag: false;
37
+ gitPush: false;
38
+ stageChanges: false;
39
+ createRelease: false;
40
+ deleteVersionPlans: false;
41
+ dryRun: boolean;
42
+ };
43
+ export declare function projectChangelogContents(result: ProjectChangelogLookupResult, projectName: string): string;
44
+ export declare function githubReleaseCommandArgs(tag: string, notesFile: string, releaseExists: boolean, version: string): string[];
45
+ export {};
46
+ //# sourceMappingURL=github-release.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"github-release.d.ts","sourceRoot":"","sources":["../../src/release/github-release.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,kBAAkB,EAAc,MAAM,WAAW,CAAC;AAYhE,UAAU,4BAA4B;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC1D;AAED,MAAM,WAAW,6BAA6B,CAAC,OAAO,SAAS,kBAAkB,GAAG,kBAAkB;IACpG,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,OAAO,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,uBAAuB;IACtC,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,wBAAsB,gCAAgC,CAAC,KAAK,EAAE,6BAA6B,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5G;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,kBAAkB,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,uBAAuB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAaf;AAED,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO;;;;;;;;;;;;;;;;;;;;;;EAa1G;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,4BAA4B,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM,CAM1G;AAED,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,OAAO,EACtB,OAAO,EAAE,MAAM,GACd,MAAM,EAAE,CAgBV"}