@rightkit/release 0.2.90 → 0.2.92
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/direct-bootstrap.mjs +51 -16
- package/package.json +2 -2
- package/publish-update.mjs +7 -4
- package/rightkit-versions.json +6 -4
- package/upload-release.mjs +14 -13
package/direct-bootstrap.mjs
CHANGED
|
@@ -205,9 +205,11 @@ export function renderPowerShellBootstrap({
|
|
|
205
205
|
expectedStatus = "complete",
|
|
206
206
|
healthAssertions = null,
|
|
207
207
|
preflightArgs = [],
|
|
208
|
+
allowLocalReleaseRoot = false,
|
|
208
209
|
}) {
|
|
209
210
|
if (!/^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/.test(repository)) throw new Error("invalid GitHub repository");
|
|
210
211
|
if (!VERSION.test(bootstrapVersion)) throw new Error("invalid bootstrap version");
|
|
212
|
+
if (typeof allowLocalReleaseRoot !== "boolean") throw new Error("allowLocalReleaseRoot must be boolean");
|
|
211
213
|
assertRelativeFile(executablePath, "executable path");
|
|
212
214
|
if (!Array.isArray(acceptedManifestSigners) || !acceptedManifestSigners.length) throw new Error("accepted manifest signers are required");
|
|
213
215
|
const signers = {};
|
|
@@ -246,6 +248,7 @@ export function renderPowerShellBootstrap({
|
|
|
246
248
|
statusArgs,
|
|
247
249
|
healthAssertions: assertions,
|
|
248
250
|
preflightArgs,
|
|
251
|
+
...(allowLocalReleaseRoot ? { allowLocalReleaseRoot: true } : {}),
|
|
249
252
|
};
|
|
250
253
|
// Bind generated contract metadata so a caller cannot pass a marker plus an
|
|
251
254
|
// arbitrary base64 payload and have it treated as a RightRelease bootstrap.
|
|
@@ -256,7 +259,9 @@ export function renderPowerShellBootstrap({
|
|
|
256
259
|
const lines = [
|
|
257
260
|
"# rightkit-direct-bootstrap:v1",
|
|
258
261
|
"# generated contract: generator=rightkit-direct-bootstrap contractSha256-bound",
|
|
259
|
-
|
|
262
|
+
allowLocalReleaseRoot
|
|
263
|
+
? "[CmdletBinding()] param([string]$Version, [switch]$AllowDowngrade, [string]$ReleaseRoot)"
|
|
264
|
+
: "[CmdletBinding()] param([string]$Version, [switch]$AllowDowngrade)",
|
|
260
265
|
"$ErrorActionPreference = 'Stop'",
|
|
261
266
|
"$ProgressPreference = 'SilentlyContinue'",
|
|
262
267
|
"$Contract = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String(" + psQuote(contractB64) + ")) | ConvertFrom-Json",
|
|
@@ -270,18 +275,32 @@ export function renderPowerShellBootstrap({
|
|
|
270
275
|
"function Expand-BootstrapArgs($Values, $ActiveVersionRoot, $ActiveVersion) { foreach ($Value in $Values) { ([string]$Value).Replace('{current}', $Current).Replace('{installRoot}', $InstallRoot).Replace('{versionRoot}', $ActiveVersionRoot).Replace('{version}', $ActiveVersion) } }",
|
|
271
276
|
"function Resolve-HealthPath($Value, [string]$JsonPath) { $CurrentValue = $Value; foreach ($Segment in $JsonPath.Split('.')) { if ($Segment -match '^\\d+$') { $Index = [int]$Segment; if ($null -eq $CurrentValue -or $Index -ge @($CurrentValue).Count) { throw ('Health path is missing: ' + $JsonPath) }; $CurrentValue = @($CurrentValue)[$Index] } else { $Property = $CurrentValue.PSObject.Properties[$Segment]; if ($null -eq $Property) { throw ('Health path is missing: ' + $JsonPath) }; $CurrentValue = $Property.Value } }; return $CurrentValue }",
|
|
272
277
|
"function Assert-Health($Health, [string]$ActiveVersion) { foreach ($Assertion in $Contract.healthAssertions) { $Actual = Resolve-HealthPath $Health ([string]$Assertion.path); if ($Assertion.PSObject.Properties.Name -contains 'equals') { $Expected = $Assertion.equals; if ($Expected -is [string]) { $Expected = $Expected.Replace('{version}', $ActiveVersion).Replace('{current}', $Current).Replace('{installRoot}', $InstallRoot) }; if ($Actual -ne $Expected) { throw ('Health assertion failed: ' + $Assertion.path) } } elseif ($Assertion.nonempty -eq $true) { if ($null -eq $Actual -or ([string]$Actual).Trim().Length -eq 0) { throw ('Health assertion failed: ' + $Assertion.path) } } elseif (@($Actual).Count -lt [int]$Assertion.minCount) { throw ('Health assertion failed: ' + $Assertion.path) } } }",
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
278
|
+
...(allowLocalReleaseRoot ? [
|
|
279
|
+
"New-Item -ItemType Directory -Force -Path $VersionsRoot | Out-Null",
|
|
280
|
+
"$LocalReleaseRoot = $null; if ($ReleaseRoot) { $LocalReleaseRoot = [IO.Path]::GetFullPath($ReleaseRoot); if (-not (Test-Path -LiteralPath $LocalReleaseRoot -PathType Container)) { throw 'Local release root is missing' } }",
|
|
281
|
+
"if (-not $Version -and -not $LocalReleaseRoot) { $Version = ((Invoke-RestMethod " + psQuote("https://api.github.com/repos/" + repository + "/releases/latest") + ").tag_name -replace '^v','') }",
|
|
282
|
+
"if ($Version -and $Version -notmatch '^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$') { throw 'Invalid stable release version' }",
|
|
283
|
+
"$ReleaseBase = if ($Version) { " + psQuote("https://github.com/" + repository + "/releases/download/v") + " + $Version } else { $null }",
|
|
284
|
+
"$Work = Join-Path ([IO.Path]::GetTempPath()) (" + psQuote(product + "-install-") + " + [guid]::NewGuid())",
|
|
285
|
+
"New-Item -ItemType Directory -Force -Path $Work | Out-Null",
|
|
286
|
+
"$ManifestPath = Join-Path $Work 'release-manifest.json'; $SignaturePath = Join-Path $Work 'release-manifest.cat'; $ChecksumsPath = Join-Path $Work 'checksums.json'",
|
|
287
|
+
"function Receive-ReleaseFile([string]$Name, [string]$Destination) { if ($LocalReleaseRoot) { $RootPrefix = $LocalReleaseRoot.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar; $Source = [IO.Path]::GetFullPath((Join-Path $LocalReleaseRoot $Name)); if (-not $Source.StartsWith($RootPrefix, [StringComparison]::OrdinalIgnoreCase) -or -not (Test-Path -LiteralPath $Source -PathType Leaf)) { throw ('Local release asset is missing or escapes root: ' + $Name) }; Copy-Item -LiteralPath $Source -Destination $Destination } else { Invoke-WebRequest ($ReleaseBase + '/' + $Name) -OutFile $Destination } }",
|
|
288
|
+
"Receive-ReleaseFile 'release-manifest.json' $ManifestPath",
|
|
289
|
+
"Receive-ReleaseFile 'release-manifest.cat' $SignaturePath",
|
|
290
|
+
] : [
|
|
291
|
+
"New-Item -ItemType Directory -Force -Path $VersionsRoot | Out-Null",
|
|
292
|
+
"if (-not $Version) { $Version = ((Invoke-RestMethod " + psQuote("https://api.github.com/repos/" + repository + "/releases/latest") + ").tag_name -replace '^v','') }",
|
|
293
|
+
"if ($Version -notmatch '^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$') { throw 'Invalid stable release version' }",
|
|
294
|
+
"$PriorTarget = $null; if (Test-Path $Current) { $PriorTarget = (Get-Item $Current).Target }",
|
|
295
|
+
"$PriorVersion = if ($PriorTarget) { ((Split-Path ([string]$PriorTarget) -Leaf) -split '-')[0] } else { $null }",
|
|
296
|
+
"if ($PriorVersion -and -not $AllowDowngrade -and ([version]$Version -lt [version]$PriorVersion)) { throw 'Downgrade requires -AllowDowngrade' }",
|
|
297
|
+
"$ReleaseBase = " + psQuote("https://github.com/" + repository + "/releases/download/v") + " + $Version",
|
|
298
|
+
"$Work = Join-Path ([IO.Path]::GetTempPath()) (" + psQuote(product + "-install-") + " + [guid]::NewGuid())",
|
|
299
|
+
"New-Item -ItemType Directory -Force -Path $Work | Out-Null",
|
|
300
|
+
"$ManifestPath = Join-Path $Work 'release-manifest.json'; $SignaturePath = Join-Path $Work 'release-manifest.cat'; $ChecksumsPath = Join-Path $Work 'checksums.json'",
|
|
301
|
+
"Invoke-WebRequest ($ReleaseBase + '/release-manifest.json') -OutFile $ManifestPath",
|
|
302
|
+
"Invoke-WebRequest ($ReleaseBase + '/release-manifest.cat') -OutFile $SignaturePath",
|
|
303
|
+
]),
|
|
285
304
|
"$ManifestBytes = [IO.File]::ReadAllBytes($ManifestPath); Import-Module Microsoft.PowerShell.Security -ErrorAction Stop",
|
|
286
305
|
"$Catalog = Test-FileCatalog -CatalogFilePath $SignaturePath -Path $ManifestPath -Detailed; if ([string]$Catalog.Status -ne 'Valid') { throw 'Release manifest catalog binding is invalid' }",
|
|
287
306
|
"$CatalogSignature = Get-AuthenticodeSignature -FilePath $SignaturePath; if ([string]$CatalogSignature.Status -ne 'Valid' -or -not $CatalogSignature.SignerCertificate) { throw 'Release manifest signature is invalid' }; $SignerCertificate = $CatalogSignature.SignerCertificate",
|
|
@@ -290,20 +309,34 @@ export function renderPowerShellBootstrap({
|
|
|
290
309
|
"$VerifiedKeyId = $null; foreach ($KeyId in $AcceptedSigners.Keys) { $Accepted = $AcceptedSigners[$KeyId]; if ($SignerSubject -eq [string]$Accepted.subject -and $SignerFingerprint -eq [string]$Accepted.certificateSha256) { $VerifiedKeyId = $KeyId; break } }",
|
|
291
310
|
"if (-not $VerifiedKeyId) { throw 'Release manifest signer is not accepted' }",
|
|
292
311
|
"$Manifest = [Text.Encoding]::UTF8.GetString($ManifestBytes) | ConvertFrom-Json",
|
|
312
|
+
...(allowLocalReleaseRoot ? [
|
|
313
|
+
"if (-not $Version) { $Version = [string]$Manifest.version }",
|
|
314
|
+
"if ($Version -notmatch '^(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)\\.(?:0|[1-9]\\d*)$') { throw 'Invalid stable release version' }",
|
|
315
|
+
"$ReleaseBase = " + psQuote("https://github.com/" + repository + "/releases/download/v") + " + $Version",
|
|
316
|
+
"$PriorTarget = $null; if (Test-Path $Current) { $PriorTarget = (Get-Item $Current).Target }",
|
|
317
|
+
"$PriorVersion = if ($PriorTarget) { ((Split-Path ([string]$PriorTarget) -Leaf) -split '-')[0] } else { $null }",
|
|
318
|
+
"if ($PriorVersion -and -not $AllowDowngrade -and ([version]$Version -lt [version]$PriorVersion)) { throw 'Downgrade requires -AllowDowngrade' }",
|
|
319
|
+
] : []),
|
|
293
320
|
"if ($Manifest.signingKeyId -ne $VerifiedKeyId -or $Manifest.signatureAlgorithm -ne 'authenticode-catalog-sha256' -or $Manifest.signatureProvider -ne 'windows-authenticode-catalog' -or $Manifest.signatureProviderVersion -ne 1) { throw 'Release manifest signer identity mismatch' }",
|
|
294
321
|
"if ($Manifest.product -ne " + psQuote(product) + " -or $Manifest.version -ne $Version -or $Manifest.tag -ne ('v' + $Version)) { throw 'Release identity mismatch' }",
|
|
295
322
|
"if ([version]$Contract.bootstrapVersion -lt [version]$Manifest.minimumBootstrapVersion) { throw 'Bootstrap update required' }",
|
|
296
323
|
"$Machine = [Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString(); $Target = if ($Machine -eq 'Arm64') { 'windows-arm64' } elseif ($Machine -eq 'X64') { 'windows-x86_64' } else { throw ('Unsupported architecture: ' + $Machine) }",
|
|
297
324
|
"$Matches = @($Manifest.assets | Where-Object { $_.target -eq $Target }); if ($Matches.Count -ne 1) { throw 'Release has no unique exact target' }; $Asset = $Matches[0]",
|
|
298
325
|
"if ($Asset.url -ne ($ReleaseBase + '/' + $Asset.name)) { throw 'Asset URL is not exact immutable GitHub release URL' }",
|
|
299
|
-
|
|
326
|
+
allowLocalReleaseRoot
|
|
327
|
+
? "Receive-ReleaseFile 'checksums.json' $ChecksumsPath"
|
|
328
|
+
: "Invoke-WebRequest ($ReleaseBase + '/checksums.json') -OutFile $ChecksumsPath",
|
|
300
329
|
"$ChecksumHash = (Get-FileHash -Algorithm SHA256 $ChecksumsPath).Hash.ToLowerInvariant(); if ($ChecksumHash -ne $Manifest.checksumsSha256) { throw 'checksums.json is not manifest-bound' }",
|
|
301
330
|
"$Checksums = Get-Content -Raw $ChecksumsPath | ConvertFrom-Json; if ($Checksums.assets.($Asset.name) -ne $Asset.sha256) { throw 'Asset checksum differs from bound checksums' }",
|
|
302
|
-
|
|
331
|
+
allowLocalReleaseRoot
|
|
332
|
+
? "$Archive = Join-Path $Work $Asset.name; Receive-ReleaseFile ([string]$Asset.name) $Archive"
|
|
333
|
+
: "$Archive = Join-Path $Work $Asset.name; Invoke-WebRequest $Asset.url -OutFile $Archive",
|
|
303
334
|
"if ((Get-FileHash -Algorithm SHA256 $Archive).Hash.ToLowerInvariant() -ne $Asset.sha256) { throw 'Archive checksum mismatch' }",
|
|
304
335
|
"if ($Checksums.assets.($Asset.provenanceName) -ne $Asset.provenanceSha256 -or $Checksums.assets.($Asset.sbomName) -ne $Asset.sbomSha256) { throw 'Bound provenance/SBOM checksums are missing' }",
|
|
305
336
|
"$ProvenancePath = Join-Path $Work $Asset.provenanceName; $SbomPath = Join-Path $Work $Asset.sbomName",
|
|
306
|
-
|
|
337
|
+
allowLocalReleaseRoot
|
|
338
|
+
? "Receive-ReleaseFile ([string]$Asset.provenanceName) $ProvenancePath; Receive-ReleaseFile ([string]$Asset.sbomName) $SbomPath"
|
|
339
|
+
: "Invoke-WebRequest $Asset.provenanceUrl -OutFile $ProvenancePath; Invoke-WebRequest $Asset.sbomUrl -OutFile $SbomPath",
|
|
307
340
|
"if ((Get-FileHash -Algorithm SHA256 $ProvenancePath).Hash.ToLowerInvariant() -ne $Asset.provenanceSha256) { throw 'Provenance checksum mismatch' }",
|
|
308
341
|
"if ((Get-FileHash -Algorithm SHA256 $SbomPath).Hash.ToLowerInvariant() -ne $Asset.sbomSha256) { throw 'SBOM checksum mismatch' }",
|
|
309
342
|
"$Stage = Join-Path $Work 'stage'; New-Item -ItemType Directory -Force -Path $Stage | Out-Null",
|
|
@@ -383,6 +416,7 @@ export function validatePowerShellBootstrap(script, expected = {}) {
|
|
|
383
416
|
statusArgs: contract.statusArgs,
|
|
384
417
|
healthAssertions: contract.healthAssertions,
|
|
385
418
|
preflightArgs: contract.preflightArgs,
|
|
419
|
+
allowLocalReleaseRoot: contract.allowLocalReleaseRoot === true,
|
|
386
420
|
});
|
|
387
421
|
if (regenerated !== script) errors.push("bootstrap source does not match canonical generated output");
|
|
388
422
|
} catch {
|
|
@@ -392,6 +426,7 @@ export function validatePowerShellBootstrap(script, expected = {}) {
|
|
|
392
426
|
const markerOffset = script.lastIndexOf("# source-sha256:");
|
|
393
427
|
if (!sourceMarker || markerOffset < 0 || createHash("sha256").update(script.slice(0, markerOffset)).digest("hex") !== sourceMarker[1]) errors.push("bootstrap source digest is missing or tampered");
|
|
394
428
|
if (expected.product && contract.product !== expected.product) errors.push("bootstrap product identity missing");
|
|
429
|
+
if (expected.allowLocalReleaseRoot === true && contract.allowLocalReleaseRoot !== true) errors.push("local release root support missing");
|
|
395
430
|
if (expected.acceptedSignerIds) for (const id of expected.acceptedSignerIds) if (!Object.hasOwn(contract.acceptedManifestSigners ?? {}, id)) errors.push("accepted manifest signer missing: " + id);
|
|
396
431
|
return { valid: errors.length === 0, errors };
|
|
397
432
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rightkit/release",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Portable
|
|
3
|
+
"version": "0.2.92",
|
|
4
|
+
"description": "Portable release CLI/SDK with fail-closed public GitHub Releases and private R2 + RightApps distribution.",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
package/publish-update.mjs
CHANGED
|
@@ -14,7 +14,7 @@ const API_BASE = process.env.RIGHTAPPS_API_URL || "https://api.spoares.com";
|
|
|
14
14
|
const DOWNLOAD_BASE = process.env.RIGHTAPPS_UPDATE_DOWNLOAD_BASE || "https://rightapps-license-gate.adrdsouza.workers.dev";
|
|
15
15
|
const PUBLIC_BASE = process.env.RIGHTAPPS_PUBLIC_DOWNLOAD_BASE || "https://pub-6c73208d46c245a9b4881d5e02f6b618.r2.dev";
|
|
16
16
|
const PIPELINE_VERSION = JSON.parse(await readFile(path.join(TOOL_ROOT, "package.json"), "utf8")).version;
|
|
17
|
-
|
|
17
|
+
let tier = process.env.RIGHT_RELEASE_TIER || "";
|
|
18
18
|
const args = process.argv.slice(2);
|
|
19
19
|
let configName = "right-release.config.mjs";
|
|
20
20
|
let platform = process.platform === "win32" ? "win" : "mac";
|
|
@@ -24,17 +24,20 @@ for (let i = 0; i < args.length; i++) {
|
|
|
24
24
|
const arg = args[i];
|
|
25
25
|
if (arg === "--config") configName = args[++i];
|
|
26
26
|
else if (arg === "--platform") platform = args[++i];
|
|
27
|
+
else if (arg === "--tier") tier = args[++i];
|
|
28
|
+
else if (arg.startsWith("--tier=")) tier = arg.slice("--tier=".length);
|
|
27
29
|
else if (arg === "--dry-run") dryRun = true;
|
|
28
30
|
else fail(`unknown argument: ${arg}`);
|
|
29
31
|
}
|
|
30
32
|
|
|
31
|
-
if (tier !== "patch" && tier !== "update")
|
|
32
|
-
fail("RIGHT_RELEASE_TIER is required (patch|update)");
|
|
33
|
-
}
|
|
33
|
+
if (tier !== "patch" && tier !== "update") fail("tier is required (--tier patch|update or RIGHT_RELEASE_TIER)");
|
|
34
34
|
|
|
35
35
|
const configPath = path.resolve(configName);
|
|
36
36
|
const root = path.dirname(configPath);
|
|
37
37
|
const config = (await import(pathToFileURL(configPath))).default;
|
|
38
|
+
if (config?.distribution?.provider !== "r2-rightapps") {
|
|
39
|
+
fail("release config distribution.provider must be r2-rightapps");
|
|
40
|
+
}
|
|
38
41
|
const target = config?.targets?.[platform];
|
|
39
42
|
const artifacts = target?.updater?.artifacts ?? [];
|
|
40
43
|
const installers = target?.installer?.artifacts ?? [];
|
package/rightkit-versions.json
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
},
|
|
15
15
|
"stagedNpm": {
|
|
16
16
|
"@rightkit/ax": "0.2.1",
|
|
17
|
-
"@rightkit/git": "0.2.
|
|
17
|
+
"@rightkit/git": "0.2.16",
|
|
18
18
|
"@rightkit/hooks": "0.1.1",
|
|
19
19
|
"@rightkit/legal": "0.3.1",
|
|
20
20
|
"@rightkit/legal-ui": "0.1.1",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"@rightkit/logs": "0.1.4",
|
|
23
23
|
"@rightkit/platform-ui": "0.1.1",
|
|
24
24
|
"@rightkit/qa": "0.2.1",
|
|
25
|
-
"@rightkit/release": "0.2.
|
|
25
|
+
"@rightkit/release": "0.2.92",
|
|
26
26
|
"@rightkit/tauri": "0.1.1",
|
|
27
27
|
"@rightkit/updates": "0.2.4"
|
|
28
28
|
},
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"0.2.10",
|
|
44
44
|
"0.2.11",
|
|
45
45
|
"0.2.12",
|
|
46
|
-
"0.2.13"
|
|
46
|
+
"0.2.13",
|
|
47
|
+
"0.2.15"
|
|
47
48
|
],
|
|
48
49
|
"@rightkit/legal-ui": [
|
|
49
50
|
"0.1.0"
|
|
@@ -92,7 +93,8 @@
|
|
|
92
93
|
"0.2.75",
|
|
93
94
|
"0.2.76",
|
|
94
95
|
"0.2.82",
|
|
95
|
-
"0.2.83"
|
|
96
|
+
"0.2.83",
|
|
97
|
+
"0.2.91"
|
|
96
98
|
],
|
|
97
99
|
"@rightkit/qa": [
|
|
98
100
|
"0.1.0",
|
package/upload-release.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { pathToFileURL } from "node:url";
|
|
6
|
-
import { prepareGitHubRelease, publishGitHubRelease
|
|
6
|
+
import { prepareGitHubRelease, publishGitHubRelease } from "./github-release.mjs";
|
|
7
7
|
import { assertPrimaryReleaseCheckout } from "./release-invocation.mjs";
|
|
8
8
|
import { verifySealedRelease } from "./release-state.mjs";
|
|
9
9
|
import { assertCleanSource } from "./source-gate.mjs";
|
|
@@ -43,22 +43,23 @@ const platformDir = platform === "win" ? "windows" : "mac";
|
|
|
43
43
|
const sealed = verifySealedRelease(path.join(repoRoot, ".right-release", "sealed", releaseId, platformDir));
|
|
44
44
|
if (sealed.manifest.commit !== candidateCommit) fail("sealed release was built from a different commit than the current checkout");
|
|
45
45
|
|
|
46
|
+
const configPath = path.resolve(configName);
|
|
47
|
+
if (!existsSync(configPath)) fail(`release config is required: ${configName}`);
|
|
48
|
+
const releaseConfig = (await import(`${pathToFileURL(configPath).href}?upload=${Date.now()}`)).default;
|
|
49
|
+
if (releaseConfig?.distribution?.provider !== "github-releases") {
|
|
50
|
+
fail("release config distribution.provider must be github-releases");
|
|
51
|
+
}
|
|
52
|
+
const configuredRepo = releaseConfig?.distribution?.repository ?? "";
|
|
53
|
+
if (!configuredRepo) fail("release config distribution.repository is required for github-releases");
|
|
54
|
+
if (repo && repo !== configuredRepo) fail(`--repo must match configured distribution.repository (${configuredRepo})`);
|
|
55
|
+
repo = configuredRepo;
|
|
56
|
+
|
|
46
57
|
const stateRoot = path.join(repoRoot, ".right-release", "state", releaseId, platformDir);
|
|
47
|
-
const verifiedMarker = path.join(stateRoot, `verified-${tier}.json`);
|
|
58
|
+
const verifiedMarker = path.join(stateRoot, `verified-${tier}-github-releases.json`);
|
|
48
59
|
if (existsSync(verifiedMarker)) {
|
|
49
|
-
console.log(`right-release upload: already verified ${releaseId} tier=${tier}`);
|
|
60
|
+
console.log(`right-release upload: already verified ${releaseId} tier=${tier} provider=github-releases`);
|
|
50
61
|
process.exit(0);
|
|
51
62
|
}
|
|
52
|
-
|
|
53
|
-
const configPath = path.resolve(configName);
|
|
54
|
-
if (existsSync(configPath)) {
|
|
55
|
-
const releaseConfig = (await import(`${pathToFileURL(configPath).href}?upload=${Date.now()}`)).default;
|
|
56
|
-
if (releaseConfig?.distribution?.provider && releaseConfig.distribution.provider !== "github-releases") {
|
|
57
|
-
fail("release config distribution.provider must be github-releases");
|
|
58
|
-
}
|
|
59
|
-
repo ||= releaseConfig?.distribution?.repository ?? "";
|
|
60
|
-
}
|
|
61
|
-
repo ||= repositoryFromRemote(repoRoot);
|
|
62
63
|
const plan = prepareGitHubRelease({ repoRoot, releaseId, platform, repo });
|
|
63
64
|
const result = publishGitHubRelease(plan, { repo, dryRun });
|
|
64
65
|
if (!dryRun) writeJson(verifiedMarker, {
|