@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.
- package/dist_ts/00_commitinfo_data.js +2 -2
- package/dist_ts/helpers.workflow.d.ts +23 -1
- package/dist_ts/helpers.workflow.js +93 -3
- package/dist_ts/mod_config/index.js +49 -7
- package/dist_ts/mod_release/classes.releasejournal.d.ts +20 -1
- package/dist_ts/mod_release/classes.releasejournal.js +191 -9
- package/dist_ts/mod_release/helpers.giteaassets.d.ts +36 -0
- package/dist_ts/mod_release/helpers.giteaassets.js +661 -0
- package/dist_ts/mod_release/helpers.releasepublication.d.ts +2 -0
- package/dist_ts/mod_release/helpers.releasepublication.js +147 -6
- package/dist_ts/mod_release/index.js +86 -11
- package/dist_ts/mod_release/interfaces.giteaassets.d.ts +50 -0
- package/dist_ts/mod_release/interfaces.giteaassets.js +2 -0
- package/package.json +2 -2
- package/readme.md +92 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/helpers.workflow.ts +154 -3
- package/ts/mod_config/index.ts +61 -6
- package/ts/mod_release/classes.releasejournal.ts +298 -14
- package/ts/mod_release/helpers.giteaassets.ts +932 -0
- package/ts/mod_release/helpers.releasepublication.ts +224 -4
- package/ts/mod_release/index.ts +111 -8
- package/ts/mod_release/interfaces.giteaassets.ts +67 -0
|
@@ -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
|
|
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
|
|
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
|
|
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
|
|
1692
|
+
if (hasReleasePackages(journal)) {
|
|
1473
1693
|
for (const registry of journal.npm.registries) {
|
|
1474
1694
|
if (
|
|
1475
1695
|
registry.state !== "failed" ||
|
package/ts/mod_release/index.ts
CHANGED
|
@@ -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:
|
|
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
|
|
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
|
|
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:
|
|
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
|
+
}
|