Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 29 additions & 19 deletions .github/workflows/publish-runtime-packages.yml
Original file line number Diff line number Diff line change
Expand Up @@ -129,30 +129,40 @@ jobs:
if: steps.token.outputs.present == 'true'
run: |
set -euo pipefail
cd release-artifacts
if [ ! -s SHA256SUMS ]; then
if [ ! -s release-artifacts/SHA256SUMS ]; then
echo "::error::The release published no SHA256SUMS; refusing to repackage unverified bytes."
exit 1
fi
# Only the ten runtime assets are checked: the release also carries
# desktop artifacts this workflow never downloads, and `-c` fails on a
# manifest line whose file is absent.
# `|| true` on every grep. Under `set -euo pipefail` a grep that
# matches nothing exits 1 and aborts the step with no message, which
# is the most likely failure here (a renamed release asset) and the
# one the count diagnostic below exists to explain.
: > expected.sums
for TARGET in darwin-arm64 darwin-x64 linux-x64 linux-arm64; do
grep -E " ade-${TARGET}(\.native\.tar\.gz)?$" SHA256SUMS >> expected.sums || true
done
grep -E " ade-win32-x64\.exe(\.native\.tar\.gz)?$" SHA256SUMS >> expected.sums || true
if [ "$(wc -l < expected.sums)" -ne 10 ]; then
echo "::error::Expected 10 runtime entries in SHA256SUMS, found $(wc -l < expected.sums)."
cat expected.sums
exit 1
fi
sha256sum -c expected.sums
rm expected.sums
# manifest line whose file is absent. Names come from runtimeAssetNames
# so Windows stays `ade-win32-x64.native.tar.gz`, matching SHA256SUMS
# and release-core.yml, not `ade-win32-x64.exe.native.tar.gz`.
node --input-type=module <<'EOF'
import fs from "node:fs";
import { RUNTIME_TARGETS, runtimeAssetNames } from "./apps/ade-cli/scripts/build-runtime-npm-packages.mjs";

const sums = fs.readFileSync("release-artifacts/SHA256SUMS", "utf8").split(/\r?\n/);
const expected = [];
for (const { target } of RUNTIME_TARGETS) {
const { binaryAsset, archiveAsset } = runtimeAssetNames(target);
for (const name of [binaryAsset, archiveAsset]) {
const line = sums.find((row) => row.endsWith(` ${name}`));
if (!line) {
console.error(`::error::SHA256SUMS has no entry for ${name}.`);
process.exit(1);
}
expected.push(line);
}
}
if (expected.length !== 10) {
console.error(`::error::Expected 10 runtime entries in SHA256SUMS, found ${expected.length}.`);
process.exit(1);
}
fs.writeFileSync("release-artifacts/expected.sums", `${expected.join("\n")}\n`);
EOF
(cd release-artifacts && sha256sum -c expected.sums)
rm release-artifacts/expected.sums

- name: Build the platform packages
if: steps.token.outputs.present == 'true'
Expand Down
14 changes: 12 additions & 2 deletions apps/ade-cli/scripts/build-runtime-npm-packages.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,14 @@ export function runtimePackageName(target) {

/** The two release assets that make one platform package. */
export function runtimeAssetNames(target) {
const binaryAsset = target === "win32-x64" ? `ade-${target}.exe` : `ade-${target}`;
return { binaryAsset, archiveAsset: `${binaryAsset}.native.tar.gz` };
// The Windows launcher is `ade-win32-x64.exe`. The native archive next to it
// is `ade-win32-x64.native.tar.gz` — not `ade-win32-x64.exe.native.tar.gz`.
// `release-core.yml` and SHA256SUMS spell it that way; gluing `.native.tar.gz`
// onto the binary name looks for a file the release never publishes.
if (target === "win32-x64") {
return { binaryAsset: "ade-win32-x64.exe", archiveAsset: "ade-win32-x64.native.tar.gz" };
}
return { binaryAsset: `ade-${target}`, archiveAsset: `ade-${target}.native.tar.gz` };
}

/**
Expand Down Expand Up @@ -326,6 +332,9 @@ function listFilesRelative(dir, base = dir) {
return out;
}

/** 50 MiB: a real native tree's `npm pack --dry-run --json` listing exceeds Node's 1 MiB default. */
export const NPM_PACK_MAX_BUFFER_BYTES = 50 * 1024 * 1024;

/**
* `npm pack --dry-run`, spawned the one way that works on every platform.
*
Expand All @@ -347,6 +356,7 @@ function defaultPackRunner(cwd) {
cwd,
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
maxBuffer: NPM_PACK_MAX_BUFFER_BYTES,
windowsHide: true,
windowsVerbatimArguments: invocation.windowsVerbatimArguments,
});
Expand Down
27 changes: 27 additions & 0 deletions apps/ade-cli/scripts/build-runtime-npm-packages.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import test from "node:test";
import {
EXCEPTION_FILE_NAME,
META_PACKAGE_NAME,
NPM_PACK_MAX_BUFFER_BYTES,
RUNTIME_TARGETS,
buildMetaPackage,
buildRuntimePackage,
Expand Down Expand Up @@ -121,6 +122,32 @@ test("sets the executable bit on the runtime binary", () => {
});
});

test("npm pack dry-run buffer is large enough for a real native tree", () => {
assert.ok(NPM_PACK_MAX_BUFFER_BYTES >= 50 * 1024 * 1024);
const source = fs.readFileSync(new URL("./build-runtime-npm-packages.mjs", import.meta.url), "utf8");
assert.match(source, /maxBuffer:\s*NPM_PACK_MAX_BUFFER_BYTES/);
});

test("Windows native archive is ade-win32-x64.native.tar.gz, not glued onto .exe", () => {
assert.deepEqual(runtimeAssetNames("win32-x64"), {
binaryAsset: "ade-win32-x64.exe",
archiveAsset: "ade-win32-x64.native.tar.gz",
});
assert.deepEqual(runtimeAssetNames("linux-x64"), {
binaryAsset: "ade-linux-x64",
archiveAsset: "ade-linux-x64.native.tar.gz",
});
});

test("publish workflow checksum step uses runtimeAssetNames", () => {
const workflow = fs.readFileSync(
new URL("../../../.github/workflows/publish-runtime-packages.yml", import.meta.url),
"utf8",
);
assert.match(workflow, /runtimeAssetNames/);
assert.doesNotMatch(workflow, /ade-win32-x64\\.exe\(\\\.native\\.tar\\.gz\)\?/);
});

test("names the Windows binary ade.exe", () => {
withTempDirs(({ artifacts, out }) => {
writeFakeArtifacts(artifacts, "win32-x64");
Expand Down
Loading