Skip to content

Commit 149bc9a

Browse files
committed
feat: add automated GitHub release workflow
- Create .github/workflows/release.yml for automated releases - Triggers on tag push (v*) to build, test, and create GitHub release - Extracts release notes from CHANGELOG.md automatically - Uploads built packages as release assets - Triggers PyPI publishing via existing publish.yml workflow - Update release:tag task with workflow information - Add comprehensive release process documentation - Add releasing.md to MkDocs navigation Benefits: - No manual GitHub release creation needed - Uses GitHub-built assets (not local builds) - Automated PyPI publishing - Consistent, reproducible releases - Full test suite runs before release
1 parent c2542e9 commit 149bc9a

5 files changed

Lines changed: 313 additions & 3 deletions

File tree

.github/workflows/release.yml

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
name: Create Release
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*'
7+
8+
jobs:
9+
create-release:
10+
name: Create GitHub Release
11+
runs-on: ubuntu-latest
12+
permissions:
13+
contents: write
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0 # Fetch all history for changelog extraction
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v5
23+
with:
24+
python-version: '3.13'
25+
26+
- name: Install uv
27+
uses: astral-sh/setup-uv@v5
28+
with:
29+
enable-cache: true
30+
31+
- name: Install dependencies
32+
run: uv sync --all-extras
33+
34+
- name: Run tests
35+
run: uv run pytest --timeout 30
36+
37+
- name: Build package
38+
run: uv build
39+
40+
- name: Extract version from tag
41+
id: get_version
42+
run: |
43+
VERSION=${GITHUB_REF#refs/tags/v}
44+
echo "version=$VERSION" >> $GITHUB_OUTPUT
45+
echo "Version: $VERSION"
46+
47+
- name: Extract release notes from CHANGELOG
48+
id: changelog
49+
run: |
50+
VERSION=${{ steps.get_version.outputs.version }}
51+
52+
# Extract the section for this version from CHANGELOG.md
53+
# Look for ## [VERSION] and capture until the next ## [ or end of file
54+
NOTES=$(awk "/## \[$VERSION\]/,/^## \[/ {
55+
if (/^## \[/ && !/\[$VERSION\]/) exit;
56+
if (!/^## \[$VERSION\]/) print
57+
}" CHANGELOG.md)
58+
59+
if [ -z "$NOTES" ]; then
60+
echo "⚠️ No release notes found for version $VERSION in CHANGELOG.md"
61+
NOTES="Release v$VERSION"
62+
fi
63+
64+
# Save to file to handle multiline content
65+
echo "$NOTES" > release_notes.md
66+
echo "Release notes extracted for v$VERSION"
67+
68+
- name: Create GitHub Release
69+
uses: softprops/action-gh-release@v2
70+
with:
71+
name: Release v${{ steps.get_version.outputs.version }}
72+
body_path: release_notes.md
73+
files: dist/*
74+
draft: false
75+
prerelease: false
76+
generate_release_notes: true # Adds auto-generated notes from commits
77+
env:
78+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [Unreleased]
99

1010
### Added
11+
- add automated GitHub release workflow (04fbcee)
1112

1213
### Changed
1314

docs/development/releasing.md

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# Release Process
2+
3+
This document describes the automated release process for taskfile-help.
4+
5+
## Overview
6+
7+
The release process is highly automated using GitHub Actions. When you push a version tag, GitHub Actions automatically:
8+
9+
1. Builds the package
10+
2. Runs the full test suite
11+
3. Creates a GitHub release with built assets
12+
4. Publishes the package to PyPI
13+
14+
## Release Workflow
15+
16+
### 1. Prepare the Release
17+
18+
First, bump the version and prepare the release:
19+
20+
```bash
21+
# Bump version (patch, minor, or major)
22+
task version:bump minor
23+
24+
# Prepare release (runs tests, updates CHANGELOG, commits changes)
25+
task release:build
26+
```
27+
28+
The `release:build` task will:
29+
30+
- Verify working directory is clean
31+
- Check version has been bumped
32+
- Validate CHANGELOG has unreleased changes
33+
- Run full test suite
34+
- Update CHANGELOG with version and date
35+
- Commit release preparation
36+
- Build distribution packages
37+
- Show next steps
38+
39+
### 2. Create and Push the Tag
40+
41+
```bash
42+
task release:tag
43+
```
44+
45+
This creates a git tag for the current version and pushes it to GitHub, which triggers the automated release workflow.
46+
47+
### 3. Monitor the Automated Release
48+
49+
After pushing the tag, GitHub Actions automatically:
50+
51+
1. **Builds the package** - Creates wheel and source distribution
52+
2. **Runs tests** - Ensures everything passes
53+
3. **Creates GitHub Release** - With release notes from CHANGELOG
54+
4. **Uploads assets** - Attaches built packages to the release
55+
5. **Publishes to PyPI** - Makes the package available via `pip install`
56+
57+
Monitor progress at: [GitHub Actions](https://github.com/royw/taskfile_help/actions)
58+
59+
## GitHub Actions Workflows
60+
61+
### Release Workflow (`.github/workflows/release.yml`)
62+
63+
Triggers on: Tag push (`v*`)
64+
65+
Steps:
66+
67+
- Checkout code with full history
68+
- Set up Python 3.13
69+
- Install dependencies with uv
70+
- Run test suite
71+
- Build package
72+
- Extract version from tag
73+
- Extract release notes from CHANGELOG
74+
- Create GitHub release with assets
75+
- Trigger PyPI publish workflow
76+
77+
### Publish Workflow (`.github/workflows/publish.yml`)
78+
79+
Triggers on: GitHub release published
80+
81+
Steps:
82+
83+
- Build distribution packages
84+
- Publish to PyPI using trusted publishing
85+
86+
## Manual Steps (If Needed)
87+
88+
### Manual PyPI Upload
89+
90+
If automatic PyPI publishing fails, you can manually upload:
91+
92+
```bash
93+
# Upload to Test PyPI first
94+
task release:pypi-test
95+
96+
# Then upload to production PyPI
97+
task release:pypi
98+
```
99+
100+
### Manual GitHub Release
101+
102+
If you need to create a release manually:
103+
104+
1. Go to [GitHub Releases](https://github.com/royw/taskfile_help/releases)
105+
2. Click "Draft a new release"
106+
3. Choose the tag
107+
4. Copy release notes from CHANGELOG.md
108+
5. Upload files from `dist/` directory
109+
6. Publish release
110+
111+
## Version Numbering
112+
113+
This project follows [Semantic Versioning](https://semver.org/):
114+
115+
- **MAJOR** version for incompatible API changes
116+
- **MINOR** version for new functionality (backwards compatible)
117+
- **PATCH** version for bug fixes (backwards compatible)
118+
119+
Use the version bump tasks:
120+
121+
```bash
122+
task version:bump patch # 0.3.0 -> 0.3.1
123+
task version:bump minor # 0.3.0 -> 0.4.0
124+
task version:bump major # 0.3.0 -> 1.0.0
125+
```
126+
127+
## CHANGELOG Management
128+
129+
The CHANGELOG follows [Keep a Changelog](https://keepachangelog.com/) format.
130+
131+
### During Development
132+
133+
Changes are automatically added to the `[Unreleased]` section by the post-commit hook based on conventional commit types:
134+
135+
- `feat:` → Added section
136+
- `fix:` → Fixed section
137+
- `docs:` → Changed section
138+
- `refactor:` → Changed section
139+
- `perf:` → Changed section
140+
141+
### During Release
142+
143+
The `release:build` task automatically:
144+
145+
1. Moves `[Unreleased]` content to a new version section
146+
2. Adds the version number and date
147+
3. Creates a new empty `[Unreleased]` section for future changes
148+
149+
## Troubleshooting
150+
151+
### Release Build Fails
152+
153+
If `task release:build` fails:
154+
155+
- **Uncommitted changes**: Commit or stash changes first
156+
- **Version not bumped**: Run `task version:bump`
157+
- **Empty CHANGELOG**: Make commits with conventional commit types
158+
- **Tests failing**: Fix tests before releasing
159+
160+
### GitHub Actions Fails
161+
162+
If the GitHub Actions workflow fails:
163+
164+
1. Check the [Actions tab](https://github.com/royw/taskfile_help/actions)
165+
2. Review the failed step logs
166+
3. Fix the issue locally
167+
4. Delete the tag: `git tag -d v0.3.1 && git push origin :refs/tags/v0.3.1`
168+
5. Re-run the release process
169+
170+
### PyPI Publishing Fails
171+
172+
If PyPI publishing fails:
173+
174+
1. Check PyPI trusted publishing is configured
175+
2. Verify the package version doesn't already exist on PyPI
176+
3. Use manual upload: `task release:pypi`
177+
178+
## Security
179+
180+
### PyPI Trusted Publishing
181+
182+
This project uses [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishers/) for secure, token-free publishing:
183+
184+
- No API tokens stored in GitHub secrets
185+
- GitHub Actions authenticates directly with PyPI
186+
- Configured in PyPI project settings
187+
188+
### GitHub Permissions
189+
190+
The release workflow requires:
191+
192+
- `contents: write` - To create releases and upload assets
193+
- `id-token: write` - For PyPI trusted publishing
194+
195+
## Best Practices
196+
197+
1. **Always run tests** before releasing (`task make`)
198+
2. **Review CHANGELOG** before releasing
199+
3. **Use semantic versioning** appropriately
200+
4. **Monitor GitHub Actions** after pushing tags
201+
5. **Test in staging** when possible (Test PyPI)
202+
6. **Keep CHANGELOG updated** with meaningful commit messages
203+
204+
## Quick Reference
205+
206+
```bash
207+
# Complete release process
208+
task version:bump minor # Bump version
209+
task release:build # Prepare release
210+
task release:tag # Create tag (triggers automation)
211+
212+
# Monitor
213+
# Visit: https://github.com/royw/taskfile_help/actions
214+
215+
# Manual fallback (if needed)
216+
task release:pypi-test # Test PyPI upload
217+
task release:pypi # Production PyPI upload
218+
```

mkdocs.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ nav:
145145
- Git Hooks: githooks.md
146146
- Testing: development/testing.md
147147
- Test Documentation: tests.md
148+
- Release Process: development/releasing.md
148149
- Contributing: development/contributing.md
149150
- Reference: reference/
150151

taskfiles/Taskfile-release.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,16 +91,28 @@ tasks:
9191

9292
tag:
9393
desc: Create and push a git tag for the current version
94-
summary: Tags the current version and pushes to origin
95-
deps:
96-
- task: :version:current
94+
summary: |
95+
Creates a git tag and pushes it to origin.
96+
This triggers GitHub Actions to:
97+
- Build the package
98+
- Run tests
99+
- Create a GitHub release with assets
100+
- Publish to PyPI automatically
97101
cmds:
98102
- |
99103
VERSION=$(task version:pyproject)
100104
echo "Creating tag v$VERSION..."
101105
git tag "v$VERSION"
102106
git push origin "v$VERSION"
103107
echo "✅ Tag v$VERSION created and pushed to origin!"
108+
echo ""
109+
echo "🤖 GitHub Actions will now:"
110+
echo " 1. Build the package"
111+
echo " 2. Run tests"
112+
echo " 3. Create GitHub release with assets"
113+
echo " 4. Publish to PyPI"
114+
echo ""
115+
echo "📊 Monitor progress at: https://github.com/royw/taskfile_help/actions"
104116
105117
pypi-test:
106118
desc: Test PyPI upload

0 commit comments

Comments
 (0)