|
1 | | -#!/bin/bash |
| 1 | +#!/usr/bin/env bash |
2 | 2 |
|
3 | | -VERSION=$1 |
| 3 | +set -euo pipefail |
4 | 4 |
|
5 | | -# check valid version format |
6 | | -if [ -n "$VERSION" ] && [[ ! $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then |
7 | | - echo "Version must be in format 1.2.3" |
| 5 | +usage() { |
| 6 | + echo "Usage: ./release.sh [VERSION] | ./release.sh --tag VERSION" >&2 |
| 7 | +} |
| 8 | + |
| 9 | +MODE="pr" |
| 10 | +if [[ "${1:-}" == "--tag" ]]; then |
| 11 | + MODE="tag" |
| 12 | + shift |
| 13 | +fi |
| 14 | + |
| 15 | +if [[ $# -gt 1 ]] || [[ "$MODE" == "tag" && $# -ne 1 ]]; then |
| 16 | + usage |
| 17 | + exit 1 |
| 18 | +fi |
| 19 | + |
| 20 | +VERSION="${1:-}" |
| 21 | +if [[ -n "$VERSION" && ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then |
| 22 | + echo "Version must be in format 1.2.3" >&2 |
8 | 23 | exit 1 |
9 | 24 | fi |
10 | 25 |
|
11 | | -# check current branch |
12 | 26 | CURRENT_BRANCH=$(git branch --show-current) |
13 | | -if [ "$CURRENT_BRANCH" != "main" ]; then |
14 | | - echo "Releases can only be created from the main branch (current: $CURRENT_BRANCH)" |
| 27 | +if [[ "$CURRENT_BRANCH" != "main" ]]; then |
| 28 | + echo "Releases must start from main (current: $CURRENT_BRANCH)" >&2 |
15 | 29 | exit 1 |
16 | 30 | fi |
17 | 31 |
|
18 | | -# bump patch version if no version provided |
19 | | -if [ -z "$VERSION" ]; then |
20 | | - (cd client && npm version patch --no-git-tag-version) |
21 | | - VERSION=$(node -p "require('./client/package.json').version") |
| 32 | +if [[ -n "$(git status --porcelain)" ]]; then |
| 33 | + echo "Releases require a clean working tree" >&2 |
| 34 | + exit 1 |
22 | 35 | fi |
23 | 36 |
|
24 | | -# check if version present in package.json |
25 | | -if ! grep -q "\"version\": \"$VERSION\"" ./client/package.json; then |
26 | | - echo "Version $VERSION not found in package.json" |
| 37 | +git pull --ff-only origin main |
| 38 | +if [[ "$(git rev-parse HEAD)" != "$(git rev-parse origin/main)" ]]; then |
| 39 | + echo "Local main must match origin/main before releasing" >&2 |
27 | 40 | exit 1 |
28 | 41 | fi |
29 | 42 |
|
30 | | -# check if version tag already exists |
31 | | -if git rev-parse "v$VERSION" >/dev/null 2>&1; then |
32 | | - echo "Release $VERSION already exists" |
| 43 | +if [[ "$MODE" == "tag" ]]; then |
| 44 | + CURRENT_VERSION=$(node -p "require('./client/package.json').version") |
| 45 | + if [[ "$CURRENT_VERSION" != "$VERSION" ]]; then |
| 46 | + echo "Version $VERSION is not the version on main ($CURRENT_VERSION)" >&2 |
| 47 | + exit 1 |
| 48 | + fi |
| 49 | + |
| 50 | + if git rev-parse --quiet --verify "refs/tags/v$VERSION" >/dev/null; then |
| 51 | + echo "Release $VERSION already exists" >&2 |
| 52 | + exit 1 |
| 53 | + fi |
| 54 | + REMOTE_TAG=$(git ls-remote --tags origin "refs/tags/v$VERSION") |
| 55 | + if [[ -n "$REMOTE_TAG" ]]; then |
| 56 | + echo "Release $VERSION already exists" >&2 |
| 57 | + exit 1 |
| 58 | + fi |
| 59 | + |
| 60 | + git tag -a "v$VERSION" origin/main -m "vscode-liquidjava $VERSION" |
| 61 | + git push origin "refs/tags/v$VERSION" |
| 62 | + exit 0 |
| 63 | +fi |
| 64 | + |
| 65 | +if ! command -v gh >/dev/null 2>&1; then |
| 66 | + echo "GitHub CLI (gh) is required to create the release pull request" >&2 |
33 | 67 | exit 1 |
34 | 68 | fi |
35 | 69 |
|
36 | | -git pull |
37 | | -git add . |
| 70 | +if [[ -z "$VERSION" ]]; then |
| 71 | + VERSION=$(node -e 'const [major, minor, patch] = require("./client/package.json").version.split(".").map(Number); console.log(`${major}.${minor}.${patch + 1}`)') |
| 72 | +fi |
| 73 | + |
| 74 | +CURRENT_VERSION=$(node -p "require('./client/package.json').version") |
| 75 | +if [[ "$CURRENT_VERSION" == "$VERSION" ]]; then |
| 76 | + echo "Version $VERSION is already on main; choose a new version" >&2 |
| 77 | + exit 1 |
| 78 | +fi |
| 79 | + |
| 80 | +BRANCH="codex/release-$VERSION" |
| 81 | +if git show-ref --verify --quiet "refs/heads/$BRANCH"; then |
| 82 | + echo "Release branch $BRANCH already exists" >&2 |
| 83 | + exit 1 |
| 84 | +fi |
| 85 | +REMOTE_BRANCH=$(git ls-remote --heads origin "refs/heads/$BRANCH") |
| 86 | +if [[ -n "$REMOTE_BRANCH" ]]; then |
| 87 | + echo "Release branch $BRANCH already exists" >&2 |
| 88 | + exit 1 |
| 89 | +fi |
| 90 | + |
| 91 | +if git rev-parse --quiet --verify "refs/tags/v$VERSION" >/dev/null; then |
| 92 | + echo "Release $VERSION already exists" >&2 |
| 93 | + exit 1 |
| 94 | +fi |
| 95 | +REMOTE_TAG=$(git ls-remote --tags origin "refs/tags/v$VERSION") |
| 96 | +if [[ -n "$REMOTE_TAG" ]]; then |
| 97 | + echo "Release $VERSION already exists" >&2 |
| 98 | + exit 1 |
| 99 | +fi |
| 100 | + |
| 101 | +git switch -c "$BRANCH" |
| 102 | +(cd client && npm version "$VERSION" --no-git-tag-version >/dev/null) |
| 103 | +git add client/package.json client/package-lock.json |
38 | 104 | git commit -m "Release $VERSION" |
39 | | -git tag -a "v$VERSION" -m "vscode-liquidjava $VERSION" |
| 105 | +git push --set-upstream origin "$BRANCH" |
| 106 | + |
| 107 | +gh pr create \ |
| 108 | + --base main \ |
| 109 | + --head "$BRANCH" \ |
| 110 | + --title "Release $VERSION" \ |
| 111 | + --body "Prepare version $VERSION for release. Merge this pull request after Checks pass, then run ./release.sh --tag $VERSION from main to publish." |
40 | 112 |
|
41 | | -git push |
42 | | -git push --tags |
| 113 | +printf 'After the release pull request is merged, run ./release.sh --tag %s from main to publish.\n' "$VERSION" |
0 commit comments