Skip to content

Commit 8b02b4c

Browse files
authored
Merge pull request #92 from DataFog/feature/automated-release-pipeline
feat(ci): implement automated alpha→beta→stable release pipeline
2 parents 970408d + 7f734ae commit 8b02b4c

File tree

7 files changed

+561
-37
lines changed

7 files changed

+561
-37
lines changed

.bumpversion.cfg

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,18 @@ commit = True
44
tag = True
55
tag_name = v{new_version}
66
message = Bump version: {current_version} → {new_version}
7+
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)((?P<pre_label>a|b)(?P<pre_number>\d+))?
8+
serialize =
9+
{major}.{minor}.{patch}{pre_label}{pre_number}
10+
{major}.{minor}.{patch}
11+
12+
[bumpversion:part:pre_label]
13+
values =
14+
release
15+
a
16+
b
17+
18+
[bumpversion:part:pre_number]
719

820
[bumpversion:file:datafog/__about__.py]
921
search = __version__ = "{current_version}"

.github/workflows/beta-release.yml

Lines changed: 238 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,238 @@
1+
name: Beta Release (Thursday)
2+
3+
on:
4+
schedule:
5+
# Thursday at 2 AM UTC - consolidate week's alpha changes into beta
6+
- cron: '0 2 * * 4'
7+
workflow_dispatch:
8+
inputs:
9+
dry_run:
10+
description: 'Dry run (skip PyPI publish)'
11+
required: false
12+
default: 'false'
13+
type: boolean
14+
force_build:
15+
description: 'Force build even if no changes'
16+
required: false
17+
default: 'false'
18+
type: boolean
19+
20+
jobs:
21+
check-changes:
22+
runs-on: ubuntu-latest
23+
outputs:
24+
has_changes: ${{ steps.changes.outputs.has_changes }}
25+
commit_count: ${{ steps.changes.outputs.commit_count }}
26+
last_beta: ${{ steps.changes.outputs.last_beta }}
27+
steps:
28+
- uses: actions/checkout@v4
29+
with:
30+
fetch-depth: 0
31+
ref: dev
32+
33+
- name: Check for changes since last beta release
34+
id: changes
35+
run: |
36+
# Get last beta release tag
37+
LAST_BETA=$(git tag -l "*b*" --sort=-version:refname | head -n1)
38+
39+
if [ -z "$LAST_BETA" ]; then
40+
echo "No previous beta release found, checking last week"
41+
SINCE="1 week ago"
42+
COMMIT_COUNT=$(git rev-list --count --since="$SINCE" dev)
43+
else
44+
echo "Last beta release: $LAST_BETA"
45+
COMMIT_COUNT=$(git rev-list --count ${LAST_BETA}..dev)
46+
fi
47+
48+
echo "Commits since last beta: $COMMIT_COUNT"
49+
echo "commit_count=$COMMIT_COUNT" >> $GITHUB_OUTPUT
50+
echo "last_beta=$LAST_BETA" >> $GITHUB_OUTPUT
51+
52+
if [ "$COMMIT_COUNT" -gt 0 ] || [ "${{ github.event.inputs.force_build }}" = "true" ]; then
53+
echo "has_changes=true" >> $GITHUB_OUTPUT
54+
echo "✅ Changes detected, proceeding with beta build"
55+
else
56+
echo "has_changes=false" >> $GITHUB_OUTPUT
57+
echo "ℹ️ No changes since last beta, skipping build"
58+
fi
59+
60+
beta-release:
61+
needs: check-changes
62+
if: needs.check-changes.outputs.has_changes == 'true'
63+
runs-on: ubuntu-latest
64+
outputs:
65+
beta_version: ${{ steps.version.outputs.beta_version }}
66+
steps:
67+
- uses: actions/checkout@v4
68+
with:
69+
fetch-depth: 0
70+
ref: dev
71+
token: ${{ secrets.GITHUB_TOKEN }}
72+
73+
- name: Set up Python
74+
uses: actions/setup-python@v5
75+
with:
76+
python-version: '3.11'
77+
78+
- name: Install dependencies
79+
run: |
80+
python -m pip install --upgrade pip
81+
pip install bump2version build twine
82+
pip install -e ".[dev]"
83+
84+
- name: Configure git
85+
run: |
86+
git config --local user.email "action@github.com"
87+
git config --local user.name "GitHub Action"
88+
89+
- name: Generate beta version
90+
id: version
91+
run: |
92+
# Get current version
93+
CURRENT_VERSION=$(python -c "from datafog.__about__ import __version__; print(__version__)")
94+
echo "Current version: $CURRENT_VERSION"
95+
96+
# Generate beta version
97+
if [[ $CURRENT_VERSION == *"b"* ]]; then
98+
# If already beta, increment beta number
99+
BASE_VERSION=$(echo $CURRENT_VERSION | cut -d'b' -f1)
100+
BETA_NUM=$(echo $CURRENT_VERSION | cut -d'b' -f2)
101+
BETA_VERSION="${BASE_VERSION}b$((BETA_NUM + 1))"
102+
elif [[ $CURRENT_VERSION == *"a"* ]]; then
103+
# If alpha, convert to beta
104+
BASE_VERSION=$(echo $CURRENT_VERSION | cut -d'a' -f1)
105+
BETA_VERSION="${BASE_VERSION}b1"
106+
else
107+
# If stable, bump minor and add beta (4.1.1 -> 4.2.0)
108+
BASE_VERSION=$(python -c "import re; version = '$CURRENT_VERSION'; parts = version.split('.'); parts[1] = str(int(parts[1]) + 1); parts[2] = '0'; print('.'.join(parts))")
109+
BETA_VERSION="${BASE_VERSION}b1"
110+
fi
111+
112+
echo "Beta version: $BETA_VERSION"
113+
echo "beta_version=$BETA_VERSION" >> $GITHUB_OUTPUT
114+
115+
# Update version in files
116+
sed -i "s/__version__ = \".*\"/__version__ = \"$BETA_VERSION\"/" datafog/__about__.py
117+
sed -i "s/version=\".*\"/version=\"$BETA_VERSION\"/" setup.py
118+
119+
- name: Generate changelog for beta
120+
run: |
121+
python scripts/generate_changelog.py --beta --output BETA_CHANGELOG.md
122+
123+
- name: Run comprehensive tests
124+
run: |
125+
echo "🧪 Running comprehensive test suite for beta release..."
126+
127+
# Run core tests
128+
python -m pytest tests/ -v --tb=short
129+
130+
# Run integration tests
131+
python -m pytest -m integration -v
132+
133+
# Run benchmarks to ensure performance
134+
python -m pytest tests/benchmark_text_service.py -v
135+
136+
echo "✅ All tests passed for beta release"
137+
138+
- name: Build package
139+
run: |
140+
python -m build
141+
142+
# Verify wheel size
143+
python scripts/check_wheel_size.py
144+
145+
echo "📦 Beta package built successfully"
146+
147+
- name: Create beta release
148+
env:
149+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
150+
run: |
151+
BETA_VERSION="${{ steps.version.outputs.beta_version }}"
152+
153+
# Create and push tag
154+
git add datafog/__about__.py setup.py
155+
git commit -m "chore: bump version to $BETA_VERSION for beta release"
156+
git tag -a "v$BETA_VERSION" -m "Beta release $BETA_VERSION"
157+
git push origin "v$BETA_VERSION"
158+
159+
# Create GitHub release
160+
gh release create "v$BETA_VERSION" \
161+
--title "🚧 Beta Release $BETA_VERSION" \
162+
--notes-file BETA_CHANGELOG.md \
163+
--prerelease \
164+
--target dev \
165+
dist/*
166+
167+
- name: Publish to PyPI (Beta)
168+
if: github.event.inputs.dry_run != 'true'
169+
env:
170+
TWINE_USERNAME: __token__
171+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
172+
run: |
173+
echo "🚀 Publishing beta release to PyPI..."
174+
python -m twine upload dist/* --verbose
175+
176+
- name: Dry run summary
177+
if: github.event.inputs.dry_run == 'true'
178+
run: |
179+
echo "🏃‍♂️ DRY RUN COMPLETED"
180+
echo "Would have published: ${{ steps.version.outputs.beta_version }}"
181+
echo "Package contents:"
182+
ls -la dist/
183+
echo "Test results: All tests would be run"
184+
185+
- name: Cleanup old beta releases
186+
env:
187+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
188+
run: |
189+
echo "🧹 Cleaning up old beta releases (keep last 5)..."
190+
191+
# Get all beta releases, sorted by creation date
192+
BETA_RELEASES=$(gh release list --limit 30 | grep "🚧.*b[0-9]" | tail -n +6 | cut -f3)
193+
194+
for release in $BETA_RELEASES; do
195+
echo "Deleting old beta release: $release"
196+
gh release delete "$release" --yes || true
197+
git push --delete origin "$release" || true
198+
done
199+
200+
notify-beta:
201+
needs: [check-changes, beta-release]
202+
if: needs.check-changes.outputs.has_changes == 'true' && success()
203+
runs-on: ubuntu-latest
204+
steps:
205+
- name: Beta release notification
206+
run: |
207+
echo "🚧 Thursday beta release completed!"
208+
echo "📦 Beta version ready for final testing"
209+
echo "💡 Install with: pip install datafog==${{ needs.beta-release.outputs.beta_version }}"
210+
echo "📊 Commits included: ${{ needs.check-changes.outputs.commit_count }}"
211+
echo "🗓️ Stable release scheduled for Friday"
212+
echo ""
213+
echo "🧪 Beta Testing Checklist:"
214+
echo " ✅ All automated tests passed"
215+
echo " ⏳ Manual testing recommended"
216+
echo " ⏳ Performance validation"
217+
echo " ⏳ Integration testing"
218+
219+
prepare-friday-release:
220+
needs: [beta-release]
221+
if: success()
222+
runs-on: ubuntu-latest
223+
steps:
224+
- name: Prepare Friday stable release
225+
run: |
226+
echo "🎯 Preparing for Friday stable release..."
227+
echo "Current beta: ${{ needs.beta-release.outputs.beta_version }}"
228+
229+
# Extract base version for Friday
230+
BETA_VERSION="${{ needs.beta-release.outputs.beta_version }}"
231+
STABLE_VERSION=$(echo $BETA_VERSION | cut -d'b' -f1)
232+
233+
echo "Planned stable version: $STABLE_VERSION"
234+
echo "📋 Friday Release Checklist:"
235+
echo " ⏳ Final beta testing"
236+
echo " ⏳ Update CHANGELOG.md"
237+
echo " ⏳ Run weekly release workflow"
238+
echo " ⏳ Social media announcement"

0 commit comments

Comments
 (0)