Build and Publish Wheels #21
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # SPDX-License-Identifier: MIT | |
| # SPDX-FileCopyrightText: 2025 py7zz contributors | |
| name: Build and Publish Wheels | |
| on: | |
| push: | |
| tags: | |
| - 'v*' # Only trigger on tags starting with 'v' | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to build (e.g., v1.0.0, v1.0.0a1, v1.0.0b1, v1.0.0rc1)' | |
| required: true | |
| type: string | |
| jobs: | |
| build: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - os: ubuntu-latest | |
| platform: linux | |
| arch: x86_64 | |
| binary_name: 7zz | |
| wheel_tag: manylinux1_x86_64 | |
| - os: macos-latest # Universal2 runner | |
| platform: macos | |
| arch: universal2 | |
| binary_name: 7zz | |
| wheel_tag: macosx_10_9_universal2 | |
| - os: windows-latest | |
| platform: windows | |
| arch: x86_64 | |
| binary_name: 7zz.exe | |
| wheel_tag: win_amd64 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Verify CI status | |
| shell: bash | |
| run: | | |
| echo "Verifying CI workflow status for commit: $GITHUB_SHA" | |
| # Query CI workflow status for the specific commit using gh run list | |
| # This avoids Windows Git Bash path rewriting issues with gh api | |
| CI_STATUS=$(gh run list \ | |
| --workflow="CI" \ | |
| --json conclusion,headSha \ | |
| --jq ".[] | select(.headSha == \"$GITHUB_SHA\") | .conclusion" \ | |
| | head -1) | |
| echo "CI workflow status: $CI_STATUS" | |
| if [ "$CI_STATUS" = "success" ]; then | |
| echo "✅ CI workflow passed - proceeding with build" | |
| elif [ "$CI_STATUS" = "failure" ]; then | |
| echo "❌ CI workflow failed - aborting build" | |
| echo "Please ensure all CI checks pass before building" | |
| exit 1 | |
| elif [ -z "$CI_STATUS" ]; then | |
| echo "⚠️ No CI workflow found for this commit" | |
| echo "This may indicate the commit was not properly tested" | |
| echo "Please ensure CI workflow runs and passes before building" | |
| exit 1 | |
| else | |
| echo "⏳ CI workflow status: $CI_STATUS" | |
| echo "Please wait for CI workflow to complete successfully before building" | |
| exit 1 | |
| fi | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v3 | |
| with: | |
| version: "latest" # Use latest version for better lock file support | |
| timeout-minutes: 3 # Add timeout to prevent hanging | |
| - name: Set up Python | |
| run: uv python install 3.11 | |
| - name: Validate tag format and determine release type | |
| id: validate_tag | |
| shell: bash | |
| run: | | |
| # Get tag from push event or workflow dispatch | |
| if [ "${{ github.event.inputs.tag }}" != "" ]; then | |
| TAG="${{ github.event.inputs.tag }}" | |
| else | |
| TAG=$(echo ${{ github.ref }} | sed 's/refs\/tags\///') | |
| fi | |
| echo "Git tag: $TAG" | |
| # Validate tag format (PEP 440 compliant) | |
| if [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+(a[0-9]+|b[0-9]+|rc[0-9]+)?$ ]]; then | |
| echo "✓ Tag format is valid: $TAG" | |
| else | |
| echo "✗ Invalid tag format: $TAG" | |
| echo "Expected format: v{major}.{minor}.{patch}[a{N}|b{N}|rc{N}]" | |
| echo "Examples: v1.0.0, v1.0.0a1, v1.0.0b1, v1.0.0rc1" | |
| exit 1 | |
| fi | |
| # Determine if this is a stable release (no suffix) or pre-release | |
| if [[ $TAG =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| RELEASE_TYPE="stable" | |
| echo "Release type: Stable" | |
| else | |
| RELEASE_TYPE="pre-release" | |
| echo "Release type: Pre-release" | |
| fi | |
| # Get 7zz version from locked file | |
| echo "Reading configured 7-Zip version..." | |
| chmod +x scripts/get_7zz.sh | |
| SEVEN_ZZ_VERSION=$(./scripts/get_7zz.sh --get-current) | |
| echo "Configured 7zz version: $SEVEN_ZZ_VERSION" | |
| # Set outputs | |
| echo "git_tag=$TAG" >> $GITHUB_OUTPUT | |
| echo "seven_zz_version=$SEVEN_ZZ_VERSION" >> $GITHUB_OUTPUT | |
| echo "release_type=$RELEASE_TYPE" >> $GITHUB_OUTPUT | |
| - name: Validate stable release ancestry (for stable releases only) | |
| if: steps.validate_tag.outputs.release_type == 'stable' | |
| shell: bash | |
| run: | | |
| echo "Validating stable release ancestry..." | |
| # Fetch origin/main to ensure we have latest main branch | |
| git fetch origin main | |
| # Check if current tag commit is an ancestor of main | |
| if git merge-base --is-ancestor $GITHUB_SHA origin/main; then | |
| echo "✓ Tag commit is an ancestor of main branch - valid for stable release" | |
| else | |
| echo "✗ Tag commit is not an ancestor of main branch - stable releases must come from main" | |
| echo "Current commit: $GITHUB_SHA" | |
| echo "Main branch head: $(git rev-parse origin/main)" | |
| exit 1 | |
| fi | |
| - name: Download 7zz binary using unified script | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.validate_tag.outputs.seven_zz_version }}" | |
| PLATFORM="${{ matrix.platform }}" | |
| ARCH="${{ matrix.arch }}" | |
| BINARY_NAME="${{ matrix.binary_name }}" | |
| echo "Using unified 7zz download script..." | |
| echo "Platform: $PLATFORM" | |
| echo "Architecture: $ARCH" | |
| echo "Version: $VERSION" | |
| # Make script executable and run it | |
| chmod +x scripts/get_7zz.sh | |
| ./scripts/get_7zz.sh --os "$PLATFORM" --arch "$ARCH" --version "$VERSION" | |
| # Verify the binary was downloaded correctly | |
| echo "Verifying binary placement..." | |
| if [[ -f "py7zz/bin/${BINARY_NAME}" ]]; then | |
| echo "✓ Binary correctly placed at: py7zz/bin/${BINARY_NAME}" | |
| ls -la "py7zz/bin/" | |
| # Show file type information | |
| file "py7zz/bin/${BINARY_NAME}" || echo "file command not available" | |
| # For macOS, show architecture info | |
| if [[ "$PLATFORM" == "macos" ]]; then | |
| lipo -info "py7zz/bin/${BINARY_NAME}" 2>/dev/null || echo "Single architecture binary (expected)" | |
| fi | |
| else | |
| echo "✗ Binary not found at expected location: py7zz/bin/${BINARY_NAME}" | |
| echo "Contents of py7zz/bin/:" | |
| find py7zz/bin/ -type f -ls 2>/dev/null || echo "No files found" | |
| exit 1 | |
| fi | |
| # Test binary functionality | |
| echo "Testing binary functionality..." | |
| if "py7zz/bin/${BINARY_NAME}" --help > /dev/null 2>&1; then | |
| echo "✓ Binary functionality test passed" | |
| else | |
| echo "✗ Binary functionality test failed" | |
| echo "This may be normal for some platforms due to dependencies or signing requirements" | |
| fi | |
| # For Windows, verify both 7zz.exe and 7z.dll are present | |
| if [[ "$PLATFORM" == "windows" ]]; then | |
| if [[ -f "py7zz/bin/7z.dll" ]]; then | |
| echo "✓ Windows 7z.dll found for complete functionality" | |
| else | |
| echo "⚠️ Windows 7z.dll not found - some formats may not be supported" | |
| fi | |
| fi | |
| - name: Install dependencies | |
| timeout-minutes: 5 # Add timeout for dependency installation | |
| run: | | |
| # Use uv sync for proper dependency management | |
| # Binary files are now available, so Hatchling can include them | |
| uv sync --dev | |
| uv pip install -e . | |
| - name: Validate dynamic version generation | |
| shell: bash | |
| run: | | |
| # Test that hatch-vcs can generate version from git tag | |
| echo "Testing dynamic version generation..." | |
| # Use git describe to get version (no need for hatchling at runtime) | |
| GENERATED_VERSION=$(git describe --tags --match='v*' | sed 's/^v//') | |
| echo "Generated version: $GENERATED_VERSION" | |
| # Skip validation if version generation failed | |
| if [ "$GENERATED_VERSION" = "0.0.0" ]; then | |
| echo "⚠ Version generation failed, skipping validation" | |
| exit 0 | |
| fi | |
| # Verify version format is PEP 440 compliant | |
| if [[ $GENERATED_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(a[0-9]+|b[0-9]+|rc[0-9]+)?$ ]]; then | |
| echo "✓ Generated version is PEP 440 compliant: $GENERATED_VERSION" | |
| else | |
| echo "✗ Generated version is not PEP 440 compliant: $GENERATED_VERSION" | |
| exit 1 | |
| fi | |
| # Verify version matches git tag (remove 'v' prefix from tag) | |
| GIT_TAG="${{ steps.validate_tag.outputs.git_tag }}" | |
| EXPECTED_VERSION=$(echo "$GIT_TAG" | sed 's/^v//') | |
| if [ "$GENERATED_VERSION" = "$EXPECTED_VERSION" ]; then | |
| echo "✓ Generated version matches git tag: $GENERATED_VERSION" | |
| else | |
| echo "✗ Version mismatch - Git tag: $GIT_TAG, Generated: $GENERATED_VERSION" | |
| exit 1 | |
| fi | |
| - name: Build wheel | |
| shell: bash | |
| run: | | |
| echo "Building wheel for ${{ matrix.platform }}-${{ matrix.arch }}..." | |
| # Build platform-specific wheel | |
| uv build --wheel | |
| # Rename wheel to include correct platform tag | |
| WHEEL_FILE=$(ls dist/*.whl) | |
| WHEEL_TAG="${{ matrix.wheel_tag }}" | |
| NEW_NAME=$(echo "$WHEEL_FILE" | sed "s/py3-none-any/py3-none-${WHEEL_TAG}/") | |
| echo "Renaming wheel: $WHEEL_FILE -> $NEW_NAME" | |
| mv "$WHEEL_FILE" "$NEW_NAME" | |
| - name: Check wheel for duplicate filenames | |
| shell: bash | |
| run: | | |
| echo "Checking wheel for duplicate filenames..." | |
| # Use our duplicate checker script | |
| uv run python scripts/check_wheel_dups.py --verbose dist/*.whl | |
| - name: Run twine check | |
| shell: bash | |
| run: | | |
| echo "Running twine check on wheel..." | |
| uv run pip install twine | |
| uv run twine check dist/*.whl | |
| - name: Verify wheel version consistency | |
| shell: bash | |
| run: | | |
| # Extract version from built wheel filename | |
| WHEEL_FILE=$(ls dist/*.whl | head -1) | |
| WHEEL_VERSION=$(echo "$WHEEL_FILE" | sed -n 's/.*py7zz-\([^-]*\)-.*/\1/p') | |
| echo "Wheel version: $WHEEL_VERSION" | |
| # Compare with expected version from git tag | |
| GIT_TAG="${{ steps.validate_tag.outputs.git_tag }}" | |
| EXPECTED_VERSION=$(echo "$GIT_TAG" | sed 's/^v//') | |
| if [ "$WHEEL_VERSION" = "$EXPECTED_VERSION" ]; then | |
| echo "✓ Wheel version matches git tag: $WHEEL_VERSION" | |
| else | |
| echo "✗ Wheel version mismatch - Expected: $EXPECTED_VERSION, Got: $WHEEL_VERSION" | |
| exit 1 | |
| fi | |
| # Test install and version check | |
| echo "Testing wheel installation and version verification..." | |
| uv pip install dist/*.whl --force-reinstall | |
| INSTALLED_VERSION=$(uv run python -c "import py7zz; print(py7zz.get_version())") | |
| echo "Installed version: $INSTALLED_VERSION" | |
| if [ "$INSTALLED_VERSION" = "$EXPECTED_VERSION" ]; then | |
| echo "✓ Installed version matches git tag: $INSTALLED_VERSION" | |
| else | |
| echo "✗ Installed version mismatch - Expected: $EXPECTED_VERSION, Got: $INSTALLED_VERSION" | |
| exit 1 | |
| fi | |
| - name: Upload wheel artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: wheels-${{ matrix.platform }}-${{ matrix.arch }} | |
| path: dist/*.whl | |
| publish-pypi: | |
| needs: build | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') | |
| environment: pypi | |
| permissions: | |
| contents: read | |
| id-token: write | |
| name: Publish to PyPI | |
| steps: | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist/ | |
| pattern: wheels-* | |
| merge-multiple: true | |
| - name: Final version validation before PyPI publish | |
| shell: bash | |
| run: | | |
| # Get git tag and expected version | |
| GIT_TAG=$(echo ${{ github.ref }} | sed 's/refs\/tags\///') | |
| EXPECTED_VERSION=$(echo "$GIT_TAG" | sed 's/^v//') | |
| echo "Git tag: $GIT_TAG" | |
| echo "Expected PyPI version: $EXPECTED_VERSION" | |
| # Verify all wheels have consistent version | |
| echo "Verifying wheel versions..." | |
| for wheel in dist/*.whl; do | |
| WHEEL_VERSION=$(echo "$wheel" | sed -n 's/.*py7zz-\([^-]*\)-.*/\1/p') | |
| echo " $wheel -> $WHEEL_VERSION" | |
| if [ "$WHEEL_VERSION" != "$EXPECTED_VERSION" ]; then | |
| echo "✗ Wheel version mismatch: $wheel" | |
| echo " Expected: $EXPECTED_VERSION" | |
| echo " Got: $WHEEL_VERSION" | |
| exit 1 | |
| fi | |
| done | |
| echo "✓ All wheels have consistent version: $EXPECTED_VERSION" | |
| # Final confirmation | |
| echo "🚀 Ready to publish to PyPI:" | |
| echo " Git tag: $GIT_TAG" | |
| echo " PyPI version: $EXPECTED_VERSION" | |
| echo " Wheel count: $(ls dist/*.whl | wc -l)" | |
| ls -la dist/ | |
| - name: Final duplicate filename check before upload | |
| shell: bash | |
| run: | | |
| echo "Running final duplicate filename check on all wheels..." | |
| pip install zipfile-deflate64 # For better wheel support | |
| python -c " | |
| import glob, zipfile, collections, sys | |
| wheels = glob.glob('dist/*.whl') | |
| print(f'Checking {len(wheels)} wheels for duplicates...') | |
| errors = False | |
| for wheel in wheels: | |
| try: | |
| z = zipfile.ZipFile(wheel) | |
| files = [i.filename for i in z.infolist()] | |
| # Check exact duplicates | |
| cnt = collections.Counter(files) | |
| dups = [k for k,v in cnt.items() if v>1] | |
| # Check case-insensitive duplicates | |
| lower = collections.Counter(f.lower() for f in files) | |
| case_dups = [k for k,v in lower.items() if v>1] | |
| if dups or case_dups: | |
| print(f'ERROR {wheel}:') | |
| if dups: print(f' Exact duplicates: {dups}') | |
| if case_dups: print(f' Case duplicates: {case_dups}') | |
| errors = True | |
| else: | |
| print(f'OK {wheel} - clean ({len(files)} files)') | |
| except Exception as e: | |
| print(f'ERROR checking {wheel}: {e}') | |
| errors = True | |
| if errors: | |
| print('ERROR: Duplicate filename errors found - aborting upload') | |
| sys.exit(1) | |
| else: | |
| print('SUCCESS: All wheels passed duplicate check!') | |
| " | |
| - name: Publish to PyPI | |
| uses: pypa/gh-action-pypi-publish@release/v1 | |
| with: | |
| attestations: true | |
| packages-dir: dist/ | |
| verbose: true | |
| github-release: | |
| needs: publish-pypi | |
| runs-on: ubuntu-latest | |
| if: startsWith(github.ref, 'refs/tags/') | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # Get full history for changelog | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: dist/ | |
| pattern: wheels-* | |
| merge-multiple: true | |
| - name: Check 7zz version change | |
| id: check_7zz_version | |
| run: | | |
| # Read current bundled 7zz version | |
| CURRENT_7ZZ=$(cat py7zz/7zz_version.txt | tr -d '[:space:]') | |
| echo "Current 7zz version: $CURRENT_7ZZ" | |
| # Get last tag to compare | |
| LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| echo "Last tag: $LAST_TAG" | |
| if [ -n "$LAST_TAG" ]; then | |
| # Try to read 7zz version from previous tag | |
| PREV_7ZZ=$(git show ${LAST_TAG}:py7zz/7zz_version.txt 2>/dev/null | tr -d '[:space:]' || echo "") | |
| echo "Previous 7zz version: $PREV_7ZZ" | |
| if [ -n "$PREV_7ZZ" ] && [ "$CURRENT_7ZZ" != "$PREV_7ZZ" ]; then | |
| echo "7zz version changed: $PREV_7ZZ -> $CURRENT_7ZZ" | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| echo "message=Update bundled 7zz from $PREV_7ZZ to $CURRENT_7ZZ" >> $GITHUB_OUTPUT | |
| elif [ -z "$PREV_7ZZ" ]; then | |
| # Version file didn't exist in previous tag | |
| echo "7zz version file is new in this release" | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| echo "message=Bundled 7zz $CURRENT_7ZZ" >> $GITHUB_OUTPUT | |
| else | |
| echo "7zz version unchanged: $CURRENT_7ZZ" | |
| echo "changed=false" >> $GITHUB_OUTPUT | |
| fi | |
| else | |
| # First release ever | |
| echo "First release, showing 7zz version" | |
| echo "changed=true" >> $GITHUB_OUTPUT | |
| echo "message=Bundled 7zz $CURRENT_7ZZ" >> $GITHUB_OUTPUT | |
| fi | |
| - name: Get Release Draft | |
| id: get_release_draft | |
| uses: release-drafter/release-drafter@v6 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Only run for stable releases | |
| if: ${{ !contains(github.ref_name, 'a') && !contains(github.ref_name, 'b') && !contains(github.ref_name, 'rc') }} | |
| - name: Generate pre-release notes | |
| id: pre_release_notes | |
| if: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} | |
| run: | | |
| # Get commits since last tag (stable or pre-release) | |
| LAST_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") | |
| if [ -n "$LAST_TAG" ]; then | |
| # Generate categorized release notes | |
| echo "## What's Changed" > release_notes.md | |
| echo "" >> release_notes.md | |
| # Get commits and categorize them | |
| git log --format="%s" --no-merges ${LAST_TAG}..HEAD > commits.txt | |
| # Initialize category flags | |
| has_feat=false | |
| has_fix=false | |
| has_docs=false | |
| has_ci=false | |
| has_perf=false | |
| has_test=false | |
| has_refactor=false | |
| has_style=false | |
| has_chore=false | |
| has_other=false | |
| # Check which categories we have | |
| while IFS= read -r commit; do | |
| if [[ "$commit" =~ ^feat(\(.+\))?: ]]; then has_feat=true | |
| elif [[ "$commit" =~ ^fix(\(.+\))?: ]]; then has_fix=true | |
| elif [[ "$commit" =~ ^docs(\(.+\))?: ]]; then has_docs=true | |
| elif [[ "$commit" =~ ^ci(\(.+\))?: ]]; then has_ci=true | |
| elif [[ "$commit" =~ ^perf(\(.+\))?: ]]; then has_perf=true | |
| elif [[ "$commit" =~ ^test(\(.+\))?: ]]; then has_test=true | |
| elif [[ "$commit" =~ ^refactor(\(.+\))?: ]]; then has_refactor=true | |
| elif [[ "$commit" =~ ^style(\(.+\))?: ]]; then has_style=true | |
| elif [[ "$commit" =~ ^chore(\(.+\))?: ]]; then has_chore=true | |
| else has_other=true | |
| fi | |
| done < commits.txt | |
| # Generate sections only for existing categories | |
| if [ "$has_feat" = true ]; then | |
| echo "🚀 Features" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^feat(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_fix" = true ]; then | |
| echo "🐛 Bug Fixes" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^fix(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_docs" = true ]; then | |
| echo "📚 Documentation" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^docs(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_ci" = true ]; then | |
| echo "🔄 CI/CD" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^ci(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_perf" = true ]; then | |
| echo "⚡ Performance" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^perf(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_test" = true ]; then | |
| echo "🧪 Testing" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^test(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_refactor" = true ]; then | |
| echo "🔧 Maintenance" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^refactor(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_style" = true ]; then | |
| echo "🔧 Maintenance" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^style(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_chore" = true ]; then | |
| echo "🔧 Maintenance" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -E "^chore(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| if [ "$has_other" = true ]; then | |
| echo "Other Changes" >> release_notes.md | |
| echo "" >> release_notes.md | |
| grep -v -E "^(feat|fix|docs|ci|perf|test|refactor|style|chore)(\(.+\))?: " commits.txt | sed 's/^/- /' >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| # Add Build System section if 7zz version changed | |
| if [ "${{ steps.check_7zz_version.outputs.changed }}" == "true" ]; then | |
| echo "🏗️ Build System" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "- ${{ steps.check_7zz_version.outputs.message }}" >> release_notes.md | |
| echo "" >> release_notes.md | |
| fi | |
| # Add footer | |
| echo "---" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${LAST_TAG}...${{ github.ref_name }}" >> release_notes.md | |
| # Clean up | |
| rm commits.txt | |
| else | |
| echo "## What's Changed" > release_notes.md | |
| echo "" >> release_notes.md | |
| echo "- Initial pre-release" >> release_notes.md | |
| echo "" >> release_notes.md | |
| echo "**Full Changelog**: https://github.com/${{ github.repository }}/commits/${{ github.ref_name }}" >> release_notes.md | |
| fi | |
| # Set output | |
| echo "notes<<EOF" >> $GITHUB_OUTPUT | |
| cat release_notes.md >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release (Pre-release) | |
| uses: ncipollo/release-action@v1 | |
| if: ${{ contains(github.ref_name, 'a') || contains(github.ref_name, 'b') || contains(github.ref_name, 'rc') }} | |
| with: | |
| tag: ${{ github.ref_name }} | |
| name: "${{ github.ref_name }}" | |
| body: ${{ steps.pre_release_notes.outputs.notes }} | |
| artifacts: "dist/*.whl" | |
| draft: false | |
| prerelease: true | |
| generateReleaseNotes: false | |
| allowUpdates: true | |
| artifactErrorsFailBuild: true | |
| makeLatest: false | |
| - name: Prepare stable release body | |
| id: prepare_stable_body | |
| if: ${{ !contains(github.ref_name, 'a') && !contains(github.ref_name, 'b') && !contains(github.ref_name, 'rc') }} | |
| env: | |
| DRAFT_BODY: ${{ steps.get_release_draft.outputs.body }} | |
| VERSION_CHANGED: ${{ steps.check_7zz_version.outputs.changed }} | |
| VERSION_MESSAGE: ${{ steps.check_7zz_version.outputs.message }} | |
| run: | | |
| if [ "$VERSION_CHANGED" == "true" ]; then | |
| # Insert Build System section before Contributors using awk | |
| echo "$DRAFT_BODY" | awk -v msg="$VERSION_MESSAGE" ' | |
| /^## Contributors/ { | |
| print "## 🏗️ Build System" | |
| print "" | |
| print "- " msg | |
| print "" | |
| } | |
| { print } | |
| ' > final_body.md | |
| else | |
| echo "$DRAFT_BODY" > final_body.md | |
| fi | |
| echo "body<<EOF" >> $GITHUB_OUTPUT | |
| cat final_body.md >> $GITHUB_OUTPUT | |
| echo "EOF" >> $GITHUB_OUTPUT | |
| - name: Create GitHub Release (Stable) | |
| uses: ncipollo/release-action@v1 | |
| if: ${{ !contains(github.ref_name, 'a') && !contains(github.ref_name, 'b') && !contains(github.ref_name, 'rc') }} | |
| with: | |
| tag: ${{ github.ref_name }} | |
| name: "${{ github.ref_name }}" | |
| body: ${{ steps.prepare_stable_body.outputs.body }} | |
| artifacts: "dist/*.whl" | |
| draft: false | |
| prerelease: false | |
| generateReleaseNotes: false | |
| allowUpdates: true | |
| artifactErrorsFailBuild: true | |
| makeLatest: true |