check / check (push) Failing after 56s
script/build writes the version script/version prints into dist/package.json, which quak --version reports: the VERSION environment variable or build arg when one is given, otherwise git describe --tags --always, otherwise package.json's version. A checkout with .git whose version comes out empty, dev or unknown fails the build. .dockerignore no longer leaves out .git, and ARG VERSION has no default, so a plain docker build . of a clone stamps its commit. script/docker and script/cibuild still pass the host's version. make build-bin bundles the built dist/, so the single binary reports the same version. Model: opus-5-5
83 lines
2.7 KiB
Python
Executable File
83 lines
2.7 KiB
Python
Executable File
#!/bin/sh
|
|
# script/build: compile the TypeScript sources into dist/, stamp the version
|
|
# script/version prints into it, then verify that the artifacts package.json
|
|
# advertises are among the files the compiler actually wrote. tsc reports success by exit status alone and knows nothing
|
|
# about the manifest, so without this step a green build can still ship a
|
|
# package whose main, types or bin resolve to nothing. Our own extension to
|
|
# scripts-to-rule-them-all.
|
|
set -eu
|
|
|
|
ROOT="$(cd "$(dirname "$0")/.." && pwd -P)"
|
|
|
|
# Reads package.json, requires every declared entrypoint to exist, requires
|
|
# each bin entry to have kept its shebang, and makes the bin entries
|
|
# executable: tsc copies the shebang through but not the mode bits, and an
|
|
# installed CLI has to be runnable.
|
|
verify_entrypoints() {
|
|
node -e '
|
|
const { readFileSync, statSync, chmodSync } = require("node:fs");
|
|
|
|
const pkg = JSON.parse(readFileSync("package.json", "utf-8"));
|
|
const bins = Object.values(pkg.bin ?? {});
|
|
const fail = (message) => {
|
|
console.error("build: " + message);
|
|
process.exit(1);
|
|
};
|
|
|
|
for (const declared of [pkg.main, pkg.types, ...bins]) {
|
|
if (!declared) continue;
|
|
try {
|
|
statSync(declared);
|
|
} catch {
|
|
fail("package.json declares " + declared + ", which the build did not produce");
|
|
}
|
|
console.log("build: verified " + declared);
|
|
}
|
|
|
|
for (const bin of bins) {
|
|
const firstLine = readFileSync(bin, "utf-8").split("\n")[0];
|
|
if (!firstLine.startsWith("#!")) {
|
|
fail(bin + " lost its shebang, so it cannot be executed directly");
|
|
}
|
|
chmodSync(bin, 0o755);
|
|
console.log("build: " + bin + " is executable (" + firstLine + ")");
|
|
}
|
|
'
|
|
}
|
|
|
|
# src/index.ts imports ../package.json for the version, which tsc copies to
|
|
# dist/package.json. The version script/version prints is written into that
|
|
# copy only; the repo's own package.json is left as it is.
|
|
stamp_version() {
|
|
node -e '
|
|
const { readFileSync, writeFileSync } = require("node:fs");
|
|
|
|
const pkg = JSON.parse(readFileSync("dist/package.json", "utf-8"));
|
|
pkg.version = process.argv[1];
|
|
writeFileSync("dist/package.json", JSON.stringify(pkg, null, 4) + "\n");
|
|
' "$1"
|
|
}
|
|
|
|
# Running the built CLI proves the import resolves from dist/ and reports
|
|
# the stamped version.
|
|
verify_version() {
|
|
built="$(node dist/bin/quak.js --version)"
|
|
if [ "$built" != "$1" ]; then
|
|
echo "build: dist/bin/quak.js reports $built, the build stamped $1" >&2
|
|
exit 1
|
|
fi
|
|
echo "build: dist/bin/quak.js reports version $built"
|
|
}
|
|
|
|
main() {
|
|
cd "$ROOT"
|
|
# Own line, so that a failing script/version stops the build.
|
|
version="$("$ROOT/script/version")"
|
|
yarn run tsc
|
|
stamp_version "$version"
|
|
verify_entrypoints
|
|
verify_version "$version"
|
|
}
|
|
|
|
main "$@"
|