diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9432b747d9e..fe3e4d416a6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -353,16 +353,15 @@ jobs: - name: Setup Node.JS uses: ./.github/actions/nodejs - # `npm publish` in release-npm returns before the registry makes the new - # versions resolvable; pack_dashmate.sh installs them from the registry. - - name: Wait for published NPM packages to become resolvable - run: "${GITHUB_WORKSPACE}/scripts/wait_for_npm_packages.sh" - - name: Create package env: # Packaging executes dependency and lifecycle scripts, including # output from the persistent builder. Signing happens in a new job. DASHMATE_UNSIGNED: 'true' + # Install the workspace packages from the tarballs release-npm + # published, not from the registry: npm can take many minutes to + # serve a version it has just accepted. + DASHMATE_NPM_TARBALLS_DIR: ${{ github.workspace }}/npm-packages run: | "${GITHUB_WORKSPACE}/scripts/pack_dashmate.sh" "${{ matrix.package_type }}" diff --git a/scripts/pack_dashmate.sh b/scripts/pack_dashmate.sh index 78125d6d226..d9025ff3e7e 100755 --- a/scripts/pack_dashmate.sh +++ b/scripts/pack_dashmate.sh @@ -51,6 +51,29 @@ echo "nodeLinker: node-modules" > .yarnrc.yml if [ "$COMMAND" = macos ] && [ "${DASHMATE_UNSIGNED:-false}" = true ]; then node -e 'const fs = require("fs"); const p = JSON.parse(fs.readFileSync("package.json", "utf8")); delete p.oclif.macos.sign; fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n");' fi +# The release workflow passes the npm tarballs it publishes. Install the +# workspace packages from them rather than from the registry, which can take +# many minutes to serve a version it has just accepted. The paths must be +# absolute: `oclif pack` installs again from a copy of this lockfile in its +# own tmp directory. +if [ -n "${DASHMATE_NPM_TARBALLS_DIR:-}" ]; then + DASHMATE_NPM_TARBALLS_DIR="$(realpath "$DASHMATE_NPM_TARBALLS_DIR")" node -e ' + const fs = require("fs"); + const path = require("path"); + const { execFileSync } = require("child_process"); + const dir = process.env.DASHMATE_NPM_TARBALLS_DIR; + const p = JSON.parse(fs.readFileSync("package.json", "utf8")); + const tarballs = fs.readdirSync(dir).filter((file) => file.endsWith(".tgz")); + if (tarballs.length === 0) throw new Error(`No npm tarballs in ${dir}`); + p.resolutions = {}; + for (const file of tarballs) { + const tarball = path.join(dir, file); + const { name } = JSON.parse(execFileSync("tar", ["-xOzf", tarball, "package/package.json"], { encoding: "utf8" })); + if (name !== p.name) p.resolutions[name] = `file:${tarball}`; + } + fs.writeFileSync("package.json", JSON.stringify(p, null, 2) + "\n"); + ' +fi yarn install --no-immutable yarn oclif manifest yarn oclif pack $COMMAND $FLAGS diff --git a/scripts/wait_for_npm_packages.sh b/scripts/wait_for_npm_packages.sh deleted file mode 100755 index 8857b02a056..00000000000 --- a/scripts/wait_for_npm_packages.sh +++ /dev/null @@ -1,76 +0,0 @@ -#!/usr/bin/env bash - -# Block until every publishable workspace package is resolvable from the npm -# registry at the version recorded in its package.json. -# -# `npm publish` returns as soon as the registry accepts the upload, but the -# registry can take several minutes before a new version is resolvable by -# installs. The dashmate packaging jobs install dashmate's freshly published -# workspace dependencies from the registry, so running them inside that -# window fails with "No candidates found". Run this script after the publish -# job and before any step that installs the published versions. -# -# Environment: -# NPM_WAIT_TIMEOUT seconds to wait before giving up (default 900) -# NPM_WAIT_INTERVAL seconds between polls (default 15) - -set -euo pipefail - -TIMEOUT="${NPM_WAIT_TIMEOUT:-900}" -INTERVAL="${NPM_WAIT_INTERVAL:-15}" - -ROOT_PATH=$(cd "$(dirname "$0")/.." && pwd) -cd "$ROOT_PATH" - -# One "name@version" per line, matching the set published by -# `yarn workspaces foreach --all --no-private npm publish`. -pending=$(yarn workspaces list --no-private --json | node -e ' - const fs = require("fs"); - const lines = fs.readFileSync(0, "utf8").split("\n").filter(Boolean); - for (const line of lines) { - const { name, location } = JSON.parse(line); - const { version } = JSON.parse(fs.readFileSync(location + "/package.json", "utf8")); - console.log(name + "@" + version); - } -') - -if [ -z "$pending" ]; then - echo "No publishable workspace packages found" - exit 1 -fi - -echo "Waiting up to ${TIMEOUT}s for packages to become resolvable from the npm registry:" -echo "$pending" - -deadline=$(( $(date +%s) + TIMEOUT )) - -while true; do - still_pending="" - - for spec in $pending; do - # --prefer-online revalidates any cached packument so a stale local cache - # cannot report a version as missing (or present) incorrectly. - if npm view --prefer-online "$spec" version >/dev/null 2>&1; then - echo "resolvable: $spec" - else - still_pending="${still_pending}${spec}"$'\n' - fi - done - - pending=$(printf '%s' "$still_pending") - - if [ -z "$pending" ]; then - echo "All packages are resolvable" - exit 0 - fi - - if [ "$(date +%s)" -ge "$deadline" ]; then - echo "::error::Timed out after ${TIMEOUT}s waiting for npm packages to become resolvable:" - echo "$pending" - exit 1 - fi - - echo "Still waiting for:" - echo "$pending" - sleep "$INTERVAL" -done