1+ name : Release
2+
3+ on :
4+ push :
5+ tags :
6+ - ' v*'
7+ workflow_dispatch :
8+ inputs :
9+ version :
10+ description : ' Version to release (e.g., v0.3.1)'
11+ required : true
12+ type : string
13+
14+ permissions :
15+ contents : write
16+ id-token : write
17+
18+ jobs :
19+ build-and-publish :
20+ runs-on : ubuntu-latest
21+
22+ steps :
23+ - uses : actions/checkout@v4
24+ with :
25+ fetch-depth : 0
26+
27+ - name : Set up Python
28+ uses : actions/setup-python@v5
29+ with :
30+ python-version : ' 3.11'
31+
32+ - name : Install build dependencies
33+ run : |
34+ python -m pip install --upgrade pip
35+ pip install build hatch
36+
37+ - name : Verify version matches tag
38+ run : |
39+ if [[ "${{ github.event_name }}" == "push" ]]; then
40+ TAG_VERSION="${GITHUB_REF#refs/tags/v}"
41+ else
42+ TAG_VERSION="${{ github.event.inputs.version }}"
43+ TAG_VERSION="${TAG_VERSION#v}"
44+ fi
45+
46+ PACKAGE_VERSION=$(python -c "import kicad_lib_manager; print(kicad_lib_manager.__version__)")
47+
48+ if [[ "$TAG_VERSION" != "$PACKAGE_VERSION" ]]; then
49+ echo "Version mismatch: tag=$TAG_VERSION, package=$PACKAGE_VERSION"
50+ exit 1
51+ fi
52+
53+ echo "VERSION=$TAG_VERSION" >> $GITHUB_ENV
54+
55+ - name : Run tests
56+ run : |
57+ pip install -e .[dev]
58+ ruff check .
59+ ruff format --check .
60+ pyrefly
61+ pytest
62+
63+ - name : Build package
64+ run : |
65+ python -m build
66+
67+ - name : Check package
68+ run : |
69+ pip install twine
70+ twine check dist/*
71+
72+ - name : Generate release notes
73+ id : release_notes
74+ env :
75+ GH_TOKEN : ${{ github.token }}
76+ run : |
77+ # Get the previous release tag
78+ PREVIOUS_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")
79+
80+ if [ -z "$PREVIOUS_TAG" ]; then
81+ # First release, get all commits
82+ COMMITS=$(git log --oneline --no-merges)
83+ else
84+ # Get commits since last release
85+ COMMITS=$(git log --oneline --no-merges ${PREVIOUS_TAG}..HEAD)
86+ fi
87+
88+ # Get PR information
89+ PRS=$(gh pr list --state merged --search "merged:>${PREVIOUS_TAG:-1970-01-01}" --json number,title,url --jq '.[] | "- #\(.number): \(.title) (\(.url))"' 2>/dev/null || echo "")
90+
91+ # Generate release notes
92+ cat > release_notes.md << EOF
93+ ## What's Changed in v${VERSION}
94+
95+ ### Commits
96+ $(echo "$COMMITS" | sed 's/^/- /')
97+
98+ EOF
99+
100+ if [ ! -z "$PRS" ]; then
101+ cat >> release_notes.md << EOF
102+
103+ ### Pull Requests
104+ $(echo "$PRS")
105+
106+ EOF
107+ fi
108+
109+ cat >> release_notes.md << 'EOF'
110+
111+ ### Installation
112+
113+ **Using pipx (recommended for CLI tools):**
114+ ```bash
115+ pipx install kilm
116+ ```
117+
118+ **Using pip:**
119+ ```bash
120+ pip install kilm
121+ ```
122+
123+ **From release assets:**
124+ 1. Download the wheel file from this release
125+ 2. Install with pipx or pip:
126+ ```bash
127+ pipx install kilm-${VERSION}-py3-none-any.whl
128+ # or
129+ pip install kilm-${VERSION}-py3-none-any.whl
130+ ```
131+
132+ ### Auto-Update (Coming Soon)
133+ Future versions will include `kilm update` functionality for easy updates.
134+ EOF
135+
136+ # Store release notes for next step
137+ echo "release_notes<<EOF" >> $GITHUB_OUTPUT
138+ cat release_notes.md >> $GITHUB_OUTPUT
139+ echo "EOF" >> $GITHUB_OUTPUT
140+
141+ - name : Create GitHub Release
142+ uses : softprops/action-gh-release@v2
143+ with :
144+ tag_name : ${{ github.event_name == 'push' && github.ref_name || format('v{0}', github.event.inputs.version) }}
145+ name : Release ${{ github.event_name == 'push' && github.ref_name || format('v{0}', github.event.inputs.version) }}
146+ body : ${{ steps.release_notes.outputs.release_notes }}
147+ draft : true
148+ prerelease : false
149+ files : |
150+ dist/*.whl
151+ dist/*.tar.gz
152+
153+ - name : Publish to PyPI
154+ uses : pypa/gh-action-pypi-publish@release/v1
155+ with :
156+ print-hash : true
157+ verbose : true
0 commit comments