Files
nuwiki/.gitea/workflows/release.yaml
T
gffranco 101cb1cea9
CI / editor tests (push) Successful in 41s
ci(release): automate plugin releases via workflow_dispatch
Adds a dispatch-triggered Release workflow for the plugin: enter a version
in the Actions UI and it stamps g:nuwiki_version in plugin/nuwiki.vim,
sanity-checks the plugin still sources (+ exposes the stamped version),
commits chore(release): X.Y.Z, pushes the vX.Y.Z tag, and publishes a Gitea
release with notes. No binary build — the plugin ships none; nuwiki-ls is
fetched from nuwiki-rs at install time. Dispatch-only so the self-created
tag doesn't double-fire.

Updates ONBOARDING (tree, CI/CD, "Releasing the plugin") to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 16:26:28 +00:00

152 lines
6.1 KiB
YAML

name: Release
# Cut a plugin release from the Actions UI: "Run workflow" → enter the
# version (e.g. 0.5.1). This repo is the Vim/Neovim plugin only and ships no
# binary (the nuwiki-ls server lives in nuwiki-rs and is downloaded at install
# time), so a release is just: stamp g:nuwiki_version, commit, tag vX.Y.Z, and
# publish a Gitea release entry. No build / cross-compile.
#
# Dispatch-only on purpose: the job creates the tag itself, so a push-tag
# trigger would double-fire.
on:
workflow_dispatch:
inputs:
version:
description: 'Release version, no leading v (e.g. 0.5.1)'
required: true
type: string
permissions:
contents: write
jobs:
release:
name: tag + release ${{ inputs.version }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# Push the release commit + tag back with a write-capable token.
token: ${{ secrets.RELEASE_TOKEN }}
- name: Validate version + stamp
id: stamp
env:
VERSION: ${{ inputs.version }}
run: |
set -euo pipefail
ver="${VERSION#v}" # tolerate a leading v
if ! printf '%s' "$ver" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([-.][0-9A-Za-z.-]+)?$'; then
echo "::error::'$ver' is not a semver version (expected e.g. 0.5.1)"
exit 1
fi
tag="v$ver"
if git rev-parse -q --verify "refs/tags/$tag" >/dev/null \
|| git ls-remote --exit-code --tags origin "$tag" >/dev/null 2>&1; then
echo "::error::tag $tag already exists"
exit 1
fi
# g:nuwiki_version in plugin/nuwiki.vim is the plugin's only version
# location (surfaced by :NuwikiShowVersion / health).
sed -i -E "s/(let g:nuwiki_version = ')[^']*(')/\1$ver\2/" plugin/nuwiki.vim
if ! grep -q "let g:nuwiki_version = '$ver'" plugin/nuwiki.vim; then
echo "::error::failed to stamp g:nuwiki_version in plugin/nuwiki.vim"
exit 1
fi
echo "version=$ver" >> "$GITHUB_OUTPUT"
echo "tag=$tag" >> "$GITHUB_OUTPUT"
- name: Sanity-check the plugin sources cleanly
run: |
set -euo pipefail
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends vim
# plugin/nuwiki.vim must source without error (silent Ex mode exits
# non-zero on any error), and expose the stamped version.
vim -e -s -u NONE -N \
-c 'set runtimepath+=.' \
-c 'runtime plugin/nuwiki.vim' \
-c "if get(g:, 'nuwiki_version', '') !=# '${{ steps.stamp.outputs.version }}' | cquit 1 | endif" \
-c 'qall!'
- name: Commit, tag, push
env:
VER: ${{ steps.stamp.outputs.version }}
TAG: ${{ steps.stamp.outputs.tag }}
run: |
set -euo pipefail
git config user.name "gitea-actions"
git config user.email "gitea-actions@users.noreply.code.gfran.co"
git add plugin/nuwiki.vim
git commit -m "chore(release): $VER"
git tag -a "$TAG" -m "nuwiki plugin $VER"
git push origin "HEAD:${GITHUB_REF_NAME}"
git push origin "$TAG"
- name: Ensure jq + curl
run: |
command -v jq >/dev/null 2>&1 || { apt-get update && apt-get install -y --no-install-recommends jq; }
command -v curl >/dev/null 2>&1 || { apt-get update && apt-get install -y --no-install-recommends curl; }
- name: Generate release notes
id: notes
env:
TAG: ${{ steps.stamp.outputs.tag }}
run: |
set -euo pipefail
git fetch --tags --force origin >/dev/null 2>&1 || true
# Previous tag = newest tag that isn't the one we just cut.
prev_tag=$(git tag --sort=-version:refname | grep -vxF "$TAG" | head -n1 || echo "")
if [ -n "$prev_tag" ]; then
log=$(git log --oneline "$prev_tag..$TAG")
compare="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/compare/${prev_tag}...${TAG}"
else
log=$(git log --oneline "$TAG")
compare="${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/commits/tag/${TAG}"
fi
cat > release-notes.md <<EOF
Vim/Neovim plugin release. The \`nuwiki-ls\` server binary is downloaded
automatically from [nuwiki-rs](${GITHUB_SERVER_URL}/gffranco/nuwiki-rs)
at install time — no binary assets are attached here by design.
**Full Changelog**: ${compare}
**Changes**:
${log}
EOF
echo "wrote release notes"
- name: Create Gitea release
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
GITEA_SERVER: ${{ github.server_url }}
REPO: ${{ github.repository }}
TAG: ${{ steps.stamp.outputs.tag }}
run: |
set -euo pipefail
if [ -z "${RELEASE_TOKEN:-}" ]; then
echo "::error::RELEASE_TOKEN secret is not set"
exit 1
fi
# Idempotent: skip if a release for this tag already exists.
existing=$(curl --silent -o /dev/null -w "%{http_code}" \
-H "Authorization: token $RELEASE_TOKEN" \
"$GITEA_SERVER/api/v1/repos/$REPO/releases/tags/$TAG" || true)
if [ "$existing" = "200" ]; then
echo "release $TAG already exists — nothing to do"
exit 0
fi
notes=$(cat release-notes.md 2>/dev/null || echo "")
payload=$(jq -n --arg tag "$TAG" --arg name "$TAG" --arg body "$notes" \
'{tag_name: $tag, name: $name, body: $body, draft: false, prerelease: false}')
code=$(curl --silent -o /tmp/rel.json -w "%{http_code}" \
-H "Authorization: token $RELEASE_TOKEN" \
-H "Content-Type: application/json" \
-d "$payload" \
"$GITEA_SERVER/api/v1/repos/$REPO/releases")
if [ "$code" != "201" ]; then
echo "::error::failed to create release (HTTP $code)"; cat /tmp/rel.json; exit 1
fi
echo "created release $TAG"