Skip to content

Commit eeb6305

Browse files
authored
fix(release): publish with relative paths, and stop skipping the wheel build (#6)
v0.1.3 reached neither registry. Two faults, both mine, both invisible to the way I tested. publish.sh used `node -p "require('${dir}/package.json')"` - Node treats a path that does not begin with ./ or / as a MODULE specifier, so `require('dist/npm/@modelslab/cli-linux-x64/package.json')` is a module lookup that fails with MODULE_NOT_FOUND. It worked in every local test because those passed absolute paths; CI passes a relative dist dir. Replaced with jq, which reads a file as a file. The PyPI guard was on the wrong step - `if: always()` was on the upload alone. npm failed, the wheel BUILD was skipped as an ordinary downstream skip, and the upload then ran and died on "Cannot find file dist/pypi/*.whl". A guard on the last step of a chain protects nothing. Every PyPI step now carries it, as `!cancelled()` so a cancelled run still stops. CI gains a dry-run of publish.sh against a stubbed npm, from the repo root with a relative dist dir — the shape the release actually uses. It asserts seven packages and that the unscoped entry package is published last. Both of the above would have failed it. Verified locally with a relative dist dir: the old call reproduces "Cannot find module", the new one resolves, and the publisher emits all six scoped platform packages followed by the entry package, with six wheels present for the PyPI step.
1 parent 13c6679 commit eeb6305

3 files changed

Lines changed: 38 additions & 3 deletions

File tree

.github/workflows/ci.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,30 @@ jobs:
8888
# The real check: the shim resolves the binary and the binary runs.
8989
./node_modules/.bin/modelslab --version
9090
91+
# Dry-runs publish.sh against a stubbed npm, from the repo root with a
92+
# relative dist dir — the shape CI and the release both use. v0.1.3 died
93+
# here on a `node -p require('dist/npm/...')` that resolves fine with an
94+
# absolute path and not at all with a relative one, so local testing with
95+
# absolute paths never saw it.
96+
- name: Dry-run the npm publisher
97+
run: |
98+
set -euo pipefail
99+
mkdir -p /tmp/stub
100+
cat > /tmp/stub/npm <<'STUB'
101+
#!/usr/bin/env bash
102+
case "$1" in
103+
view) exit 1 ;;
104+
publish) echo "would publish $2"; exit 0 ;;
105+
*) exit 0 ;;
106+
esac
107+
STUB
108+
chmod +x /tmp/stub/npm
109+
output=$(PATH="/tmp/stub:$PATH" bash packaging/npm/publish.sh dist/npm)
110+
echo "$output"
111+
# Seven packages, and the unscoped entry must come last.
112+
test "$(grep -c '^publish ' <<<"$output")" -eq 7
113+
test "$(grep '^publish ' <<<"$output" | tail -1)" = "publish modelslab-cli@0.0.0"
114+
91115
- name: Build PyPI wheels
92116
run: python3 packaging/pypi/build.py v0.0.0 artifacts dist/pypi
93117

.github/workflows/release.yml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,18 @@ jobs:
8484
if: ${{ env.NODE_AUTH_TOKEN != '' }}
8585
run: bash packaging/npm/publish.sh dist/npm
8686

87+
# `!cancelled()` on every PyPI step, not just the upload. v0.1.3 had the
88+
# guard on the upload alone: npm failed, the build step was skipped as a
89+
# normal downstream skip, and the upload then ran and died on
90+
# "Cannot find file dist/pypi/*.whl". A guard on the last step of a chain
91+
# protects nothing.
8792
- uses: actions/setup-python@v5
93+
if: ${{ !cancelled() }}
8894
with:
8995
python-version: "3.12"
9096

9197
- name: Build PyPI wheels
98+
if: ${{ !cancelled() }}
9299
run: python3 packaging/pypi/build.py "${GITHUB_REF_NAME}" artifacts dist/pypi
93100

94101
# `if: always()` because npm and PyPI are independent registries and a
@@ -100,7 +107,7 @@ jobs:
100107
TWINE_USERNAME: __token__
101108
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
102109
# `secrets` is not an available context in a step-level `if` — hence env.
103-
if: ${{ always() && env.TWINE_PASSWORD != '' }}
110+
if: ${{ !cancelled() && env.TWINE_PASSWORD != '' }}
104111
run: |
105112
set -euo pipefail
106113
python3 -m pip install --quiet twine

packaging/npm/publish.sh

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,12 @@ already_published() {
3333
publish_one() {
3434
local dir="$1"
3535
local name version attempt delay output
36-
name=$(node -p "require('${dir}/package.json').name")
37-
version=$(node -p "require('${dir}/package.json').version")
36+
# jq, not `node -p require(...)`. Node treats a path that does not start with
37+
# ./ or / as a MODULE specifier, so `require('dist/npm/@modelslab/cli-linux-x64/package.json')`
38+
# is a module lookup that fails with MODULE_NOT_FOUND. It only worked in local
39+
# testing because that passed absolute paths; CI passes a relative dist dir.
40+
name=$(jq -r .name "${dir}/package.json")
41+
version=$(jq -r .version "${dir}/package.json")
3842

3943
if already_published "$name" "$version"; then
4044
echo "skip ${name}@${version} (already on the registry)"

0 commit comments

Comments
 (0)