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
24 changes: 24 additions & 0 deletions .github/workflows/ci.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -88,6 +88,30 @@ jobs:
# The real check: the shim resolves the binary and the binary runs.
./node_modules/.bin/modelslab --version

# Dry-runs publish.sh against a stubbed npm, from the repo root with a
# relative dist dir — the shape CI and the release both use. v0.1.3 died
# here on a `node -p require('dist/npm/...')` that resolves fine with an
# absolute path and not at all with a relative one, so local testing with
# absolute paths never saw it.
- name: Dry-run the npm publisher
run: |
set -euo pipefail
mkdir -p /tmp/stub
cat > /tmp/stub/npm <<'STUB'
#!/usr/bin/env bash
case "$1" in
view) exit 1 ;;
publish) echo "would publish $2"; exit 0 ;;
*) exit 0 ;;
esac
STUB
chmod +x /tmp/stub/npm
output=$(PATH="/tmp/stub:$PATH" bash packaging/npm/publish.sh dist/npm)
echo "$output"
# Seven packages, and the unscoped entry must come last.
test "$(grep -c '^publish ' <<<"$output")" -eq 7
test "$(grep '^publish ' <<<"$output" | tail -1)" = "publish modelslab-cli@0.0.0"

- name: Build PyPI wheels
run: python3 packaging/pypi/build.py v0.0.0 artifacts dist/pypi

Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/release.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -84,11 +84,18 @@ jobs:
if: ${{ env.NODE_AUTH_TOKEN != '' }}
run: bash packaging/npm/publish.sh dist/npm

# `!cancelled()` on every PyPI step, not just the upload. v0.1.3 had the
# guard on the upload alone: npm failed, the build step was skipped as a
# normal 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.
- uses: actions/setup-python@v5
if: ${{ !cancelled() }}
with:
python-version: "3.12"

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

# `if: always()` because npm and PyPI are independent registries and a
Expand All@@ -100,7 +107,7 @@ jobs:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
# `secrets` is not an available context in a step-level `if` — hence env.
if: ${{ always() && env.TWINE_PASSWORD != '' }}
if: ${{ !cancelled() && env.TWINE_PASSWORD != '' }}
run: |
set -euo pipefail
python3 -m pip install --quiet twine
Expand Down
8 changes: 6 additions & 2 deletions packaging/npm/publish.sh
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,8 +33,12 @@ already_published() {
publish_one() {
local dir="$1"
local name version attempt delay output
name=$(node -p "require('${dir}/package.json').name")
version=$(node -p "require('${dir}/package.json').version")
# jq, not `node -p require(...)`. Node treats a path that does not start 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 only worked in local
# testing because that passed absolute paths; CI passes a relative dist dir.
name=$(jq -r .name "${dir}/package.json")
version=$(jq -r .version "${dir}/package.json")

if already_published "$name" "$version"; then
echo "skip ${name}@${version} (already on the registry)"
Expand Down
Loading