Skip to content

Commit c60db22

Browse files
committed
Create GitHub Action to publish new release
How to trigger a manual workflow: https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manually-run-a-workflow
1 parent 238e877 commit c60db22

File tree

4 files changed

+319
-0
lines changed

4 files changed

+319
-0
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/bin/bash
2+
3+
# Script to calculate new version based on current version and release type
4+
# Usage: calculate_version.sh <current_version> <release_type>
5+
6+
set -e
7+
8+
if [ $# -ne 2 ]; then
9+
echo "Usage: $0 <current_version> <release_type>"
10+
echo "Example: $0 1.2.3 minor"
11+
echo "Release types: major, minor, patch"
12+
exit 1
13+
fi
14+
15+
CURRENT_VERSION="$1"
16+
RELEASE_TYPE="$2"
17+
18+
echo "Calculating new version from $CURRENT_VERSION using $RELEASE_TYPE bump"
19+
20+
# Validate release type
21+
case $RELEASE_TYPE in
22+
"major"|"minor"|"patch")
23+
;;
24+
*)
25+
echo "Error: Invalid release type '$RELEASE_TYPE'. Must be major, minor, or patch."
26+
exit 1
27+
;;
28+
esac
29+
30+
# Parse current version
31+
IFS='.' read -r major minor patch <<< "$CURRENT_VERSION"
32+
33+
# Validate version components are numbers
34+
if ! [[ "$major" =~ ^[0-9]+$ ]] || ! [[ "$minor" =~ ^[0-9]+$ ]] || ! [[ "$patch" =~ ^[0-9]+$ ]]; then
35+
echo "Error: Invalid version format '$CURRENT_VERSION'. Expected format: x.y.z"
36+
exit 1
37+
fi
38+
39+
# Increment based on release type
40+
case $RELEASE_TYPE in
41+
"major")
42+
major=$((major + 1))
43+
minor=0
44+
patch=0
45+
;;
46+
"minor")
47+
minor=$((minor + 1))
48+
patch=0
49+
;;
50+
"patch")
51+
patch=$((patch + 1))
52+
;;
53+
esac
54+
55+
NEW_VERSION="$major.$minor.$patch"
56+
echo "New version: $NEW_VERSION"
57+
58+
# Output for GitHub Actions
59+
if [ -n "$GITHUB_OUTPUT" ]; then
60+
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
61+
fi
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#!/bin/bash
2+
3+
# Script to update CHANGELOG.md with commits since the last tag
4+
# Filters out dependabot commits, merge commits, and version bump commits
5+
# Usage: update_changelog.sh <new_version> <current_version>
6+
7+
set -euo pipefail
8+
9+
# Colors for output
10+
RED='\033[0;31m'
11+
GREEN='\033[0;32m'
12+
YELLOW='\033[1;33m'
13+
NC='\033[0m' # No Color
14+
15+
# Check arguments
16+
if [[ $# -ne 2 ]]; then
17+
echo -e "${RED}Error: Please provide both new version and current version as arguments${NC}"
18+
echo "Usage: $0 <new_version> <current_version>"
19+
echo "Example: $0 1.2.0 1.1.0"
20+
exit 1
21+
fi
22+
23+
NEW_VERSION="$1"
24+
CURRENT_VERSION="$2"
25+
26+
echo -e "${GREEN}Updating changelog from v$CURRENT_VERSION to v$NEW_VERSION${NC}"
27+
28+
# Get commits since the current version tag, excluding merges
29+
COMMITS=$(git log --oneline --no-merges "v${CURRENT_VERSION}..HEAD" --pretty=format:"%s")
30+
31+
if [[ -z "$COMMITS" ]]; then
32+
echo -e "${YELLOW}No new commits since v$CURRENT_VERSION${NC}"
33+
exit 0
34+
fi
35+
36+
echo -e "${GREEN}Found commits since v$CURRENT_VERSION${NC}"
37+
38+
# Filter out unwanted commits
39+
FILTERED_COMMITS=""
40+
while IFS= read -r commit; do
41+
# Skip empty lines
42+
[[ -z "$commit" ]] && continue
43+
44+
# Skip dependabot commits (format: "Bump .. from x to y")
45+
if [[ "$commit" =~ ^Bump[[:space:]].+[[:space:]]from[[:space:]].+[[:space:]]to[[:space:]].+ ]]; then
46+
echo -e "${YELLOW}Skipping dependabot commit: $commit${NC}"
47+
continue
48+
fi
49+
50+
# Skip version bump commits (format: "bump version to <version>" - case insensitive)
51+
if [[ "$commit" =~ ^[Bb]ump[[:space:]]version[[:space:]]to[[:space:]].+ ]]; then
52+
echo -e "${YELLOW}Skipping version bump commit: $commit${NC}"
53+
continue
54+
fi
55+
56+
# Add to filtered commits
57+
if [[ -z "$FILTERED_COMMITS" ]]; then
58+
FILTERED_COMMITS="* $commit"
59+
else
60+
FILTERED_COMMITS="$FILTERED_COMMITS"$'\n'"* $commit"
61+
fi
62+
done <<< "$COMMITS"
63+
64+
if [[ -z "$FILTERED_COMMITS" ]]; then
65+
echo -e "${YELLOW}No valid commits to add to changelog after filtering${NC}"
66+
exit 0
67+
fi
68+
69+
echo -e "${GREEN}Creating changelog entry for version $NEW_VERSION${NC}"
70+
71+
# Create temporary file with new changelog content
72+
TEMP_FILE=$(mktemp)
73+
74+
# Add new version header and commits
75+
echo "# v$NEW_VERSION" > "$TEMP_FILE"
76+
echo "" >> "$TEMP_FILE"
77+
printf "%s\n" "$FILTERED_COMMITS" >> "$TEMP_FILE"
78+
echo "" >> "$TEMP_FILE"
79+
80+
# Append existing changelog content
81+
cat CHANGELOG.md >> "$TEMP_FILE"
82+
83+
# Replace the original file
84+
mv "$TEMP_FILE" CHANGELOG.md
85+
86+
echo -e "${GREEN}Successfully updated CHANGELOG.md with $NEW_VERSION${NC}"
87+
echo -e "${GREEN}Added the following commits:${NC}"
88+
echo "$FILTERED_COMMITS"

.github/workflows/release.yml

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
---
2+
3+
name: Release
4+
5+
on:
6+
workflow_dispatch:
7+
inputs:
8+
release_type:
9+
description: "Type of release"
10+
required: true
11+
default: "patch"
12+
type: choice
13+
options:
14+
- major
15+
- minor
16+
- patch
17+
18+
jobs:
19+
test:
20+
name: Run tests
21+
uses: ./.github/workflows/test.yml
22+
23+
read-version:
24+
name: Read current version and calculate new version
25+
runs-on: ubuntu-latest
26+
outputs:
27+
current_version: ${{ steps.current_version.outputs.version }}
28+
new_version: ${{ steps.new_version.outputs.version }}
29+
steps:
30+
-
31+
name: Checkout
32+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
33+
-
34+
name: Set up Ruby
35+
uses: ruby/[email protected]
36+
with:
37+
ruby-version: "3.4"
38+
bundler-cache: true
39+
-
40+
name: Read current version
41+
id: current_version
42+
run: |
43+
current_version=$(ruby -e "require './lib/semian/version'; puts Semian::VERSION")
44+
echo "version=$current_version" >> $GITHUB_OUTPUT
45+
echo "Current version: $current_version"
46+
-
47+
name: Calculate new version
48+
id: new_version
49+
run: |
50+
chmod +x .github/scripts/calculate_version.sh
51+
.github/scripts/calculate_version.sh \
52+
"${{ steps.current_version.outputs.version }}" \
53+
"${{ github.event.inputs.release_type }}"
54+
55+
update-version:
56+
name: Update version file and create tag
57+
runs-on: ubuntu-latest
58+
needs: [test, read-version]
59+
permissions:
60+
contents: write
61+
env:
62+
BUNDLE_FROZEN: false
63+
steps:
64+
-
65+
name: Checkout
66+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
67+
with:
68+
fetch-depth: 30
69+
fetch-tags: true
70+
-
71+
name: Set up Ruby
72+
uses: ruby/[email protected]
73+
with:
74+
ruby-version: "3.4"
75+
bundler-cache: true
76+
-
77+
name: Update version file
78+
run: |
79+
new_version="${{ needs.read-version.outputs.new_version }}"
80+
sed -i "s/VERSION = \".*\"/VERSION = \"$new_version\"/" lib/semian/version.rb
81+
echo "Updated version file:"
82+
cat lib/semian/version.rb
83+
-
84+
name: Update Gemfile.lock
85+
run: |
86+
# Update Gemfile.lock with new version
87+
bundle install
88+
-
89+
name: Update CHANGELOG
90+
run: |
91+
chmod +x .github/scripts/update_changelog.sh
92+
.github/scripts/update_changelog.sh \
93+
"${{ needs.read-version.outputs.new_version }}" \
94+
"${{ needs.read-version.outputs.current_version }}"
95+
-
96+
name: Commit and tag version
97+
run: |
98+
new_version="${{ needs.read-version.outputs.new_version }}"
99+
git config --local user.email "[email protected]"
100+
git config --local user.name "GitHub Action"
101+
git add lib/semian/version.rb Gemfile.lock CHANGELOG.md
102+
git commit -m "Bump version to $new_version" -m "Triggered by @${{ github.actor }}"
103+
git tag "v$new_version"
104+
git push origin main
105+
git push origin "v$new_version"
106+
107+
build-and-release:
108+
name: Build gem and create GitHub release
109+
runs-on: ubuntu-latest
110+
needs: [update-version, read-version]
111+
permissions:
112+
contents: write
113+
steps:
114+
-
115+
name: Checkout
116+
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
117+
with:
118+
# Uses main branch to get the updated version after the commit
119+
ref: main
120+
-
121+
name: Set up Ruby
122+
uses: ruby/[email protected]
123+
with:
124+
ruby-version: "3.4"
125+
bundler-cache: true
126+
-
127+
name: Build C extension
128+
run: bundle exec rake build
129+
-
130+
name: Build gem
131+
run: |
132+
gem build semian.gemspec
133+
-
134+
name: Generate SHA512 checksum
135+
run: |
136+
for gem in semian-*.gem; do
137+
sha512sum "$gem" > "${gem}.sha512"
138+
done
139+
-
140+
name: Draft GitHub release
141+
env:
142+
GH_TOKEN: ${{ github.token }}
143+
run: |
144+
tag="v${{ needs.read-version.outputs.new_version }}"
145+
gh release create "$tag" \
146+
--title "$tag" \
147+
--generate-notes \
148+
--draft \
149+
semian-*.gem \
150+
semian-*.gem.sha512
151+
-
152+
name: Filter dependabot commits
153+
env:
154+
GH_TOKEN: ${{ github.token }}
155+
run: |
156+
tag="v${{ needs.read-version.outputs.new_version }}"
157+
gh release view "$tag" --json body -q '.body' > temp_notes.md
158+
grep -v -i "bump.*by.*dependabot" temp_notes.md > filtered_notes.md || true
159+
-
160+
name: Publish release
161+
env:
162+
GH_TOKEN: ${{ github.token }}
163+
run: |
164+
tag="v${{ needs.read-version.outputs.new_version }}"
165+
gh release edit "$tag" \
166+
--notes-file filtered_notes.md \
167+
--draft=false
168+
169+

.github/workflows/test.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
branches: [ main ]
88
pull_request:
99
branches: [ main ]
10+
workflow_call:
1011

1112
concurrency:
1213
group: ${{ github.ref }}-test

0 commit comments

Comments
 (0)