Skip to content

Commit 68b114b

Browse files
authored
Add tilegym wheel building (#41)
1 parent 7576046 commit 68b114b

File tree

4 files changed

+333
-11
lines changed

4 files changed

+333
-11
lines changed

.github/workflows/build-wheel.yml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
name: Build Python Wheel (Reusable)
6+
7+
on:
8+
workflow_call:
9+
inputs:
10+
package-name:
11+
description: 'Python package name (e.g., tilegym)'
12+
required: true
13+
type: string
14+
artifact-suffix:
15+
description: 'Optional suffix for artifact name (e.g., -pr for PRs)'
16+
required: false
17+
type: string
18+
default: ''
19+
python-versions:
20+
description: 'JSON array of Python versions to build (e.g., ["3.10", "3.11", "3.12"])'
21+
required: false
22+
type: string
23+
default: '["3.10"]'
24+
architectures:
25+
description: 'JSON array of architectures to build (e.g., ["x86_64", "arm64"])'
26+
required: false
27+
type: string
28+
default: '["x86_64"]'
29+
runner-x86-64:
30+
description: 'Runner label for x86_64 builds (default: ubuntu-latest)'
31+
required: false
32+
type: string
33+
default: 'ubuntu-latest'
34+
runner-arm64:
35+
description: 'Runner label for arm64 builds (default: ubuntu-24.04-arm)'
36+
required: false
37+
type: string
38+
default: 'ubuntu-24.04-arm'
39+
retention-days:
40+
description: 'Artifact retention days'
41+
required: false
42+
type: number
43+
default: 7
44+
skip-import-test:
45+
description: 'Skip import test (for CUDA/GPU-dependent packages)'
46+
required: false
47+
type: boolean
48+
default: false
49+
outputs:
50+
artifact-name:
51+
description: 'Name of the uploaded wheel artifact (base name, without version suffix)'
52+
value: ${{ jobs.build-wheel.outputs.artifact-name }}
53+
54+
permissions:
55+
contents: read
56+
57+
jobs:
58+
build-wheel:
59+
name: Build wheel (Python ${{ matrix.python-version }}, ${{ matrix.arch }})
60+
runs-on: ${{ matrix.arch == 'x86_64' && inputs.runner-x86-64 || inputs.runner-arm64 }}
61+
strategy:
62+
matrix:
63+
python-version: ${{ fromJSON(inputs.python-versions) }}
64+
arch: ${{ fromJSON(inputs.architectures) }}
65+
outputs:
66+
artifact-name: ${{ steps.artifact.outputs.base-name }}
67+
steps:
68+
- uses: actions/checkout@v4
69+
70+
- name: Set up Python ${{ matrix.python-version }}
71+
uses: actions/setup-python@v5
72+
with:
73+
python-version: ${{ matrix.python-version }}
74+
75+
- name: Build wheel
76+
run: |
77+
pip install build
78+
python -m build --wheel
79+
ls -lh dist/
80+
echo "Built wheel for Python ${{ matrix.python-version }}"
81+
82+
- name: Validate wheel
83+
run: |
84+
pip install twine check-wheel-contents
85+
check-wheel-contents dist/*.whl
86+
twine check dist/*
87+
88+
- name: Test import
89+
if: ${{ !inputs.skip-import-test }}
90+
run: |
91+
pip install dist/*.whl
92+
python -c "import ${{ inputs.package-name }}; print('✅ Imported successfully')"
93+
94+
- name: Set artifact names
95+
id: artifact
96+
run: |
97+
# Base name (for outputs)
98+
BASE_NAME="${{ inputs.package-name }}${{ inputs.artifact-suffix }}-wheel-${{ github.sha }}"
99+
echo "base-name=${BASE_NAME}" >> $GITHUB_OUTPUT
100+
101+
# Versioned name with arch (for upload)
102+
PY_VERSION="${{ matrix.python-version }}"
103+
PY_SUFFIX="py${PY_VERSION//./}" # e.g., 3.10 -> py310
104+
ARCH="${{ matrix.arch }}"
105+
VERSIONED_NAME="${BASE_NAME}-${PY_SUFFIX}-${ARCH}"
106+
echo "versioned-name=${VERSIONED_NAME}" >> $GITHUB_OUTPUT
107+
108+
echo "📦 Base artifact name: ${BASE_NAME}"
109+
echo "📦 Versioned artifact name: ${VERSIONED_NAME}"
110+
111+
- name: Upload artifact
112+
uses: actions/upload-artifact@v4
113+
with:
114+
name: ${{ steps.artifact.outputs.versioned-name }}
115+
path: dist/*.whl
116+
retention-days: ${{ inputs.retention-days }}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2+
#
3+
# SPDX-License-Identifier: MIT
4+
5+
name: Publish Python Wheel (Reusable)
6+
7+
on:
8+
workflow_call:
9+
inputs:
10+
artifact-name:
11+
description: 'Base name of wheel artifacts to download (e.g., tilegym-wheel-abc123)'
12+
required: true
13+
type: string
14+
python-versions:
15+
description: 'JSON array of Python versions to publish (e.g., ["3.10", "3.11", "3.12"])'
16+
required: false
17+
type: string
18+
default: '["3.10"]'
19+
architectures:
20+
description: 'JSON array of architectures to publish (e.g., ["x86_64", "arm64"])'
21+
required: false
22+
type: string
23+
default: '["x86_64"]'
24+
retention-days:
25+
description: 'Days to retain verified artifact'
26+
required: false
27+
type: number
28+
default: 30
29+
publish-to-pypi:
30+
description: 'Publish to public PyPI'
31+
required: false
32+
type: boolean
33+
default: false
34+
secrets:
35+
PYPI_TOKEN:
36+
description: 'PyPI API token (required if publish-to-pypi is true)'
37+
required: false
38+
39+
permissions:
40+
contents: read
41+
packages: write
42+
43+
jobs:
44+
publish:
45+
name: Publish wheels (Python ${{ matrix.python-version }}, ${{ matrix.arch }})
46+
runs-on: ubuntu-latest
47+
strategy:
48+
matrix:
49+
python-version: ${{ fromJSON(inputs.python-versions) }}
50+
arch: ${{ fromJSON(inputs.architectures) }}
51+
steps:
52+
- name: Set artifact suffix
53+
id: suffix
54+
run: |
55+
PY_VERSION="${{ matrix.python-version }}"
56+
PY_SUFFIX="py${PY_VERSION//./}" # e.g., 3.10 -> py310
57+
ARCH="${{ matrix.arch }}"
58+
FULL_SUFFIX="${PY_SUFFIX}-${ARCH}"
59+
echo "full=${FULL_SUFFIX}" >> $GITHUB_OUTPUT
60+
61+
- name: Download wheel (Python ${{ matrix.python-version }}, ${{ matrix.arch }})
62+
uses: actions/download-artifact@v4
63+
with:
64+
name: ${{ inputs.artifact-name }}-${{ steps.suffix.outputs.full }}
65+
path: dist/
66+
67+
- name: Re-upload as verified
68+
uses: actions/upload-artifact@v4
69+
with:
70+
name: ${{ inputs.artifact-name }}-${{ steps.suffix.outputs.full }}-verified
71+
path: dist/
72+
retention-days: ${{ inputs.retention-days }}
73+
74+
publish-to-pypi:
75+
name: Publish all wheels to PyPI
76+
needs: publish
77+
if: inputs.publish-to-pypi
78+
runs-on: ubuntu-latest
79+
strategy:
80+
matrix:
81+
python-version: ${{ fromJSON(inputs.python-versions) }}
82+
arch: ${{ fromJSON(inputs.architectures) }}
83+
steps:
84+
- name: Set artifact suffix
85+
id: suffix
86+
run: |
87+
PY_VERSION="${{ matrix.python-version }}"
88+
PY_SUFFIX="py${PY_VERSION//./}" # e.g., 3.10 -> py310
89+
ARCH="${{ matrix.arch }}"
90+
FULL_SUFFIX="${PY_SUFFIX}-${ARCH}"
91+
echo "full=${FULL_SUFFIX}" >> $GITHUB_OUTPUT
92+
93+
- name: Download verified wheel
94+
uses: actions/download-artifact@v4
95+
with:
96+
name: ${{ inputs.artifact-name }}-${{ steps.suffix.outputs.full }}-verified
97+
path: dist/
98+
99+
- name: Publish to PyPI
100+
run: |
101+
pip install twine
102+
twine upload --skip-existing dist/*
103+
env:
104+
TWINE_USERNAME: __token__
105+
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
106+
107+
- name: Summary
108+
run: |
109+
echo "✅ Wheel for Python ${{ matrix.python-version }} (${{ matrix.arch }}) published to PyPI"
110+
ls -lh dist/

.github/workflows/tilegym-ci.yml

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,14 +155,39 @@ jobs:
155155
# Pass through image name from context
156156
echo "image_name=${{ steps.context.outputs.image_name }}" >> $GITHUB_OUTPUT
157157
158+
build-wheel:
159+
name: build-python-wheels
160+
needs: config
161+
if: needs.config.outputs.build == 'true'
162+
uses: ./.github/workflows/build-wheel.yml
163+
with:
164+
package-name: tilegym
165+
# Artifact naming: PR builds -> tilegym-pr-wheel-{sha}, Main -> tilegym-wheel-{sha}
166+
artifact-suffix: ${{ needs.config.outputs.is_pr == 'true' && '-pr' || '' }}
167+
python-versions: '["3.10", "3.11", "3.12"]' # Build for multiple Python versions
168+
architectures: '["x86_64", "arm64"]' # Build for both architectures (6 wheels total)
169+
retention-days: 7 # All wheels kept for 7 days; only tested wheel gets -verified (30 days)
170+
skip-import-test: true # TileGym requires CUDA, test in Docker instead
171+
# Optional: Override default runners (ubuntu-latest for x86_64, ubuntu-24.04-arm for arm64)
172+
# runner-x86-64: [self-hosted, linux, x64, gpu]
173+
158174
build:
159175
name: build-tilegym-image
160-
needs: config
176+
needs: [config, build-wheel]
161177
if: needs.config.outputs.build == 'true'
162178
runs-on: ubuntu-latest
179+
# Note: Wheels are built for Python 3.10/3.11/3.12 and x86_64/arm64 (6 wheels total)
180+
# However, Docker build and tests only use Python 3.10 x86_64 wheel
181+
# Only the tested wheel (py310-x86_64) gets marked as "-verified" after tests pass
163182
steps:
164183
- name: Checkout code
165184
uses: actions/checkout@v4
185+
186+
- name: Download TileGym wheel (Python 3.10, x86_64)
187+
uses: actions/download-artifact@v4
188+
with:
189+
name: ${{ needs.build-wheel.outputs.artifact-name }}-py310-x86_64
190+
path: ./wheel
166191

167192
- name: Set image variables
168193
id: vars
@@ -212,6 +237,7 @@ jobs:
212237
with:
213238
context: .
214239
file: ./modeling/transformers/Dockerfile
240+
target: wheel # Use wheel target for CI builds
215241
tags: ${{ steps.tags.outputs.tags }}
216242
push: true
217243
provenance: false
@@ -233,6 +259,13 @@ jobs:
233259
(needs.build.result == 'success' || needs.build.result == 'skipped')
234260
runs-on: linux-amd64-gpu-rtxpro6000-latest-1
235261
steps:
262+
- name: Checkout code (sparse - need ops tests and shared utilities)
263+
uses: actions/checkout@v4
264+
with:
265+
sparse-checkout: |
266+
tests
267+
sparse-checkout-cone-mode: false
268+
236269
- name: Create test results directory
237270
run: mkdir -p ${{ github.workspace }}/test-results
238271

@@ -252,6 +285,7 @@ jobs:
252285
docker pull ${IMAGE}
253286
docker run --rm \
254287
--gpus all \
288+
-v ${{ github.workspace }}/tests:/workspace/tilegym/tests \
255289
-v ${{ github.workspace }}/test-results:/test-results \
256290
-w /workspace/tilegym \
257291
${IMAGE} \
@@ -500,6 +534,24 @@ jobs:
500534
fi
501535
fi
502536
537+
publish-wheel:
538+
name: publish-verified-wheel
539+
needs: [config, build-wheel, test-ops, test-benchmark]
540+
if: |
541+
always() &&
542+
needs.build-wheel.result == 'success' &&
543+
needs.test-ops.result == 'success' &&
544+
needs.test-benchmark.result == 'success'
545+
# Note: Only marks the py310-x86_64 wheel as "verified" because that's the wheel
546+
# actually tested in Docker. Other wheels (py311, py312, arm64) are available but unverified.
547+
uses: ./.github/workflows/publish-wheel.yml
548+
with:
549+
artifact-name: ${{ needs.build-wheel.outputs.artifact-name }}
550+
python-versions: '["3.10"]' # Only verify the wheel actually tested in Docker
551+
architectures: '["x86_64"]' # Only verify the x86_64 wheel used in Docker tests
552+
retention-days: 30 # Verified wheel kept longer than initial builds (7 days)
553+
publish-to-pypi: false # Set to true and add PYPI_TOKEN secret when ready
554+
503555
promote-to-latest:
504556
name: promote-to-latest
505557
needs: [config, build, test-ops, test-benchmark]

0 commit comments

Comments
 (0)