diff --git a/scripts/release/lib/pipeline.mjs b/scripts/release/lib/pipeline.mjs index 19eac14f..1375f428 100644 --- a/scripts/release/lib/pipeline.mjs +++ b/scripts/release/lib/pipeline.mjs @@ -1,5 +1,7 @@ +import {existsSync, readFileSync} from "node:fs" +import {join} from "node:path" import {parseArgs} from "node:util" -import {followUps, git, name, notes, repository, version} from "./context.mjs" +import {followUps, git, name, notes, repository, root, version} from "./context.mjs" import {ask, bold, dim, fail, green, red, yellow} from "./shell.mjs" export const release = async (command, steps) => { @@ -29,6 +31,19 @@ export const release = async (command, steps) => { const problems = selected.map(step => ({step, missing: step.missing?.() ?? []})) const warnings = [] + // pnpm keeps a copy of the lockfile it last installed from, so any difference means a pull or + // checkout since then changed dependencies the build would silently go without + const installed = join(root, "node_modules/.pnpm/lock.yaml") + + if ( + !existsSync(installed) || + readFileSync(installed, "utf-8") !== readFileSync(join(root, "pnpm-lock.yaml"), "utf-8") + ) { + problems.push({ + missing: ["node_modules doesn't match pnpm-lock.yaml: pnpm install --frozen-lockfile"], + }) + } + if (!notes) { problems.push({missing: [`CHANGELOG.md has no "# ${version}" section`]}) } diff --git a/scripts/release/steps/desktop.mjs b/scripts/release/steps/desktop.mjs index 4cc2cebc..e82b4ced 100644 --- a/scripts/release/steps/desktop.mjs +++ b/scripts/release/steps/desktop.mjs @@ -1,4 +1,4 @@ -import {existsSync} from "node:fs" +import {existsSync, readFileSync} from "node:fs" import {join, resolve} from "node:path" import {followUps, missingEnv, root} from "../lib/context.mjs" import {installed, run} from "../lib/shell.mjs" @@ -6,12 +6,29 @@ import {installed, run} from "../lib/shell.mjs" const targets = {darwin: ["macos"], linux: ["linux", "windows"]}[process.platform] ?? [] const docker = process.env.DOCKER || "docker" +// Optional packages for other platforms are in the lockfile but never installed +const electronInstalled = () => { + const path = join(root, "electron/node_modules/.package-lock.json") + + if (!existsSync(path)) { + return false + } + + const {packages: wanted} = JSON.parse(readFileSync(join(root, "electron/package-lock.json"))) + const {packages: installed} = JSON.parse(readFileSync(path)) + + return Object.entries(wanted).every( + ([key, {version, optional}]) => + !key || installed[key]?.version === version || (optional && !installed[key]), + ) +} + export default { name: "desktop", title: "Package the desktop app", missing: () => [ ...(targets.length > 0 ? [] : [`desktop packaging on ${process.platform}`]), - ...(existsSync(join(root, "electron/node_modules")) ? [] : ["electron dependencies"]), + ...(electronInstalled() ? [] : ["electron dependencies that match electron/package-lock.json"]), ...(targets.includes("windows") && !installed(docker) ? [docker] : []), ...(targets.includes("macos") ? missingEnv("CSC_NAME", "ASC_KEY_ID", "ASC_ISSUER_ID", "ASC_KEY_PATH")