@git.zone/cli 6.8.0 → 6.10.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.
@@ -12,6 +12,7 @@ import {
12
12
  resolveReleaseDockerConfiguration,
13
13
  resolveReleaseWorkflow,
14
14
  resolveReleaseResumeConfiguration,
15
+ assertGiteaAssetsGitDestination,
15
16
  type IResolvedReleaseResumeConfiguration,
16
17
  type IResolvedReleaseWorkflow,
17
18
  } from "../helpers.workflow.js";
@@ -35,6 +36,7 @@ import {
35
36
  normalizeReleaseVersion,
36
37
  resolveGitCommonDirectory,
37
38
  getReleaseArtifacts,
39
+ hasReleasePackages,
38
40
  releasePackageArtifactFile,
39
41
  type IReleasePackage,
40
42
  type IReleaseArtifact,
@@ -42,6 +44,10 @@ import {
42
44
  type IReleaseJournalV1,
43
45
  type IReleaseJournalV2,
44
46
  } from "./classes.releasejournal.js";
47
+ import {
48
+ GiteaAssetsClient,
49
+ prepareGiteaAssets,
50
+ } from "./helpers.giteaassets.js";
45
51
  import {
46
52
  assertNoLegacyNpmPublisher,
47
53
  assertPnpmReleaseCapability,
@@ -49,6 +55,7 @@ import {
49
55
  normalizeNpmRegistryUrl,
50
56
  packNpmArtifact,
51
57
  verifyStoredNpmArtifact,
58
+ type IPnpmReleaseCapability,
52
59
  } from "./helpers.npmartifact.js";
53
60
  import { executeReleasePublication } from "./helpers.releasepublication.js";
54
61
  import {
@@ -126,6 +133,11 @@ const runInternal = async (argvArg: any): Promise<void> => {
126
133
  mergeRequested,
127
134
  planMode: workflow.confirmation === "plan",
128
135
  });
136
+ if (workflow.giteaAssets)
137
+ assertGiteaAssetsGitDestination(
138
+ workflow.giteaAssets,
139
+ branchContext.pushUrl || "",
140
+ );
129
141
  printReleasePlan(workflow, branchContext);
130
142
  if (
131
143
  workflow.targets.includes("npm") &&
@@ -143,7 +155,7 @@ const runInternal = async (argvArg: any): Promise<void> => {
143
155
  const preflightTsdocker = workflow.targets.includes("docker")
144
156
  ? new TsdockerReleaseClient(smartshellInstance, branchContext.sourceCwd)
145
157
  : undefined;
146
- await assertFreshReleaseCapabilities(
158
+ const pnpmCapability = await assertFreshReleaseCapabilities(
147
159
  smartshellInstance,
148
160
  workflow,
149
161
  branchContext.sourceCwd,
@@ -171,6 +183,20 @@ const runInternal = async (argvArg: any): Promise<void> => {
171
183
  currentVersion,
172
184
  versionType,
173
185
  );
186
+ if (workflow.giteaAssets) {
187
+ const { tokenEnv, manifestPath, ...destination } = workflow.giteaAssets;
188
+ const token = process.env[tokenEnv];
189
+ if (!token)
190
+ throw new Error(
191
+ `Gitea assets require the configured credential in ${tokenEnv}.`,
192
+ );
193
+ await new GiteaAssetsClient({
194
+ destination,
195
+ tag: `v${plannedVersion}`,
196
+ commit: branchContext.sourceOid,
197
+ token,
198
+ }).preflight();
199
+ }
174
200
  if (preflightTsdocker) {
175
201
  await preflightTsdocker.validate(
176
202
  createDockerQualificationRequest(
@@ -293,6 +319,7 @@ const runInternal = async (argvArg: any): Promise<void> => {
293
319
  )
294
320
  : undefined;
295
321
  const journalContext = await createReleaseJournal({
322
+ pnpmCapability,
296
323
  smartshell: smartshellInstance,
297
324
  workflow,
298
325
  releaseCwd,
@@ -305,6 +332,7 @@ const runInternal = async (argvArg: any): Promise<void> => {
305
332
  ensurePublicationState,
306
333
  });
307
334
  const finalJournal = await executeReleasePublication({
335
+ pnpmCapability,
308
336
  smartshell: smartshellInstance,
309
337
  cwd: releaseCwd,
310
338
  store: journalContext.store,
@@ -322,7 +350,7 @@ const assertFreshReleaseCapabilities = async (
322
350
  cwdArg: string,
323
351
  pushUrlArg?: string,
324
352
  tsdockerArg?: ITsdockerReleaseClient,
325
- ): Promise<void> => {
353
+ ): Promise<IPnpmReleaseCapability | undefined> => {
326
354
  if (workflowArg.targets.includes("docker")) {
327
355
  if (!tsdockerArg) {
328
356
  throw new Error("Docker release target requires project-local tSDocker.");
@@ -341,7 +369,7 @@ const assertFreshReleaseCapabilities = async (
341
369
  await assertNoLegacyNpmPublisher(cwdArg);
342
370
  }
343
371
  if (workflowArg.targets.includes("npm")) {
344
- await assertPnpmReleaseCapability(smartshellArg, cwdArg);
372
+ return assertPnpmReleaseCapability(smartshellArg, cwdArg);
345
373
  }
346
374
  };
347
375
 
@@ -349,6 +377,18 @@ const assertReleaseConfiguration = (
349
377
  workflowArg: IResolvedReleaseWorkflow,
350
378
  mergeRequestedArg: boolean,
351
379
  ): void => {
380
+ if (
381
+ workflowArg.targets.includes("giteaAssets") &&
382
+ (!workflowArg.giteaAssets ||
383
+ !workflowArg.targets.includes("git") ||
384
+ !workflowArg.pushBranch ||
385
+ !workflowArg.pushTags ||
386
+ workflowArg.targets.includes("docker") ||
387
+ mergeRequestedArg)
388
+ )
389
+ throw new Error(
390
+ "Gitea asset releases require integrated main and Git branch/tag publication without Docker.",
391
+ );
352
392
  if (workflowArg.targets.includes("docker")) {
353
393
  if (mergeRequestedArg) {
354
394
  throw new Error(
@@ -408,6 +448,7 @@ const assertReleaseConfiguration = (
408
448
  };
409
449
 
410
450
  interface ICreateReleaseJournalOptions {
451
+ pnpmCapability?: IPnpmReleaseCapability;
411
452
  smartshell: plugins.smartshell.Smartshell;
412
453
  workflow: IResolvedReleaseWorkflow;
413
454
  releaseCwd: string;
@@ -509,6 +550,7 @@ export const createReleaseJournal = async (
509
550
  module.directory,
510
551
  temporaryDirectory,
511
552
  optionsArg.version,
553
+ optionsArg.pnpmCapability,
512
554
  releasePackageArtifactFile(module.name),
513
555
  );
514
556
  if (packed.packageName !== module.name)
@@ -524,6 +566,7 @@ export const createReleaseJournal = async (
524
566
  npmSourceCwd,
525
567
  temporaryDirectory,
526
568
  optionsArg.version,
569
+ optionsArg.pnpmCapability,
527
570
  );
528
571
  }
529
572
  await verifyCleanTree(
@@ -543,10 +586,47 @@ export const createReleaseJournal = async (
543
586
  }
544
587
  const now = new Date().toISOString();
545
588
  const gitStatus = createInitialTargetStatus(gitEnabled);
589
+ const assetConfiguration = optionsArg.workflow.giteaAssets;
590
+ let giteaAssets:
591
+ | import("./classes.releasejournal.js").IReleaseGiteaAssetsJournal
592
+ | undefined;
593
+ if (optionsArg.workflow.targets.includes("giteaAssets")) {
594
+ if (!assetConfiguration || !gitEnabled || optionsArg.dockerRequest)
595
+ throw new Error("Invalid Gitea asset target combination.");
596
+ assertGiteaAssetsGitDestination(
597
+ assetConfiguration,
598
+ optionsArg.releasePushUrl!,
599
+ );
600
+ const { tokenEnv, manifestPath, ...destination } = assetConfiguration;
601
+ const assets = await prepareGiteaAssets({
602
+ repositoryRoot: npmSourceCwd,
603
+ manifestPath,
604
+ version: optionsArg.version,
605
+ tag: `v${optionsArg.version}`,
606
+ artifactDirectory: temporaryDirectory,
607
+ destination,
608
+ });
609
+ giteaAssets = {
610
+ destination,
611
+ tokenEnv,
612
+ manifestPath,
613
+ release: { ...createInitialTargetStatus(true), id: null },
614
+ assets: assets.map((asset) => ({
615
+ ...createInitialTargetStatus(true),
616
+ asset,
617
+ })),
618
+ };
619
+ }
546
620
  const journal = finalizeJournalCompletion(
547
621
  {
548
622
  kind: "gitzone-release-journal",
549
- schemaVersion: packages.length ? 3 : optionsArg.dockerRequest ? 2 : 1,
623
+ schemaVersion: giteaAssets
624
+ ? 4
625
+ : packages.length
626
+ ? 3
627
+ : optionsArg.dockerRequest
628
+ ? 2
629
+ : 1,
550
630
  revision: 1,
551
631
  release: {
552
632
  version: optionsArg.version,
@@ -555,7 +635,7 @@ export const createReleaseJournal = async (
555
635
  tagOid: optionsArg.refs.tagOid,
556
636
  },
557
637
  artifact,
558
- ...(packages.length ? { packages } : {}),
638
+ ...(packages.length || giteaAssets ? { packages } : {}),
559
639
  git: {
560
640
  state: gitStatus.state,
561
641
  attempts: gitStatus.attempts,
@@ -596,6 +676,7 @@ export const createReleaseJournal = async (
596
676
  })
597
677
  : [],
598
678
  },
679
+ ...(giteaAssets ? { giteaAssets } : {}),
599
680
  ...(optionsArg.dockerRequest
600
681
  ? {
601
682
  docker: createInitialReleaseDockerJournal(
@@ -745,7 +826,7 @@ const runReleaseRecover = async (
745
826
  `Recover existing ${packageName}@${version}\ncommit: ${refs.mainOid}\ntag object: ${refs.tagOid}\nGit destination: ${branch.gitRemote}\nnpm registries: ${workflow.npmRegistries.join(", ")}\nBuild and pack an isolated checkout, install its journal, then publish configured targets.`,
746
827
  );
747
828
  if (argvArg.plan) return;
748
- await assertFreshReleaseCapabilities(
829
+ const pnpmCapability = await assertFreshReleaseCapabilities(
749
830
  shell,
750
831
  workflow,
751
832
  paths.cwd,
@@ -784,6 +865,7 @@ const runReleaseRecover = async (
784
865
  ensureUnpublished,
785
866
  async (checkout, ensureCheckout) =>
786
867
  createReleaseJournal({
868
+ pnpmCapability,
787
869
  smartshell: shell,
788
870
  workflow,
789
871
  releaseCwd: paths.cwd,
@@ -799,6 +881,7 @@ const runReleaseRecover = async (
799
881
  }),
800
882
  );
801
883
  const result = await executeReleasePublication({
884
+ pnpmCapability,
802
885
  smartshell: shell,
803
886
  cwd: paths.cwd,
804
887
  store: context.store,
@@ -879,6 +962,7 @@ const runReleaseResume = async (
879
962
  const resumeConfiguration = await resolveReleaseResumeConfiguration({
880
963
  git: gitEnabled,
881
964
  npm: journal.npm.registries.length > 0,
965
+ giteaAssets: journal.schemaVersion === 4,
882
966
  });
883
967
  await assertResumeConfiguration(resumeConfiguration, journal, paths.cwd);
884
968
  let tsdocker: ITsdockerReleaseClient | undefined;
@@ -913,8 +997,12 @@ const runReleaseResume = async (
913
997
  await tsdocker.assertCapabilities();
914
998
  await tsdocker.validate(journal.docker.request);
915
999
  }
1000
+ let pnpmCapability: IPnpmReleaseCapability | undefined;
916
1001
  if (getReleaseArtifacts(journal).length) {
917
- await assertPnpmReleaseCapability(smartshellInstance, paths.cwd);
1002
+ pnpmCapability = await assertPnpmReleaseCapability(
1003
+ smartshellInstance,
1004
+ paths.cwd,
1005
+ );
918
1006
  await assertNoLegacyNpmPublisher(paths.cwd);
919
1007
  for (const artifact of getReleaseArtifacts(journal)) {
920
1008
  await verifyStoredNpmArtifact(
@@ -984,6 +1072,7 @@ const runReleaseResume = async (
984
1072
  );
985
1073
  };
986
1074
  const finalJournal = await executeReleasePublication({
1075
+ pnpmCapability,
987
1076
  smartshell: smartshellInstance,
988
1077
  cwd: paths.cwd,
989
1078
  store,
@@ -1020,13 +1109,24 @@ const assertResumeConfiguration = async (
1020
1109
  ]) ||
1021
1110
  workflowArg.npmAccessLevel !== journalArg.npm.access ||
1022
1111
  workflowArg.npmPackageSource !==
1023
- (journalArg.schemaVersion === 3 ? "tspublish" : "root") ||
1112
+ (hasReleasePackages(journalArg) ? "tspublish" : "root") ||
1024
1113
  workflowArg.npmAlreadyPublished !== journalArg.npm.alreadyPublished)
1025
1114
  ) {
1026
1115
  throw new Error(
1027
1116
  "Current npm release configuration does not match the journal.",
1028
1117
  );
1029
1118
  }
1119
+ if (journalArg.schemaVersion === 4) {
1120
+ const { destination, tokenEnv, manifestPath } = journalArg.giteaAssets;
1121
+ if (
1122
+ JSON.stringify(workflowArg.giteaAssets) !==
1123
+ JSON.stringify({ ...destination, tokenEnv, manifestPath })
1124
+ ) {
1125
+ throw new Error(
1126
+ "Current Gitea asset configuration does not match the journal.",
1127
+ );
1128
+ }
1129
+ }
1030
1130
  if (
1031
1131
  journalArg.git.state !== "skipped" ||
1032
1132
  getReleaseArtifacts(journalArg).length
@@ -1048,12 +1148,19 @@ const printReleaseJournalSummary = (journalArg: TReleaseJournal): void => {
1048
1148
  `npm ${registry.packageName ? `${registry.packageName} ` : ""}${registry.registry}: ${registry.state}`,
1049
1149
  );
1050
1150
  }
1051
- if (journalArg.schemaVersion === 3) {
1151
+ if (hasReleasePackages(journalArg)) {
1052
1152
  for (const { artifact } of journalArg.packages)
1053
1153
  console.log(
1054
1154
  `artifact ${artifact.packageName}: ${artifact.integrity} (${artifact.sha256})`,
1055
1155
  );
1056
1156
  }
1157
+ if (journalArg.schemaVersion === 4) {
1158
+ console.log(`Gitea release: ${journalArg.giteaAssets.release.state}`);
1159
+ for (const entry of journalArg.giteaAssets.assets)
1160
+ console.log(
1161
+ `asset ${entry.asset.name}: ${entry.state} (${entry.asset.sha256})`,
1162
+ );
1163
+ }
1057
1164
  if (journalArg.schemaVersion === 2) {
1058
1165
  console.log(
1059
1166
  `docker qualification ${journalArg.docker.request.candidateId}: ${journalArg.docker.qualification.state}`,
@@ -1403,6 +1510,14 @@ function printReleasePlan(
1403
1510
  `npm registries: ${workflow.npmRegistries.length > 0 ? workflow.npmRegistries.join(", ") : "none"}`,
1404
1511
  );
1405
1512
  }
1513
+ if (workflow.giteaAssets) {
1514
+ const assets = workflow.giteaAssets;
1515
+ console.log(
1516
+ `Gitea assets: ${assets.apiOrigin}/${assets.owner}/${assets.repository}`,
1517
+ );
1518
+ console.log(`asset manifest: ${assets.manifestPath}`);
1519
+ console.log(`asset credential variable: ${assets.tokenEnv}`);
1520
+ }
1406
1521
  if (workflow.targets.includes("docker")) {
1407
1522
  console.log(`docker engine: ${workflow.dockerEngine}`);
1408
1523
  console.log(
@@ -1466,7 +1581,7 @@ export function showHelp(mode?: ICliMode): void {
1466
1581
  {
1467
1582
  flag: "--target <names>",
1468
1583
  description:
1469
- "Replace configured targets with a non-empty subset of git,npm,docker",
1584
+ "Replace configured targets with a non-empty subset of git,giteaAssets,npm,docker",
1470
1585
  },
1471
1586
  { flag: "--npm", description: "Explicitly select the npm target" },
1472
1587
  {
@@ -1476,7 +1591,8 @@ export function showHelp(mode?: ICliMode): void {
1476
1591
  },
1477
1592
  {
1478
1593
  flag: "--no-publish",
1479
- description: "Remove npm and Docker without implicitly enabling Git",
1594
+ description:
1595
+ "Remove Gitea assets, npm and Docker without implicitly enabling Git",
1480
1596
  },
1481
1597
  {
1482
1598
  flag: "--merge",
@@ -1529,14 +1645,14 @@ export function showHelp(mode?: ICliMode): void {
1529
1645
  console.log(" --no-build Disable the post-metadata release build");
1530
1646
  console.log(" -p, --push Explicitly select the git target");
1531
1647
  console.log(
1532
- " --target <names> Replace configured targets with a non-empty subset of git,npm,docker",
1648
+ " --target <names> Replace configured targets with a non-empty subset of git,giteaAssets,npm,docker",
1533
1649
  );
1534
1650
  console.log(" --npm Explicitly select the npm target");
1535
1651
  console.log(
1536
1652
  " --docker Select digest-qualified Docker publication through project-local tSDocker >= 3.5.1",
1537
1653
  );
1538
1654
  console.log(
1539
- " --no-publish Remove npm and Docker without implicitly enabling Git",
1655
+ " --no-publish Remove Gitea assets, npm and Docker without implicitly enabling Git",
1540
1656
  );
1541
1657
  console.log(
1542
1658
  " --merge Fast-forward and lease-push a cleanly rebased feature branch before release metadata",
@@ -0,0 +1,67 @@
1
+ export interface IGiteaAssetDestination {
2
+ apiOrigin: string;
3
+ owner: string;
4
+ repository: string;
5
+ }
6
+
7
+ export interface IGiteaFrozenAsset {
8
+ name: string;
9
+ size: number;
10
+ sha256: string;
11
+ fileName: string;
12
+ publicUrl: string;
13
+ }
14
+
15
+ export interface IPrepareGiteaAssetsOptions {
16
+ repositoryRoot: string;
17
+ manifestPath: string;
18
+ version: string;
19
+ tag: string;
20
+ artifactDirectory: string;
21
+ destination: IGiteaAssetDestination;
22
+ }
23
+
24
+ export interface IGiteaRelease {
25
+ id: number;
26
+ tag: string;
27
+ publicUrl: string;
28
+ }
29
+
30
+ export interface IGiteaAssetInspection {
31
+ present: IGiteaFrozenAsset[];
32
+ missing: IGiteaFrozenAsset[];
33
+ }
34
+
35
+ export interface IGiteaAssetsClientOptions {
36
+ destination: IGiteaAssetDestination;
37
+ tag: string;
38
+ commit: string;
39
+ token: string;
40
+ fetchImplementation?: typeof fetch;
41
+ timeoutMs?: number;
42
+ }
43
+
44
+ export interface IGiteaAssetPreflight {
45
+ repositoryId: number;
46
+ /** Issue-attachment setting; Gitea's release FILE_MAX_SIZE is separate. */
47
+ generalAttachmentMaximumBytes: number;
48
+ }
49
+
50
+ export interface IGiteaAssetsClient {
51
+ preflight(): Promise<IGiteaAssetPreflight>;
52
+ inspectRelease(): Promise<IGiteaRelease | null>;
53
+ createRelease(): Promise<IGiteaRelease>;
54
+ inspectAssets(
55
+ releaseId: number,
56
+ expected: IGiteaFrozenAsset[],
57
+ ): Promise<IGiteaAssetInspection>;
58
+ uploadAsset(
59
+ releaseId: number,
60
+ asset: IGiteaFrozenAsset,
61
+ artifactDirectory: string,
62
+ ): Promise<void>;
63
+ verifyComplete(
64
+ releaseId: number,
65
+ expected: IGiteaFrozenAsset[],
66
+ ): Promise<void>;
67
+ }