fix: update cli commands in env and plugin skill (#44) #7
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release Tag | |
| on: | |
| push: | |
| branches: | |
| - main | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: Version to release. Leave empty to bump package.json automatically. Accepts 1.2.3 or v1.2.3. | |
| required: false | |
| type: string | |
| bump: | |
| description: Version bump to use when version is empty. | |
| required: false | |
| default: patch | |
| type: choice | |
| options: | |
| - patch | |
| - minor | |
| - major | |
| ref: | |
| description: Branch to release from. Must be a branch because this workflow commits package.json. | |
| required: false | |
| default: main | |
| type: string | |
| permissions: | |
| actions: write | |
| contents: write | |
| jobs: | |
| tag: | |
| name: Create release tag | |
| runs-on: ubuntu-latest | |
| if: "github.event_name != 'push' || !startsWith(github.event.head_commit.message, 'chore: release v')" | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| ref: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| - name: Resolve and validate version | |
| id: version | |
| shell: bash | |
| env: | |
| VERSION_INPUT: ${{ github.event_name == 'workflow_dispatch' && inputs.version || '' }} | |
| BUMP_INPUT: ${{ github.event_name == 'workflow_dispatch' && inputs.bump || 'patch' }} | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| if ! git ls-remote --exit-code --heads origin "$RELEASE_REF" >/dev/null 2>&1; then | |
| echo "Release ref '$RELEASE_REF' is not a branch. Use a branch name because this workflow commits package.json." >&2 | |
| exit 1 | |
| fi | |
| current_version="$(node -p "require('./package.json').version")" | |
| VERSION_INPUT="$VERSION_INPUT" BUMP_INPUT="$BUMP_INPUT" CURRENT_VERSION="$current_version" node <<'NODE' > /tmp/release-version.env | |
| const input = (process.env.VERSION_INPUT || '').trim(); | |
| const bump = process.env.BUMP_INPUT || 'patch'; | |
| const current = process.env.CURRENT_VERSION; | |
| const semver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/; | |
| function parse(version, label) { | |
| const match = version.match(semver); | |
| if (!match) { | |
| console.error(`Invalid semver ${label}: ${version}`); | |
| process.exit(1); | |
| } | |
| return { | |
| major: Number(match[1]), | |
| minor: Number(match[2]), | |
| patch: Number(match[3]), | |
| prerelease: match[4] ? match[4].split('.') : [], | |
| build: match[5] || '', | |
| }; | |
| } | |
| function comparePrerelease(left, right) { | |
| if (!left.length && !right.length) return 0; | |
| if (!left.length) return 1; | |
| if (!right.length) return -1; | |
| const length = Math.max(left.length, right.length); | |
| for (let index = 0; index < length; index += 1) { | |
| const a = left[index]; | |
| const b = right[index]; | |
| if (a === undefined) return -1; | |
| if (b === undefined) return 1; | |
| if (a === b) continue; | |
| const aNumeric = /^(0|[1-9]\d*)$/.test(a); | |
| const bNumeric = /^(0|[1-9]\d*)$/.test(b); | |
| if (aNumeric && bNumeric) return Number(a) > Number(b) ? 1 : -1; | |
| if (aNumeric) return -1; | |
| if (bNumeric) return 1; | |
| return a > b ? 1 : -1; | |
| } | |
| return 0; | |
| } | |
| function compareVersions(left, right) { | |
| for (const key of ['major', 'minor', 'patch']) { | |
| if (left[key] > right[key]) return 1; | |
| if (left[key] < right[key]) return -1; | |
| } | |
| return comparePrerelease(left.prerelease, right.prerelease); | |
| } | |
| const currentParsed = parse(current, 'package.json version'); | |
| let next = input.replace(/^v/, ''); | |
| if (!next) { | |
| if (!['patch', 'minor', 'major'].includes(bump)) { | |
| console.error(`Invalid bump input: ${bump}`); | |
| process.exit(1); | |
| } | |
| if (currentParsed.prerelease.length || currentParsed.build) { | |
| console.error('Automatic bump only supports plain X.Y.Z package versions. Provide an explicit version for prerelease or build metadata releases.'); | |
| process.exit(1); | |
| } | |
| const parts = [currentParsed.major, currentParsed.minor, currentParsed.patch]; | |
| if (bump === 'major') { | |
| parts[0] += 1; | |
| parts[1] = 0; | |
| parts[2] = 0; | |
| } else if (bump === 'minor') { | |
| parts[1] += 1; | |
| parts[2] = 0; | |
| } else { | |
| parts[2] += 1; | |
| } | |
| next = parts.join('.'); | |
| } | |
| const nextParsed = parse(next, 'release version'); | |
| if (compareVersions(nextParsed, currentParsed) <= 0) { | |
| console.error(`Release version '${next}' must be greater than package.json version '${current}'.`); | |
| process.exit(1); | |
| } | |
| console.log(`version=${next}`); | |
| console.log(`tag=v${next}`); | |
| NODE | |
| source /tmp/release-version.env | |
| tag="v$version" | |
| if git rev-parse "$tag" >/dev/null 2>&1; then | |
| echo "Tag '$tag' already exists." >&2 | |
| exit 1 | |
| fi | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | |
| - name: Update package version | |
| shell: bash | |
| env: | |
| RELEASE_VERSION: ${{ steps.version.outputs.version }} | |
| run: | | |
| set -euo pipefail | |
| VERSION="$RELEASE_VERSION" node <<'NODE' | |
| const fs = require('node:fs'); | |
| const path = 'package.json'; | |
| const packageJson = JSON.parse(fs.readFileSync(path, 'utf8')); | |
| packageJson.version = process.env.VERSION; | |
| fs.writeFileSync(path, `${JSON.stringify(packageJson, null, 2)}\n`); | |
| NODE | |
| - name: Create and push tag | |
| id: release | |
| shell: bash | |
| env: | |
| RELEASE_TAG: ${{ steps.version.outputs.tag }} | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| run: | | |
| set -euo pipefail | |
| tag="$RELEASE_TAG" | |
| git config user.name 'github-actions[bot]' | |
| git config user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| git add package.json | |
| git commit -m "chore: release $tag" | |
| git push origin "HEAD:$RELEASE_REF" | |
| git tag -a "$tag" -m "Release $tag" | |
| git push origin "$tag" | |
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | |
| - name: Dispatch npm publish | |
| shell: bash | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| RELEASE_REF: ${{ github.event_name == 'workflow_dispatch' && inputs.ref || github.ref_name }} | |
| RELEASE_TAG: ${{ steps.release.outputs.tag }} | |
| run: | | |
| set -euo pipefail | |
| curl -fsSL \ | |
| -X POST \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer $GH_TOKEN" \ | |
| -H "X-GitHub-Api-Version: 2022-11-28" \ | |
| "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/actions/workflows/npm-publish.yml/dispatches" \ | |
| -d "{\"ref\":\"$RELEASE_REF\",\"inputs\":{\"tag\":\"$RELEASE_TAG\"}}" |