Skip to content

Commit 20a45f3

Browse files
committed
feat: add release workflow
1 parent d983a68 commit 20a45f3

2 files changed

Lines changed: 150 additions & 1 deletion

File tree

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ repos:
1313
- id: detect-private-key
1414

1515
- repo: https://github.com/astral-sh/uv-pre-commit
16-
rev: 0.8.18
16+
rev: 0.8.22
1717
hooks:
1818
- id: uv-lock
1919

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
name: "Create release"
3+
description: "Prepare a repository for a new release"
4+
inputs:
5+
spec-file:
6+
description: "Path to the specification file; must be JSON type."
7+
required: true
8+
release-notes-dir:
9+
description: "Path to the directory containing release notes."
10+
required: false
11+
default: ".github/release"
12+
13+
runs:
14+
using: composite
15+
steps:
16+
- name: Read version from spec file
17+
shell: bash
18+
id: read_version
19+
run: |
20+
# Check if ${{ inputs.spec-file }} exists
21+
if [ ! -f "${{ inputs.spec-file }}" ]; then
22+
echo "❌ ${{ inputs.spec-file }} file not found!"
23+
exit 1
24+
fi
25+
26+
# Extract version from ${{ inputs.spec-file }}
27+
VERSION=$(jq -r '.version' ${{ inputs.spec-file }})
28+
29+
if [ "$VERSION" = "null" ] || [ -z "$VERSION" ]; then
30+
echo "❌ Version not found in ${{ inputs.spec-file }} or is empty"
31+
exit 1
32+
fi
33+
34+
# Ensure version starts with 'v'
35+
if [[ ! $VERSION =~ ^v ]]; then
36+
VERSION="v$VERSION"
37+
fi
38+
39+
# Validate version format (semantic versioning)
40+
if [[ ! $VERSION =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?(\+[a-zA-Z0-9.-]+)?$ ]]; then
41+
echo "❌ Invalid version format in ${{ inputs.spec-file }}: ${VERSION}"
42+
echo "Expected format: x.y.z (semantic versioning)"
43+
exit 1
44+
fi
45+
46+
echo "version=$VERSION" >> $GITHUB_OUTPUT
47+
echo "📋 Version from ${{ inputs.spec-file }}: $VERSION"
48+
49+
- name: Get previous tag
50+
shell: bash
51+
id: previous_tag
52+
run: |
53+
git fetch --tags
54+
PREVIOUS_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
55+
echo "tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT
56+
57+
- name: Check if version already exists
58+
shell: bash
59+
id: check_version
60+
run: |
61+
SPEC_VERSION="${{ steps.read_version.outputs.version }}"
62+
PREVIOUS_TAG="${{ steps.previous_tag.outputs.tag }}"
63+
64+
# Check if tag already exists
65+
if git rev-parse "$SPEC_VERSION" >/dev/null 2>&1; then
66+
echo "❌ Tag $SPEC_VERSION already exists!"
67+
echo "Please update the version in ${{ inputs.spec-file }} to create a new release."
68+
exit 1
69+
fi
70+
71+
# Check if version is the same as previous (no version bump)
72+
if [ "$SPEC_VERSION" = "$PREVIOUS_TAG" ]; then
73+
echo "ℹ️ Version $SPEC_VERSION hasn't changed from previous release"
74+
echo "This indicates ${{ inputs.spec-file }} was updated with non-version changes only"
75+
echo "Skipping release creation..."
76+
echo "should_release=false" >> $GITHUB_OUTPUT
77+
exit 0
78+
fi
79+
80+
# Check if version is newer than previous
81+
if [ "$PREVIOUS_TAG" != "v0.0.0" ]; then
82+
# Remove 'v' prefix for comparison
83+
SPEC_NUM=${SPEC_VERSION#v}
84+
PREV_NUM=${PREVIOUS_TAG#v}
85+
86+
# Simple version comparison (works for semantic versioning)
87+
if printf '%s\n' "$PREV_NUM" "$SPEC_NUM" | sort -V | head -n1 | grep -q "^$SPEC_NUM$"; then
88+
echo "⚠️ Warning: Version $SPEC_VERSION appears to be older than previous version $PREVIOUS_TAG"
89+
echo "Proceeding anyway..."
90+
fi
91+
fi
92+
93+
echo "should_release=true" >> $GITHUB_OUTPUT
94+
echo "✅ Version validation passed: $PREVIOUS_TAG → $SPEC_VERSION"
95+
96+
- name: Generate changelog
97+
shell: bash
98+
id: changelog
99+
if: steps.check_version.outputs.should_release == 'true'
100+
run: |
101+
SPEC_VERSION="${{ steps.read_version.outputs.version }}"
102+
PREVIOUS_TAG="${{ steps.previous_tag.outputs.tag }}"
103+
104+
# Get description from ${{ inputs.spec-file }} if available
105+
CHANGELOG=$(cat ".github/release/${SPEC_VERSION}.md")
106+
107+
if [ "$PREVIOUS_TAG" = "v0.0.0" ]; then
108+
COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD)
109+
else
110+
COMMITS=$(git log --pretty=format:"- %s (%h)" $PREVIOUS_TAG..HEAD)
111+
fi
112+
113+
{
114+
echo 'changelog<<EOF'
115+
echo "$CHANGELOG"
116+
echo 'EOF'
117+
} >> $GITHUB_OUTPUT
118+
119+
- name: Create tag
120+
shell: bash
121+
if: steps.check_version.outputs.should_release == 'true'
122+
run: |
123+
SPEC_VERSION="${{ steps.read_version.outputs.version }}"
124+
git config user.name "github-actions[bot]"
125+
git config user.email "github-actions[bot]@users.noreply.github.com"
126+
git tag -a $SPEC_VERSION -m "Release $SPEC_VERSION"
127+
git push origin $SPEC_VERSION
128+
129+
- name: Create GitHub Release
130+
if: steps.check_version.outputs.should_release == 'true'
131+
uses: actions/create-release@v1
132+
env:
133+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
134+
with:
135+
tag_name: ${{ steps.read_version.outputs.version }}
136+
release_name: ${{ steps.read_version.outputs.version }}
137+
body: ${{ steps.changelog.outputs.changelog }}
138+
draft: false
139+
prerelease: false
140+
141+
- name: Skip release notification
142+
shell: bash
143+
if: steps.check_version.outputs.should_release == 'false'
144+
run: |
145+
echo "🔄 Workflow completed without creating a release"
146+
echo "💡 To create a new release, update the 'version' field in ${{ inputs.spec-file }}"
147+
echo ""
148+
echo "Current version in ${{ inputs.spec-file }}: ${{ steps.read_version.outputs.version }}"
149+
echo "Latest released version: ${{ steps.previous_tag.outputs.tag }}"

0 commit comments

Comments
 (0)