feat(npm): mkS390xNpmPublishMulti — multi-version npm publish per tag (#192)
Mirrors mkPyPiWheelPublishMulti for npm: publishes a fixed {version,file,
distTag?} list, each staged into its own dir and npm-published with its
dist-tag (idempotent). file may be a .node or a plain binary; packageJson
declares main-vs-bin. Unblocks nextjs-swc (next15 dist-tag) + sentry-cli.
Shared parity_npm_publish_dir helper added.
This commit is contained in:
@@ -7,6 +7,15 @@ semantic versioning; the version is a conceptual tag (no git tag is created).
|
||||
|
||||
## Unreleased
|
||||
|
||||
- **Feature: `mkS390xNpmPublishMulti` (cluster #192).** A multi-version npm
|
||||
builder mirroring the PyPI multi one: publishes a fixed list of
|
||||
`{ version; file; distTag? }` per tag, each staged into its own dir and
|
||||
`npm publish`ed with its dist-tag (idempotent — "already exists" == success).
|
||||
`file` may be a `.node` addon OR a plain binary, and `packageJson` (with a
|
||||
`$VERSION` the stage heredoc expands) declares the shape (`main` vs `bin`), so
|
||||
it covers both nextjs-swc (16.1.6 `@latest` + 15.2.0 `@next15`) and sentry-cli
|
||||
(a binary published as an npm package at two versions). Shared
|
||||
`parity_npm_publish_dir` helper added to `ci/parity-lib.sh`.
|
||||
- **Feature: `mkPyPiWheelPublishMulti` (cluster #197).** A multi-version PyPI
|
||||
builder that publishes a fixed list of `{ version; wheel; }` per tag instead of
|
||||
just the default — the pre-parity behaviour several `*-s390x` repos rely on.
|
||||
|
||||
@@ -173,6 +173,30 @@ parity_wheel_version() {
|
||||
basename "$1" | cut -d- -f2
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# `npm publish` a ready-to-publish package directory to the Gitea npm registry.
|
||||
# Idempotent: an "already exists"/409 is treated as success. Never echoes the
|
||||
# token (the output is sed-redacted). Args: <dir> <token> [<dist-tag>]. Used by
|
||||
# both the single- and multi-version npm publish apps.
|
||||
# ---------------------------------------------------------------------------
|
||||
parity_npm_publish_dir() {
|
||||
local dir="$1" tok="$2" dt="${3:-latest}" reg out rc
|
||||
reg="https://$PARITY_REGISTRY_HOST/api/packages/$PARITY_REGISTRY_OWNER/npm/"
|
||||
out="$(cd "$dir" && npm publish --registry="$reg" \
|
||||
"--//$PARITY_REGISTRY_HOST/api/packages/$PARITY_REGISTRY_OWNER/npm/:_authToken=$tok" \
|
||||
--tag "$dt" 2>&1)"
|
||||
rc=$?
|
||||
printf '%s\n' "$out" | sed "s/$tok/***REDACTED***/g"
|
||||
if [ "$rc" -ne 0 ]; then
|
||||
if printf '%s' "$out" | grep -qiE 'already exists|409|conflict'; then
|
||||
echo "npm: $(basename "$dir") already published — idempotent success."
|
||||
return 0
|
||||
fi
|
||||
return "$rc"
|
||||
fi
|
||||
echo "Published $(basename "$dir") (dist-tag $dt)"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stage directory helpers. The convention: each staged artifact is written to
|
||||
# ${PARITY_STAGE_DIR}/<arch>/ alongside a one-line meta file recording the
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
mkPyPiWheelPublish = wrap "mkPyPiWheelPublish";
|
||||
mkPyPiWheelPublishMulti = wrap "mkPyPiWheelPublishMulti";
|
||||
mkS390xNpmPublish = wrap "mkS390xNpmPublish";
|
||||
mkS390xNpmPublishMulti = wrap "mkS390xNpmPublishMulti";
|
||||
mkGenericBinaryPublish = wrap "mkGenericBinaryPublish";
|
||||
mkNix2ContainerPublish = wrap "mkNix2ContainerPublish";
|
||||
mkGoBinaryPublish = wrap "mkGoBinaryPublish";
|
||||
|
||||
@@ -355,6 +355,121 @@ let
|
||||
};
|
||||
};
|
||||
|
||||
# =========================================================================
|
||||
# s390x npm native addon / binary, MULTI-version (cluster #192). Publishes a
|
||||
# fixed list of { version; file; distTag? } per tag — the behaviour repos like
|
||||
# nextjs-swc (16.1.6 @latest + 15.2.0 @next15) and sentry-cli (3.2.2 + 2.38.2)
|
||||
# rely on. `file` may be a .node addon OR a plain binary; `fileName` is its name
|
||||
# inside the package and `packageJson` (with a $VERSION the stage heredoc
|
||||
# expands) declares the shape (a `main` for an addon, a `bin` for an exe). Each
|
||||
# version is staged into its own dir and published with its dist-tag; idempotent
|
||||
# (npm "already exists" == success). No dev-tag guard: explicit fixed version
|
||||
# list, gated by the dry-run default.
|
||||
# Args: { pname, versions = [ { version; file; distTag ? "latest"; } ],
|
||||
# fileName, packageJson, arch ? "s390x", registry* }
|
||||
# =========================================================================
|
||||
mkS390xNpmPublishMulti =
|
||||
{
|
||||
pname,
|
||||
versions,
|
||||
fileName,
|
||||
packageJson,
|
||||
arch ? "s390x",
|
||||
registryHost ? "git.oleks.space",
|
||||
registryOwner ? "oleks",
|
||||
passEntry ? "infra/gitea/personal_access_token_packages_rw",
|
||||
}:
|
||||
let
|
||||
head = preamble { inherit registryHost registryOwner passEntry; };
|
||||
nVersions = builtins.length versions;
|
||||
# One stage block per version: its own dir, the file, a version-stamped
|
||||
# package.json (the <<EOF heredoc expands the per-version $VERSION), and a
|
||||
# .disttag marker the publish loop reads.
|
||||
stageEntries = lib.concatMapStringsSep "\n" (e: ''
|
||||
vd="$d/${e.version}"
|
||||
mkdir -p "$vd"
|
||||
install -m 0755 ${lib.escapeShellArg "${e.file}"} "$vd/${fileName}"
|
||||
printf '%s' ${lib.escapeShellArg (e.distTag or "latest")} >"$vd/.disttag"
|
||||
VERSION=${lib.escapeShellArg e.version}
|
||||
cat >"$vd/package.json" <<PARITY_PKGJSON
|
||||
${packageJson}
|
||||
PARITY_PKGJSON
|
||||
'') versions;
|
||||
stageText = ''
|
||||
${head}
|
||||
echo "→ staging ${pname} (${toString nVersions} versions, ${arch}, no registry contact)"
|
||||
d="$(parity_stage_reset ${lib.escapeShellArg arch})"
|
||||
${stageEntries}
|
||||
printf 'npm-multi %s %s\n' ${lib.escapeShellArg pname} "${toString nVersions}" >"$d/.parity-meta"
|
||||
echo " staged ${toString nVersions} version dir(s) under $d"
|
||||
'';
|
||||
stage = pkgs.writeShellApplication {
|
||||
name = "stage-${arch}";
|
||||
runtimeInputs = baseInputs ++ [ pkgs.nodejs ];
|
||||
text = stageText;
|
||||
};
|
||||
dryList = ''
|
||||
echo "[dry-run] would 'npm publish' these ${pname} versions -> https://$PARITY_REGISTRY_HOST/api/packages/$PARITY_REGISTRY_OWNER/npm/:"
|
||||
for vd in "$d"/*/; do
|
||||
[ -f "$vd/package.json" ] || continue
|
||||
echo " - $(basename "$vd") (dist-tag $(cat "$vd/.disttag"))"
|
||||
done
|
||||
echo "[dry-run] re-run with --publish / PUBLISH=1 to push."
|
||||
'';
|
||||
uploadLoop = ''
|
||||
tok="$(parity_resolve_token)"
|
||||
parity_registry_preflight
|
||||
rc=0
|
||||
for vd in "$d"/*/; do
|
||||
[ -f "$vd/package.json" ] || continue
|
||||
parity_npm_publish_dir "$vd" "$tok" "$(cat "$vd/.disttag")" || rc=1
|
||||
done
|
||||
exit "$rc"
|
||||
'';
|
||||
publish = pkgs.writeShellApplication {
|
||||
name = "publish-${arch}";
|
||||
runtimeInputs = baseInputs ++ [ pkgs.nodejs ];
|
||||
text = ''
|
||||
${head}
|
||||
parity_parse_args "Build + publish all ${toString nVersions} ${pname} ${arch} npm versions to the Gitea npm registry" "$@"
|
||||
${lib.getExe stage}
|
||||
d="$(parity_stage_path ${lib.escapeShellArg arch})"
|
||||
if [ "$PARITY_PUBLISH" != "1" ]; then
|
||||
${dryList}
|
||||
exit 0
|
||||
fi
|
||||
${uploadLoop}
|
||||
'';
|
||||
};
|
||||
pushStaged = pkgs.writeShellApplication {
|
||||
name = "push-staged";
|
||||
runtimeInputs = baseInputs ++ [ pkgs.nodejs ];
|
||||
text = ''
|
||||
${head}
|
||||
parity_parse_args "Replay the staged ${pname} ${arch} npm versions from .parity-stage" "$@"
|
||||
d="$(parity_stage_path ${lib.escapeShellArg arch})"
|
||||
if ! find "$d" -mindepth 2 -name package.json -print -quit | grep -q .; then
|
||||
echo "BLOCKER(no-stage): no staged versions under $d — run 'nix run .#stage-${arch}' first." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [ "$PARITY_PUBLISH" != "1" ]; then
|
||||
${dryList}
|
||||
exit 0
|
||||
fi
|
||||
${uploadLoop}
|
||||
'';
|
||||
};
|
||||
in
|
||||
{
|
||||
"stage-${arch}" =
|
||||
mkApp stage "Stage all ${nVersions} ${pname} ${arch} npm versions into .parity-stage (no registry contact).";
|
||||
"publish-${arch}" =
|
||||
mkApp publish "Stage + publish all ${pname} ${arch} npm versions (dry-run by default; --publish to push).";
|
||||
"publish" = mkApp publish "Publish all ${pname} ${arch} npm versions (${arch} only for this repo).";
|
||||
"push-staged" =
|
||||
mkApp pushStaged "Replay the staged ${pname} ${arch} npm versions from .parity-stage (dry-run by default; --publish to push).";
|
||||
};
|
||||
|
||||
# =========================================================================
|
||||
# Generic binary (single-arch). Stage a built binary, PUT it to the Gitea
|
||||
# generic registry (idempotent: 201 created / 409 exists).
|
||||
@@ -857,6 +972,7 @@ in
|
||||
mkPyPiWheelPublish
|
||||
mkPyPiWheelPublishMulti
|
||||
mkS390xNpmPublish
|
||||
mkS390xNpmPublishMulti
|
||||
mkGenericBinaryPublish
|
||||
mkNix2ContainerPublish
|
||||
mkGoBinaryPublish
|
||||
|
||||
Reference in New Issue
Block a user