|
1 | 1 | name: Build and Release Python Packages to PyPI |
2 | 2 |
|
3 | 3 | on: |
4 | | - release: |
5 | | - types: [published] # Trigger when GitHub Release is published |
6 | | - # Release tag must match 'v*-python' (e.g., v3.0.5-python) |
| 4 | + push: |
| 5 | + tags: |
| 6 | + - '[0-9]+.[0-9]+.[0-9]+*' # Matches: 25.10.1, 25.10.1.dev0, 25.10.1.post1, etc. |
7 | 7 |
|
8 | 8 | jobs: |
9 | | - # Check if this is a Python release |
10 | | - check-release: |
11 | | - name: Validate Python Release Tag |
| 9 | + # Validate version compatibility between tag and pom.xml |
| 10 | + validate-version: |
| 11 | + name: Validate Version Compatibility |
12 | 12 | runs-on: ubuntu-latest |
13 | 13 | outputs: |
14 | | - is-python-release: ${{ steps.check.outputs.is-python-release }} |
| 14 | + python-version: ${{ steps.validate.outputs.python-version }} |
| 15 | + base-version: ${{ steps.validate.outputs.base-version }} |
15 | 16 | steps: |
16 | | - - name: Check if release tag contains 'python' (case-insensitive) |
17 | | - id: check |
| 17 | + - name: Checkout code |
| 18 | + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 |
| 19 | + |
| 20 | + - name: Set up Python |
| 21 | + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 |
| 22 | + with: |
| 23 | + python-version: '3.11' |
| 24 | + |
| 25 | + - name: Validate version compatibility |
| 26 | + id: validate |
18 | 27 | run: | |
19 | | - TAG_NAME="${{ github.event.release.tag_name }}" |
20 | | - TAG_LOWER=$(echo "$TAG_NAME" | tr '[:upper:]' '[:lower:]') |
21 | | -
|
22 | | - if [[ "$TAG_LOWER" == *"python"* ]]; then |
23 | | - echo "✅ This is a Python release: $TAG_NAME" |
24 | | - echo "is-python-release=true" >> $GITHUB_OUTPUT |
25 | | - else |
26 | | - echo "⏭️ Not a Python release (tag: $TAG_NAME), skipping workflow" |
27 | | - echo "is-python-release=false" >> $GITHUB_OUTPUT |
| 28 | + cd bindings/python |
| 29 | +
|
| 30 | + # Get version from git tag |
| 31 | + TAG_VERSION="${{ github.ref_name }}" |
| 32 | + echo "📌 Git tag version: $TAG_VERSION" |
| 33 | +
|
| 34 | + # Extract base version from tag (remove .dev0, .post1, etc.) |
| 35 | + TAG_BASE=$(echo "$TAG_VERSION" | sed -E 's/\.(dev|post|rc|a|b)[0-9]+$//') |
| 36 | + echo "📌 Tag base version: $TAG_BASE" |
| 37 | +
|
| 38 | + # Get version from pom.xml |
| 39 | + POM_VERSION=$(python3 extract_version.py --format=docker) |
| 40 | + echo "📌 pom.xml version: $POM_VERSION" |
| 41 | +
|
| 42 | + # Extract base version from pom.xml (remove -SNAPSHOT, etc.) |
| 43 | + POM_BASE=$(echo "$POM_VERSION" | sed 's/-SNAPSHOT$//' | sed 's/-RC.*//') |
| 44 | + echo "📌 pom.xml base version: $POM_BASE" |
| 45 | +
|
| 46 | + # Compare base versions |
| 47 | + if [ "$TAG_BASE" != "$POM_BASE" ]; then |
| 48 | + echo "❌ Version mismatch!" |
| 49 | + echo " Tag base version: $TAG_BASE" |
| 50 | + echo " pom.xml base version: $POM_BASE" |
| 51 | + echo "" |
| 52 | + echo "This prevents accidentally releasing the wrong version." |
| 53 | + echo "For example, tagging 25.9.1.dev0 when pom.xml says 25.10.1-SNAPSHOT" |
| 54 | + exit 1 |
28 | 55 | fi |
29 | 56 |
|
30 | | - # Run tests first to ensure quality |
| 57 | + echo "✅ Version compatibility check passed!" |
| 58 | + echo " Base version: $TAG_BASE" |
| 59 | + echo " Full tag version: $TAG_VERSION" |
| 60 | +
|
| 61 | + # Output for later jobs |
| 62 | + echo "python-version=$TAG_VERSION" >> $GITHUB_OUTPUT |
| 63 | + echo "base-version=$TAG_BASE" >> $GITHUB_OUTPUT |
| 64 | +
|
| 65 | + # Run example tests before building (workflow_call) |
| 66 | + test-examples: |
| 67 | + name: Run Example Tests |
| 68 | + needs: validate-version |
| 69 | + uses: ./.github/workflows/test-python-examples.yml |
| 70 | + secrets: inherit |
| 71 | + |
| 72 | + # Run unit tests before building |
31 | 73 | test: |
32 | | - name: Run Tests Before Release |
33 | | - needs: check-release |
34 | | - if: needs.check-release.outputs.is-python-release == 'true' |
| 74 | + name: Run Unit Tests |
| 75 | + needs: validate-version |
35 | 76 | uses: ./.github/workflows/test-python-bindings.yml |
36 | 77 | secrets: inherit |
37 | 78 |
|
38 | 79 | build: |
39 | | - needs: test # Wait for tests to pass |
40 | | - name: Build Python Package (${{ matrix.variant }}) |
| 80 | + needs: [validate-version, test, test-examples] # Wait for validation and tests |
| 81 | + name: Build arcadedb-embedded (${{ matrix.platform }}) |
41 | 82 | runs-on: ubuntu-latest |
| 83 | + environment: pypi |
42 | 84 | strategy: |
43 | 85 | matrix: |
44 | | - variant: [base] # Only base variant for now, jre coming soon |
45 | | - include: |
46 | | - - variant: base |
47 | | - environment: pypi-base |
| 86 | + platform: [linux/amd64, linux/arm64, darwin/amd64, darwin/arm64, windows/amd64] |
48 | 87 |
|
49 | 88 | steps: |
50 | 89 | - name: Checkout code |
51 | 90 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 |
52 | 91 |
|
| 92 | + - name: Set up Python |
| 93 | + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6.0.0 |
| 94 | + with: |
| 95 | + python-version: '3.11' |
| 96 | + |
| 97 | + - name: Set up QEMU (for ARM64 emulation) |
| 98 | + if: contains(matrix.platform, 'arm64') |
| 99 | + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 |
| 100 | + with: |
| 101 | + platforms: arm64 |
| 102 | + |
53 | 103 | - name: Set up Docker Buildx |
54 | 104 | uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 |
55 | 105 |
|
56 | | - - name: Build ${{ matrix.variant }} variant |
| 106 | + - name: Write version file for Docker build |
| 107 | + run: | |
| 108 | + cd bindings/python |
| 109 | + # Use tag version directly - pass it to extract_version.py |
| 110 | + echo "${{ needs.validate-version.outputs.python-version }}" > .build_version.txt |
| 111 | + echo "📦 Building version: ${{ needs.validate-version.outputs.python-version }}" |
| 112 | +
|
| 113 | + - name: Build arcadedb-embedded (${{ matrix.platform }}) |
57 | 114 | run: | |
58 | 115 | cd bindings/python |
59 | | - ./build-all.sh ${{ matrix.variant }} |
| 116 | + # Build script will use .build_version.txt if it exists |
| 117 | + ./build.sh ${{ matrix.platform }} |
| 118 | + env: |
| 119 | + BUILD_VERSION: ${{ needs.validate-version.outputs.python-version }} |
60 | 120 |
|
61 | 121 | - name: Upload wheel artifact |
62 | 122 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 |
63 | 123 | with: |
64 | | - name: wheel-${{ matrix.variant }} |
| 124 | + name: wheel-${{ matrix.platform }} |
65 | 125 | path: bindings/python/dist/*.whl |
66 | 126 | retention-days: 5 |
67 | 127 |
|
68 | | - publish-base: |
| 128 | + publish: |
69 | 129 | name: Publish arcadedb-embedded to PyPI |
70 | | - needs: [check-release, build] |
71 | | - if: needs.check-release.outputs.is-python-release == 'true' |
| 130 | + needs: [validate-version, build] |
72 | 131 | runs-on: ubuntu-latest |
73 | | - environment: pypi-base |
| 132 | + environment: pypi |
74 | 133 | permissions: |
75 | 134 | id-token: write |
76 | 135 | steps: |
77 | | - - name: Download base wheel |
| 136 | + - name: Download all wheels |
78 | 137 | uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0 |
79 | 138 | with: |
80 | | - name: wheel-base |
| 139 | + pattern: wheel-* |
81 | 140 | path: dist/ |
| 141 | + merge-multiple: true |
| 142 | + |
| 143 | + - name: Verify wheels |
| 144 | + run: | |
| 145 | + ls -lh dist/ |
| 146 | + echo "📦 Wheels:" |
| 147 | + ls dist/*.whl |
| 148 | +
|
| 149 | + # Count wheels (should be 5: one for each platform) |
| 150 | + WHEEL_COUNT=$(ls dist/*.whl | wc -l) |
| 151 | + echo "📊 Wheel count: $WHEEL_COUNT (expected: 5)" |
| 152 | +
|
| 153 | + if [ "$WHEEL_COUNT" -ne 5 ]; then |
| 154 | + echo "❌ Expected 5 wheels (5 platforms), got $WHEEL_COUNT" |
| 155 | + exit 1 |
| 156 | + fi |
| 157 | +
|
| 158 | + - name: Verify wheel versions |
| 159 | + run: | |
| 160 | + for WHEEL_FILE in dist/*.whl; do |
| 161 | + echo "📦 Checking: $WHEEL_FILE" |
| 162 | + # Extract version from wheel filename |
| 163 | + WHEEL_VERSION=$(echo "$WHEEL_FILE" | grep -oP '\d+\.\d+\.\d+(\.(dev|post|rc|a|b)\d+)?') |
| 164 | + echo " Version: $WHEEL_VERSION" |
| 165 | +
|
| 166 | + if [ "$WHEEL_VERSION" != "${{ needs.validate-version.outputs.python-version }}" ]; then |
| 167 | + echo "❌ Wheel version mismatch in $WHEEL_FILE!" |
| 168 | + exit 1 |
| 169 | + fi |
| 170 | + done |
| 171 | + echo "✅ All wheel versions match tag version" |
| 172 | +
|
82 | 173 | - name: Publish to PyPI |
83 | 174 | uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # release/v1 |
0 commit comments