Skip to content

Commit 91557ae

Browse files
authored
Merge pull request #297 from dhorions/copilot/create-release-notes-and-publish
Github Workflows for automated and retroactive releases creation.
2 parents 2b07a4f + 010cbbc commit 91557ae

File tree

4 files changed

+425
-0
lines changed

4 files changed

+425
-0
lines changed
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
name: Create GitHub Release
2+
3+
on:
4+
push:
5+
tags:
6+
- '[0-9]+.[0-9]+.[0-9]+'
7+
- '[0-9]+.[0-9]+'
8+
- '[0-9]+.[0-9]+.[0-9]+-*'
9+
10+
jobs:
11+
create-release:
12+
runs-on: ubuntu-latest
13+
permissions:
14+
contents: write
15+
16+
steps:
17+
- name: Check if version is after 1.7.0
18+
id: version_check
19+
run: |
20+
VERSION="${{ github.ref_name }}"
21+
echo "Checking version: $VERSION"
22+
23+
# Remove any pre-release suffix (e.g., 1.8.0-alpha -> 1.8.0)
24+
BASE_VERSION=$(echo "$VERSION" | sed 's/-.*//')
25+
26+
# Split version into major, minor, patch
27+
IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE_VERSION"
28+
29+
# Default patch to 0 if not present
30+
PATCH=${PATCH:-0}
31+
32+
echo "Parsed version: $MAJOR.$MINOR.$PATCH"
33+
34+
# Check if version is after 1.7.0
35+
# We want to skip 1.0.x through 1.7.0
36+
if [ "$MAJOR" -gt 1 ]; then
37+
echo "Version is after 1.7.0 (major > 1)"
38+
echo "should_create_release=true" >> $GITHUB_OUTPUT
39+
elif [ "$MAJOR" -eq 1 ]; then
40+
if [ "$MINOR" -gt 7 ]; then
41+
echo "Version is after 1.7.0 (1.x where x > 7)"
42+
echo "should_create_release=true" >> $GITHUB_OUTPUT
43+
elif [ "$MINOR" -eq 7 ] && [ "$PATCH" -gt 0 ]; then
44+
echo "Version is after 1.7.0 (1.7.x where x > 0)"
45+
echo "should_create_release=true" >> $GITHUB_OUTPUT
46+
else
47+
echo "Version is 1.7.0 or earlier, skipping"
48+
echo "should_create_release=false" >> $GITHUB_OUTPUT
49+
fi
50+
else
51+
echo "Version is before 1.7.0, skipping"
52+
echo "should_create_release=false" >> $GITHUB_OUTPUT
53+
fi
54+
55+
- name: Checkout code
56+
if: steps.version_check.outputs.should_create_release == 'true'
57+
uses: actions/checkout@v4
58+
with:
59+
fetch-depth: 0
60+
61+
- name: Get previous tag
62+
if: steps.version_check.outputs.should_create_release == 'true'
63+
id: previoustag
64+
run: |
65+
# Get all tags sorted by version
66+
git fetch --tags
67+
CURRENT_TAG="${{ github.ref_name }}"
68+
echo "Current tag: $CURRENT_TAG"
69+
70+
# Get the previous tag (excluding the current one)
71+
PREVIOUS_TAG=$(git tag -l --sort=-v:refname | grep -v "^${CURRENT_TAG}$" | head -n 1)
72+
73+
if [ -z "$PREVIOUS_TAG" ]; then
74+
echo "No previous tag found, using first commit"
75+
PREVIOUS_TAG=$(git rev-list --max-parents=0 HEAD)
76+
fi
77+
78+
echo "Previous tag: $PREVIOUS_TAG"
79+
echo "previous_tag=$PREVIOUS_TAG" >> $GITHUB_OUTPUT
80+
81+
- name: Build Changelog
82+
if: steps.version_check.outputs.should_create_release == 'true'
83+
id: build_changelog
84+
run: |
85+
CURRENT_TAG="${{ github.ref_name }}"
86+
PREVIOUS_TAG="${{ steps.previoustag.outputs.previous_tag }}"
87+
88+
echo "Generating changelog from $PREVIOUS_TAG to $CURRENT_TAG"
89+
90+
# Create changelog file
91+
CHANGELOG_FILE=$(mktemp)
92+
93+
# Header
94+
echo "## What's Changed" > $CHANGELOG_FILE
95+
echo "" >> $CHANGELOG_FILE
96+
97+
# Get commits between tags
98+
git log ${PREVIOUS_TAG}..${CURRENT_TAG} --pretty=format:"* %s (%h)" --no-merges >> $CHANGELOG_FILE
99+
100+
echo "" >> $CHANGELOG_FILE
101+
echo "" >> $CHANGELOG_FILE
102+
103+
# Add dependency information from pom.xml if available
104+
if [ -f "pom.xml" ]; then
105+
echo "## Dependencies" >> $CHANGELOG_FILE
106+
echo "" >> $CHANGELOG_FILE
107+
echo "For a complete list of dependencies, see [pom.xml](https://github.com/${{ github.repository }}/blob/${CURRENT_TAG}/pom.xml)" >> $CHANGELOG_FILE
108+
fi
109+
110+
echo "" >> $CHANGELOG_FILE
111+
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${CURRENT_TAG}" >> $CHANGELOG_FILE
112+
113+
# Output the changelog
114+
cat $CHANGELOG_FILE
115+
116+
# Set output for next step
117+
echo "changelog_file=$CHANGELOG_FILE" >> $GITHUB_OUTPUT
118+
119+
- name: Create Release
120+
if: steps.version_check.outputs.should_create_release == 'true'
121+
uses: softprops/action-gh-release@v2
122+
with:
123+
tag_name: ${{ github.ref_name }}
124+
name: Boxable ${{ github.ref_name }}
125+
body_path: ${{ steps.build_changelog.outputs.changelog_file }}
126+
draft: false
127+
prerelease: ${{ contains(github.ref_name, '-') }}
128+
env:
129+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
name: Create Retroactive Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
version:
7+
description: 'Version to create release for (e.g., 1.7.3, 1.8.0, 1.8.1, 1.8.2)'
8+
required: true
9+
type: string
10+
git_ref:
11+
description: 'Git reference (commit SHA, branch, or tag) where the tag should be created. Leave empty to use current master.'
12+
required: false
13+
type: string
14+
default: ''
15+
previous_version:
16+
description: 'Previous version for changelog (e.g., 1.7.0)'
17+
required: true
18+
type: string
19+
default: '1.7.0'
20+
21+
jobs:
22+
create-release:
23+
runs-on: ubuntu-latest
24+
permissions:
25+
contents: write
26+
27+
steps:
28+
- name: Checkout code
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 0
32+
33+
- name: Determine target reference
34+
id: determine_ref
35+
run: |
36+
GIT_REF="${{ github.event.inputs.git_ref }}"
37+
38+
if [ -z "$GIT_REF" ]; then
39+
echo "No git reference provided, using master"
40+
echo "target_ref=master" >> $GITHUB_OUTPUT
41+
echo "ref_type=default" >> $GITHUB_OUTPUT
42+
else
43+
echo "Using provided git reference: $GIT_REF"
44+
45+
# Validate that the reference exists
46+
if git rev-parse "$GIT_REF" >/dev/null 2>&1; then
47+
echo "target_ref=$GIT_REF" >> $GITHUB_OUTPUT
48+
echo "ref_type=custom" >> $GITHUB_OUTPUT
49+
echo "Git reference is valid"
50+
else
51+
echo "Error: Git reference '$GIT_REF' does not exist"
52+
exit 1
53+
fi
54+
fi
55+
56+
- name: Validate version format
57+
run: |
58+
VERSION="${{ github.event.inputs.version }}"
59+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
60+
echo "Error: Version must be in format X.Y.Z (e.g., 1.8.0)"
61+
exit 1
62+
fi
63+
echo "Version format is valid: $VERSION"
64+
65+
- name: Check if tag already exists
66+
id: check_tag
67+
run: |
68+
VERSION="${{ github.event.inputs.version }}"
69+
if git rev-parse "refs/tags/$VERSION" >/dev/null 2>&1; then
70+
echo "Tag $VERSION already exists"
71+
echo "tag_exists=true" >> $GITHUB_OUTPUT
72+
echo "tag_sha=$(git rev-parse refs/tags/$VERSION)" >> $GITHUB_OUTPUT
73+
else
74+
echo "Tag $VERSION does not exist"
75+
echo "tag_exists=false" >> $GITHUB_OUTPUT
76+
fi
77+
78+
- name: Create tag if it doesn't exist
79+
if: steps.check_tag.outputs.tag_exists == 'false'
80+
run: |
81+
VERSION="${{ github.event.inputs.version }}"
82+
TARGET_REF="${{ steps.determine_ref.outputs.target_ref }}"
83+
REF_TYPE="${{ steps.determine_ref.outputs.ref_type }}"
84+
85+
git config user.name "github-actions[bot]"
86+
git config user.email "github-actions[bot]@users.noreply.github.com"
87+
88+
# Get the commit SHA for the target reference
89+
TARGET_SHA=$(git rev-parse "$TARGET_REF")
90+
echo "Creating tag at commit: $TARGET_SHA"
91+
92+
# Create tag at the specified reference
93+
if [ "$REF_TYPE" = "custom" ]; then
94+
git tag -a "$VERSION" "$TARGET_SHA" -m "Release version $VERSION at $TARGET_REF"
95+
echo "Created tag $VERSION at git reference $TARGET_REF (commit: $TARGET_SHA)"
96+
else
97+
git tag -a "$VERSION" "$TARGET_SHA" -m "Release version $VERSION"
98+
echo "Created tag $VERSION at master (commit: $TARGET_SHA)"
99+
fi
100+
101+
git push origin "$VERSION"
102+
echo "Pushed tag $VERSION"
103+
104+
- name: Get tag SHA
105+
id: get_sha
106+
run: |
107+
VERSION="${{ github.event.inputs.version }}"
108+
TAG_SHA=$(git rev-parse refs/tags/$VERSION)
109+
echo "tag_sha=$TAG_SHA" >> $GITHUB_OUTPUT
110+
echo "Tag SHA: $TAG_SHA"
111+
112+
- name: Get previous tag
113+
id: get_previous
114+
run: |
115+
PREVIOUS_VERSION="${{ github.event.inputs.previous_version }}"
116+
117+
# Check if previous version tag exists
118+
if git rev-parse "refs/tags/$PREVIOUS_VERSION" >/dev/null 2>&1; then
119+
echo "previous_tag=$PREVIOUS_VERSION" >> $GITHUB_OUTPUT
120+
echo "Using specified previous version: $PREVIOUS_VERSION"
121+
else
122+
# Try to find the closest previous tag
123+
PREV_TAG=$(git tag -l --sort=-v:refname | grep -v "^${{ github.event.inputs.version }}$" | head -n 1)
124+
if [ -n "$PREV_TAG" ]; then
125+
echo "previous_tag=$PREV_TAG" >> $GITHUB_OUTPUT
126+
echo "Using latest tag as previous: $PREV_TAG"
127+
else
128+
# Use first commit as fallback
129+
FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD)
130+
echo "previous_tag=$FIRST_COMMIT" >> $GITHUB_OUTPUT
131+
echo "No previous tag found, using first commit: $FIRST_COMMIT"
132+
fi
133+
fi
134+
135+
- name: Build Changelog
136+
id: build_changelog
137+
run: |
138+
CURRENT_VERSION="${{ github.event.inputs.version }}"
139+
PREVIOUS_TAG="${{ steps.get_previous.outputs.previous_tag }}"
140+
CURRENT_TAG="${{ github.event.inputs.version }}"
141+
GIT_REF="${{ github.event.inputs.git_ref }}"
142+
REF_TYPE="${{ steps.determine_ref.outputs.ref_type }}"
143+
TAG_SHA="${{ steps.get_sha.outputs.tag_sha }}"
144+
145+
echo "Generating changelog from $PREVIOUS_TAG to $CURRENT_TAG"
146+
147+
# Create changelog file
148+
CHANGELOG_FILE=$(mktemp)
149+
150+
# Header
151+
echo "## What's Changed" > $CHANGELOG_FILE
152+
echo "" >> $CHANGELOG_FILE
153+
154+
# Add note about git reference if custom reference was provided
155+
if [ "$REF_TYPE" = "custom" ]; then
156+
echo "_This release was created at git reference \`$GIT_REF\` (commit: \`${TAG_SHA:0:7}\`)._" >> $CHANGELOG_FILE
157+
echo "" >> $CHANGELOG_FILE
158+
fi
159+
160+
# Get commits between tags/versions
161+
if git rev-parse "refs/tags/$CURRENT_TAG" >/dev/null 2>&1; then
162+
# Tag exists, use it
163+
git log ${PREVIOUS_TAG}..${CURRENT_TAG} --pretty=format:"* %s (%h)" --no-merges >> $CHANGELOG_FILE || echo "* Version released to Maven Central" >> $CHANGELOG_FILE
164+
else
165+
# Tag doesn't exist yet, use HEAD
166+
git log ${PREVIOUS_TAG}..HEAD --pretty=format:"* %s (%h)" --no-merges >> $CHANGELOG_FILE || echo "* Version released to Maven Central" >> $CHANGELOG_FILE
167+
fi
168+
169+
echo "" >> $CHANGELOG_FILE
170+
echo "" >> $CHANGELOG_FILE
171+
172+
# Add note about Maven Central
173+
echo "## Maven Central" >> $CHANGELOG_FILE
174+
echo "" >> $CHANGELOG_FILE
175+
echo "This version is available on Maven Central:" >> $CHANGELOG_FILE
176+
echo "" >> $CHANGELOG_FILE
177+
echo '```xml' >> $CHANGELOG_FILE
178+
echo '<dependency>' >> $CHANGELOG_FILE
179+
echo ' <groupId>com.github.dhorions</groupId>' >> $CHANGELOG_FILE
180+
echo ' <artifactId>boxable</artifactId>' >> $CHANGELOG_FILE
181+
echo " <version>${CURRENT_VERSION}</version>" >> $CHANGELOG_FILE
182+
echo '</dependency>' >> $CHANGELOG_FILE
183+
echo '```' >> $CHANGELOG_FILE
184+
185+
echo "" >> $CHANGELOG_FILE
186+
echo "" >> $CHANGELOG_FILE
187+
188+
# Add dependency information
189+
echo "## Dependencies" >> $CHANGELOG_FILE
190+
echo "" >> $CHANGELOG_FILE
191+
echo "For a complete list of dependencies, see [pom.xml](https://github.com/${{ github.repository }}/blob/${CURRENT_TAG}/pom.xml)" >> $CHANGELOG_FILE
192+
193+
echo "" >> $CHANGELOG_FILE
194+
echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${PREVIOUS_TAG}...${CURRENT_TAG}" >> $CHANGELOG_FILE
195+
196+
# Output the changelog
197+
cat $CHANGELOG_FILE
198+
199+
# Set output for next step
200+
echo "changelog_file=$CHANGELOG_FILE" >> $GITHUB_OUTPUT
201+
202+
- name: Check if release already exists
203+
id: check_release
204+
run: |
205+
VERSION="${{ github.event.inputs.version }}"
206+
if gh release view "$VERSION" > /dev/null 2>&1; then
207+
echo "Release $VERSION already exists"
208+
echo "release_exists=true" >> $GITHUB_OUTPUT
209+
else
210+
echo "Release $VERSION does not exist"
211+
echo "release_exists=false" >> $GITHUB_OUTPUT
212+
fi
213+
env:
214+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
215+
216+
- name: Create Release
217+
if: steps.check_release.outputs.release_exists == 'false'
218+
uses: softprops/action-gh-release@v2
219+
with:
220+
tag_name: ${{ github.event.inputs.version }}
221+
name: Boxable ${{ github.event.inputs.version }}
222+
body_path: ${{ steps.build_changelog.outputs.changelog_file }}
223+
draft: false
224+
prerelease: false
225+
env:
226+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
227+
228+
- name: Update existing release
229+
if: steps.check_release.outputs.release_exists == 'true'
230+
run: |
231+
VERSION="${{ github.event.inputs.version }}"
232+
CHANGELOG_FILE="${{ steps.build_changelog.outputs.changelog_file }}"
233+
234+
echo "Updating existing release $VERSION with new release notes"
235+
gh release edit "$VERSION" --notes-file "$CHANGELOG_FILE"
236+
env:
237+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Boxable is a library that can be used to easily create tables in PDF documents.
3030
```
3131
For other build systems, check the [Maven Central Repository](http://search.maven.org/#search%7Cga%7C1%7Ca%3A%22boxable%22).
3232

33+
For information about the release process, see [RELEASE.md](RELEASE.md).
3334

3435
# Tutorial
3536

0 commit comments

Comments
 (0)