mirror of
https://github.com/less/less.js.git
synced 2026-05-01 03:00:22 -04:00
* Initial plan * fix: correct release automation for master merges and publishing - create-release-pr.yml: add set -euo pipefail; track whether a commit was created; skip push + gh pr create when no version changes (no-op safety - fixes the "no commits between head and base" failure). - scripts/bump-and-publish.js: on master, use the version already in package.json as-is (no auto-increment). Validate it is > NPM version. Skip updateAllVersions/git-add/git-commit on master so the published tag always points to the release PR merge commit on master, not to a local detached commit. Alpha behavior is unchanged. - Fix error message: on master say "Git tag was pushed" rather than "Version bump commit and tag were pushed". Co-authored-by: matthew-dean <414752+matthew-dean@users.noreply.github.com> * test: add release automation test suite (20 tests) Proves the three components of the release flow work correctly: - publish.yml if: conditions (6 scenarios) - create-release-pr.yml if: conditions (4 scenarios) - bump-and-publish.js master path: existing version, no commit, no push (4 tests) - bump-and-publish.js alpha path: auto-increment, commit, alpha tag (4 tests) - create-release-pr no-op safety: commit when needed, clean exit when not (2 tests) Run with: node scripts/test-release-automation.js or: npm run test:release (after pnpm install) Co-authored-by: matthew-dean <414752+matthew-dean@users.noreply.github.com> * plan: implement PR-based release flow for alpha branch Co-authored-by: matthew-dean <414752+matthew-dean@users.noreply.github.com> * feat: PR-based release flow for alpha branch (mirrors master) - create-release-pr.yml: listen on alpha push; compute alpha version increment (X.Y.Z-alpha.N → X.Y.Z-alpha.N+1); use branch-specific PR title/base/branch naming; update loop guards for both flavours - publish.yml: remove push:alpha trigger; add alpha to pull_request branches; update if: condition for alpha release PR title+base - bump-and-publish.js: remove auto-increment/commit/push for alpha; add getNpmAlphaVersion(); alpha now validates and publishes like master - test-release-automation.js: 34 tests covering new flows end-to-end Co-authored-by: matthew-dean <414752+matthew-dean@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: matthew-dean <414752+matthew-dean@users.noreply.github.com>
216 lines
7.8 KiB
YAML
216 lines
7.8 KiB
YAML
name: Publish to NPM
|
|
|
|
on:
|
|
# Publish when a release PR is merged:
|
|
# master branch: "chore: release vX.Y.Z" PR → publishes latest
|
|
# alpha branch: "chore: alpha release vX.Y.Z" PR → publishes alpha
|
|
# Both release PRs are created automatically by create-release-pr.yml.
|
|
pull_request:
|
|
types: [closed]
|
|
branches:
|
|
- master
|
|
- alpha
|
|
|
|
permissions:
|
|
id-token: write # Required for OIDC trusted publishing
|
|
contents: write # Required for creating releases and pushing tags
|
|
|
|
jobs:
|
|
publish:
|
|
name: Publish to NPM
|
|
runs-on: ubuntu-latest
|
|
# Only run when a release PR with the expected title is merged into master
|
|
# or alpha. Any other PR close (or merge without the right title) is
|
|
# silently skipped.
|
|
if: |
|
|
github.repository == 'less/less.js' &&
|
|
github.event.pull_request.merged == true &&
|
|
(
|
|
(github.event.pull_request.base.ref == 'master' &&
|
|
startsWith(github.event.pull_request.title, 'chore: release v')) ||
|
|
(github.event.pull_request.base.ref == 'alpha' &&
|
|
startsWith(github.event.pull_request.title, 'chore: alpha release v'))
|
|
)
|
|
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
token: ${{ secrets.GITHUB_TOKEN }}
|
|
# Check out the base branch (master or alpha) post-merge so the
|
|
# version bump from the release PR is already present.
|
|
ref: ${{ github.event.pull_request.base.ref }}
|
|
|
|
- name: Install pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 'lts/*'
|
|
registry-url: 'https://registry.npmjs.org'
|
|
cache: 'pnpm'
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Run node tests (ESM + CJS)
|
|
run: pnpm run test:node
|
|
|
|
- name: Build
|
|
run: |
|
|
cd packages/less
|
|
pnpm run build
|
|
|
|
- name: Configure Git
|
|
run: |
|
|
git config --global user.name "github-actions[bot]"
|
|
git config --global user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
- name: Determine branch and tag type
|
|
id: branch-info
|
|
run: |
|
|
# Always a pull_request event; base.ref is master or alpha.
|
|
BRANCH="${{ github.event.pull_request.base.ref }}"
|
|
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
|
|
if [ "$BRANCH" = "alpha" ]; then
|
|
echo "is_alpha=true" >> $GITHUB_OUTPUT
|
|
echo "npm_tag=alpha" >> $GITHUB_OUTPUT
|
|
echo "release_type=prerelease" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "is_alpha=false" >> $GITHUB_OUTPUT
|
|
echo "npm_tag=latest" >> $GITHUB_OUTPUT
|
|
echo "release_type=release" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Validate alpha branch requirements
|
|
if: steps.branch-info.outputs.is_alpha == 'true'
|
|
run: |
|
|
# Fetch master branch
|
|
git fetch origin master:master || true
|
|
|
|
# Check 1: Alpha branch must not be behind master
|
|
echo "🔍 Checking if alpha branch is up to date with master..."
|
|
MASTER_COMMITS=$(git rev-list --count alpha..master 2>/dev/null || echo "0")
|
|
|
|
if [ "$MASTER_COMMITS" -gt 0 ]; then
|
|
echo "❌ ERROR: Alpha branch is behind master by $MASTER_COMMITS commit(s)"
|
|
echo " Alpha branch must include all commits from master before publishing"
|
|
exit 1
|
|
fi
|
|
echo "✅ Alpha branch is up to date with master"
|
|
|
|
# Check 2: Get current version and validate it contains 'alpha'
|
|
CURRENT_VERSION=$(node -p "require('./packages/less/package.json').version")
|
|
echo "📦 Current version: $CURRENT_VERSION"
|
|
|
|
if [[ ! "$CURRENT_VERSION" =~ -alpha\. ]]; then
|
|
echo "❌ ERROR: Alpha branch version must contain '-alpha.'"
|
|
echo " Current version: $CURRENT_VERSION"
|
|
echo " Expected format: X.Y.Z-alpha.N"
|
|
exit 1
|
|
fi
|
|
echo "✅ Version contains 'alpha' suffix"
|
|
|
|
# Check 3: Alpha base version must be >= master version
|
|
echo "🔍 Comparing alpha base version with master version..."
|
|
MASTER_VERSION=$(git show master:packages/less/package.json 2>/dev/null | node -p "try { JSON.parse(require('fs').readFileSync(0, 'utf-8')).version } catch(e) { '0.0.0' }" || echo "0.0.0")
|
|
|
|
if [ "$MASTER_VERSION" = "0.0.0" ]; then
|
|
echo "⚠️ Could not determine master version, skipping comparison"
|
|
else
|
|
echo "📦 Master version: $MASTER_VERSION"
|
|
|
|
# Extract base version (remove -alpha.X suffix)
|
|
ALPHA_BASE=$(echo "$CURRENT_VERSION" | sed 's/-alpha\.[0-9]*$//')
|
|
echo "📦 Alpha base version: $ALPHA_BASE"
|
|
|
|
# Compare versions using semver from root workspace
|
|
COMPARE_RESULT=$(node -e "
|
|
const semver = require('semver');
|
|
const alphaBase = process.argv[1];
|
|
const master = process.argv[2];
|
|
if (semver.lt(alphaBase, master)) {
|
|
console.log('ERROR');
|
|
} else {
|
|
console.log('OK');
|
|
}
|
|
" "$ALPHA_BASE" "$MASTER_VERSION" 2>/dev/null || echo "ERROR")
|
|
|
|
if [ "$COMPARE_RESULT" = "ERROR" ]; then
|
|
echo "❌ ERROR: Alpha base version ($ALPHA_BASE) is lower than master version ($MASTER_VERSION)"
|
|
echo " According to semver, alpha base version must be >= master version"
|
|
exit 1
|
|
fi
|
|
echo "✅ Alpha base version is >= master version"
|
|
fi
|
|
|
|
- name: Ensure npm 11.5.1 or later for trusted publishing
|
|
run: npm install -g npm@latest
|
|
|
|
- name: Bump version and publish
|
|
id: publish
|
|
env:
|
|
# Pass the resolved base branch name (master or alpha) so that
|
|
# bump-and-publish.js knows which branch it is publishing for.
|
|
GITHUB_REF_NAME: ${{ steps.branch-info.outputs.branch }}
|
|
run: |
|
|
pnpm run publish
|
|
|
|
# Extract version from package.json
|
|
VERSION=$(node -p "require('./packages/less/package.json').version")
|
|
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
|
echo "tag=v$VERSION" >> $GITHUB_OUTPUT
|
|
|
|
- name: Create GitHub Release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
TAG="${{ steps.publish.outputs.tag }}"
|
|
VERSION="${{ steps.publish.outputs.version }}"
|
|
IS_ALPHA="${{ steps.branch-info.outputs.is_alpha }}"
|
|
|
|
if [ "$IS_ALPHA" = "true" ]; then
|
|
TITLE="Alpha Release $TAG"
|
|
PRERELEASE="--prerelease"
|
|
BODY="## Alpha Release
|
|
|
|
This is an alpha release from the alpha branch.
|
|
|
|
## Installation
|
|
|
|
\`\`\`bash
|
|
npm install less@${VERSION} --tag alpha
|
|
\`\`\`
|
|
|
|
Or:
|
|
|
|
\`\`\`bash
|
|
npm install less@alpha
|
|
\`\`\`"
|
|
else
|
|
TITLE="Release $TAG"
|
|
PRERELEASE=""
|
|
BODY="## Changes
|
|
|
|
See [CHANGELOG.md](https://github.com/less/less.js/blob/master/CHANGELOG.md) for details.
|
|
|
|
## Installation
|
|
|
|
\`\`\`bash
|
|
npm install less@${VERSION}
|
|
\`\`\`"
|
|
fi
|
|
|
|
if gh release view "$TAG" &>/dev/null; then
|
|
echo "Release $TAG already exists, uploading assets to existing release"
|
|
gh release upload "$TAG" packages/less/dist/less.js packages/less/dist/less.min.js --clobber
|
|
else
|
|
gh release create "$TAG" \
|
|
--title "$TITLE" \
|
|
$PRERELEASE \
|
|
--notes "$BODY" \
|
|
packages/less/dist/less.js \
|
|
packages/less/dist/less.min.js
|
|
fi
|