Skip to content

Commit 15c71cb

Browse files
committed
ci: add automated release workflow
1 parent cde6c6a commit 15c71cb

2 files changed

Lines changed: 117 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*.*.*"
7+
8+
permissions:
9+
contents: write
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout tag
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0
20+
21+
- name: Validate release tag
22+
id: tag
23+
shell: bash
24+
run: |
25+
tag="${GITHUB_REF_NAME}"
26+
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+([-.+][0-9A-Za-z.-]+)?$ ]]; then
27+
echo "::error title=Invalid release tag::Expected a tag like v1.2.3, got ${tag}."
28+
exit 1
29+
fi
30+
target_sha="$(git rev-list -n 1 "$tag")"
31+
32+
git fetch --no-tags origin +refs/heads/*:refs/remotes/origin/*
33+
34+
on_release_branch=false
35+
if git show-ref --verify --quiet refs/remotes/origin/master &&
36+
git merge-base --is-ancestor "$target_sha" origin/master; then
37+
on_release_branch=true
38+
fi
39+
if git show-ref --verify --quiet refs/remotes/origin/main &&
40+
git merge-base --is-ancestor "$target_sha" origin/main; then
41+
on_release_branch=true
42+
fi
43+
44+
if [[ "$on_release_branch" != "true" ]]; then
45+
echo "::error title=Tag is not on the release branch::${tag} must point to a commit contained in master or main."
46+
exit 1
47+
fi
48+
49+
{
50+
echo "tag=${tag}"
51+
echo "version=${tag#v}"
52+
echo "target_sha=${target_sha}"
53+
} >> "$GITHUB_OUTPUT"
54+
55+
- name: Extract release notes from CHANGELOG
56+
env:
57+
RELEASE_VERSION: ${{ steps.tag.outputs.version }}
58+
shell: python
59+
run: |
60+
import json
61+
import os
62+
import pathlib
63+
import re
64+
65+
version = os.environ["RELEASE_VERSION"]
66+
changelog = pathlib.Path("CHANGELOG.md")
67+
text = changelog.read_text(encoding="utf-8")
68+
match = re.search(
69+
rf"^## \[{re.escape(version)}\](?: - [^\n]+)?\s*\n(?P<body>.*?)(?=^## \[|\Z)",
70+
text,
71+
re.MULTILINE | re.DOTALL,
72+
)
73+
if not match:
74+
raise SystemExit(f"Could not find CHANGELOG.md section for {version}.")
75+
76+
body = match.group("body").strip()
77+
if not body:
78+
raise SystemExit(f"CHANGELOG.md section for {version} is empty.")
79+
80+
package_json = pathlib.Path("Packages/com.kurisu.ceres/package.json")
81+
package_version = json.loads(package_json.read_text(encoding="utf-8")).get("version")
82+
if package_version != version:
83+
raise SystemExit(
84+
f"package.json is {package_version}, but release tag is v{version}."
85+
)
86+
87+
pathlib.Path("release_notes.md").write_text(body + "\n", encoding="utf-8")
88+
89+
- name: Ensure release does not already exist
90+
env:
91+
GH_TOKEN: ${{ github.token }}
92+
shell: bash
93+
run: |
94+
if gh release view "${{ steps.tag.outputs.tag }}" >/dev/null 2>&1; then
95+
echo "::error title=Release already exists::Release ${{ steps.tag.outputs.tag }} already exists."
96+
exit 1
97+
fi
98+
99+
- name: Create GitHub release
100+
env:
101+
GH_TOKEN: ${{ github.token }}
102+
shell: bash
103+
run: |
104+
gh release create "${{ steps.tag.outputs.tag }}" \
105+
--title "${{ steps.tag.outputs.tag }}" \
106+
--notes "$(cat release_notes.md)" \
107+
--generate-notes

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Changelog
2+
3+
All notable changes to this package will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [1.0.0] - 2026-08-15
9+
10+
Initial stable release.

0 commit comments

Comments
 (0)