diff --git a/.github/actions/setup-binary-builds-v2/action.yml b/.github/actions/setup-binary-builds-v2/action.yml new file mode 100644 index 0000000000..f08baaf6c8 --- /dev/null +++ b/.github/actions/setup-binary-builds-v2/action.yml @@ -0,0 +1,113 @@ +name: Set up binary builds + +description: Clean workspace and check out PyTorch + +inputs: + repository: + description: If set to any value, don't use sudo to clean the workspace + required: false + type: string + default: '' + ref: + description: Works as stated in actions/checkout + required: false + type: string + default: nightly + submodules: + description: Works as stated in actions/checkout, but the default value is recursive + required: false + type: string + default: recursive + python-version: + description: The target Python version + required: true + type: string + cuda-version: + description: The target CUDA version + required: true + type: string + arch: + description: The target ARCH + required: true + type: string + upload-to-base-bucket: + description: One of the parameter used by pkg-helpers + required: false + type: boolean + default: no + +runs: + using: composite + steps: + - name: Remove repository directory (if exists) + shell: bash + env: + REPOSITORY: ${{ inputs.repository }} + run: | + set -euxo pipefail + rm -rf "${REPOSITORY}" + + - uses: actions/checkout@v4 + with: + repository: ${{ inputs.repository }} + ref: ${{ inputs.ref }} + submodules: ${{ inputs.submodules }} + path: ${{ inputs.repository }} + + - name: Log Available Webhook Fields + shell: bash + run: | + echo "ENV VARS" + echo "${GITHUB_REF_NAME}" + echo "${GITHUB_REF}" + echo "${GITHUB_BASE_REF}" + + echo "GITHUB PROVIDED" + echo "${{ github.ref_name }}" + echo "${{ github.event.ref }}" + echo "${{ github.ref }}" + echo "${{ github.base_ref }}" + - name: Set artifact name + shell: bash + env: + PYTHON_VERSION: ${{ inputs.python-version }} + CU_VERSION: ${{ inputs.cuda-version }} + ARCH: ${{ inputs.arch }} + run: | + set -euxo pipefail + # Set artifact name here since github actions doesn't have string manipulation tools + # and "/" is not allowed in artifact names. //\//_ is to replace all forward slashes, + # not just the first one + echo "ARTIFACT_NAME=${REPOSITORY//\//_}_${REF//\//_}_${PYTHON_VERSION}_${CU_VERSION}_${ARCH}" >> "${GITHUB_ENV}" + + - name: Install uv environment + shell: bash -l {0} + run: | + set -euxo pipefail + curl -LsSf https://astral.sh/uv/install.sh | sh + + - name: Generate file from pytorch_pkg_helpers + working-directory: ${{ inputs.repository }} + shell: bash -l {0} + run: | + set -euxo pipefail + uv venv --python 3.9 + source .venv/bin/activate + + uv pip install ${GITHUB_WORKSPACE}/test-infra/tools/pkg-helpers + BUILD_ENV_FILE="${RUNNER_TEMP}/build_env_${GITHUB_RUN_ID}" + python -m pytorch_pkg_helpers > "${BUILD_ENV_FILE}" + cat "${BUILD_ENV_FILE}" + echo "BUILD_ENV_FILE=${BUILD_ENV_FILE}" >> "${GITHUB_ENV}" + + - name: Setup uv environment for build + shell: bash -l {0} + env: + PYTHON_VERSION: ${{ inputs.python-version }} + run: | + set -euxo pipefail + + uv venv py${PYTHON_VERSION} --python ${PYTHON_VERSION} + source ./py${PYTHON_VERSION}/bin/activate + uv pip install cmake==3.31.2 ninja wheel==0.37 setuptools + echo "VIRTUAL_ENV=${VIRTUAL_ENV}" >> "${GITHUB_ENV}" diff --git a/.github/workflows/build_wheels_linux_v2.yml b/.github/workflows/build_wheels_linux_v2.yml new file mode 100644 index 0000000000..abf5edc7b1 --- /dev/null +++ b/.github/workflows/build_wheels_linux_v2.yml @@ -0,0 +1,313 @@ +name: Build Linux Wheels v2 + +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 + submodules: + description: Works as stated in actions/checkout, but the default value is recursive + required: false + type: string + default: recursive + 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 + pip-install-torch-extra-args: + # NOTE: Why does this exist? + # Well setuptools / python packaging doesn't actually allow you to specify dependencies + # that come from other index URLs when you are building a package for "security" purposes. + # Unfortunately for us our nightlies (torch, torchvision, etc.) only exist on download.pytorch.org + # which means that if our users depend on things like torchvision then they need to have + # an ability to install these dependencies from download.pytorch.org, as part of the build process + # which currently the do not have the ability to do through normal means, hence this parameter + # Reference: https://discuss.python.org/t/specifying-extra-index-url-in-setup-cfg-option-dependencies/19377 + 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 + +permissions: + id-token: write + contents: read + +jobs: + build: + strategy: + fail-fast: false + matrix: ${{ fromJSON(inputs.build-matrix) }} + env: + 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 }} + name: build-${{ matrix.build_name }} + runs-on: ${{ 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' || ' ' }} + 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}" + + - uses: ./test-infra/.github/actions/setup-binary-builds-v2 + env: + PLATFORM: ${{ inputs.architecture == 'aarch64' && 'linux-aarch64' || ''}} + with: + repository: ${{ inputs.repository }} + ref: ${{ inputs.ref }} + submodules: ${{ inputs.submodules }} + setup-miniconda: false + python-version: ${{ env.PYTHON_VERSION }} + cuda-version: ${{ env.CU_VERSION }} + arch: ${{ env.ARCH }} + + - 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}" + source ${VIRTUAL_ENV}/bin/activate + # shellcheck disable=SC2086 + uv ${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}" + source ${VIRTUAL_ENV}/bin/activate + export PYTORCH_VERSION="$(uv pip show torch | grep ^Version: | sed 's/Version: *//' | sed 's/+.\+//')" + uv pip install build==1.2.2 + 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}" + source ${VIRTUAL_ENV}/bin/activate + export PYTORCH_VERSION="$(uv pip show torch | grep ^Version: | sed 's/Version: *//' | sed 's/+.\+//')" + python setup.py clean + echo "Successfully ran `python setup.py clean`" + 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}" + source ${VIRTUAL_ENV}/bin/activate + 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 + 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}" + source ${VIRTUAL_ENV}/bin/activate + WHEEL_NAME=$(ls "${{ inputs.repository }}/dist/") + echo "$WHEEL_NAME" + + uv 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" + if [[ "${PACKAGE_NAME}" = "torchrec" ]]; then + # Special case for torchrec temporarily since __version__ does not + # work correctly on main in torchrec. This block will be + # removed once we fix it. + python -c "import ${PACKAGE_NAME}" + else + python -c "import ${PACKAGE_NAME}; print('package version is ', ${PACKAGE_NAME}.__version__)" + fi + else + echo "${{ inputs.repository }}/${SMOKE_TEST_SCRIPT} found" + 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 }} + secrets: + PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}-${{ inputs.repository }}-${{ github.event_name == 'workflow_dispatch' }} + cancel-in-progress: true diff --git a/.github/workflows/test_build_wheels_linux_v2_with_cuda.yml b/.github/workflows/test_build_wheels_linux_v2_with_cuda.yml new file mode 100644 index 0000000000..6237ad0041 --- /dev/null +++ b/.github/workflows/test_build_wheels_linux_v2_with_cuda.yml @@ -0,0 +1,49 @@ +name: Test Build Linux Wheels v2 with CUDA + +on: + pull_request: + paths: + - .github/actions/setup-binary-builds-v2/action.yml + - .github/actions/binary-upload/action.yml + - .github/workflows/test_build_wheels_linux.yml + - .github/workflows/build_wheels_linux_v2.yml + - .github/workflows/generate_binary_build_matrix.yml + - .github/workflows/test_build_wheels_linux_with_cuda.yml + - tools/scripts/generate_binary_build_matrix.py + workflow_dispatch: + +permissions: + id-token: write + contents: read + +jobs: + generate-matrix: + uses: ./.github/workflows/generate_binary_build_matrix.yml + with: + package-type: wheel + os: linux + test-infra-repository: ${{ github.repository }} + test-infra-ref: ${{ github.ref }} + with-xpu: enable + test: + needs: generate-matrix + strategy: + fail-fast: false + matrix: + include: + - repository: pytorch/audio + smoke-test-script: test/smoke_test/smoke_test.py + package-name: torchaudio + uses: ./.github/workflows/build_wheels_linux_v2.yml + name: ${{ matrix.repository }} + with: + repository: ${{ matrix.repository }} + ref: nightly + test-infra-repository: ${{ github.repository }} + test-infra-ref: ${{ github.ref }} + build-matrix: ${{ needs.generate-matrix.outputs.matrix }} + pre-script: ${{ matrix.pre-script }} + post-script: ${{ matrix.post-script }} + smoke-test-script: ${{ matrix.smoke-test-script }} + package-name: ${{ matrix.package-name }} + trigger-event: "${{ github.event_name }}"