Skip to content

Commit 562d413

Browse files
committed
Big update
1 parent c1db2c5 commit 562d413

28 files changed

Lines changed: 5143 additions & 256 deletions

.github/workflows/build-publish.yml

Lines changed: 244 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,13 @@ jobs:
183183
package-version: ${{ steps.version.outputs.version }}
184184
wheel-name: ${{ steps.build.outputs.wheel-name }}
185185
sdist-name: ${{ steps.build.outputs.sdist-name }}
186+
is-release: ${{ steps.version.outputs.is-release }}
186187

187188
steps:
188189
- name: Checkout repository
189190
uses: actions/checkout@v4
191+
with:
192+
fetch-depth: 0 # Full history for version detection
190193

191194
- name: Set up Python
192195
uses: actions/setup-python@v4
@@ -198,106 +201,124 @@ jobs:
198201
python -m pip install --upgrade pip
199202
pip install build twine wheel tomli tomli-w
200203
201-
- name: Determine and set version information
204+
- name: Detect version context
202205
id: version
203206
run: |
204-
# Determine version based on trigger type
207+
# Determine if this is a release
208+
IS_RELEASE=false
205209
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
206-
# For release tags, extract version from tag
207-
TAG_VERSION="${{ github.ref_name }}"
208-
VERSION=$(echo "$TAG_VERSION" | sed 's/^v//')
209-
echo "🏷️ Release build - using tag version: $VERSION"
210-
211-
# Update pyproject.toml with tag version
212-
python -c "
213-
import tomli_w
214-
import tomli
215-
216-
# Read current pyproject.toml
217-
with open('pyproject.toml', 'rb') as f:
218-
data = tomli.load(f)
219-
220-
# Update version
221-
data['project']['version'] = '$VERSION'
222-
223-
# Write back to file
224-
with open('pyproject.toml', 'wb') as f:
225-
tomli_w.dump(data, f)
226-
227-
print(f'✅ Updated pyproject.toml version to: $VERSION')
228-
"
210+
IS_RELEASE=true
211+
echo "🏷️ RELEASE BUILD DETECTED"
212+
else
213+
echo "🔧 Development build"
214+
fi
215+
216+
# Get version information
217+
if [[ "$IS_RELEASE" == "true" ]]; then
218+
# Extract version from tag (v1.2.3 -> 1.2.3)
219+
VERSION="${{ github.ref_name }}"
220+
VERSION="${VERSION#v}"
221+
echo "📌 Release version from tag: $VERSION"
229222
else
230-
# For development builds, extract base version from pyproject.toml
231-
VERSION=$(python -c "
232-
try:
223+
# Get base version from pyproject.toml
224+
if python3 -c "import sys; sys.version_info >= (3,11)" 2>/dev/null; then
225+
BASE_VERSION=$(python -c "
233226
import tomllib
234227
with open('pyproject.toml', 'rb') as f:
235-
data = tomllib.load(f)
236-
except ImportError:
228+
data = tomllib.load(f)
229+
print(data['project']['version'])
230+
")
231+
else
232+
BASE_VERSION=$(python -c "
237233
import tomli
238234
with open('pyproject.toml', 'rb') as f:
239-
data = tomli.load(f)
240-
print(data['project']['version'])
241-
")
242-
echo "🔧 Development build - using pyproject.toml version: $VERSION"
235+
data = tomli.load(f)
236+
print(data['project']['version'])
237+
")
238+
fi
239+
240+
# Build development version with branch context
241+
BRANCH="${{ github.ref_name }}"
242+
SHA="${{ github.sha }}"
243+
SHA_SHORT="${SHA:0:7}"
244+
RUN_NUM="${{ github.run_number }}"
245+
246+
# Add branch-specific suffix
247+
if [[ "$BRANCH" == "main" ]]; then
248+
VERSION="${BASE_VERSION}.dev${RUN_NUM}+main.${SHA_SHORT}"
249+
elif [[ "$BRANCH" == "develop" ]]; then
250+
VERSION="${BASE_VERSION}.dev${RUN_NUM}+develop.${SHA_SHORT}"
251+
elif [[ "$BRANCH" == feature/* ]]; then
252+
# Feature branch: v1.2.3.dev123+feature.branch-name.abc1234
253+
FEATURE_NAME="${BRANCH#feature/}"
254+
FEATURE_NAME="${FEATURE_NAME//\//-}"
255+
VERSION="${BASE_VERSION}.dev${RUN_NUM}+feature.${FEATURE_NAME}.${SHA_SHORT}"
256+
else
257+
# Other branches
258+
CLEAN_BRANCH="${BRANCH//\//-}"
259+
VERSION="${BASE_VERSION}.dev${RUN_NUM}+${CLEAN_BRANCH}.${SHA_SHORT}"
260+
fi
261+
262+
echo "📌 Development version: $VERSION"
243263
fi
244264
265+
# Output version information
245266
echo "version=$VERSION" >> $GITHUB_OUTPUT
246-
echo "Final package version: $VERSION"
267+
echo "is-release=$IS_RELEASE" >> $GITHUB_OUTPUT
268+
echo "branch=${{ github.ref_name }}" >> $GITHUB_OUTPUT
247269
248-
- name: Update version for development builds
249-
if: ${{ !startsWith(github.ref, 'refs/tags/v') }}
270+
- name: Update pyproject.toml with version
250271
run: |
251-
# For development builds, append build metadata
252-
CURRENT_VERSION="${{ steps.version.outputs.version }}"
253-
BUILD_VERSION="${CURRENT_VERSION}.dev${{ github.run_number }}+${{ github.sha }}"
272+
VERSION="${{ steps.version.outputs.version }}"
273+
IS_RELEASE="${{ steps.version.outputs.is-release }}"
274+
275+
echo "📝 Setting version to: $VERSION (Release: $IS_RELEASE)"
254276
255-
# Update pyproject.toml temporarily for the build
256277
python -c "
257278
import tomli_w
258-
import tomli
259-
260-
# Read current pyproject.toml
261-
with open('pyproject.toml', 'rb') as f:
279+
try:
280+
import tomllib
281+
with open('pyproject.toml', 'rb') as f:
282+
data = tomllib.load(f)
283+
except ImportError:
284+
import tomli
285+
with open('pyproject.toml', 'rb') as f:
262286
data = tomli.load(f)
263287
264-
# Update version with development suffix
265-
data['project']['version'] = '$BUILD_VERSION'
288+
data['project']['version'] = '$VERSION'
266289
267-
# Write back to file
268290
with open('pyproject.toml', 'wb') as f:
269-
tomli_w.dump(data, f)
291+
tomli_w.dump(data, f)
270292
271-
print(f'✅ Updated development version to: $BUILD_VERSION')
293+
print(f'✅ Updated pyproject.toml to version: $VERSION')
272294
"
273-
274-
echo "Updated version to: $BUILD_VERSION"
275-
echo "version=$BUILD_VERSION" >> $GITHUB_OUTPUT
276295
277-
- name: Verify version update
296+
- name: Display version information
278297
run: |
279-
echo "📋 Final version information:"
280-
echo "=============================="
281-
FINAL_VERSION=$(python -c "
298+
echo "════════════════════════════════════════"
299+
echo "📋 VERSION INFORMATION"
300+
echo "════════════════════════════════════════"
301+
echo "Version: ${{ steps.version.outputs.version }}"
302+
echo "Is Release: ${{ steps.version.outputs.is-release }}"
303+
echo "Branch: ${{ steps.version.outputs.branch }}"
304+
echo "GitHub Ref: ${{ github.ref }}"
305+
echo "GitHub Event: ${{ github.event_name }}"
306+
307+
# Verify in pyproject.toml
308+
echo ""
309+
echo "Current pyproject.toml version:"
310+
python -c "
282311
try:
283-
import tomllib
284-
with open('pyproject.toml', 'rb') as f:
285-
data = tomllib.load(f)
312+
import tomllib
313+
with open('pyproject.toml', 'rb') as f:
314+
data = tomllib.load(f)
286315
except ImportError:
287-
import tomli
288-
with open('pyproject.toml', 'rb') as f:
289-
data = tomli.load(f)
290-
print(data['project']['version'])
291-
")
292-
echo "pyproject.toml version: $FINAL_VERSION"
293-
echo "GitHub ref: ${{ github.ref }}"
294-
echo "Trigger: ${{ github.event_name }}"
295-
296-
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
297-
echo "🏷️ Release build detected"
298-
else
299-
echo "🔧 Development build detected"
300-
fi
316+
import tomli
317+
with open('pyproject.toml', 'rb') as f:
318+
data = tomli.load(f)
319+
print(f\" {data['project']['version']}\")
320+
"
321+
echo "════════════════════════════════════════"
301322
302323
- name: Build package
303324
id: build
@@ -552,9 +573,157 @@ jobs:
552573
asset_name: ${{ needs.build.outputs.sdist-name }}
553574
asset_content_type: application/gzip
554575

576+
# Auto-create release tags on push to main/develop
577+
auto-tag:
578+
needs: [test, build]
579+
runs-on: ubuntu-latest
580+
if: |
581+
github.event_name == 'push' &&
582+
!startsWith(github.ref, 'refs/tags/') &&
583+
(github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop') &&
584+
needs.test.result == 'success' &&
585+
needs.build.result == 'success'
586+
permissions:
587+
contents: write
588+
589+
steps:
590+
- name: Checkout repository
591+
uses: actions/checkout@v4
592+
with:
593+
fetch-depth: 0
594+
token: ${{ secrets.GITHUB_TOKEN }}
595+
596+
- name: Set up Python
597+
uses: actions/setup-python@v4
598+
with:
599+
python-version: ${{ env.PYTHON_VERSION }}
600+
601+
- name: Get current version and determine next version
602+
id: next-version
603+
run: |
604+
pip install tomli
605+
606+
python << 'PYTHON_SCRIPT'
607+
import tomli
608+
import os
609+
610+
# Get base version from pyproject.toml
611+
with open('pyproject.toml', 'rb') as f:
612+
data = tomli.load(f)
613+
614+
current_version = data['project']['version']
615+
616+
# Parse MAJOR.MINOR.PATCH
617+
parts = current_version.split('.')
618+
major = int(parts[0].split('-')[0].split('+')[0])
619+
minor = int(parts[1].split('-')[0].split('+')[0]) if len(parts) > 1 else 0
620+
patch = int(parts[2].split('-')[0].split('+')[0]) if len(parts) > 2 else 0
621+
622+
# Determine bump strategy based on branch
623+
branch = os.getenv('GITHUB_REF')
624+
if 'refs/heads/main' in branch:
625+
# Main: bump minor version (1.0.0 -> 1.1.0)
626+
next_version = f"{major}.{minor + 1}.0"
627+
print("📌 Main branch: bumping minor version")
628+
else:
629+
# Develop: bump patch version (1.0.0 -> 1.0.1)
630+
next_version = f"{major}.{minor}.{patch + 1}"
631+
print("📌 Develop branch: bumping patch version")
632+
633+
# Write outputs
634+
with open(os.getenv('GITHUB_OUTPUT'), 'a') as f:
635+
f.write(f"current={current_version}\n")
636+
f.write(f"next={next_version}\n")
637+
f.write(f"branch={os.getenv('GITHUB_REF_NAME')}\n")
638+
639+
print("════════════════════════════════════════")
640+
print("Version Bump Information")
641+
print("════════════════════════════════════════")
642+
print(f"Current version: {current_version}")
643+
print(f"Next version: {next_version}")
644+
print(f"Branch: {os.getenv('GITHUB_REF_NAME')}")
645+
print("════════════════════════════════════════")
646+
PYTHON_SCRIPT
647+
648+
- name: Check if tag already exists
649+
id: check-tag
650+
run: |
651+
TAG_NAME="v${{ steps.next-version.outputs.next }}"
652+
653+
if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
654+
echo "⚠️ Tag $TAG_NAME already exists, skipping auto-tag"
655+
echo "tag-exists=true" >> $GITHUB_OUTPUT
656+
else
657+
echo "✅ Tag $TAG_NAME does not exist, will create it"
658+
echo "tag-exists=false" >> $GITHUB_OUTPUT
659+
fi
660+
661+
- name: Update pyproject.toml with next version
662+
if: steps.check-tag.outputs.tag-exists == 'false'
663+
run: |
664+
pip install tomli tomli-w
665+
666+
python -c "
667+
import tomli_w
668+
import tomli
669+
670+
with open('pyproject.toml', 'rb') as f:
671+
data = tomli.load(f)
672+
673+
data['project']['version'] = '${{ steps.next-version.outputs.next }}'
674+
675+
with open('pyproject.toml', 'wb') as f:
676+
tomli_w.dump(data, f)
677+
678+
print('✅ Updated pyproject.toml to version: ${{ steps.next-version.outputs.next }}')
679+
"
680+
681+
- name: Create and push tag
682+
if: steps.check-tag.outputs.tag-exists == 'false'
683+
run: |
684+
TAG_NAME="v${{ steps.next-version.outputs.next }}"
685+
686+
# Configure git
687+
git config user.name "github-actions[bot]"
688+
git config user.email "github-actions[bot]@users.noreply.github.com"
689+
690+
# Commit version update
691+
git add pyproject.toml
692+
git commit -m "chore: bump version to ${{ steps.next-version.outputs.next }}"
693+
694+
# Create and push tag
695+
git tag -a "$TAG_NAME" -m "Release ${{ steps.next-version.outputs.next }}"
696+
git push origin "$TAG_NAME"
697+
698+
# Also push the version update commit
699+
git push origin ${{ steps.next-version.outputs.branch }}
700+
701+
echo "✅ Created and pushed tag: $TAG_NAME"
702+
echo ""
703+
echo "🚀 This will automatically trigger the release workflow"
704+
echo " Release will be published to PyPI and GitHub Releases"
705+
706+
- name: Summary
707+
if: always()
708+
run: |
709+
echo "════════════════════════════════════════"
710+
echo "🏷️ Auto-Tag Summary"
711+
echo "════════════════════════════════════════"
712+
echo "Branch: ${{ steps.next-version.outputs.branch }}"
713+
echo "Current version: ${{ steps.next-version.outputs.current }}"
714+
echo "Next version: ${{ steps.next-version.outputs.next }}"
715+
echo "Tag exists: ${{ steps.check-tag.outputs.tag-exists }}"
716+
if [[ "${{ steps.check-tag.outputs.tag-exists }}" == "false" ]]; then
717+
echo "Status: ✅ Tag created and pushed"
718+
echo "Next: Release workflow will be triggered automatically"
719+
else
720+
echo "Status: ⚠️ Tag already exists, no action taken"
721+
fi
722+
echo "════════════════════════════════════════"
723+
555724
# Notify on completion
556725
notify:
557-
needs: [test, build, publish-test, publish-production, create-release]
726+
needs: [test, build, publish-test, publish-production, create-release, auto-tag]
558727
runs-on: ubuntu-latest
559728
if: always()
560729
steps:

0 commit comments

Comments
 (0)