Build (Windows) / activation / mode=release / request=pr1007-activation-build-windows.yaml-508ae807abe7 #65
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build (Windows) | |
| run-name: >- | |
| Build (Windows) / ${{ inputs.kernel_name || '' }} / mode=${{ inputs.mode || 'release' }} / request=${{ inputs.dispatch_key || '' }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| kernel_name: | |
| description: "Kernel directory name to build" | |
| required: true | |
| type: string | |
| dispatch_key: | |
| description: "Unique key for matching this run back to a bot dispatch" | |
| required: false | |
| type: string | |
| mode: | |
| description: "Build mode: pr (CI only) or release (build + upload)" | |
| required: false | |
| type: string | |
| default: "release" | |
| skip_build: | |
| description: "Skip build and upload steps (for testing workflow plumbing)" | |
| required: false | |
| type: boolean | |
| default: false | |
| pr_number: | |
| description: "Optional PR number to checkout before building" | |
| required: false | |
| type: string | |
| default: "" | |
| target_branch: | |
| description: "Target branch for upload (default: repo default)" | |
| required: false | |
| type: string | |
| default: "" | |
| upload: | |
| description: "Whether to upload after build" | |
| required: false | |
| type: boolean | |
| default: true | |
| backends: | |
| description: "Comma-separated list of backends from build.toml (set by dispatch script)" | |
| required: false | |
| type: string | |
| default: "" | |
| repo_prefix: | |
| description: "Hub org prefix for uploads (e.g. kernels-community, kernels-staging)" | |
| required: false | |
| type: string | |
| default: "kernels-community" | |
| head_sha: | |
| description: "PR head SHA for posting commit statuses (empty = no status)" | |
| required: false | |
| type: string | |
| default: "" | |
| permissions: | |
| contents: read | |
| statuses: write | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | |
| cancel-in-progress: true | |
| jobs: | |
| # Post a running commit status so the PR shows the build is in progress. | |
| set-running-status: | |
| if: inputs.head_sha != '' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Set running status | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| HEAD_SHA: ${{ inputs.head_sha }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| STATUS_CONTEXT: ${{ github.workflow }} / ${{ inputs.kernel_name }} | |
| run: | | |
| gh api "repos/$REPO/statuses/$HEAD_SHA" \ | |
| -f state="pending" \ | |
| -f target_url="$RUN_URL" \ | |
| -f description="Build in progress" \ | |
| -f context="$STATUS_CONTEXT" | |
| # Build the kernel for each CUDA/XPU variant; release mode uploads to the Hub. | |
| build-kernel: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| os: [windows-2022] | |
| python: [3.12] | |
| platform: [ | |
| # CUDA platforms | |
| # { backend: 'cuda', torch_version: '2.9.1', cuda: '12.6.3', wheel: '126' }, | |
| { | |
| backend: "cuda", | |
| torch_version: "2.9.1", | |
| cuda: "12.8.1", | |
| wheel: "128", | |
| }, | |
| # { backend: 'cuda', torch_version: '2.9.1', cuda: '13.0.1', wheel: '130' }, | |
| # Intel XPU platform | |
| { | |
| backend: "xpu", | |
| torch_version: "2.10.0", | |
| oneapi: "2025.3.1", | |
| oneapi_url: "https://registrationcenter-download.intel.com/akdlm/IRC_NAS/076e961b-2c29-48a8-9203-c96f00e7051b/intel-oneapi-base-toolkit-2025.3.1.35_offline.exe", | |
| }, | |
| ] | |
| runs-on: windows-2022 | |
| steps: | |
| # Reject kernel names outside the safe charset before any step uses them. | |
| # Accepts e.g.: flash-attn3, rejects: $(myevilcommand). | |
| - name: Validate kernel name | |
| shell: pwsh | |
| env: | |
| KERNEL: ${{ inputs.kernel_name }} | |
| run: | | |
| if ("$env:KERNEL" -notmatch '^[A-Za-z0-9_-]+$') { | |
| Write-Error "Invalid kernel_name input: must match ^[A-Za-z0-9_-]+$" | |
| exit 1 | |
| } | |
| # Guard against injection via pr_number input. | |
| - name: Validate PR number | |
| if: inputs.pr_number != '' | |
| shell: pwsh | |
| env: | |
| PR_NUMBER: ${{ inputs.pr_number }} | |
| run: | | |
| if ("$env:PR_NUMBER" -notmatch '^\d+$') { | |
| Write-Error "Invalid pr_number input: must be numeric" | |
| exit 1 | |
| } | |
| # When building for a PR, check out the PR head; otherwise use default branch. | |
| - name: Checkout PR branch | |
| if: inputs.pr_number != '' | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: refs/pull/${{ inputs.pr_number }}/head | |
| fetch-depth: 0 | |
| - name: Checkout default branch | |
| if: inputs.pr_number == '' | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| # Ensure the kernel directory exists and has the required config files. | |
| - name: Validate kernel directory | |
| id: validate | |
| shell: pwsh | |
| env: | |
| KERNEL: ${{ inputs.kernel_name }} | |
| run: | | |
| $ErrorActionPreference = "Continue" | |
| $KERNEL = $env:KERNEL | |
| if ((Test-Path "$KERNEL") -and (Test-Path "$KERNEL/flake.nix") -and (Test-Path "$KERNEL/build.toml")) { | |
| echo "kernel=$KERNEL" >> $env:GITHUB_OUTPUT | |
| echo "skip=false" >> $env:GITHUB_OUTPUT | |
| } else { | |
| echo "skip=true" >> $env:GITHUB_OUTPUT | |
| } | |
| exit 0 | |
| # Check if the kernel supports this matrix backend and meets CUDA | |
| # minimum version. Backend list is passed by the dispatch script. | |
| - name: Check backend support | |
| id: check-backend | |
| if: steps.validate.outputs.skip == 'false' | |
| shell: pwsh | |
| env: | |
| KERNEL: ${{ steps.validate.outputs.kernel }} | |
| BACKENDS: ${{ inputs.backends }} | |
| run: | | |
| $KERNEL = $env:KERNEL | |
| $BACKEND = "${{ matrix.platform.backend }}" | |
| $backends = "$env:BACKENDS" -split "," | |
| if ($BACKEND -notin $backends) { | |
| Write-Output "Kernel '$KERNEL' does not support backend '$BACKEND' - skipping" | |
| echo "supported=false" >> $env:GITHUB_OUTPUT | |
| exit 0 | |
| } | |
| # Check CUDA minimum version requirement from build.toml [general.cuda] minver | |
| if ($BACKEND -eq "cuda") { | |
| $CUDA_VERSION = "${{ matrix.platform.cuda }}" | |
| $buildToml = Get-Content "${KERNEL}/build.toml" -Raw | |
| if ($buildToml -match 'minver\s*=\s*"([^"]+)"') { | |
| $minver = $matches[1] | |
| $cudaMajorMinor = ($CUDA_VERSION -split '\.')[0..1] -join '.' | |
| if ([version]$cudaMajorMinor -lt [version]$minver) { | |
| Write-Output "Kernel '$KERNEL' requires CUDA >= $minver but matrix provides $CUDA_VERSION - skipping" | |
| echo "supported=false" >> $env:GITHUB_OUTPUT | |
| exit 0 | |
| } | |
| } | |
| } | |
| Write-Output "Kernel '$KERNEL' supports backend '$BACKEND'" | |
| echo "supported=true" >> $env:GITHUB_OUTPUT | |
| # Log the kernel being built for easier debugging in CI output. | |
| - name: Kernel Info | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| shell: pwsh | |
| env: | |
| KERNEL: ${{ steps.validate.outputs.kernel }} | |
| run: | | |
| $KERNEL = $env:KERNEL | |
| Write-Output "Building Kernel: $KERNEL" | |
| # Read the pinned kernel-builder revision from flake.lock so we build | |
| # with the exact same tooling the kernel was developed against. | |
| - name: Kernel extract required builder version | |
| id: extract-builder-version | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| shell: pwsh | |
| env: | |
| KERNEL: ${{ steps.validate.outputs.kernel }} | |
| run: | | |
| $KERNEL = $env:KERNEL | |
| $lock = Get-Content "${KERNEL}/flake.lock" | ConvertFrom-Json | |
| $revision = $lock.nodes."kernel-builder".locked.rev | |
| Write-Output "Building Kernel with revision: $revision" | |
| echo "revision=$revision" >> $env:GITHUB_OUTPUT | |
| # Install the CUDA toolkit for CUDA backend builds. | |
| - uses: huggingface/cuda-toolkit@714c97b32958862237b96401fb253a4261453c3b # v0.1.0 | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true && matrix.platform.backend == 'cuda' | |
| id: setup-cuda-toolkit | |
| with: | |
| cuda: ${{ matrix.platform.cuda }} | |
| # Install Intel oneAPI for XPU builds (provides the icx-cl compiler). | |
| - name: Setup Intel oneAPI | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true && matrix.platform.backend == 'xpu' | |
| shell: pwsh | |
| run: | | |
| & "$env:GITHUB_WORKSPACE\.github\scripts\windows\install-oneapi.ps1" -OneApiVersion "${{ matrix.platform.oneapi }}" -OneApiUrl "${{ matrix.platform.oneapi_url }}" | |
| # Python is needed for PyTorch and the build toolchain. | |
| - name: Setup Python | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 | |
| with: | |
| python-version: ${{ matrix.python }} | |
| # Install backend-specific PyTorch wheel. | |
| - name: Install PyTorch (CUDA) | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true && matrix.platform.backend == 'cuda' | |
| run: pip install torch --index-url https://download.pytorch.org/whl/cu${{ matrix.platform.wheel }} | |
| - name: Install PyTorch (XPU) | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true && matrix.platform.backend == 'xpu' | |
| run: pip3 install torch==${{ matrix.platform.torch_version }} --index-url https://download.pytorch.org/whl/xpu | |
| # Check out the kernel-builder repo at the pinned revision for building. | |
| - name: Checkout kernels | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| id: checkout-kernels | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| repository: huggingface/kernels | |
| ref: "${{ steps.extract-builder-version.outputs.revision }}" | |
| path: kernels | |
| # Cache Rust compilation artifacts to speed up kernel-builder builds. | |
| - name: Cache Rust build | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 | |
| with: | |
| path: | | |
| kernels/kernel-builder/target | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| key: ${{ runner.os }}-rust-debug-${{ hashFiles('kernels/kernel-builder/Cargo.lock') }} | |
| restore-keys: | | |
| ${{ runner.os }}-rust-debug- | |
| # Build the kernel-builder CLI tool from source. | |
| - name: Build kernel-builder | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| working-directory: kernels\kernel-builder | |
| shell: pwsh | |
| run: cargo build | |
| # Compile the kernel using the Windows build script, then run | |
| # cmake local_install to create the directory layout for upload. | |
| - name: Build kernel | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true | |
| shell: pwsh | |
| env: | |
| KERNEL_SOURCE: ${{ steps.validate.outputs.kernel }} | |
| PLATFORM_BACKEND: ${{ matrix.platform.backend }} | |
| run: | | |
| # Initialize oneAPI environment for XPU builds | |
| if ($env:PLATFORM_BACKEND -eq "xpu") { | |
| $setvarsPath = "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" | |
| if (Test-Path $setvarsPath) { | |
| Write-Host "Initializing Intel oneAPI environment for XPU build..." -ForegroundColor Cyan | |
| # Create a temporary file to capture environment variables | |
| $tempFile = [System.IO.Path]::GetTempFileName() | |
| # Run setvars.bat and capture all environment variables | |
| cmd.exe /c "`"$setvarsPath`" && set > `"$tempFile`"" | |
| # Parse and set each environment variable in PowerShell | |
| Get-Content $tempFile | ForEach-Object { | |
| if ($_ -match "^(.*?)=(.*)$") { | |
| $varName = $matches[1] | |
| $varValue = $matches[2] | |
| [System.Environment]::SetEnvironmentVariable($varName, $varValue, [System.EnvironmentVariableTarget]::Process) | |
| } | |
| } | |
| Remove-Item $tempFile -ErrorAction SilentlyContinue | |
| # Verify Intel compiler is now in PATH | |
| $icxPath = (Get-Command icx-cl -ErrorAction SilentlyContinue).Path | |
| if ($icxPath) { | |
| Write-Host "Intel oneAPI environment initialized successfully" -ForegroundColor Green | |
| Write-Host "Intel C++ Compiler found at: $icxPath" -ForegroundColor Green | |
| } else { | |
| Write-Error "Intel compiler (icx-cl) still not found in PATH after initialization" | |
| exit 1 | |
| } | |
| } else { | |
| Write-Error "setvars.bat not found at $setvarsPath" | |
| exit 1 | |
| } | |
| } | |
| & "$env:GITHUB_WORKSPACE\kernels\nix-builder\scripts\windows\builder.ps1" -Backend $env:PLATFORM_BACKEND -SourceFolder "$env:KERNEL_SOURCE" -BuildConfig Release -Build | |
| # Run the local_install target to create the correct directory structure for kernels upload | |
| # This installs to build/<variant>/<package>/ which is what kernels CLI expects | |
| Push-Location "$env:KERNEL_SOURCE\build" | |
| cmake --build . --config Release --target local_install | |
| Pop-Location | |
| # Upload built artifacts to both model and kernel Hub repos. | |
| - name: Upload kernel to Hub | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true && inputs.mode != 'pr' && inputs.upload != false | |
| shell: pwsh | |
| env: | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| KERNEL_SOURCE: ${{ steps.validate.outputs.kernel }} | |
| REPO_PREFIX: ${{ inputs.repo_prefix }} | |
| TARGET_BRANCH: ${{ inputs.target_branch }} | |
| run: | | |
| $KB = "$env:GITHUB_WORKSPACE\kernels\kernel-builder\target\debug\kernel-builder.exe" | |
| $branchArgs = @() | |
| if ($env:TARGET_BRANCH -ne "") { | |
| $branchArgs = @("--branch", $env:TARGET_BRANCH) | |
| } | |
| # Upload to both model and kernel repo types | |
| & $KB upload "$env:KERNEL_SOURCE\build" --repo-type kernel --repo-id "$env:REPO_PREFIX/$env:KERNEL_SOURCE" @branchArgs | |
| # v1 kernels without an explicit branch override also get uploaded to main. | |
| - name: Upload v1 kernels to main | |
| if: steps.validate.outputs.skip == 'false' && steps.check-backend.outputs.supported == 'true' && inputs.skip_build != true && inputs.mode != 'pr' && inputs.upload != false && inputs.target_branch == '' | |
| shell: pwsh | |
| env: | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| KERNEL_SOURCE: ${{ steps.validate.outputs.kernel }} | |
| REPO_PREFIX: ${{ inputs.repo_prefix }} | |
| run: | | |
| $KB = "$env:GITHUB_WORKSPACE\kernels\kernel-builder\target\debug\kernel-builder.exe" | |
| # Check if build.toml exists and has version = 1 | |
| $buildTomlPath = "$env:KERNEL_SOURCE\build.toml" | |
| if (Test-Path $buildTomlPath) { | |
| $content = Get-Content $buildTomlPath -Raw | |
| if ($content -match '(?m)^\s*version\s*=\s*1\s*(\r)?$' -and $content -notmatch '(?m)^\s*branch\s*=') { | |
| Write-Host "Kernel version is 1 and no branch override, uploading to main branch..." | |
| & $KB upload "$env:KERNEL_SOURCE\build" --repo-type kernel --repo-id "$env:REPO_PREFIX/$env:KERNEL_SOURCE" --branch main | |
| } else { | |
| Write-Host "Kernel version is not 1 or branch is overridden, skipping main branch upload" | |
| } | |
| } else { | |
| Write-Host "build.toml not found, skipping main branch upload" | |
| } | |
| # Report the final build outcome as a commit status on the PR head SHA. | |
| report-status: | |
| if: always() && inputs.head_sha != '' | |
| needs: [build-kernel] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Set commit status | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| REPO: ${{ github.repository }} | |
| HEAD_SHA: ${{ inputs.head_sha }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| STATUS_CONTEXT: ${{ github.workflow }} / ${{ inputs.kernel_name }} | |
| run: | | |
| BUILD="${{ needs.build-kernel.result }}" | |
| if [ "$BUILD" = "success" ]; then | |
| STATE="success" | |
| DESC="Build passed" | |
| elif [ "$BUILD" = "failure" ]; then | |
| STATE="failure" | |
| DESC="Build failed" | |
| else | |
| STATE="error" | |
| DESC="Build did not complete (${BUILD})" | |
| fi | |
| gh api "repos/$REPO/statuses/$HEAD_SHA" \ | |
| -f state="$STATE" \ | |
| -f target_url="$RUN_URL" \ | |
| -f description="$DESC" \ | |
| -f context="$STATUS_CONTEXT" |