diff --git a/.github/workflows/scripts/determine-npm-tag.sh b/.github/workflows/scripts/determine-npm-tag.sh new file mode 100755 index 00000000000..b603eb11211 --- /dev/null +++ b/.github/workflows/scripts/determine-npm-tag.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env bash +set -euo pipefail + +fail() { echo "Error: $*" >&2; exit 1; } + +# Ensure required variables are set +if [[ -z "${REFERENCE_PKG}" || -z "${VERSION_TYPE}" || -z "${VERSION}" ]]; then + fail "Missing required environment variables: REFERENCE_PKG, VERSION_TYPE, VERSION" +fi + +semver_cmp () { + IFS='.' read -r -a arr_a <<< "$1" + IFS='.' read -r -a arr_b <<< "$2" + + for i in 0 1 2; do + local aa=${arr_a[i]:-0} + local bb=${arr_b[i]:-0} + # shellcheck disable=SC2004 + if (( 10#$aa > 10#$bb )); then echo gt; return 0; fi + if (( 10#$aa < 10#$bb )); then echo lt; return 0; fi + done + + echo "eq" +} + + +STABLE_REGEX='^([0-9]+)\.([0-9]+)\.([0-9]+)$' # x.y.z +PRE_REGEX='^([0-9]+)\.([0-9]+)\.([0-9]+)-([0-9]+)$' # x.y.z-123456 + +# Validate that the VERSION matches VERSION_TYPE +# - stable must be x.y.z +# - nightly/canary must be x.y.z-123456 +case "$VERSION_TYPE" in + stable) + [[ $VERSION =~ $STABLE_REGEX ]] || fail "For 'stable', version must match x.y.z" ;; + nightly|canary) + [[ $VERSION =~ $PRE_REGEX ]] || fail "For '$VERSION_TYPE', version must match x.y.z-123456" ;; + *) + fail "Unknown version_type '$VERSION_TYPE'" ;; +esac + +# Extract major, minor from VERSION +IFS=.- read -r major minor patch _ <<< "$VERSION" + +# Determine NPM tag +case "$VERSION_TYPE" in + canary) TAG="canary" ;; + nightly) TAG="nightly" ;; + stable) + # Use npm dist-tag "latest" as the reference + LATEST="$(npm view --silent "$REFERENCE_PKG" dist-tags.latest 2>/dev/null || true)" + echo "Latest for $REFERENCE_PKG is ${LATEST:-}" >&2 + + if [[ -z ${LATEST:-} ]]; then + TAG="latest" # first ever publish + else + case "$(semver_cmp "$VERSION" "$LATEST")" in + gt) TAG="latest" ;; # newer than reference -> latest + lt|eq) TAG="v${major}.${minor}-latest" ;; # older or equal -> vX.Y-latest + esac + fi + ;; +esac + +echo "Resolved NPM_TAG=$TAG (VERSION=$VERSION, current latest=${LATEST:-none})" 1>&2 # stderr +printf '%s' "$TAG" diff --git a/scripts/publish-npm-packages.sh b/scripts/publish-npm-packages.sh index 98a799edefa..eaa2e595824 100755 --- a/scripts/publish-npm-packages.sh +++ b/scripts/publish-npm-packages.sh @@ -5,12 +5,11 @@ dist_tag="canary" registry="http://localhost:4873" -# shellcheck source=./scripts/helpers/exit-if-fail.sh -source "$(dirname "$0")/helpers/exit-if-fail.sh" - -if [ -z "$NPM_TOKEN" ]; then - echo "The NPM_TOKEN environment variable does not exist." - exit 1 +# Require either ACTIONS_ID_TOKEN_REQUEST_URL or NPM_TOKEN to be set +if [ -z "$ACTIONS_ID_TOKEN_REQUEST_URL" ] && [ -z "$NPM_TOKEN" ]; then + echo "ERROR: Either ACTIONS_ID_TOKEN_REQUEST_URL or NPM_TOKEN environment variable must be set." + echo "If running in Github Actions, ensure that 'id-token: write' permission is granted." + exit 1 fi # Parse command line arguments @@ -34,17 +33,32 @@ while [[ $# -gt 0 ]]; do esac done -echo "Starting to release $dist_tag version" +echo "Starting to release $dist_tag version with NPM version $(npm --version) to registry $registry" -registry_without_protocol=${registry#*:} - -echo "$registry_without_protocol/:_authToken=${NPM_TOKEN}" >> ~/.npmrc +if [ -n "$NPM_TOKEN" ]; then + echo "Configured NPM_TOKEN in ~/.npmrc" + registry_without_protocol=${registry#*:} + echo "$registry_without_protocol/:_authToken=${NPM_TOKEN}" >> ~/.npmrc +fi # Loop over .tar files in directory and publish them to npm registry +failed_packages=() for file in ./npm-artifacts/*.tgz; do - npm publish "$file" --tag "$dist_tag" --registry "$registry" + if ! npm publish "$file" --tag "$dist_tag" --registry "$registry"; then + failed_packages+=("$file") + fi done +# Log failed packages and exit with error if any failed +if (( ${#failed_packages[@]} > 0 )); then + echo "" + echo "ERROR: The following packages failed to publish:" + for pkg in "${failed_packages[@]}"; do + echo " - $pkg" + done + exit 1 +fi + # Check if any files in packages/grafana-e2e-selectors were changed. If so, add a 'modified' tag to the package CHANGES_COUNT=$(git diff HEAD~1..HEAD --name-only -- packages/grafana-e2e-selectors | awk 'END{print NR}') if (( CHANGES_COUNT > 0 )); then