diff --git a/.github/workflows/refresh-build-dependencies.yml b/.github/workflows/refresh-build-dependencies.yml index ca56de461..45a360a6d 100644 --- a/.github/workflows/refresh-build-dependencies.yml +++ b/.github/workflows/refresh-build-dependencies.yml @@ -130,18 +130,30 @@ jobs: - name: Linux build artifact: linux lock: requirements-build-linux.txt - versions: "3.10 3.11 3.12 3.13 3.14" + versions: "3.10 3.11 3.12 3.13 3.14 3.15" platforms: "x86_64-manylinux_2_28 aarch64-manylinux_2_28 x86_64-unknown-linux-musl aarch64-unknown-linux-musl" - name: Linux test artifact: linux lock: requirements-test-linux.txt versions: "3.10 3.11 3.12 3.13 3.14" platforms: "x86_64-manylinux_2_28 aarch64-manylinux_2_28 x86_64-unknown-linux-musl aarch64-unknown-linux-musl" + - name: Linux test Python 3.15 + artifact: linux + lock: requirements-test-linux.txt + versions: "3.15" + platforms: "x86_64-manylinux_2_28 aarch64-manylinux_2_28 x86_64-unknown-linux-musl aarch64-unknown-linux-musl" + allowSourceBuilds: true - name: macOS artifact: macos lock: requirements-build-macos.txt versions: "3.10 3.11 3.12 3.13 3.14" platforms: "x86_64-apple-darwin aarch64-apple-darwin" + - name: macOS Python 3.15 + artifact: macos + lock: requirements-build-macos.txt + versions: "3.15" + platforms: "x86_64-apple-darwin aarch64-apple-darwin" + allowSourceBuilds: true # Windows ARM64 stages install build tools into the x64 host # interpreter before cross-compiling the target extension. - name: Windows build host @@ -149,6 +161,12 @@ jobs: lock: requirements-build-windows.txt versions: "3.10 3.11 3.12 3.13 3.14" platforms: "x86_64-pc-windows-msvc" + - name: Windows build host Python 3.15 + artifact: windows + lock: requirements-build-windows.txt + versions: "3.15" + platforms: "x86_64-pc-windows-msvc" + allowSourceBuilds: true - name: ODBC artifact: odbc lock: requirements-build-odbc.txt @@ -168,8 +186,11 @@ jobs: LOCK_FILE: generated-lock/${{ matrix.lock }} PLATFORMS: ${{ matrix.platforms }} PYTHON_VERSIONS: ${{ matrix.versions }} + ALLOW_SOURCE_BUILDS: ${{ matrix.allowSourceBuilds || false }} run: | set -euo pipefail + binary_args=(--only-binary :all:) + if [ "$ALLOW_SOURCE_BUILDS" = true ]; then binary_args=(); fi for platform in $PLATFORMS; do for version in $PYTHON_VERSIONS; do echo "Validating $LOCK_FILE for Python $version on $platform" @@ -179,7 +200,7 @@ jobs: --target "$RUNNER_TEMP/lock-validation" \ --python-version "$version" \ --python-platform "$platform" \ - --only-binary :all: \ + "${binary_args[@]}" \ --require-hashes \ --default-index https://pypi.org/simple \ -r "$LOCK_FILE" diff --git a/OneBranchPipelines/build-release-package-pipeline.yml b/OneBranchPipelines/build-release-package-pipeline.yml index b5b719cef..bf0904658 100644 --- a/OneBranchPipelines/build-release-package-pipeline.yml +++ b/OneBranchPipelines/build-release-package-pipeline.yml @@ -2,9 +2,9 @@ # OneBranch Release Pipeline for mssql-python # ========================================================================================= # Builds Python wheels for all supported platforms with SDL compliance: -# - Windows: Python 3.10-3.14 (x64 + ARM64) -# - macOS: Python 3.10-3.14 (Universal2 = x86_64 + ARM64 in single binary) -# - Linux: Python 3.10-3.14 on manylinux/musllinux (x86_64 + ARM64) +# - Windows: Python 3.10-3.15 (x64 + ARM64) +# - macOS: Python 3.10-3.15 (Universal2 = x86_64 + ARM64 in single binary) +# - Linux: Python 3.10-3.15 on manylinux/musllinux (x86_64 + ARM64) # # Security Features: # - ESRP code signing (Windows .pyd files only) @@ -82,19 +82,19 @@ parameters: # PLATFORM CONFIGURATIONS # ========================= # Each platform uses different matrix strategy: - # - Windows: Explicit per-version stages (9 stages for x64/ARM64 combos) - # - macOS: Explicit per-version stages (5 stages for universal2 builds) + # - Windows: Explicit per-version stages (11 stages for x64/ARM64 combos) + # - macOS: Explicit per-version stages (6 stages for universal2 builds) # - Linux: Per-distro stages, builds ALL Python versions in loop (4 stages) # Windows Configuration Matrix # Each entry creates separate stage: Win_py_ - # pyVer format: '310' = Python 3.10, '314' = Python 3.14 + # pyVer format: '310' = Python 3.10, '315' = Python 3.15 # arch: 'x64' (Intel/AMD 64-bit) or 'arm64' (ARM64, cross-compiled on x64) # Note: ARM64 builds use x64 host with ARM64 python.lib for cross-compilation - name: windowsConfigs type: object default: - # x64 builds (5 versions: 3.10-3.14) + # x64 builds (6 versions: 3.10-3.15) - pyVer: '310' arch: 'x64' - pyVer: '311' @@ -105,7 +105,9 @@ parameters: arch: 'x64' - pyVer: '314' arch: 'x64' - # ARM64 builds (4 versions: 3.11-3.14) + - pyVer: '315' + arch: 'x64' + # ARM64 builds (5 versions: 3.11-3.15) # 3.10 excluded due to limited ARM64 support - pyVer: '311' arch: 'arm64' @@ -115,23 +117,26 @@ parameters: arch: 'arm64' - pyVer: '314' arch: 'arm64' + - pyVer: '315' + arch: 'arm64' # macOS Configuration Matrix # Each entry creates separate stage: MacOS_py # All builds are Universal2 (x86_64 + ARM64 in single binary) - # pyVer format: '310' = Python 3.10, '314' = Python 3.14 + # pyVer format: '310' = Python 3.10, '315' = Python 3.15 - name: macosConfigs type: object default: - # 5 versions: 3.10-3.14 (all universal2) + # 6 versions: 3.10-3.15 (all universal2) - pyVer: '310' - pyVer: '311' - pyVer: '312' - pyVer: '313' - pyVer: '314' + - pyVer: '315' # Linux Configuration Matrix - # Each entry creates ONE stage that builds ALL Python versions (3.10-3.14) + # Each entry creates ONE stage that builds ALL Python versions (3.10-3.15) # tag: 'manylinux' (glibc-based, e.g., Ubuntu/CentOS) or 'musllinux' (musl-based, e.g., Alpine) # arch: CPU architecture for Docker platform # platform: Docker platform identifier for multi-arch builds @@ -375,17 +380,17 @@ extends: # ========================= # PIPELINE STAGES # ========================= - # mssql-python: 9 Windows + 5 macOS + 4 Linux + 1 Consolidate = 19 stages + # mssql-python: 11 Windows + 6 macOS + 4 Linux + 1 Consolidate = 22 stages # mssql-python-odbc: 1 ODBC_BuildAll (single host, all 7 wheels) + 1 ConsolidateOdbc = 2 stages - # Total: 21 stages, always built together. The mssql-python build stages depend on + # Total: 24 stages, always built together. The mssql-python build stages depend on # ConsolidateOdbc so they install the external ODBC wheel before pytest. stages: # ========================= # WINDOWS BUILD STAGES # ========================= # Strategy: Explicit stage per Python version × architecture - # Total: 9 stages (5 x64 + 4 ARM64) - # Python versions: 3.10-3.14 (x64), 3.11-3.14 (ARM64) + # Total: 11 stages (6 x64 + 5 ARM64) + # Python versions: 3.10-3.15 (x64), 3.11-3.15 (ARM64) # Each stage: # 1. Installs Python (UsePythonVersion or NuGet for 3.14) # 2. Downloads ARM64 python.lib if cross-compiling @@ -416,7 +421,7 @@ extends: # MACOS BUILD STAGES # ========================= # Strategy: Explicit stage per Python version - # Total: 5 stages (3.10-3.14) + # Total: 6 stages (3.10-3.15) # All builds are Universal2 (x86_64 + ARM64 in single .so binary) # Each stage: # 1. Installs Python via UsePythonVersion@0 @@ -446,7 +451,7 @@ extends: # ========================= # Strategy: One stage per distribution × architecture # Total: 4 stages (manylinux_2_28×2 + musllinux×2) - # Each stage builds ALL Python versions (3.10-3.14) in a loop + # Each stage builds ALL Python versions (3.10-3.15) in a loop # Distributions: # - manylinux_2_28: glibc 2.28+ (RHEL 8, Ubuntu 20.04+, etc.) — forward-compatible with newer glibc # - musllinux: musl-based (Alpine Linux) @@ -454,12 +459,12 @@ extends: # Each stage: # 1. Starts PyPA Docker container (manylinux_2_28 or musllinux_1_2) # 2. Starts SQL Server Docker container - # 3. For each Python version (cp310-cp314): + # 3. For each Python version (cp310-cp315): # a. Builds .so native extension # b. Builds wheel # c. Installs wheel in isolated directory # d. Runs pytest against SQL Server - # 4. Publishes artifacts (all 5 wheels) + # 4. Publishes artifacts (all 6 wheels) # 5. Component Governance + AntiMalware scanning - ${{ each config in parameters.linuxConfigs }}: - template: /OneBranchPipelines/stages/build-linux-single-stage.yml@self @@ -479,7 +484,7 @@ extends: # CONSOLIDATE STAGE # ========================= # Purpose: Collect all artifacts from platform builds into single dist/ folder - # Dependencies: All 18 build stages (9 Windows + 5 macOS + 4 Linux) + # Dependencies: All 21 build stages (11 Windows + 6 macOS + 4 Linux) # Stages run in parallel, Consolidate waits for ALL to complete # Outputs: # - dist/wheels/*.whl (all platform wheels) @@ -490,22 +495,25 @@ extends: - stage: Consolidate displayName: 'Consolidate All Artifacts' dependsOn: - # Windows dependencies (9 stages) + # Windows dependencies (11 stages) - Win_py310_x64 - Win_py311_x64 - Win_py312_x64 - Win_py313_x64 - Win_py314_x64 + - Win_py315_x64 - Win_py311_arm64 - Win_py312_arm64 - Win_py313_arm64 - Win_py314_arm64 - # macOS dependencies (5 stages) + - Win_py315_arm64 + # macOS dependencies (6 stages) - MacOS_py310 - MacOS_py311 - MacOS_py312 - MacOS_py313 - MacOS_py314 + - MacOS_py315 # Linux dependencies (4 stages) - Linux_manylinux_2_28_x86_64 - Linux_manylinux_2_28_aarch64 diff --git a/OneBranchPipelines/jobs/consolidate-artifacts-job.yml b/OneBranchPipelines/jobs/consolidate-artifacts-job.yml index 5ca4c5efe..d2b7b9ff1 100644 --- a/OneBranchPipelines/jobs/consolidate-artifacts-job.yml +++ b/OneBranchPipelines/jobs/consolidate-artifacts-job.yml @@ -1,7 +1,7 @@ # Consolidate Artifacts Job Template # Downloads artifacts from all platform build stages and consolidates into single dist/ folder -# Works with individual stage artifacts (18 stages total: 9 Windows + 5 macOS + 4 Linux) -# Each Linux stage builds 5 Python versions (3.10-3.14), resulting in 34 total wheels +# Works with individual stage artifacts (21 stages total: 11 Windows + 6 macOS + 4 Linux) +# Each Linux stage builds 6 Python versions (3.10-3.15), resulting in 41 total wheels parameters: - name: oneBranchType type: string @@ -75,17 +75,17 @@ jobs: echo "" WHEEL_COUNT=$(ls -1 $(ob_outputDirectory)/dist/*.whl 2>/dev/null | wc -l) echo "Total wheel count: $WHEEL_COUNT" - echo "Expected: 34 wheels (9 Windows + 5 macOS + 20 Linux)" + echo "Expected: 41 wheels (11 Windows + 6 macOS + 24 Linux)" # Hard-fail on a wheel-count mismatch (symmetric with the odbc consolidate job). # A mismatch means a build stage silently produced a partial set (e.g. a missing # Python version) or the build matrix changed without updating this count. - # Update the expected 34 whenever the Windows/macOS/Linux build matrix changes. - if [ "$WHEEL_COUNT" -ne 34 ]; then - echo "ERROR: Expected 34 wheels but found $WHEEL_COUNT" >&2 + # Update the expected 41 whenever the Windows/macOS/Linux build matrix changes. + if [ "$WHEEL_COUNT" -ne 41 ]; then + echo "ERROR: Expected 41 wheels but found $WHEEL_COUNT" >&2 exit 1 else - echo "SUCCESS: All 34 wheels consolidated!" + echo "SUCCESS: All 41 wheels consolidated!" fi displayName: 'Consolidate wheels from all platforms' diff --git a/OneBranchPipelines/stages/build-linux-single-stage.yml b/OneBranchPipelines/stages/build-linux-single-stage.yml index 62b500b5a..06565f34b 100644 --- a/OneBranchPipelines/stages/build-linux-single-stage.yml +++ b/OneBranchPipelines/stages/build-linux-single-stage.yml @@ -1,6 +1,6 @@ # Linux Single Configuration Stage Template # Builds Python wheels for a specific Linux distribution and architecture -# Builds for Python 3.10, 3.11, 3.12, 3.13, 3.14 within single job +# Builds for Python 3.10, 3.11, 3.12, 3.13, 3.14, 3.15 within single job # Tests each wheel after building with isolated pytest execution parameters: # Stage identifier (e.g., 'Linux_manylinux_2_28_x86_64') @@ -256,14 +256,14 @@ stages: ls -1 "$(Build.SourcesDirectory)/odbc_wheels"/*.whl displayName: 'Flatten ODBC wheels for pip find-links' - # Build wheels for all Python versions (3.10-3.14) and test each one + # Build wheels for all Python versions (3.10-3.15) and test each one - script: | set -euo pipefail if [[ "$(LINUX_TAG)" == "manylinux_2_28" ]]; then SHELL_EXE=bash; else SHELL_EXE=sh; fi docker exec build-$(LINUX_TAG)-$(ARCH) $SHELL_EXE -lc 'mkdir -p /workspace/dist' # Loop through all Python versions: build wheel -> test wheel -> repeat - for PYBIN in cp310 cp311 cp312 cp313 cp314; do + for PYBIN in cp310 cp311 cp312 cp313 cp314 cp315; do echo "" echo "=====================================================" echo "Building and testing $PYBIN on $(LINUX_TAG)/$(ARCH)" @@ -440,7 +440,7 @@ stages: echo "=====================================================" echo "✓ All Python versions built and tested successfully!" echo "=====================================================" - displayName: 'Build and test wheels for Python 3.10-3.14' + displayName: 'Build and test wheels for Python 3.10-3.15' env: DB_PASSWORD: $(DB_PASSWORD) diff --git a/OneBranchPipelines/stages/build-windows-single-stage.yml b/OneBranchPipelines/stages/build-windows-single-stage.yml index a81e045db..b1c8cdbb3 100644 --- a/OneBranchPipelines/stages/build-windows-single-stage.yml +++ b/OneBranchPipelines/stages/build-windows-single-stage.yml @@ -201,6 +201,7 @@ stages: "3.12" { "3.12.7" } "3.13" { "3.13.0" } "3.14" { "3.14.0" } + "3.15" { "3.15.0" } } $nugetUrl = "https://www.nuget.org/api/v2/package/pythonarm64/$nugetVersion"