From ffb3ff029a037e66b963a9bfa74b2efa3b9a6b4a Mon Sep 17 00:00:00 2001 From: dawsbot <3408480+dawsbot@users.noreply.github.com> Date: Mon, 6 Jul 2026 21:55:54 -0600 Subject: [PATCH] chore(release): add one-shot publish script and `npm run release` Add scripts/publish.sh: interactively picks major/minor/patch, bumps and tags, pushes to the dawsbot remote, creates the GitHub release with the built VSIX attached, and walks through the manual Marketplace upload. It targets the repo explicitly and includes preflight guards plus failure recovery. Wire it up as `npm run release`, and drop the old `postversion` hook so a bare `npm version` just bumps (the script now owns push/release, targeting the correct remote and repo). Co-Authored-By: Claude Opus 4.8 (1M context) --- package.json | 4 +- scripts/publish.sh | 117 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 2 deletions(-) create mode 100755 scripts/publish.sh diff --git a/package.json b/package.json index 1102bce..3cd9832 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "clean": "node -e \"require('fs').rmSync('out', { recursive: true, force: true })\"", "test": "npm run clean && tsc && node --test out/test/**/*.test.js", "package": "vsce package", - "prepare": "husky install", - "postversion": "git push --follow-tags && gh release create \"v$npm_package_version\" --generate-notes" + "release": "bash scripts/publish.sh", + "prepare": "husky install" }, "repository": { "type": "git", diff --git a/scripts/publish.sh b/scripts/publish.sh new file mode 100755 index 0000000..05fad10 --- /dev/null +++ b/scripts/publish.sh @@ -0,0 +1,117 @@ +#!/usr/bin/env bash +# +# publish.sh: cut a new RelativePath release in one shot. +# 1. pick major / minor / patch +# 2. bump version, commit, tag +# 3. push tag to GitHub and create the release +# 4. build the VSIX and attach it to the release +# 5. walk you through the manual Marketplace upload +# +# Run it from anywhere inside the repo: ./scripts/publish.sh +# +set -euo pipefail + +# ---- config ----------------------------------------------------------------- +REMOTE="dawsbot" # git remote that hosts releases +REPO="dawsbot/RelativePath" # owner/name for the gh CLI +RELEASE_BRANCH="master" # releases are cut from here +PUBLISHER="jakob101" +MARKETPLACE_URL="https://marketplace.visualstudio.com/manage/publishers/${PUBLISHER}" + +# ---- helpers ---------------------------------------------------------------- +bold() { printf "\033[1m%s\033[0m\n" "$1"; } +die() { printf "\033[31mError:\033[0m %s\n" "$1" >&2; exit 1; } + +# ---- move to repo root ------------------------------------------------------ +cd "$(git rev-parse --show-toplevel)" || die "not inside a git repository" + +# ---- preflight checks ------------------------------------------------------- +command -v gh >/dev/null || die "gh (GitHub CLI) is not installed" +command -v npm >/dev/null || die "npm is not installed" +gh auth status >/dev/null 2>&1 || die "not logged in to gh. Run: gh auth login" + +branch="$(git branch --show-current)" +[ "$branch" = "$RELEASE_BRANCH" ] || \ + die "on '$branch', but releases must come from '$RELEASE_BRANCH'. Run: git checkout $RELEASE_BRANCH" + +[ -z "$(git status --porcelain)" ] || die "working tree is not clean. Commit or stash first." + +bold "Fetching $REMOTE..." +git fetch --quiet "$REMOTE" +[ -z "$(git log --oneline "${REMOTE}/${RELEASE_BRANCH}..${RELEASE_BRANCH}")" ] || \ + die "local $RELEASE_BRANCH has commits not on ${REMOTE}/${RELEASE_BRANCH}. Push or merge them first." +[ -z "$(git log --oneline "${RELEASE_BRANCH}..${REMOTE}/${RELEASE_BRANCH}")" ] || \ + die "local $RELEASE_BRANCH is behind ${REMOTE}/${RELEASE_BRANCH}. Run: git pull --ff-only" + +[ -d node_modules ] || { bold "Installing dependencies..."; npm install; } + +# ---- choose the bump -------------------------------------------------------- +current="$(node -p "require('./package.json').version")" +IFS=. read -r MA MI PA <<< "$current" +echo +bold "Current version: $current" +printf " 1) patch -> %s.%s.%s (bug fixes)\n" "$MA" "$MI" "$((PA + 1))" +printf " 2) minor -> %s.%s.0 (new features)\n" "$MA" "$((MI + 1))" +printf " 3) major -> %s.0.0 (breaking changes)\n" "$((MA + 1))" +printf "Pick 1/2/3 (or q to quit): " +read -r choice +case "$choice" in + 1) BUMP="patch" ;; + 2) BUMP="minor" ;; + 3) BUMP="major" ;; + q | Q) echo "Aborted."; exit 0 ;; + *) die "invalid choice: $choice" ;; +esac + +printf "Release a %s bump from %s? [y/N]: " "$BUMP" "$current" +read -r confirm +[ "$confirm" = "y" ] || [ "$confirm" = "Y" ] || { echo "Aborted."; exit 0; } + +# ---- bump + tag ------------------------------------------------------------- +# --ignore-scripts skips this repo's `postversion` hook so THIS script owns the +# push/release flow (the hook would push to the branch's upstream and create the +# release against gh's default repo, which are not guaranteed to be $REMOTE/$REPO). +BUMPED=0 +recover() { + [ "$BUMPED" = "1" ] || return + echo + printf "\033[31mFailed after the version bump.\033[0m To undo the local commit + tag:\n" + echo " git tag -d $TAG && git reset --hard HEAD~1" +} +trap recover ERR + +TAG="$(npm version "$BUMP" --ignore-scripts -m "release: v%s")" +BUMPED=1 +VERSION="${TAG#v}" +bold "Bumped to $TAG" + +# ---- push, release, build, attach ------------------------------------------ +bold "Pushing $RELEASE_BRANCH + $TAG to $REMOTE..." +git push --follow-tags "$REMOTE" "$RELEASE_BRANCH" + +bold "Creating GitHub release $TAG..." +gh release create "$TAG" --repo "$REPO" --title "$TAG" --generate-notes + +bold "Building the VSIX..." +npm run package +VSIX="RelativePath-${VERSION}.vsix" +[ -f "$VSIX" ] || die "expected $VSIX but the build did not produce it" + +bold "Attaching $VSIX to release $TAG..." +gh release upload "$TAG" "$VSIX" --repo "$REPO" --clobber + +trap - ERR # past the risky part + +# ---- manual Marketplace step ------------------------------------------------ +echo +bold "GitHub release is live with the VSIX attached:" +echo " https://github.com/${REPO}/releases/tag/${TAG}" +echo +bold ">>> NOW upload to the VS Code Marketplace (manual step) <<<" +echo " 1. Opening: $MARKETPLACE_URL" +echo " 2. Find 'Relative Path' -> ... menu -> Update" +echo " 3. Upload this file:" +printf " \033[1m%s/%s\033[0m\n" "$(pwd)" "$VSIX" +command -v open >/dev/null && open "$MARKETPLACE_URL" || true +echo +bold "Done. v$VERSION is tagged, released on GitHub, and ready to publish."