diff --git a/.github/workflows/pr-scripts.yml b/.github/workflows/pr-scripts.yml new file mode 100644 index 00000000..eb7809d1 --- /dev/null +++ b/.github/workflows/pr-scripts.yml @@ -0,0 +1,19 @@ +name: PR Scripts + +on: + pull_request: + paths: + - 'scripts/**' + - '.github/workflows/pr-scripts.yml' + +jobs: + publish-cli-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-node@v4 + with: + node-version: '21' + - run: bash scripts/tests/publish-cli-test.sh diff --git a/cli/RELEASE.md b/cli/RELEASE.md index dc5c6ccf..f260531b 100644 --- a/cli/RELEASE.md +++ b/cli/RELEASE.md @@ -77,11 +77,13 @@ Review and merge the PR on GitHub as usual. After the PR is merged: ```bash -git pull origin main -git tag cli-vX.Y.Z # replace with the actual version +git fetch origin main +git tag cli-vX.Y.Z origin/main # replace with the actual version git push origin cli-vX.Y.Z ``` +This ensures the tag is always placed on the merge commit on `origin/main`, regardless of your local branch state. + Pushing the tag triggers CI which builds, publishes to npm, and creates a GitHub Release. ### CI Workflow diff --git a/scripts/publish-cli.sh b/scripts/publish-cli.sh index dbad3985..822038d6 100755 --- a/scripts/publish-cli.sh +++ b/scripts/publish-cli.sh @@ -140,6 +140,13 @@ log_stage "computing next version from latest cli-v* tag" LATEST_TAG="$(git -C "$REPO_ROOT" tag --list 'cli-v*' --sort=-version:refname | head -n1)" if [[ -n "$LATEST_TAG" ]]; then BASE_VERSION="${LATEST_TAG#cli-v}" + # Reject prerelease tags (e.g., cli-v0.2.0-rc.1). Only pure X.Y.Z is supported. + if [[ "$BASE_VERSION" =~ [^0-9.] ]]; then + echo "latest tag $LATEST_TAG contains prerelease suffix: $BASE_VERSION" >&2 + echo "this script only supports pure X.Y.Z versions" >&2 + echo "skip prerelease tags manually or use a different baseline" >&2 + exit 1 + fi log_stage "baseline: $BASE_VERSION (from $LATEST_TAG)" else BASE_VERSION="$(PACKAGE_JSON="$PACKAGE_JSON" node -p "require(process.env.PACKAGE_JSON).version")" @@ -251,8 +258,10 @@ Local build-and-test passed (lint, typecheck, test, build). After merging, tag and push to trigger the release: \`\`\`bash -git pull origin main -git tag $TAG +git fetch origin main +git checkout main +git merge --ff-only origin/main +git tag $TAG origin/main git push origin $TAG \`\`\` @@ -271,7 +280,7 @@ git -C "$REPO_ROOT" branch -D "$RELEASE_BRANCH" log_stage "done — PR opened. After merge, tag manually:" echo "" -echo " git pull origin main" -echo " git tag $TAG" +echo " git fetch origin main" +echo " git tag $TAG origin/main" echo " git push origin $TAG" echo "" diff --git a/scripts/tests/publish-cli-test.sh b/scripts/tests/publish-cli-test.sh index b14b0ed2..cee5e54a 100755 --- a/scripts/tests/publish-cli-test.sh +++ b/scripts/tests/publish-cli-test.sh @@ -411,4 +411,17 @@ if [[ -f "$REPO10/gh-stub.log" ]] && grep -F "pr create" "$REPO10/gh-stub.log" > fail "gh pr create ran despite push failure" fi +# ---------------------------------------------------------------------------- +# Test 11: prerelease tag → abort with clear message +# ---------------------------------------------------------------------------- +echo "[test] prerelease tag aborts with message" +REPO11="$(new_tmp)" +init_repo "$REPO11" "0.1.0" "cli-v0.2.0-rc.1" +status="$(run_publish "$REPO11" "patch")" +[[ "$status" -ne 0 ]] || fail "expected non-zero exit for prerelease tag" +grep -F "contains prerelease suffix" "$REPO11/stderr.log" >/dev/null \ + || { cat "$REPO11/stderr.log" >&2; fail "expected prerelease rejection message"; } +grep -F "only supports pure X.Y.Z" "$REPO11/stderr.log" >/dev/null \ + || fail "expected X.Y.Z hint in error" + echo "all tests passed"