Repository navigation
233 lines (195 loc) · 9.37 KB
/
Copy pathrelease-python-packages.yml
File metadata and controls
233 lines (195 loc) · 9.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
name: Build and Release Python Packages to PyPI
on:
push:
tags:
- '[0-9]+.[0-9]+.[0-9]+*' # Matches: 25.10.1, 25.10.1.dev0, 25.10.1.post1, etc.
jobs:
# Validate version compatibility between tag and pom.xml
validate-version:
name: Validate Version Compatibility
runs-on: ubuntu-24.04
outputs:
python-version: ${{ steps.validate.outputs.python-version }}
base-version: ${{ steps.validate.outputs.base-version }}
steps:
- name: Checkout code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.12'
- name: Validate version compatibility
id: validate
run: |
cd bindings/python
# Get version from git tag
TAG_VERSION="${{ github.ref_name }}"
echo "📌 Git tag version: $TAG_VERSION"
# The counting rule (release.md, Version Numbering): only X.Y.Z, X.Y.Z.devN (N from 0) or
# X.Y.Z.postN (N from 1), never aN/bN/rcN, and the tag must be the next number after the
# versions already in the git tags and on PyPI. It checks only and fails closed: a source
# it cannot read stops the release.
python3 scripts/check_version.py "$TAG_VERSION" --git-remote origin --pypi arcadedb-embedded
# Extract base version from tag (remove .dev0, .post1)
TAG_BASE=$(echo "$TAG_VERSION" | sed -E 's/\.(dev|post)[0-9]+$//')
echo "📌 Tag base version: $TAG_BASE"
# Get version from pom.xml
POM_VERSION=$(python3 scripts/extract_version.py --format=docker)
echo "📌 pom.xml version: $POM_VERSION"
# Extract base version from pom.xml (remove -SNAPSHOT, etc.)
POM_BASE=$(echo "$POM_VERSION" | sed 's/-SNAPSHOT$//' | sed 's/-RC.*//')
echo "📌 pom.xml base version: $POM_BASE"
# Compare base versions
if [ "$TAG_BASE" != "$POM_BASE" ]; then
echo "❌ Version mismatch!"
echo " Tag base version: $TAG_BASE"
echo " pom.xml base version: $POM_BASE"
echo ""
echo "This prevents accidentally releasing the wrong version."
echo "For example, tagging 25.9.1.dev0 when pom.xml says 25.10.1-SNAPSHOT"
exit 1
fi
echo "✅ Version compatibility check passed!"
echo " Base version: $TAG_BASE"
echo " Full tag version: $TAG_VERSION"
# Output for later jobs
echo "python-version=$TAG_VERSION" >> $GITHUB_OUTPUT
echo "base-version=$TAG_BASE" >> $GITHUB_OUTPUT
# Run example tests before building (workflow_call)
test-examples:
name: Run Example Tests
needs: validate-version
uses: ./.github/workflows/test-python-examples.yml
with:
build-version: ${{ needs.validate-version.outputs.python-version }}
secrets: inherit
# Run unit tests before building
test:
name: Run Unit Tests
needs: validate-version
uses: ./.github/workflows/test-python-bindings.yml
with:
build-version: ${{ needs.validate-version.outputs.python-version }}
secrets: inherit
publish:
name: Publish arcadedb-embedded to PyPI (4 platforms)
needs: [validate-version, test, test-examples]
runs-on: ubuntu-24.04
timeout-minutes: 60
continue-on-error: true # Don't block GitHub Release if PyPI upload fails (size limit)
environment: pypi
permissions:
id-token: write
steps:
- name: Download wheels for all tested Python versions
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
pattern: wheel-*-py*
path: dist/
merge-multiple: true
- name: Check out the verification scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
path: repo-scripts
sparse-checkout: bindings/python/scripts
persist-credentials: false
- name: Verify wheels
run: |
ls -lh dist/
echo "📦 Wheels for PyPI (current platforms):"
ls dist/*.whl
# Count wheels (should be 16: 4 platforms x 4 Python versions; the informational 3.15 leg uploads no wheel)
WHEEL_COUNT=$(ls dist/*.whl | wc -l)
echo "📊 Wheel count: $WHEEL_COUNT (expected: 16)"
echo ""
echo "ℹ️ Current PyPI platforms: linux x86_64, linux arm64, macOS Apple Silicon, windows x86_64"
if [ "$WHEEL_COUNT" -ne 16 ]; then
echo "❌ Expected 16 wheels (4 platforms x 4 Python versions), got $WHEEL_COUNT"
exit 1
fi
# Size policy: every wheel stays under 100 MB (decimal), also where the PyPI project's own limit is higher.
# An embedded database does not ship huge wheels; a larger one means a mistake. build.sh checks the same limit.
for WHEEL in dist/*.whl; do
SIZE=$(stat -c %s "$WHEEL")
if [ "$SIZE" -ge 100000000 ]; then
echo "❌ $WHEEL is $SIZE bytes, at or over the 100 MB size policy"
exit 1
fi
done
echo "✅ Every wheel is under 100 MB"
# Licence guard: Studio bundles ApexCharts, which is not open source since 5.1.0 (ArcadeData/arcadedb#10579).
# A wheel with a Studio jar or an ApexCharts file must never reach PyPI.
python3 repo-scripts/bindings/python/scripts/verify_wheel_no_studio.py dist/*.whl
# Show checksums to verify wheels are different
echo ""
echo "🔐 Wheel checksums (SHA256):"
sha256sum dist/*.whl
# Report wheel sizes with actual component breakdown
echo "" >> $GITHUB_STEP_SUMMARY
echo "## 📦 Built Wheels" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Platform | Wheel Size | JRE Size | JARs Size | Installed Size | SHA256 (first 8 chars) |" >> $GITHUB_STEP_SUMMARY
echo "|----------|------------|----------|-----------|----------------|------------------------|" >> $GITHUB_STEP_SUMMARY
for WHEEL_FILE in dist/*.whl; do
WHEEL_NAME=$(basename "$WHEEL_FILE")
WHEEL_SIZE_BYTES=$(stat -c%s "$WHEEL_FILE")
WHEEL_SIZE_MB=$(echo "scale=1; $WHEEL_SIZE_BYTES / 1024 / 1024" | bc)
# Extract platform from filename
if [[ "$WHEEL_NAME" == *"manylinux"*"x86_64"* ]]; then
PLATFORM="linux/amd64"
elif [[ "$WHEEL_NAME" == *"manylinux"*"aarch64"* ]]; then
PLATFORM="linux/arm64"
elif [[ "$WHEEL_NAME" == *"macosx"*"arm64"* ]]; then
PLATFORM="darwin/arm64"
# elif [[ "$WHEEL_NAME" == *"macosx"*"x86_64"* ]]; then
# PLATFORM="darwin/amd64"
elif [[ "$WHEEL_NAME" == *"win_amd64"* ]]; then
PLATFORM="windows/amd64"
else
PLATFORM="unknown"
fi
# Analyze wheel contents
TEMP_DIR=$(mktemp -d)
unzip -q "$WHEEL_FILE" -d "$TEMP_DIR"
# Calculate component sizes (find jre directory anywhere)
JRE_DIR=$(find "$TEMP_DIR" -type d -name "jre" | head -n1)
if [ -n "$JRE_DIR" ] && [ -d "$JRE_DIR" ]; then
JRE_SIZE_BYTES=$(du -sb "$JRE_DIR" | cut -f1)
JRE_SIZE_MB=$(echo "scale=1; $JRE_SIZE_BYTES / 1024 / 1024" | bc)
else
JRE_SIZE_MB="N/A"
fi
JAR_SIZE_BYTES=$(find "$TEMP_DIR" -name "*.jar" -exec du -cb {} + 2>/dev/null | tail -1 | cut -f1)
if [ -n "$JAR_SIZE_BYTES" ] && [ "$JAR_SIZE_BYTES" != "0" ]; then
JAR_SIZE_MB=$(echo "scale=1; $JAR_SIZE_BYTES / 1024 / 1024" | bc)
else
JAR_SIZE_MB="N/A"
fi
INSTALLED_SIZE_BYTES=$(du -sb "$TEMP_DIR" | cut -f1)
INSTALLED_SIZE_MB=$(echo "scale=0; $INSTALLED_SIZE_BYTES / 1024 / 1024" | bc)
# Calculate SHA256 checksum
CHECKSUM=$(sha256sum "$WHEEL_FILE" | cut -d' ' -f1 | cut -c1-8)
rm -rf "$TEMP_DIR"
echo "| $PLATFORM | ${WHEEL_SIZE_MB}M | ${JRE_SIZE_MB}M | ${JAR_SIZE_MB}M | ~${INSTALLED_SIZE_MB}M | \`$CHECKSUM\` |" >> $GITHUB_STEP_SUMMARY
done
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Note**: Sizes are uncompressed except for Wheel Size (compressed)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
- name: Verify wheel versions
run: |
TAG_VERSION="${{ needs.validate-version.outputs.python-version }}"
EXPECTED_VERSION="$TAG_VERSION"
for WHEEL_FILE in dist/*.whl; do
echo "📦 Checking: $WHEEL_FILE"
# Extract version from wheel filename
WHEEL_VERSION=$(echo "$WHEEL_FILE" | grep -oP '\d+\.\d+\.\d+(\.(dev|post|rc|a|b)\d+)?')
echo " Version: $WHEEL_VERSION"
if [ "$WHEEL_VERSION" != "$EXPECTED_VERSION" ]; then
echo "❌ Wheel version mismatch in $WHEEL_FILE!"
echo " Expected: $EXPECTED_VERSION"
exit 1
fi
done
echo "✅ All wheel versions match expected version ($EXPECTED_VERSION)"
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2