@git.zone/cli 6.9.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.
@@ -7,12 +7,20 @@ import {
7
7
  getReleaseDockerPromotionContext,
8
8
  getReleaseArtifacts,
9
9
  getReleaseNpmArtifact,
10
+ hasReleasePackages,
10
11
  type TReleaseJournal,
11
12
  type IReleaseJournalV2,
13
+ type IReleaseJournalV4,
12
14
  type IReleaseTargetStatus,
13
15
  type TReleaseErrorCode,
14
16
  type TReleaseTargetState,
15
17
  } from "./classes.releasejournal.js";
18
+ import {
19
+ GiteaAssetsClient,
20
+ GiteaAssetConflictError,
21
+ validateGiteaAssets,
22
+ } from "./helpers.giteaassets.js";
23
+ import { assertGiteaAssetsGitDestination } from "../helpers.workflow.js";
16
24
  import {
17
25
  probeAnonymousNpmArtifact,
18
26
  publishNpmArtifact,
@@ -75,6 +83,8 @@ export function buildReleaseGitPushArgs(
75
83
 
76
84
  type TReleaseTargetSelector =
77
85
  | { kind: "git" }
86
+ | { kind: "gitea-release" }
87
+ | { kind: "gitea-asset"; name: string }
78
88
  | { kind: "npm"; registry: string; packageName?: string }
79
89
  | { kind: "docker-qualification" }
80
90
  | { kind: "docker-promotion"; promotionId: string }
@@ -96,6 +106,15 @@ export interface IReleasePublicationOptions {
96
106
  recoveryAttemptId?: string;
97
107
  npmProbeOptions?: INpmArtifactProbeOptions;
98
108
  tsdocker?: ITsdockerReleaseClient;
109
+ giteaAssets?: Pick<
110
+ GiteaAssetsClient,
111
+ | "preflight"
112
+ | "inspectRelease"
113
+ | "createRelease"
114
+ | "inspectAssets"
115
+ | "uploadAsset"
116
+ | "verifyComplete"
117
+ >;
99
118
  ensurePublicationState: (expectedRemoteMainOidArg?: string) => Promise<void>;
100
119
  }
101
120
 
@@ -106,6 +125,20 @@ const getTargetStatus = (
106
125
  if (selectorArg.kind === "git") {
107
126
  return journalArg.git;
108
127
  }
128
+ if (
129
+ selectorArg.kind === "gitea-release" ||
130
+ selectorArg.kind === "gitea-asset"
131
+ ) {
132
+ if (journalArg.schemaVersion !== 4)
133
+ throw new Error("Release journal has no Gitea assets.");
134
+ if (selectorArg.kind === "gitea-release")
135
+ return journalArg.giteaAssets.release;
136
+ const entry = journalArg.giteaAssets.assets.find(
137
+ (entry) => entry.asset.name === selectorArg.name,
138
+ );
139
+ if (!entry) throw new Error("Release journal has no matching Gitea asset.");
140
+ return entry;
141
+ }
109
142
  if (selectorArg.kind === "docker-qualification") {
110
143
  if (journalArg.schemaVersion !== 2) {
111
144
  throw new Error("Release journal does not contain Docker qualification.");
@@ -616,7 +649,7 @@ const executeNpmRegistry = async (
616
649
  // the accepted artifact on resume. Older root/Docker journal behavior stays
617
650
  // unchanged.
618
651
  if (
619
- journal.schemaVersion === 3 &&
652
+ hasReleasePackages(journal) &&
620
653
  status.state === "failed" &&
621
654
  status.attempts > 0 &&
622
655
  status.error === "verification-inconclusive" &&
@@ -692,7 +725,7 @@ const executeNpmRegistry = async (
692
725
  }
693
726
  if (probe.status !== "absent") {
694
727
  if (
695
- journal.schemaVersion === 3 &&
728
+ hasReleasePackages(journal) &&
696
729
  status.state === "failed" &&
697
730
  probe.status === "inconclusive"
698
731
  ) {
@@ -1432,6 +1465,165 @@ const executeDockerPromotion = async (
1432
1465
  );
1433
1466
  };
1434
1467
 
1468
+ const executeGiteaTarget = async (
1469
+ options: IReleasePublicationOptions,
1470
+ journalArg: TReleaseJournal,
1471
+ selector: TReleaseTargetSelector,
1472
+ inspect: () => Promise<boolean>,
1473
+ publish: () => Promise<void>,
1474
+ onVerified?: (target: IReleaseTargetStatus) => void,
1475
+ ): Promise<TReleaseJournal> => {
1476
+ let journal = journalArg;
1477
+ let status = getTargetStatus(journal, selector);
1478
+ if (status.state === "conflict")
1479
+ throw new Error("Gitea publication has a recorded destination conflict.");
1480
+ const mark = async (
1481
+ state: "verified" | "failed" | "conflict",
1482
+ error: TReleaseErrorCode | null,
1483
+ ) => {
1484
+ status = getTargetStatus(journal, selector);
1485
+ journal = await updateTarget(
1486
+ options.store,
1487
+ journal,
1488
+ selector,
1489
+ status.state,
1490
+ status.attempt?.id || null,
1491
+ (target) => {
1492
+ target.state = state;
1493
+ target.error = error;
1494
+ target.attempt = null;
1495
+ if (state === "verified") onVerified?.(target);
1496
+ },
1497
+ );
1498
+ };
1499
+ let present: boolean;
1500
+ try {
1501
+ present = await inspect();
1502
+ } catch (error) {
1503
+ if (error instanceof GiteaAssetConflictError)
1504
+ await mark("conflict", "destination-conflict");
1505
+ throw error;
1506
+ }
1507
+ if (present) {
1508
+ if (status.state !== "verified") await mark("verified", null);
1509
+ return journal;
1510
+ }
1511
+ if (status.state === "verified") {
1512
+ await mark("conflict", "destination-conflict");
1513
+ throw new Error(
1514
+ "A previously verified Gitea release or attachment is missing.",
1515
+ );
1516
+ }
1517
+ if (status.state === "publishing") {
1518
+ journal = await recoverPublishingTarget(
1519
+ options.store,
1520
+ journal,
1521
+ selector,
1522
+ options.recoveryAttemptId,
1523
+ );
1524
+ }
1525
+ await options.ensurePublicationState(journal.release.mainOid);
1526
+ journal = await claimTarget(options.store, journal, selector);
1527
+ // One mutation per claimed attempt. Reconcile an accepted request even when
1528
+ // its response was lost; never overwrite an attachment or recreate a tag.
1529
+ let publicationError: unknown;
1530
+ try {
1531
+ await publish();
1532
+ } catch (error) {
1533
+ publicationError = error;
1534
+ }
1535
+ try {
1536
+ present = await inspect();
1537
+ } catch (error) {
1538
+ await mark(
1539
+ error instanceof GiteaAssetConflictError ? "conflict" : "failed",
1540
+ error instanceof GiteaAssetConflictError
1541
+ ? "destination-conflict"
1542
+ : "verification-inconclusive",
1543
+ );
1544
+ throw error;
1545
+ }
1546
+ if (present) {
1547
+ await mark("verified", null);
1548
+ return journal;
1549
+ }
1550
+ await mark(
1551
+ publicationError instanceof GiteaAssetConflictError ? "conflict" : "failed",
1552
+ publicationError instanceof GiteaAssetConflictError
1553
+ ? "destination-conflict"
1554
+ : publicationError
1555
+ ? "command-failed"
1556
+ : "verification-inconclusive",
1557
+ );
1558
+ throw new Error(
1559
+ "Gitea publication could not be verified; npm publication remains blocked. Inspect the retained journal before resuming.",
1560
+ );
1561
+ };
1562
+
1563
+ const executeGiteaAssets = async (
1564
+ options: IReleasePublicationOptions,
1565
+ journalArg: IReleaseJournalV4,
1566
+ client: NonNullable<IReleasePublicationOptions["giteaAssets"]>,
1567
+ ): Promise<IReleaseJournalV4> => {
1568
+ let releaseId = journalArg.giteaAssets.release.id;
1569
+ let journal = (await executeGiteaTarget(
1570
+ options,
1571
+ journalArg,
1572
+ { kind: "gitea-release" },
1573
+ async () => {
1574
+ const release = await client.inspectRelease();
1575
+ if (!release) return false;
1576
+ if (releaseId !== null && release.id !== releaseId)
1577
+ throw new GiteaAssetConflictError("Gitea release identity changed.");
1578
+ releaseId = release.id;
1579
+ return true;
1580
+ },
1581
+ async () => {
1582
+ await client.createRelease();
1583
+ },
1584
+ (target) => {
1585
+ (target as IReleaseJournalV4["giteaAssets"]["release"]).id = releaseId;
1586
+ },
1587
+ )) as IReleaseJournalV4;
1588
+ if (releaseId === null)
1589
+ throw new Error("Gitea release has no verified identity.");
1590
+ const expected = journal.giteaAssets.assets.map((entry) => entry.asset);
1591
+ const directory = options.store.getReleaseDirectory(journal.release.version);
1592
+ for (const { asset } of journal.giteaAssets.assets) {
1593
+ journal = (await executeGiteaTarget(
1594
+ options,
1595
+ journal,
1596
+ { kind: "gitea-asset", name: asset.name },
1597
+ async () => {
1598
+ const inspection = await client.inspectAssets(releaseId!, expected);
1599
+ return inspection.present.some((entry) => entry.name === asset.name);
1600
+ },
1601
+ async () => {
1602
+ await validateGiteaAssets(directory, expected);
1603
+ await client.uploadAsset(releaseId!, asset, directory);
1604
+ },
1605
+ )) as IReleaseJournalV4;
1606
+ }
1607
+ // One full anonymous verification immediately before entering the npm phase.
1608
+ // Resume always repeats it, including an otherwise completed journal.
1609
+ try {
1610
+ await client.verifyComplete(releaseId, expected);
1611
+ } catch (error) {
1612
+ if (error instanceof GiteaAssetConflictError) {
1613
+ await markUnclaimedTarget(
1614
+ options.store,
1615
+ journal,
1616
+ { kind: "gitea-release" },
1617
+ ["verified"],
1618
+ "conflict",
1619
+ "destination-conflict",
1620
+ );
1621
+ }
1622
+ throw error;
1623
+ }
1624
+ return journal;
1625
+ };
1626
+
1435
1627
  export const executeReleasePublication = async (
1436
1628
  optionsArg: IReleasePublicationOptions,
1437
1629
  ): Promise<TReleaseJournal> => {
@@ -1443,6 +1635,32 @@ export const executeReleasePublication = async (
1443
1635
  artifact,
1444
1636
  );
1445
1637
  }
1638
+ let giteaClient = optionsArg.giteaAssets;
1639
+ if (journal.schemaVersion === 4) {
1640
+ const { destination, tokenEnv, manifestPath, assets } = journal.giteaAssets;
1641
+ assertGiteaAssetsGitDestination(
1642
+ { ...destination, tokenEnv, manifestPath },
1643
+ optionsArg.pushUrl || "",
1644
+ );
1645
+ await validateGiteaAssets(
1646
+ optionsArg.store.getReleaseDirectory(journal.release.version),
1647
+ assets.map((entry) => entry.asset),
1648
+ );
1649
+ if (!giteaClient) {
1650
+ const token = process.env[tokenEnv];
1651
+ if (!token)
1652
+ throw new Error(
1653
+ `Gitea assets require the configured credential in ${tokenEnv}.`,
1654
+ );
1655
+ giteaClient = new GiteaAssetsClient({
1656
+ destination,
1657
+ token,
1658
+ tag: journal.release.tag,
1659
+ commit: journal.release.mainOid,
1660
+ });
1661
+ }
1662
+ await giteaClient.preflight();
1663
+ }
1446
1664
  if (journal.schemaVersion === 2) {
1447
1665
  journal = await executeDockerQualification(optionsArg, journal);
1448
1666
  if (
@@ -1453,6 +1671,8 @@ export const executeReleasePublication = async (
1453
1671
  }
1454
1672
  }
1455
1673
  journal = await executeGitTarget(optionsArg, journal);
1674
+ if (journal.schemaVersion === 4)
1675
+ journal = await executeGiteaAssets(optionsArg, journal, giteaClient!);
1456
1676
  const expectedRemoteMainOid =
1457
1677
  journal.git.state === "verified"
1458
1678
  ? journal.release.mainOid
@@ -1464,12 +1684,12 @@ export const executeReleasePublication = async (
1464
1684
  journal,
1465
1685
  registry.registry,
1466
1686
  registry.packageName,
1467
- journal.schemaVersion === 3,
1687
+ hasReleasePackages(journal),
1468
1688
  );
1469
1689
  }
1470
1690
  // Submit in dependency order before waiting for npm's publish-time scans.
1471
1691
  // Success still requires every package/registry cell to verify exactly.
1472
- if (journal.schemaVersion === 3) {
1692
+ if (hasReleasePackages(journal)) {
1473
1693
  for (const registry of journal.npm.registries) {
1474
1694
  if (
1475
1695
  registry.state !== "failed" ||
@@ -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,
@@ -127,6 +133,11 @@ const runInternal = async (argvArg: any): Promise<void> => {
127
133
  mergeRequested,
128
134
  planMode: workflow.confirmation === "plan",
129
135
  });
136
+ if (workflow.giteaAssets)
137
+ assertGiteaAssetsGitDestination(
138
+ workflow.giteaAssets,
139
+ branchContext.pushUrl || "",
140
+ );
130
141
  printReleasePlan(workflow, branchContext);
131
142
  if (
132
143
  workflow.targets.includes("npm") &&
@@ -172,6 +183,20 @@ const runInternal = async (argvArg: any): Promise<void> => {
172
183
  currentVersion,
173
184
  versionType,
174
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
+ }
175
200
  if (preflightTsdocker) {
176
201
  await preflightTsdocker.validate(
177
202
  createDockerQualificationRequest(
@@ -352,6 +377,18 @@ const assertReleaseConfiguration = (
352
377
  workflowArg: IResolvedReleaseWorkflow,
353
378
  mergeRequestedArg: boolean,
354
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
+ );
355
392
  if (workflowArg.targets.includes("docker")) {
356
393
  if (mergeRequestedArg) {
357
394
  throw new Error(
@@ -549,10 +586,47 @@ export const createReleaseJournal = async (
549
586
  }
550
587
  const now = new Date().toISOString();
551
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
+ }
552
620
  const journal = finalizeJournalCompletion(
553
621
  {
554
622
  kind: "gitzone-release-journal",
555
- 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,
556
630
  revision: 1,
557
631
  release: {
558
632
  version: optionsArg.version,
@@ -561,7 +635,7 @@ export const createReleaseJournal = async (
561
635
  tagOid: optionsArg.refs.tagOid,
562
636
  },
563
637
  artifact,
564
- ...(packages.length ? { packages } : {}),
638
+ ...(packages.length || giteaAssets ? { packages } : {}),
565
639
  git: {
566
640
  state: gitStatus.state,
567
641
  attempts: gitStatus.attempts,
@@ -602,6 +676,7 @@ export const createReleaseJournal = async (
602
676
  })
603
677
  : [],
604
678
  },
679
+ ...(giteaAssets ? { giteaAssets } : {}),
605
680
  ...(optionsArg.dockerRequest
606
681
  ? {
607
682
  docker: createInitialReleaseDockerJournal(
@@ -887,6 +962,7 @@ const runReleaseResume = async (
887
962
  const resumeConfiguration = await resolveReleaseResumeConfiguration({
888
963
  git: gitEnabled,
889
964
  npm: journal.npm.registries.length > 0,
965
+ giteaAssets: journal.schemaVersion === 4,
890
966
  });
891
967
  await assertResumeConfiguration(resumeConfiguration, journal, paths.cwd);
892
968
  let tsdocker: ITsdockerReleaseClient | undefined;
@@ -1033,13 +1109,24 @@ const assertResumeConfiguration = async (
1033
1109
  ]) ||
1034
1110
  workflowArg.npmAccessLevel !== journalArg.npm.access ||
1035
1111
  workflowArg.npmPackageSource !==
1036
- (journalArg.schemaVersion === 3 ? "tspublish" : "root") ||
1112
+ (hasReleasePackages(journalArg) ? "tspublish" : "root") ||
1037
1113
  workflowArg.npmAlreadyPublished !== journalArg.npm.alreadyPublished)
1038
1114
  ) {
1039
1115
  throw new Error(
1040
1116
  "Current npm release configuration does not match the journal.",
1041
1117
  );
1042
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
+ }
1043
1130
  if (
1044
1131
  journalArg.git.state !== "skipped" ||
1045
1132
  getReleaseArtifacts(journalArg).length
@@ -1061,12 +1148,19 @@ const printReleaseJournalSummary = (journalArg: TReleaseJournal): void => {
1061
1148
  `npm ${registry.packageName ? `${registry.packageName} ` : ""}${registry.registry}: ${registry.state}`,
1062
1149
  );
1063
1150
  }
1064
- if (journalArg.schemaVersion === 3) {
1151
+ if (hasReleasePackages(journalArg)) {
1065
1152
  for (const { artifact } of journalArg.packages)
1066
1153
  console.log(
1067
1154
  `artifact ${artifact.packageName}: ${artifact.integrity} (${artifact.sha256})`,
1068
1155
  );
1069
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
+ }
1070
1164
  if (journalArg.schemaVersion === 2) {
1071
1165
  console.log(
1072
1166
  `docker qualification ${journalArg.docker.request.candidateId}: ${journalArg.docker.qualification.state}`,
@@ -1416,6 +1510,14 @@ function printReleasePlan(
1416
1510
  `npm registries: ${workflow.npmRegistries.length > 0 ? workflow.npmRegistries.join(", ") : "none"}`,
1417
1511
  );
1418
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
+ }
1419
1521
  if (workflow.targets.includes("docker")) {
1420
1522
  console.log(`docker engine: ${workflow.dockerEngine}`);
1421
1523
  console.log(
@@ -1479,7 +1581,7 @@ export function showHelp(mode?: ICliMode): void {
1479
1581
  {
1480
1582
  flag: "--target <names>",
1481
1583
  description:
1482
- "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",
1483
1585
  },
1484
1586
  { flag: "--npm", description: "Explicitly select the npm target" },
1485
1587
  {
@@ -1489,7 +1591,8 @@ export function showHelp(mode?: ICliMode): void {
1489
1591
  },
1490
1592
  {
1491
1593
  flag: "--no-publish",
1492
- description: "Remove npm and Docker without implicitly enabling Git",
1594
+ description:
1595
+ "Remove Gitea assets, npm and Docker without implicitly enabling Git",
1493
1596
  },
1494
1597
  {
1495
1598
  flag: "--merge",
@@ -1542,14 +1645,14 @@ export function showHelp(mode?: ICliMode): void {
1542
1645
  console.log(" --no-build Disable the post-metadata release build");
1543
1646
  console.log(" -p, --push Explicitly select the git target");
1544
1647
  console.log(
1545
- " --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",
1546
1649
  );
1547
1650
  console.log(" --npm Explicitly select the npm target");
1548
1651
  console.log(
1549
1652
  " --docker Select digest-qualified Docker publication through project-local tSDocker >= 3.5.1",
1550
1653
  );
1551
1654
  console.log(
1552
- " --no-publish Remove npm and Docker without implicitly enabling Git",
1655
+ " --no-publish Remove Gitea assets, npm and Docker without implicitly enabling Git",
1553
1656
  );
1554
1657
  console.log(
1555
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
+ }