forked from pytorch/test-infra
-
Notifications
You must be signed in to change notification settings - Fork 0
442 lines (411 loc) · 17.5 KB
/
Copy pathbuild_wheels_linux_v2.yml
File metadata and controls
442 lines (411 loc) · 17.5 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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
name: Build Linux Wheels V2 (uv)
# V2 of build_wheels_linux.yml that provisions Python and the build toolchain
# with `uv` instead of conda.
#
# What changed vs. v1 (build_wheels_linux.yml):
# - No conda / miniforge. `uv` installs the requested Python (including
# free-threaded builds like 3.13t/3.14t and pre-releases) via
# python-build-standalone and creates an isolated venv.
# - The build env is a uv `--seed` venv (ships pip) that is activated for every
# build/test step, so the existing `pip`/`python`/`setup.py` invocations work
# unchanged. `CONDA_RUN` is kept (as an empty string) only so the step bodies
# stay diff-minimal against v1.
# - `pytorch_pkg_helpers` (which produces BUILD_ENV_FILE) is run through uv.
#
# Notes / caveats:
# - conda previously also supplied some *system* libraries (openssl, libpng,
# libwebp, pkg-config). Those are expected to come from the manylinux builder
# image (or the caller's pre-script). Only pip-installable build tools
# (cmake/ninja/wheel/build) are installed here.
# - BUILD_ENV_FILE (from pytorch_pkg_helpers) exports
# `PATH="/opt/python/<abi>/bin:$PATH"` for the in-image CPython. Since v2 uses
# a uv venv instead, every step re-prepends the venv bin *after* sourcing
# BUILD_ENV_FILE so the uv interpreter wins.
on:
workflow_call:
inputs:
repository:
description: 'Repository to checkout, defaults to ""'
default: ""
type: string
ref:
description: 'Reference to checkout, defaults to "nightly"'
default: "nightly"
type: string
test-infra-repository:
description: "Test infra repository to use"
default: "pytorch/test-infra"
type: string
test-infra-ref:
description: "Test infra reference to use"
default: ""
type: string
build-matrix:
description: "Build matrix to utilize"
default: ""
type: string
pre-script:
description: "Pre script to run prior to build"
default: ""
type: string
post-script:
description: "Post script to run prior to build"
default: ""
type: string
smoke-test-script:
description: "Script for Smoke Test for a specific domain"
default: ""
type: string
env-var-script:
description: "Script that sets Domain-Specific Environment Variables"
default: ""
type: string
package-name:
description: "Name of the actual python package that is imported in the smoke test"
default: ""
type: string
build-target:
description: "The target to build and publish (for repos that build multiple packages)"
default: ""
type: string
trigger-event:
description: "Trigger Event in caller that determines whether or not to upload"
default: ""
type: string
cache-path:
description: "The path(s) on the runner to cache or restore. The path is relative to repository."
default: ""
type: string
cache-key:
description: "The key created when saving a cache and the key used to search for a cache."
default: ""
type: string
architecture:
description: Architecture to build for x86_64 for default Linux, or aarch64 for Linux aarch64 builds
required: false
type: string
default: x86_64
runner:
description: "Override runner for builds"
default: ""
type: string
submodules:
description: Works as stated in actions/checkout, but the default value is recursive
required: false
type: string
default: recursive
setup-miniconda:
description: "Kept for caller compatibility; ignored in the uv-based v2."
required: false
type: boolean
default: false
build-platform:
description: Platform to build wheels, choose from 'python-build-package' or 'setup-py'
required: false
type: string
default: 'setup-py'
upload-to-pypi:
description: The comma-separated list of CUDA arch to be uploaded to pypi
default: ""
type: string
build-command:
description: The build command to use if build-platform is python-build-package
required: false
default: "python -m build --wheel"
type: string
wheel-upload-path:
description: Custom wheel upload path
required: false
type: string
wheel-nightly-policy:
description: Custom wheel upload policy for nightly
type: string
default: ''
also-upload-to-gpu-arch-versions:
description: "Comma-separated list of extra gpu_arch_versions to upload the wheel to (e.g. 'xpu' to also upload a cpu wheel to the xpu index)"
required: false
type: string
default: ''
run-smoke-test:
description: Set to true if smoke test is needed
required: false
type: boolean
default: true
python-version:
description: "Override the uv-provisioned Python version (blank = use matrix.python_version)"
required: false
type: string
default: ""
pip-install-torch-extra-args:
description: Extra arguments to pass to the command that install base torch dependency
required: false
default: ""
type: string
timeout:
description: 'Timeout for the job (in minutes)'
default: 120
type: number
secrets:
PYPI_API_TOKEN:
description: An optional token to upload to pypi
required: false
R2_ACCOUNT_ID:
description: Cloudflare R2 account ID
required: false
R2_ACCESS_KEY_ID:
description: Cloudflare R2 access key ID
required: false
R2_SECRET_ACCESS_KEY:
description: Cloudflare R2 secret access key
required: false
permissions:
id-token: write
contents: read
jobs:
build:
strategy:
fail-fast: false
matrix: ${{ fromJSON(inputs.build-matrix) }}
env:
PYTHON_VERSION: ${{ inputs.python-version != '' && inputs.python-version || matrix.python_version }}
PACKAGE_TYPE: wheel
REPOSITORY: ${{ inputs.repository }}
REF: ${{ inputs.ref }}
CU_VERSION: ${{ matrix.desired_cuda }}
UPLOAD_TO_BASE_BUCKET: ${{ matrix.upload_to_base_bucket }}
ARCH: ${{ inputs.architecture }}
BUILD_TARGET: ${{ inputs.build-target }}
# Where the uv-managed build venv lives; activated in every build/test step.
BUILD_VENV: ${{ runner.temp }}/build_venv
name: build-${{ matrix.build_name }}
runs-on: ${{ (inputs.runner != '' && inputs.runner) || matrix.validation_runner }}
environment: ${{(inputs.trigger-event == 'schedule' || (inputs.trigger-event == 'push' && (startsWith(github.event.ref, 'refs/heads/nightly') || startsWith(github.event.ref, 'refs/tags/v')))) && 'pytorchbot-env' || ''}}
container:
image: ${{ matrix.container_image }}
options: ${{ matrix.gpu_arch_type == 'cuda' && '--gpus all -e NVIDIA_DRIVER_CAPABILITIES=compute,utility,video' || ' ' }}
timeout-minutes: ${{ inputs.timeout }}
steps:
- name: Clean workspace
shell: bash -l {0}
run: |
set -euxo pipefail
echo "::group::Cleanup debug output"
rm -rf "${GITHUB_WORKSPACE}"
mkdir -p "${GITHUB_WORKSPACE}"
if [[ "${{ inputs.architecture }}" = "aarch64" ]]; then
rm -rf "${RUNNER_TEMP}/*"
fi
echo "::endgroup::"
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
# Support the use case where we need to checkout someone's fork
repository: ${{ inputs.test-infra-repository }}
ref: ${{ inputs.test-infra-ref }}
path: test-infra
- uses: ./test-infra/.github/actions/set-channel
- name: Set PYTORCH_VERSION
if: ${{ env.CHANNEL == 'test' }}
run: |
# When building RC, set the version to be the current candidate version,
# otherwise, leave it alone so nightly will pick up the latest
echo "PYTORCH_VERSION=${{ matrix.stable_version }}" >> "${GITHUB_ENV}"
# Checkout the target repository (v1 did this inside setup-binary-builds).
- name: Checkout target repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
repository: ${{ inputs.repository }}
ref: ${{ inputs.ref }}
submodules: ${{ inputs.submodules }}
path: ${{ inputs.repository }}
- name: Set artifact name
shell: bash -l {0}
run: |
set -euxo pipefail
# "/" is not allowed in artifact names; replace all forward slashes.
# Convert e.g. 3.10.19 -> 3.10 while preserving suffixes like 3.13t.
SHORT_PYTHON_VERSION=$(echo "${PYTHON_VERSION}" | sed -E 's/^([0-9]+\.[0-9]+[a-z]?).*/\1/')
echo "ARTIFACT_NAME=${REPOSITORY//\//_}_${REF//\//_}_${SHORT_PYTHON_VERSION}_${CU_VERSION}_${ARCH}" >> "${GITHUB_ENV}"
- name: Install uv
shell: bash -l {0}
run: |
set -euxo pipefail
# Container-safe install (no node/JS action needed inside the builder image).
if ! command -v uv >/dev/null 2>&1; then
curl -LsSf https://astral.sh/uv/install.sh | sh
fi
# uv installs to ~/.local/bin
echo "${HOME}/.local/bin" >> "${GITHUB_PATH}"
- name: Provision Python + build venv with uv
shell: bash -l {0}
run: |
set -euxo pipefail
export PATH="${HOME}/.local/bin:${PATH}"
# uv understands the free-threaded suffix (e.g. 3.13t / 3.14t) and can
# fetch pre-release interpreters, so no special-casing is needed.
uv python install "${PYTHON_VERSION}"
# --seed installs pip/setuptools so the existing `pip`/`python -m pip`
# step bodies work unchanged.
uv venv --seed --python "${PYTHON_VERSION}" "${BUILD_VENV}"
# Build toolchain that conda used to provide (pip-installable subset).
# System libs (openssl/libpng/libwebp/pkg-config) come from the builder
# image or the caller's pre-script.
VIRTUAL_ENV="${BUILD_VENV}" uv pip install \
"cmake==3.31.2" "ninja==1.12.1" "wheel==0.37" "build==1.2.2"
# Activate the venv for all subsequent steps. CONDA_RUN is kept as an
# empty string only to keep the step bodies diff-minimal vs v1.
echo "VIRTUAL_ENV=${BUILD_VENV}" >> "${GITHUB_ENV}"
echo "${BUILD_VENV}/bin" >> "${GITHUB_PATH}"
echo "CONDA_RUN=" >> "${GITHUB_ENV}"
{
echo "Provisioned interpreter:"
"${BUILD_VENV}/bin/python" --version
}
- name: Generate BUILD_ENV_FILE from pytorch_pkg_helpers
working-directory: ${{ inputs.repository }}
shell: bash -l {0}
run: |
set -euxo pipefail
export PATH="${HOME}/.local/bin:${PATH}"
BUILD_ENV_FILE="${RUNNER_TEMP}/build_env_${GITHUB_RUN_ID}"
# Run the helper isolated via uv (it only needs a stable 3.10 runtime;
# it does not need the build interpreter).
uv run --python 3.10 --with "${GITHUB_WORKSPACE}/test-infra/tools/pkg-helpers" \
python -m pytorch_pkg_helpers > "${BUILD_ENV_FILE}"
cat "${BUILD_ENV_FILE}"
echo "BUILD_ENV_FILE=${BUILD_ENV_FILE}" >> "${GITHUB_ENV}"
- name: Combine Env Var and Build Env Files
if: ${{ inputs.env-var-script != '' }}
working-directory: ${{ inputs.repository }}
run: |
set -euxo pipefail
cat "${{ inputs.env-var-script }}" >> "${BUILD_ENV_FILE}"
- name: Add XPU Env Vars in Build Env File
if: ${{ matrix.gpu_arch_type == 'xpu' }}
run: |
{
echo "set +u"
echo "source /opt/intel/oneapi/compiler/latest/env/vars.sh"
echo "source /opt/intel/oneapi/pti/latest/env/vars.sh"
} >> "${BUILD_ENV_FILE}"
- name: Install torch dependency
run: |
set -euxo pipefail
# shellcheck disable=SC1090
source "${BUILD_ENV_FILE}"
# Re-prepend the uv venv so it wins over the /opt/python PATH that
# BUILD_ENV_FILE exports.
export PATH="${BUILD_VENV}/bin:${PATH}"
# shellcheck disable=SC2086
${CONDA_RUN} ${PIP_INSTALL_TORCH} ${{ inputs.pip-install-torch-extra-args }}
- name: Run Pre-Script with Caching
if: ${{ inputs.pre-script != '' }}
uses: ./test-infra/.github/actions/run-script-with-cache
with:
cache-path: ${{ inputs.cache-path }}
cache-key: ${{ inputs.cache-key }}
repository: ${{ inputs.repository }}
script: ${{ inputs.pre-script }}
- name: Build the wheel (python-build-package)
if: ${{ inputs.build-platform == 'python-build-package' }}
working-directory: ${{ inputs.repository }}
shell: bash -l {0}
run: |
set -euxo pipefail
source "${BUILD_ENV_FILE}"
export PATH="${BUILD_VENV}/bin:${PATH}"
export PYTORCH_VERSION="$(${CONDA_RUN} pip show torch | grep ^Version: | sed 's/Version: *//' | sed 's/+.\+//')"
echo "Successfully installed Python build package"
${CONDA_RUN} ${{ inputs.build-command }}
- name: Build the wheel (setup-py)
if: ${{ inputs.build-platform == 'setup-py' }}
working-directory: ${{ inputs.repository }}
shell: bash -l {0}
run: |
set -euxo pipefail
source "${BUILD_ENV_FILE}"
export PATH="${BUILD_VENV}/bin:${PATH}"
export PYTORCH_VERSION="$(${CONDA_RUN} pip show torch | grep ^Version: | sed 's/Version: *//' | sed 's/+.\+//')"
${CONDA_RUN} python setup.py clean
echo "Successfully ran python setup.py clean"
${CONDA_RUN} python setup.py bdist_wheel
- name: Repair Manylinux_2_28 Wheel
shell: bash -l {0}
env:
PACKAGE_NAME: ${{ inputs.package-name }}
SMOKE_TEST_SCRIPT: ${{ inputs.smoke-test-script }}
run: |
set -euxo pipefail
source "${BUILD_ENV_FILE}"
export PATH="${BUILD_VENV}/bin:${PATH}"
for pkg in ${{ inputs.repository }}/dist/*-linux_*.whl; do
# if the glob didn't match anything
if [[ ! -e $pkg ]]; then
continue
fi
abs_pkg=$(realpath $pkg)
./test-infra/.github/scripts/repair_manylinux_2_28.sh $abs_pkg
done
- name: Run Post-Script
if: ${{ inputs.post-script != '' }}
uses: ./test-infra/.github/actions/run-script-with-cache
with:
repository: ${{ inputs.repository }}
script: ${{ inputs.post-script }}
- name: Smoke Test
if: ${{ inputs.run-smoke-test }}
shell: bash -l {0}
env:
PACKAGE_NAME: ${{ inputs.package-name }}
SMOKE_TEST_SCRIPT: ${{ inputs.smoke-test-script }}
run: |
set -euxo pipefail
source "${BUILD_ENV_FILE}"
export PATH="${BUILD_VENV}/bin:${PATH}"
WHEEL_NAME=$(ls "${{ inputs.repository }}/dist/")
echo "$WHEEL_NAME"
${CONDA_RUN} pip install "${{ inputs.repository }}/dist/$WHEEL_NAME"
# Checking that we have a pinned version of torch in our dependency tree
(
pushd "${RUNNER_TEMP}"
unzip -o "${GITHUB_WORKSPACE}/${{ inputs.repository }}/dist/$WHEEL_NAME"
# Ensure that pytorch version is pinned, should output file where it was found
grep "Requires-Dist: torch (==.*)" -r .
)
if [[ (! -f "${{ inputs.repository }}"/${SMOKE_TEST_SCRIPT}) ]]; then
echo "${{ inputs.repository }}/${SMOKE_TEST_SCRIPT} not found"
${CONDA_RUN} python -c "import ${PACKAGE_NAME}; print('package version is ', ${PACKAGE_NAME}.__version__)"
else
echo "${{ inputs.repository }}/${SMOKE_TEST_SCRIPT} found"
${CONDA_RUN} python "${{ inputs.repository }}/${SMOKE_TEST_SCRIPT}"
fi
# NB: Only upload to GitHub after passing smoke tests
- name: Upload wheel to GitHub
continue-on-error: true
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ env.ARTIFACT_NAME }}
path: ${{ inputs.repository }}/dist/
upload:
needs: build
uses: ./.github/workflows/_binary_upload.yml
if: always()
with:
repository: ${{ inputs.repository }}
ref: ${{ inputs.ref }}
test-infra-repository: ${{ inputs.test-infra-repository }}
test-infra-ref: ${{ inputs.test-infra-ref }}
build-matrix: ${{ inputs.build-matrix }}
architecture: ${{ inputs.architecture }}
trigger-event: ${{ inputs.trigger-event }}
upload-to-pypi: ${{ inputs.upload-to-pypi }}
wheel-upload-path: ${{ inputs.wheel-upload-path }}
wheel-nightly-policy: ${{ inputs.wheel-nightly-policy }}
also-upload-to-gpu-arch-versions: ${{ inputs.also-upload-to-gpu-arch-versions }}
secrets:
PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ inputs.repository }}-${{ github.event_name == 'workflow_dispatch' }}
cancel-in-progress: true