@@ -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