From b24ca1214c9ae06b50454146e7e1cff0049e2c96 Mon Sep 17 00:00:00 2001 From: Micheal Wilkinson Date: Sat, 21 Mar 2026 23:21:40 +0000 Subject: [PATCH] ci(release): replace vociferate with local release scripts --- .gitea/workflows/prepare-release.yml | 28 ++--- .gitea/workflows/tag-build-artifacts.yml | 12 ++- script/prepare-release.sh | 132 +++++++++++++++++++++++ script/publish-release.sh | 63 +++++++++++ 4 files changed, 215 insertions(+), 20 deletions(-) create mode 100644 script/prepare-release.sh create mode 100644 script/publish-release.sh diff --git a/.gitea/workflows/prepare-release.yml b/.gitea/workflows/prepare-release.yml index adf57fd..3f2b199 100644 --- a/.gitea/workflows/prepare-release.yml +++ b/.gitea/workflows/prepare-release.yml @@ -9,6 +9,7 @@ permissions: jobs: prepare: + if: ${{ !startsWith(github.event.head_commit.message, 'chore(release): prepare ') }} runs-on: ubuntu-latest steps: - name: Checkout @@ -23,24 +24,15 @@ jobs: ln -s CHANGELOG.md changelog.md fi - - name: Vociferate prepare - uses: https://git.hrafn.xyz/aether/vociferate/prepare@v1.1.0 + - name: Prepare release + run: bash ./script/prepare-release.sh - publish: - needs: prepare - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Provide lowercase changelog compatibility + - name: Summary + if: ${{ always() }} run: | set -euo pipefail - if [[ -f CHANGELOG.md && ! -e changelog.md ]]; then - ln -s CHANGELOG.md changelog.md - fi - - - name: Vociferate publish - uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.1.0 \ No newline at end of file + if git rev-parse -q --verify "refs/tags/$(sed -n 's/^const String = "\([^"]*\)"$/v\1/p' internal/homesick/version/version.go)" >/dev/null; then + echo "Prepared and pushed release tag $(sed -n 's/^const String = "\([^"]*\)"$/v\1/p' internal/homesick/version/version.go)." >> "$GITHUB_STEP_SUMMARY" + else + echo "No release prepared in this run." >> "$GITHUB_STEP_SUMMARY" + fi \ No newline at end of file diff --git a/.gitea/workflows/tag-build-artifacts.yml b/.gitea/workflows/tag-build-artifacts.yml index 6b15f30..953fb27 100644 --- a/.gitea/workflows/tag-build-artifacts.yml +++ b/.gitea/workflows/tag-build-artifacts.yml @@ -89,5 +89,13 @@ jobs: ln -s CHANGELOG.md changelog.md fi - - name: Vociferate publish - uses: https://git.hrafn.xyz/aether/vociferate/publish@v1.1.0 + - name: Install jq + run: | + set -euo pipefail + apt-get update + apt-get install -y jq + + - name: Create or update release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: bash ./script/publish-release.sh diff --git a/script/prepare-release.sh b/script/prepare-release.sh new file mode 100644 index 0000000..0203dac --- /dev/null +++ b/script/prepare-release.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +cd "$repo_root" + +version_file="internal/homesick/version/version.go" +primary_changelog="CHANGELOG.md" +compat_changelog="changelog.md" + +current_version="$(sed -n 's/^const String = "\([^"]*\)"$/\1/p' "$version_file")" +if [[ -z "$current_version" ]]; then + echo "Failed to read current version from ${version_file}" >&2 + exit 1 +fi + +bump="$(awk ' + BEGIN { in_unreleased = 0; section = ""; has_entries = 0; bump = "" } + /^## \[Unreleased\]/ { in_unreleased = 1; next } + /^## \[/ && in_unreleased { exit } + /^### / && in_unreleased { section = substr($0, 5); next } + in_unreleased && /^- / { + has_entries = 1 + if (section == "Breaking" || section == "Removed") { + bump = "major" + } else if (section == "Added") { + if (bump != "major") { + bump = "minor" + } + } else if (bump == "") { + bump = "patch" + } + } + END { + if (!has_entries) { + print "none" + exit + } + if (bump == "") { + bump = "patch" + } + print bump + } +' "$primary_changelog")" + +if [[ "$bump" == "none" ]]; then + echo "No unreleased changelog entries found; skipping release preparation." + exit 0 +fi + +IFS=. read -r major minor patch <<< "$current_version" +case "$bump" in + major) + major=$((major + 1)) + minor=0 + patch=0 + ;; + minor) + minor=$((minor + 1)) + patch=0 + ;; + patch) + patch=$((patch + 1)) + ;; + *) + echo "Unsupported bump type: ${bump}" >&2 + exit 1 + ;; +esac + +next_version="${major}.${minor}.${patch}" +tag="v${next_version}" +today="$(date -u +%F)" + +if git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then + echo "Tag ${tag} already exists; skipping release preparation." + exit 0 +fi + +unreleased_line="$(grep -n '^## \[Unreleased\]' "$primary_changelog" | cut -d: -f1)" +if [[ -z "$unreleased_line" ]]; then + echo "Missing [Unreleased] section in ${primary_changelog}" >&2 + exit 1 +fi + +next_heading_line="$(awk -v start="$unreleased_line" 'NR > start && /^## \[/ { print NR; exit }' "$primary_changelog")" +total_lines="$(wc -l < "$primary_changelog" | tr -d ' ')" +if [[ -z "$next_heading_line" ]]; then + next_heading_line=$((total_lines + 1)) +fi + +tmp_changelog="$(mktemp)" +{ + sed -n "1,$((unreleased_line - 1))p" "$primary_changelog" + echo "## [Unreleased]" + echo + echo "### Breaking" + echo + echo "### Added" + echo + echo "### Changed" + echo + echo "### Fixed" + echo + echo "### Removed" + echo + echo "## [${next_version}] - ${today}" + echo + sed -n "$((unreleased_line + 2)),$((next_heading_line - 1))p" "$primary_changelog" + if (( next_heading_line <= total_lines )); then + sed -n "${next_heading_line},${total_lines}p" "$primary_changelog" + fi +} > "$tmp_changelog" + +tmp_version="$(mktemp)" +sed "s/^const String = \".*\"$/const String = \"${next_version}\"/" "$version_file" > "$tmp_version" + +mv "$tmp_version" "$version_file" +mv "$tmp_changelog" "$primary_changelog" +cp "$primary_changelog" "$compat_changelog" + +git config user.name "gitea-actions[bot]" +git config user.email "gitea-actions[bot]@users.noreply.local" + +git add "$version_file" "$primary_changelog" "$compat_changelog" +git commit -m "chore(release): prepare ${tag}" +git tag "$tag" +git push origin HEAD:main +git push origin "$tag" + +echo "Prepared ${tag} from ${current_version} with a ${bump} bump." \ No newline at end of file diff --git a/script/publish-release.sh b/script/publish-release.sh new file mode 100644 index 0000000..977679f --- /dev/null +++ b/script/publish-release.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +cd "$repo_root" + +if [[ -z "${GITHUB_REF_NAME:-}" ]]; then + echo "GITHUB_REF_NAME is required" >&2 + exit 1 +fi + +if [[ -z "${GITHUB_REPOSITORY:-}" || -z "${GITHUB_SERVER_URL:-}" || -z "${GITHUB_TOKEN:-}" ]]; then + echo "GITHUB_REPOSITORY, GITHUB_SERVER_URL, and GITHUB_TOKEN are required" >&2 + exit 1 +fi + +tag="${GITHUB_REF_NAME}" +version="${tag#v}" +notes_file="$(mktemp)" + +awk -v version="$version" ' + $0 ~ ("^## \\\[" version "\\\] - ") { in_section = 1 } + /^## \[/ && in_section && $0 !~ ("^## \\\[" version "\\\] - ") { exit } + in_section { print } +' CHANGELOG.md > "$notes_file" + +if [[ ! -s "$notes_file" ]]; then + printf '## [%s]\n\n- Release %s\n' "$version" "$tag" > "$notes_file" +fi + +payload_file="$(mktemp)" +jq -n \ + --arg tag "$tag" \ + --arg name "$tag" \ + --arg target "main" \ + --rawfile body "$notes_file" \ + '{tag_name: $tag, target_commitish: $target, name: $name, body: $body, draft: false, prerelease: false}' > "$payload_file" + +api_base="${GITHUB_SERVER_URL}/api/v1/repos/${GITHUB_REPOSITORY}" +status="$(curl -sS -o /tmp/release_lookup.json -w '%{http_code}' \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H 'accept: application/json' \ + "${api_base}/releases/tags/${tag}" || true)" + +if [[ "$status" == "200" ]]; then + release_id="$(jq -r '.id' /tmp/release_lookup.json)" + curl -fsSL -X PATCH \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H 'accept: application/json' \ + -H 'content-type: application/json' \ + --data @"$payload_file" \ + "${api_base}/releases/${release_id}" >/dev/null + echo "Updated release ${tag}." +else + curl -fsSL -X POST \ + -H "Authorization: token ${GITHUB_TOKEN}" \ + -H 'accept: application/json' \ + -H 'content-type: application/json' \ + --data @"$payload_file" \ + "${api_base}/releases" >/dev/null + echo "Created release ${tag}." +fi \ No newline at end of file