From 08f8753f7112793d7c405c21cfd2f9555958be30 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 11:47:23 -0400 Subject: [PATCH 01/24] ci: add windows-cmake cloudbuild --- ci/cloudbuild/builds/windows-startup.ps1 | 101 +++++++++++++++++++ ci/cloudbuild/triggers/windows-cmake-ci.yaml | 29 ++++++ ci/cloudbuild/triggers/windows-cmake-pr.yaml | 30 ++++++ ci/cloudbuild/windows.yaml | 97 ++++++++++++++++++ 4 files changed, 257 insertions(+) create mode 100644 ci/cloudbuild/builds/windows-startup.ps1 create mode 100644 ci/cloudbuild/triggers/windows-cmake-ci.yaml create mode 100644 ci/cloudbuild/triggers/windows-cmake-pr.yaml create mode 100644 ci/cloudbuild/windows.yaml diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 new file mode 100644 index 0000000000000..b6f867c57b246 --- /dev/null +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -0,0 +1,101 @@ +# Setup log output redirection +$LogPath = "C:\build.log" +Start-Transcript -Path $LogPath + +try { + # 1. Fetch metadata values + $MetadataUrl = "http://metadata.google.internal/computeMetadata/v1/instance/attributes" + $Headers = @{"Metadata-Flavor"="Google"} + + $SourceArchive = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/source-archive" + $BuildType = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/build-type" + $Features = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/features" + $LogsBucket = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/logs-bucket" + $VcpkgVersion = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/vcpkg-version" + + Write-Host "Source Archive: $SourceArchive" + Write-Host "Build Type: $BuildType" + Write-Host "Features: $Features" + Write-Host "Vcpkg Version: $VcpkgVersion" + + # 2. Ensure Git is installed and in the PATH + if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + Write-Host "Installing Git..." + choco install -y git --no-progress + $env:Path += ";C:\Program Files\Git\cmd" + } + + # 3. Ensure CMake is installed and in the PATH + if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { + Write-Host "Installing CMake..." + choco install -y cmake --version 3.31.6 --no-progress + $env:Path += ";C:\Program Files\CMake\bin" + } + + # 4. Download and Install sccache + Write-Host "Installing sccache..." + $SccacheDir = "C:\sccache" + New-Item -ItemType Directory -Force -Path $SccacheDir + $SccacheUrl = "https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-pc-windows-msvc.tar.gz" + Invoke-WebRequest -Uri $SccacheUrl -OutFile "$SccacheDir\sccache.tar.gz" + tar -xzf "$SccacheDir\sccache.tar.gz" -C $SccacheDir --strip-components=1 + $env:Path += ";$SccacheDir" + + # 5. Download and bootstrap vcpkg + Write-Host "Setting up vcpkg..." + $VcpkgDir = "C:\vcpkg" + New-Item -ItemType Directory -Force -Path $VcpkgDir + $VcpkgUrl = "https://github.com/microsoft/vcpkg/archive/$VcpkgVersion.tar.gz" + Invoke-WebRequest -Uri $VcpkgUrl -OutFile "$VcpkgDir\vcpkg.tar.gz" + tar -xzf "$VcpkgDir\vcpkg.tar.gz" -C $VcpkgDir --strip-components=1 + & "$VcpkgDir\bootstrap-vcpkg.sh" -disableMetrics + + # 6. Extract workspace source codebase + Write-Host "Extracting source..." + $Workspace = "C:\workspace" + New-Item -ItemType Directory -Force -Path $Workspace + Set-Location $Workspace + gcloud storage cp $SourceArchive source.tar.gz + tar -xzf source.tar.gz + Remove-Item source.tar.gz + + # 7. Configure environment for build + $env:VCPKG_ROOT = $VcpkgDir + $env:CMAKE_OUT = "C:\b" # Directory for build output (keep it short) + $env:EXECUTE_INTEGRATION_TESTS = "false" + + # 8. Run MSVC Developer Environment Config + # Locates and runs vcvarsall.bat to configure compile paths + Write-Host "Locating VS / MSVC compiler..." + $VsInstallPath = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath + if (-not $VsInstallPath) { + throw "Visual Studio installation not found!" + } + $VcVarsPath = Join-Path $VsInstallPath "VC\Auxiliary\Build\vcvarsall.x64.bat" + Write-Host "Running vcvarsall.bat: $VcVarsPath" + cmd.exe /c "`"$VcVarsPath`" && set" | Foreach-Object { + if ($_ -match "^(.*?)=(.*)$") { + Set-Content "env:\$($Matches[1])" $Matches[2] + } + } + + # 9. Run the build script using Git Bash + $GitBashPath = "C:\Program Files\Git\bin\bash.exe" + Write-Host "Executing windows-cmake.sh..." + & $GitBashPath -c "ci/gha/builds/windows-cmake.sh $BuildType $Features" + + # Report success status + $Status = @{ status = "success" } + $Status | ConvertTo-Json | Out-File -FilePath "C:\status.json" -Encoding ascii +} +catch { + Write-Host "Error occurred during build: $_" + $Status = @{ status = "failed"; error = $_.Exception.Message } + $Status | ConvertTo-Json | Out-File -FilePath "C:\status.json" -Encoding ascii +} +finally { + Stop-Transcript + # Upload final logs and status to GCS bucket + gcloud storage cp C:\build.log "$LogsBucket/build.log" + gcloud storage cp C:\status.json "$LogsBucket/status.json" +} diff --git a/ci/cloudbuild/triggers/windows-cmake-ci.yaml b/ci/cloudbuild/triggers/windows-cmake-ci.yaml new file mode 100644 index 0000000000000..0973123be5fef --- /dev/null +++ b/ci/cloudbuild/triggers/windows-cmake-ci.yaml @@ -0,0 +1,29 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +filename: ci/cloudbuild/windows.yaml +github: + name: google-cloud-cpp + owner: googleapis + push: + branch: main +includeBuildLogs: INCLUDE_BUILD_LOGS_WITH_STATUS +name: windows-cmake-ci +substitutions: + _BUILD_TYPE: Release + _FEATURES: all # Run full features on pushes to main + _TRIGGER_TYPE: ci +tags: +- ci +- windows diff --git a/ci/cloudbuild/triggers/windows-cmake-pr.yaml b/ci/cloudbuild/triggers/windows-cmake-pr.yaml new file mode 100644 index 0000000000000..2a5ff4e6c0c9c --- /dev/null +++ b/ci/cloudbuild/triggers/windows-cmake-pr.yaml @@ -0,0 +1,30 @@ +# Copyright 2026 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +filename: ci/cloudbuild/windows.yaml +github: + name: google-cloud-cpp + owner: googleapis + pullRequest: + branch: main + commentControl: COMMENTS_ENABLED_FOR_EXTERNAL_CONTRIBUTORS_ONLY +includeBuildLogs: INCLUDE_BUILD_LOGS_WITH_STATUS +name: windows-cmake-pr +substitutions: + _BUILD_TYPE: Debug + _FEATURES: storage # Subset of features for PR builds to run faster + _TRIGGER_TYPE: pr +tags: +- pr +- windows diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml new file mode 100644 index 0000000000000..0a8d1946470c0 --- /dev/null +++ b/ci/cloudbuild/windows.yaml @@ -0,0 +1,97 @@ +options: + dynamic_substitutions: true + substitutionOption: 'ALLOW_LOOSE' + +substitutions: + _ZONE: 'us-east1-b' + _MACHINE_TYPE: 'n2-standard-16' # 16 vCPUs, 64 GB RAM for fast compilation + _IMAGE_FAMILY: 'windows-server-2022-dc-core-cplusplus' # Public image family with VS and MSVC + _IMAGE_PROJECT: 'windows-cloud' + _SERVICE_ACCOUNT: 'windows-builder-sa@cloud-cpp-testing-resources.iam.gserviceaccount.com' + _CACHE_BUCKET: 'cloud-cpp-testing-resources_cloudbuild' + _LOGS_BUCKET: 'cloud-cpp-testing-resources_cloudbuild' + _BUILD_TYPE: 'Release' + _FEATURES: 'storage' + +steps: + # Step 1: Compress and upload workspace source code to GCS + - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' + id: 'upload-source' + entrypoint: 'bash' + args: + - '-c' + - | + tar --exclude='.git' -czf "source-${BUILD_ID}.tar.gz" . + gcloud storage cp "source-${BUILD_ID}.tar.gz" "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" + rm "source-${BUILD_ID}.tar.gz" + + # Step 2: Create ephemeral GCE Windows Instance and run startup script + - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' + id: 'create-vm' + entrypoint: 'bash' + args: + - '-c' + - | + vcpkg_version=$(cat ci/etc/vcpkg-version.txt) + gcloud compute instances create "wincmake-${BUILD_ID}" \ + --project="${PROJECT_ID}" \ + --zone="${_ZONE}" \ + --machine-type="${_MACHINE_TYPE}" \ + --image-family="${_IMAGE_FAMILY}" \ + --image-project="${_IMAGE_PROJECT}" \ + --service-account="${_SERVICE_ACCOUNT}" \ + --scopes="https://www.googleapis.com/auth/cloud-platform" \ + --metadata="source-archive=gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz,build-type=${_BUILD_TYPE},features=${_FEATURES},logs-bucket=gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID},vcpkg-version=${vcpkg_version}" \ + --metadata-from-file="windows-startup-script-ps1=ci/cloudbuild/builds/windows-startup.ps1" + + # Step 3: Poll GCS for status file and stream build logs + - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' + id: 'poll-build-status' + entrypoint: 'bash' + args: + - '-c' + - | + echo "Waiting for build completion..." + # Wait a bit for the VM to start up and begin writing logs + sleep 60 + + # Read the logs continuously + gcloud storage cp "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/build.log" build.log 2>/dev/null || touch build.log + log_lines=$(wc -l < build.log) + + until gcloud storage objects describe "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/status.json" >/dev/null 2>&1; do + sleep 20 + if gcloud storage cp "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/build.log" build.log 2>/dev/null; then + new_lines=$(wc -l < build.log) + if [ "$new_lines" -gt "$log_lines" ]; then + tail -n +"$((log_lines + 1))" build.log + log_lines=$new_lines + fi + fi + done + + # Output final logs and verify success status + gcloud storage cp "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/build.log" build.log 2>/dev/null + new_lines=$(wc -l < build.log) + if [ "$new_lines" -gt "$log_lines" ]; then + tail -n +"$((log_lines + 1))" build.log + fi + + status=$(gcloud storage cat "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/status.json" | grep -o '"status": "[^"]*' | cut -d'"' -f4) + if [ "$status" != "success" ]; then + echo "Build failed!" + exit 1 + fi + +# Step 4: Ensure VM cleanup (runs always, even if compilation or polling fails) +teardown: + - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' + id: 'cleanup-vm' + entrypoint: 'bash' + allowFailure: true + waitFor: ['-'] + args: + - '-c' + - | + gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet + gcloud storage rm "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" || true From f5a2d2f3025d9e5b6497f9b54861646213b7f350 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 11:54:12 -0400 Subject: [PATCH 02/24] refactor teardown step to bash exit trap --- ci/cloudbuild/windows.yaml | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 0a8d1946470c0..5143e87075c51 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -44,13 +44,20 @@ steps: --metadata="source-archive=gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz,build-type=${_BUILD_TYPE},features=${_FEATURES},logs-bucket=gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID},vcpkg-version=${vcpkg_version}" \ --metadata-from-file="windows-startup-script-ps1=ci/cloudbuild/builds/windows-startup.ps1" - # Step 3: Poll GCS for status file and stream build logs + # Step 3: Poll GCS for status file and stream build logs, then clean up GCE VM - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' id: 'poll-build-status' entrypoint: 'bash' args: - '-c' - | + cleanup() { + echo "Cleaning up VM and source archive..." + gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet || true + gcloud storage rm "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" || true + } + trap cleanup EXIT + echo "Waiting for build completion..." # Wait a bit for the VM to start up and begin writing logs sleep 60 @@ -82,16 +89,3 @@ steps: echo "Build failed!" exit 1 fi - -# Step 4: Ensure VM cleanup (runs always, even if compilation or polling fails) -teardown: - - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' - id: 'cleanup-vm' - entrypoint: 'bash' - allowFailure: true - waitFor: ['-'] - args: - - '-c' - - | - gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet - gcloud storage rm "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" || true From c924627d63fa671ce6c7dc4494476608553169f6 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 12:01:09 -0400 Subject: [PATCH 03/24] install msvc manually --- ci/cloudbuild/builds/windows-startup.ps1 | 6 ++++++ ci/cloudbuild/windows.yaml | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index b6f867c57b246..ce316b86e43fc 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -65,6 +65,12 @@ try { $env:EXECUTE_INTEGRATION_TESTS = "false" # 8. Run MSVC Developer Environment Config + # Ensure Visual Studio 2022 Build Tools with C++ workload is installed + if (-not (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe")) { + Write-Host "Installing Visual Studio 2022 Build Tools..." + choco install -y visualstudio2022buildtools --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.22000 --includeRecommended --quiet --noclose" --no-progress + } + # Locates and runs vcvarsall.bat to configure compile paths Write-Host "Locating VS / MSVC compiler..." $VsInstallPath = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 5143e87075c51..80f55a1a93b90 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -5,7 +5,7 @@ options: substitutions: _ZONE: 'us-east1-b' _MACHINE_TYPE: 'n2-standard-16' # 16 vCPUs, 64 GB RAM for fast compilation - _IMAGE_FAMILY: 'windows-server-2022-dc-core-cplusplus' # Public image family with VS and MSVC + _IMAGE_FAMILY: 'windows-2022' # Public image family _IMAGE_PROJECT: 'windows-cloud' _SERVICE_ACCOUNT: 'windows-builder-sa@cloud-cpp-testing-resources.iam.gserviceaccount.com' _CACHE_BUCKET: 'cloud-cpp-testing-resources_cloudbuild' From 91b21517445cc2a12e1d34f5a4feef83aa95982a Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 13:01:57 -0400 Subject: [PATCH 04/24] install choco if missing --- ci/cloudbuild/builds/windows-startup.ps1 | 27 +++++++++++++++++------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index ce316b86e43fc..a1edc060d96e6 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -18,21 +18,32 @@ try { Write-Host "Features: $Features" Write-Host "Vcpkg Version: $VcpkgVersion" - # 2. Ensure Git is installed and in the PATH + # 2. Ensure Chocolatey is installed + if (-not (Get-Command choco -ErrorAction SilentlyContinue)) { + if (-not (Test-Path "C:\ProgramData\chocolatey\bin\choco.exe")) { + Write-Host "Installing Chocolatey..." + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + } + $env:Path += ";C:\ProgramData\chocolatey\bin" + } + + # 3. Ensure Git is installed and in the PATH if (-not (Get-Command git -ErrorAction SilentlyContinue)) { Write-Host "Installing Git..." choco install -y git --no-progress $env:Path += ";C:\Program Files\Git\cmd" } - # 3. Ensure CMake is installed and in the PATH + # 4. Ensure CMake is installed and in the PATH if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { Write-Host "Installing CMake..." choco install -y cmake --version 3.31.6 --no-progress $env:Path += ";C:\Program Files\CMake\bin" } - # 4. Download and Install sccache + # 5. Download and Install sccache Write-Host "Installing sccache..." $SccacheDir = "C:\sccache" New-Item -ItemType Directory -Force -Path $SccacheDir @@ -41,7 +52,7 @@ try { tar -xzf "$SccacheDir\sccache.tar.gz" -C $SccacheDir --strip-components=1 $env:Path += ";$SccacheDir" - # 5. Download and bootstrap vcpkg + # 6. Download and bootstrap vcpkg Write-Host "Setting up vcpkg..." $VcpkgDir = "C:\vcpkg" New-Item -ItemType Directory -Force -Path $VcpkgDir @@ -50,7 +61,7 @@ try { tar -xzf "$VcpkgDir\vcpkg.tar.gz" -C $VcpkgDir --strip-components=1 & "$VcpkgDir\bootstrap-vcpkg.sh" -disableMetrics - # 6. Extract workspace source codebase + # 7. Extract workspace source codebase Write-Host "Extracting source..." $Workspace = "C:\workspace" New-Item -ItemType Directory -Force -Path $Workspace @@ -59,12 +70,12 @@ try { tar -xzf source.tar.gz Remove-Item source.tar.gz - # 7. Configure environment for build + # 8. Configure environment for build $env:VCPKG_ROOT = $VcpkgDir $env:CMAKE_OUT = "C:\b" # Directory for build output (keep it short) $env:EXECUTE_INTEGRATION_TESTS = "false" - # 8. Run MSVC Developer Environment Config + # 9. Run MSVC Developer Environment Config # Ensure Visual Studio 2022 Build Tools with C++ workload is installed if (-not (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe")) { Write-Host "Installing Visual Studio 2022 Build Tools..." @@ -85,7 +96,7 @@ try { } } - # 9. Run the build script using Git Bash + # 10. Run the build script using Git Bash $GitBashPath = "C:\Program Files\Git\bin\bash.exe" Write-Host "Executing windows-cmake.sh..." & $GitBashPath -c "ci/gha/builds/windows-cmake.sh $BuildType $Features" From 230cfe8b56c837ec6dfd62dc5bd9a1be6d738eb0 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 13:24:13 -0400 Subject: [PATCH 05/24] expand search for msvc --- ci/cloudbuild/builds/windows-startup.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index a1edc060d96e6..856aa31093b5a 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -84,7 +84,7 @@ try { # Locates and runs vcvarsall.bat to configure compile paths Write-Host "Locating VS / MSVC compiler..." - $VsInstallPath = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -property installationPath + $VsInstallPath = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -property installationPath if (-not $VsInstallPath) { throw "Visual Studio installation not found!" } From e2787b91637431e73e6466d2d0dca32646b13bcf Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 13:42:25 -0400 Subject: [PATCH 06/24] keep looking for msvc --- ci/cloudbuild/builds/windows-startup.ps1 | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index 856aa31093b5a..a9eef2f9f064c 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -79,7 +79,17 @@ try { # Ensure Visual Studio 2022 Build Tools with C++ workload is installed if (-not (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe")) { Write-Host "Installing Visual Studio 2022 Build Tools..." - choco install -y visualstudio2022buildtools --package-parameters "--add Microsoft.VisualStudio.Workload.VCTools --add Microsoft.VisualStudio.Component.VC.Tools.x86.x64 --add Microsoft.VisualStudio.Component.Windows11SDK.22000 --includeRecommended --quiet --noclose" --no-progress + $VsBootstrapperPath = "C:\vs_buildtools.exe" + Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vs_buildtools.exe" -OutFile $VsBootstrapperPath + + Write-Host "Running Visual Studio Installer..." + $Process = Start-Process -FilePath $VsBootstrapperPath -ArgumentList "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --passive --norestart --wait" -Wait -NoNewWindow -PassThru + + if ($Process.ExitCode -ne 0 -and $Process.ExitCode -ne 3010) { + throw "Visual Studio Build Tools installation failed with exit code: $($Process.ExitCode)" + } + Write-Host "Visual Studio Build Tools installed successfully." + Remove-Item $VsBootstrapperPath } # Locates and runs vcvarsall.bat to configure compile paths From 55d7d81a418e1b41775417e25a71d09910c85ef2 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 14:51:13 -0400 Subject: [PATCH 07/24] redirect stderr and limit features to kms --- ci/cloudbuild/builds/windows-startup.ps1 | 5 ++++- ci/gha/builds/windows-cmake.sh | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index a9eef2f9f064c..b509f9bd9a371 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -109,7 +109,10 @@ try { # 10. Run the build script using Git Bash $GitBashPath = "C:\Program Files\Git\bin\bash.exe" Write-Host "Executing windows-cmake.sh..." - & $GitBashPath -c "ci/gha/builds/windows-cmake.sh $BuildType $Features" + & $GitBashPath -c "ci/gha/builds/windows-cmake.sh $BuildType $Features" 2>&1 + if ($LastExitCode -ne 0) { + throw "windows-cmake.sh failed with exit code: $LastExitCode" + } # Report success status $Status = @{ status = "success" } diff --git a/ci/gha/builds/windows-cmake.sh b/ci/gha/builds/windows-cmake.sh index 674b7202e7000..4d8a842d74ede 100755 --- a/ci/gha/builds/windows-cmake.sh +++ b/ci/gha/builds/windows-cmake.sh @@ -57,7 +57,7 @@ TIMEFORMAT="==> 🕑 CMake configuration done in %R seconds" time { # Always run //google/cloud:status_test in case the list of targets has # no unit tests. - io::run cmake "${args[@]}" "${vcpkg_args[@]}" -DGOOGLE_CLOUD_CPP_ENABLE="$*" + io::run cmake "${args[@]}" "${vcpkg_args[@]}" -DGOOGLE_CLOUD_CPP_ENABLE="kms" } if command -v sccache >/dev/null 2>&1; then From 48b2538cf999df8960ba813fbfcef34ce72d525d Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 15:59:16 -0400 Subject: [PATCH 08/24] increase vm size and install ninja --- ci/cloudbuild/builds/windows-startup.ps1 | 18 ++++++++++++------ ci/cloudbuild/windows.yaml | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index b509f9bd9a371..4a452b3d60309 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -43,7 +43,13 @@ try { $env:Path += ";C:\Program Files\CMake\bin" } - # 5. Download and Install sccache + # 5. Ensure Ninja is installed and in the PATH + if (-not (Get-Command ninja -ErrorAction SilentlyContinue)) { + Write-Host "Installing Ninja..." + choco install -y ninja --no-progress + } + + # 6. Download and Install sccache Write-Host "Installing sccache..." $SccacheDir = "C:\sccache" New-Item -ItemType Directory -Force -Path $SccacheDir @@ -52,7 +58,7 @@ try { tar -xzf "$SccacheDir\sccache.tar.gz" -C $SccacheDir --strip-components=1 $env:Path += ";$SccacheDir" - # 6. Download and bootstrap vcpkg + # 7. Download and bootstrap vcpkg Write-Host "Setting up vcpkg..." $VcpkgDir = "C:\vcpkg" New-Item -ItemType Directory -Force -Path $VcpkgDir @@ -61,7 +67,7 @@ try { tar -xzf "$VcpkgDir\vcpkg.tar.gz" -C $VcpkgDir --strip-components=1 & "$VcpkgDir\bootstrap-vcpkg.sh" -disableMetrics - # 7. Extract workspace source codebase + # 8. Extract workspace source codebase Write-Host "Extracting source..." $Workspace = "C:\workspace" New-Item -ItemType Directory -Force -Path $Workspace @@ -70,12 +76,12 @@ try { tar -xzf source.tar.gz Remove-Item source.tar.gz - # 8. Configure environment for build + # 9. Configure environment for build $env:VCPKG_ROOT = $VcpkgDir $env:CMAKE_OUT = "C:\b" # Directory for build output (keep it short) $env:EXECUTE_INTEGRATION_TESTS = "false" - # 9. Run MSVC Developer Environment Config + # 10. Run MSVC Developer Environment Config # Ensure Visual Studio 2022 Build Tools with C++ workload is installed if (-not (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe")) { Write-Host "Installing Visual Studio 2022 Build Tools..." @@ -106,7 +112,7 @@ try { } } - # 10. Run the build script using Git Bash + # 11. Run the build script using Git Bash $GitBashPath = "C:\Program Files\Git\bin\bash.exe" Write-Host "Executing windows-cmake.sh..." & $GitBashPath -c "ci/gha/builds/windows-cmake.sh $BuildType $Features" 2>&1 diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 80f55a1a93b90..a343b4cb31334 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -4,7 +4,7 @@ options: substitutions: _ZONE: 'us-east1-b' - _MACHINE_TYPE: 'n2-standard-16' # 16 vCPUs, 64 GB RAM for fast compilation + _MACHINE_TYPE: 'n2-standard-64' # 64 vCPUs, 256 GB RAM for fast compilation _IMAGE_FAMILY: 'windows-2022' # Public image family _IMAGE_PROJECT: 'windows-cloud' _SERVICE_ACCOUNT: 'windows-builder-sa@cloud-cpp-testing-resources.iam.gserviceaccount.com' From 498770a3b51c72ccbbec51cea50c590def1fcdae Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 17:01:23 -0400 Subject: [PATCH 09/24] download ninja directly --- ci/cloudbuild/builds/windows-startup.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index 4a452b3d60309..22a20fbea3578 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -46,7 +46,12 @@ try { # 5. Ensure Ninja is installed and in the PATH if (-not (Get-Command ninja -ErrorAction SilentlyContinue)) { Write-Host "Installing Ninja..." - choco install -y ninja --no-progress + $NinjaDir = "C:\ninja" + New-Item -ItemType Directory -Force -Path $NinjaDir + Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-win.zip" -OutFile "$NinjaDir\ninja.zip" + Expand-Archive -Path "$NinjaDir\ninja.zip" -DestinationPath $NinjaDir -Force + Remove-Item "$NinjaDir\ninja.zip" + $env:Path += ";$NinjaDir" } # 6. Download and Install sccache From 781772982b475aacbdd97a0bc8f859488314ff9f Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 9 Jun 2026 18:21:08 -0400 Subject: [PATCH 10/24] more logs --- ci/gha/builds/windows-cmake.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ci/gha/builds/windows-cmake.sh b/ci/gha/builds/windows-cmake.sh index 4d8a842d74ede..da674682b5a18 100755 --- a/ci/gha/builds/windows-cmake.sh +++ b/ci/gha/builds/windows-cmake.sh @@ -54,11 +54,13 @@ args+=("-DCMAKE_EXE_LINKER_FLAGS=/MANIFEST:NO") io::log_h1 "Starting Build" TIMEFORMAT="==> 🕑 CMake configuration done in %R seconds" -time { - # Always run //google/cloud:status_test in case the list of targets has - # no unit tests. - io::run cmake "${args[@]}" "${vcpkg_args[@]}" -DGOOGLE_CLOUD_CPP_ENABLE="kms" -} + if ! io::run cmake "${args[@]}" "${vcpkg_args[@]}" -DGOOGLE_CLOUD_CPP_ENABLE="kms"; then + if [[ -f "${CMAKE_OUT}/vcpkg-manifest-install.log" ]]; then + io::log_red "vcpkg installation failed! Content of ${CMAKE_OUT}/vcpkg-manifest-install.log:" + cat "${CMAKE_OUT}/vcpkg-manifest-install.log" + fi + exit 1 + fi if command -v sccache >/dev/null 2>&1; then io::log "Current sccache stats" From 03224a796de3e118ed0b65487026e1bc7c2f5c43 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 10 Jun 2026 13:12:27 -0400 Subject: [PATCH 11/24] grab log contents on timeout --- ci/cloudbuild/windows.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index a343b4cb31334..2f2c7b11135a5 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -51,7 +51,16 @@ steps: args: - '-c' - | + log_lines=0 cleanup() { + echo "Fetching final logs..." + gcloud storage cp "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/build.log" build.log 2>/dev/null || true + if [ -f build.log ]; then + new_lines=$(wc -l < build.log) + if [ "$new_lines" -gt "$log_lines" ]; then + tail -n +"$((log_lines + 1))" build.log + fi + fi echo "Cleaning up VM and source archive..." gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet || true gcloud storage rm "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" || true From d4a1dfa25d53c238f567a4da53373a6a8fa0fe42 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Thu, 11 Jun 2026 16:01:59 -0400 Subject: [PATCH 12/24] get vcpkg log --- ci/gha/builds/windows-cmake.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/ci/gha/builds/windows-cmake.sh b/ci/gha/builds/windows-cmake.sh index da674682b5a18..a6ce316866806 100755 --- a/ci/gha/builds/windows-cmake.sh +++ b/ci/gha/builds/windows-cmake.sh @@ -32,6 +32,10 @@ source module ci/gha/builds/lib/ctest.sh if [[ -z "${CMAKE_OUT:-}" ]]; then CMAKE_OUT=cmake-out fi +CMAKE_OUT_UNIX="${CMAKE_OUT}" +if command -v cygpath >/dev/null 2>&1; then + CMAKE_OUT_UNIX=$(cygpath -u "${CMAKE_OUT}") +fi mapfile -t args < <(cmake::common_args "${CMAKE_OUT}") mapfile -t vcpkg_args < <(cmake::vcpkg_args) mapfile -t ctest_args < <(ctest::common_args) @@ -55,9 +59,9 @@ args+=("-DCMAKE_EXE_LINKER_FLAGS=/MANIFEST:NO") io::log_h1 "Starting Build" TIMEFORMAT="==> 🕑 CMake configuration done in %R seconds" if ! io::run cmake "${args[@]}" "${vcpkg_args[@]}" -DGOOGLE_CLOUD_CPP_ENABLE="kms"; then - if [[ -f "${CMAKE_OUT}/vcpkg-manifest-install.log" ]]; then - io::log_red "vcpkg installation failed! Content of ${CMAKE_OUT}/vcpkg-manifest-install.log:" - cat "${CMAKE_OUT}/vcpkg-manifest-install.log" + if [[ -f "${CMAKE_OUT_UNIX}/vcpkg-manifest-install.log" ]]; then + io::log_red "vcpkg installation failed! Content of ${CMAKE_OUT_UNIX}/vcpkg-manifest-install.log:" + cat "${CMAKE_OUT_UNIX}/vcpkg-manifest-install.log" fi exit 1 fi From 7b7b701a81cdf03a4218c205cf4e249e4f99463b Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Thu, 11 Jun 2026 16:17:09 -0400 Subject: [PATCH 13/24] lower timeout for faster iteration --- ci/cloudbuild/windows.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 2f2c7b11135a5..a05b704369b25 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -13,6 +13,8 @@ substitutions: _BUILD_TYPE: 'Release' _FEATURES: 'storage' +timeout: 600s + steps: # Step 1: Compress and upload workspace source code to GCS - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' From 8fe86714a489d91f039f2048db648267c366e290 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Thu, 11 Jun 2026 16:40:33 -0400 Subject: [PATCH 14/24] revert timeout --- ci/cloudbuild/windows.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index a05b704369b25..2f2c7b11135a5 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -13,8 +13,6 @@ substitutions: _BUILD_TYPE: 'Release' _FEATURES: 'storage' -timeout: 600s - steps: # Step 1: Compress and upload workspace source code to GCS - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' From 1fa006456352ab57170a402cfa0346a666b154c4 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 16 Jun 2026 16:02:23 -0400 Subject: [PATCH 15/24] sync with PR 16178 --- google/cloud/internal/http_header_test.cc | 6 ++++++ .../oauth2_gdch_service_account_credentials_test.cc | 5 +++++ .../internal/oauth2_minimal_iam_credentials_rest_test.cc | 5 +++++ .../oauth2_regional_access_boundary_token_manager.h | 9 +++++++++ google/cloud/internal/rest_opentelemetry.cc | 2 +- google/cloud/internal/tracing_rest_client.cc | 2 +- google/cloud/internal/unified_rest_credentials_test.cc | 5 +++++ google/cloud/internal/win32/sign_using_sha256.cc | 4 +++- .../async/connection_impl_appendable_upload_test.cc | 5 +++++ 9 files changed, 40 insertions(+), 3 deletions(-) diff --git a/google/cloud/internal/http_header_test.cc b/google/cloud/internal/http_header_test.cc index 4e8441d385fee..5bcc6bd8eccf8 100644 --- a/google/cloud/internal/http_header_test.cc +++ b/google/cloud/internal/http_header_test.cc @@ -12,6 +12,10 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO(#16171): MSVC is a lot pickier about the conversion operators. +// Skip for now. +#ifndef _WIN32 + #include "google/cloud/internal/http_header.h" #include @@ -179,3 +183,5 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace rest_internal } // namespace cloud } // namespace google + +#endif diff --git a/google/cloud/internal/oauth2_gdch_service_account_credentials_test.cc b/google/cloud/internal/oauth2_gdch_service_account_credentials_test.cc index 772930cc68c31..85f1864327a4a 100644 --- a/google/cloud/internal/oauth2_gdch_service_account_credentials_test.cc +++ b/google/cloud/internal/oauth2_gdch_service_account_credentials_test.cc @@ -12,6 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. +// TODO(#16172): GDCH is not currently supported on Windows. +#ifndef _WIN32 + #include "google/cloud/internal/oauth2_gdch_service_account_credentials.h" #include "google/cloud/credentials.h" #include "google/cloud/internal/base64_transforms.h" @@ -464,3 +467,5 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace oauth2_internal } // namespace cloud } // namespace google + +#endif diff --git a/google/cloud/internal/oauth2_minimal_iam_credentials_rest_test.cc b/google/cloud/internal/oauth2_minimal_iam_credentials_rest_test.cc index 7a81fe2ad43f2..1652d9fad160b 100644 --- a/google/cloud/internal/oauth2_minimal_iam_credentials_rest_test.cc +++ b/google/cloud/internal/oauth2_minimal_iam_credentials_rest_test.cc @@ -364,6 +364,9 @@ TEST(MinimalIamCredentialsRestTest, AllowedLocationsAuthorizationFailure) { EXPECT_THAT(access_token, StatusIs(StatusCode::kPermissionDenied)); } +// TODO(#16177): Update these tests to compile with MSVC. +#ifndef _WIN32 + TEST(MinimalIamCredentialsRestTest, AllowedLocationsMalformedResponseFailure) { std::string service_account = "foo@somewhere.com"; std::chrono::seconds lifetime(3600); @@ -560,6 +563,8 @@ TEST(MinimalIamCredentialsRestTest, WorkforceIdentityAllowedLocations) { EXPECT_THAT(allowed_locations->encoded_locations, Eq("0xA30")); } +#endif + } // namespace GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace oauth2_internal diff --git a/google/cloud/internal/oauth2_regional_access_boundary_token_manager.h b/google/cloud/internal/oauth2_regional_access_boundary_token_manager.h index a6ef56f2bf37b..10d8a13c3faf0 100644 --- a/google/cloud/internal/oauth2_regional_access_boundary_token_manager.h +++ b/google/cloud/internal/oauth2_regional_access_boundary_token_manager.h @@ -184,12 +184,21 @@ class RegionalAccessBoundaryTokenManager promise pending_refresh; pending_refresh_ = pending_refresh.get_future(); auto constexpr kLocation = __func__; +#ifdef _WIN32 + auto pending_refresh_fn = [p = std::move(pending_refresh), + weak = weak_from_this(), request, + stub = iam_stub_, + retry_policy = retry_policy_->clone(), + backoff_policy = backoff_policy_->clone(), + options = options_, kLocation]() mutable { +#else auto pending_refresh_fn = [p = std::move(pending_refresh), weak = weak_from_this(), request, stub = iam_stub_, retry_policy = retry_policy_->clone(), backoff_policy = backoff_policy_->clone(), options = options_]() mutable { +#endif auto refresh_attempt_fn = [stub](rest_internal::RestContext&, Options const&, Request const& request) { return stub->AllowedLocations(request); diff --git a/google/cloud/internal/rest_opentelemetry.cc b/google/cloud/internal/rest_opentelemetry.cc index 4d5d1d839b194..927e5852841b6 100644 --- a/google/cloud/internal/rest_opentelemetry.cc +++ b/google/cloud/internal/rest_opentelemetry.cc @@ -81,7 +81,7 @@ opentelemetry::nostd::shared_ptr MakeSpanHttp( {/*sc::kUrlFull=*/"url.full", request.path()}}, options); for (auto const& kv : request.headers()) { - auto const name = "http.request.header." + std::string{kv.first}; + auto const name = absl::StrCat("http.request.header.", kv.first.name()); if (kv.second.EmptyValues()) { span->SetAttribute(name, ""); continue; diff --git a/google/cloud/internal/tracing_rest_client.cc b/google/cloud/internal/tracing_rest_client.cc index 0e92b092919e7..422a00ea62e9c 100644 --- a/google/cloud/internal/tracing_rest_client.cc +++ b/google/cloud/internal/tracing_rest_client.cc @@ -71,7 +71,7 @@ StatusOr> EndResponseSpan( *context.local_port()); } for (auto const& kv : context.headers()) { - auto const name = "http.request.header." + std::string{kv.first}; + auto const name = absl::StrCat("http.request.header.", kv.first.name()); if (kv.second.EmptyValues()) { span->SetAttribute(name, ""); continue; diff --git a/google/cloud/internal/unified_rest_credentials_test.cc b/google/cloud/internal/unified_rest_credentials_test.cc index 9f8375cb87cc7..1f9bdc380066f 100644 --- a/google/cloud/internal/unified_rest_credentials_test.cc +++ b/google/cloud/internal/unified_rest_credentials_test.cc @@ -571,6 +571,9 @@ TEST(UnifiedRestCredentialsTest, ApiKey) { IsOkAndHolds(Contains(HttpHeader("x-goog-api-key", "api-key")))); } +// TODO(#16172): GDCH is not currently supported on Windows. +#ifndef _WIN32 + TEST(UnifiedRestCredentialsTest, MakeGDCHServiceAccountUsesAudienceParameter) { auto constexpr kAudience = "test-audience"; auto const post_response = std::string{R"""({ @@ -617,6 +620,8 @@ TEST(UnifiedRestCredentialsTest, MakeGDCHServiceAccountUsesAudienceParameter) { "Authorization", "Bearer access-token-value")))); } +#endif + TEST(UnifiedRestCredentialsTest, LoadError) { // Create a name for a non-existing file, try to load it, and verify it // returns errors. diff --git a/google/cloud/internal/win32/sign_using_sha256.cc b/google/cloud/internal/win32/sign_using_sha256.cc index 15ecc6e6f9103..3ffd6fac53c29 100644 --- a/google/cloud/internal/win32/sign_using_sha256.cc +++ b/google/cloud/internal/win32/sign_using_sha256.cc @@ -135,8 +135,10 @@ StatusOr> SignSha256Digest(BCRYPT_KEY_HANDLE key, } // namespace +// TODO(#16172): GDCH is not currently supported on Windows. +// Only supports RAW signature format as only RSA keys are supported. StatusOr> SignUsingSha256( - std::string const& str, std::string const& pem_contents) { + std::string const& str, std::string const& pem_contents, SignatureFormat) { auto pem_buffer = DecodePem(pem_contents); if (!pem_buffer) return std::move(pem_buffer).status(); diff --git a/google/cloud/storage/internal/async/connection_impl_appendable_upload_test.cc b/google/cloud/storage/internal/async/connection_impl_appendable_upload_test.cc index 49b6348f4be3c..ef541d8f7b972 100644 --- a/google/cloud/storage/internal/async/connection_impl_appendable_upload_test.cc +++ b/google/cloud/storage/internal/async/connection_impl_appendable_upload_test.cc @@ -764,6 +764,9 @@ TEST_F(AsyncConnectionImplAppendableTest, next.first.set_value(true); } +// TODO(#16174): Figure out why this test fails to compile in MSVC. +#ifndef _WIN32 + TEST_F(AsyncConnectionImplAppendableTest, ResumeAppendableObjectUploadWithChecksum) { auto constexpr kRequestText = R"pb( @@ -882,6 +885,8 @@ TEST_F(AsyncConnectionImplAppendableTest, next.first.set_value(true); } +#endif + } // namespace GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END } // namespace storage_internal From 2ac4735adc706dbe6b6bda4dc78300d4b70d51eb Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 16 Jun 2026 18:03:47 -0400 Subject: [PATCH 16/24] output vcpkg log --- ci/cloudbuild/builds/windows-startup.ps1 | 3 +++ ci/cloudbuild/windows.yaml | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index 22a20fbea3578..c05293f61f94f 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -136,6 +136,9 @@ catch { } finally { Stop-Transcript + if (Test-Path "C:\b\vcpkg-manifest-install.log") { + gcloud storage cp "C:\b\vcpkg-manifest-install.log" "$LogsBucket/vcpkg-manifest-install.log" + } # Upload final logs and status to GCS bucket gcloud storage cp C:\build.log "$LogsBucket/build.log" gcloud storage cp C:\status.json "$LogsBucket/status.json" diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 2f2c7b11135a5..0364552bd4126 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -61,6 +61,14 @@ steps: tail -n +"$((log_lines + 1))" build.log fi fi + if gcloud storage cp "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/vcpkg-manifest-install.log" vcpkg-manifest-install.log 2>/dev/null; then + echo "=========================================================================" + echo " Content of vcpkg-manifest-install.log:" + echo "=========================================================================" + cat vcpkg-manifest-install.log + echo "=========================================================================" + rm -f vcpkg-manifest-install.log + fi echo "Cleaning up VM and source archive..." gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet || true gcloud storage rm "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" || true From 1127a12b9c1287ae80cb78beef78db5b1af01c39 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Tue, 16 Jun 2026 18:58:19 -0400 Subject: [PATCH 17/24] output even more log files --- ci/cloudbuild/builds/windows-startup.ps1 | 13 ++++++-- ci/cloudbuild/windows.yaml | 38 +++++++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index c05293f61f94f..b4bd1053af6dc 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -136,8 +136,17 @@ catch { } finally { Stop-Transcript - if (Test-Path "C:\b\vcpkg-manifest-install.log") { - gcloud storage cp "C:\b\vcpkg-manifest-install.log" "$LogsBucket/vcpkg-manifest-install.log" + if (Test-Path "C:\vcpkg\buildtrees") { + Get-ChildItem -Path "C:\vcpkg\buildtrees" -Filter "*.log" -Recurse | ForEach-Object { + $RelativePath = $_.FullName.Substring("C:\vcpkg\buildtrees\".Length).Replace("\", "/") + gcloud storage cp $_.FullName "$LogsBucket/build-logs/vcpkg/$RelativePath" + } + } + if (Test-Path "C:\b") { + Get-ChildItem -Path "C:\b" -Filter "*.log" -Recurse | ForEach-Object { + $RelativePath = $_.FullName.Substring("C:\b\".Length).Replace("\", "/") + gcloud storage cp $_.FullName "$LogsBucket/build-logs/cmake/$RelativePath" + } } # Upload final logs and status to GCS bucket gcloud storage cp C:\build.log "$LogsBucket/build.log" diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 0364552bd4126..e8a1e8e4d5c9c 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -61,13 +61,37 @@ steps: tail -n +"$((log_lines + 1))" build.log fi fi - if gcloud storage cp "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/vcpkg-manifest-install.log" vcpkg-manifest-install.log 2>/dev/null; then - echo "=========================================================================" - echo " Content of vcpkg-manifest-install.log:" - echo "=========================================================================" - cat vcpkg-manifest-install.log - echo "=========================================================================" - rm -f vcpkg-manifest-install.log + rm -rf build-logs + if gcloud storage cp -r "gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID}/build-logs" . 2>/dev/null; then + if [ -f build-logs/cmake/vcpkg-manifest-install.log ]; then + echo "=========================================================================" + echo " Content of vcpkg-manifest-install.log:" + echo "=========================================================================" + cat build-logs/cmake/vcpkg-manifest-install.log + echo "=========================================================================" + fi + + files_to_scan="build.log" + if [ -f build-logs/cmake/vcpkg-manifest-install.log ]; then + files_to_scan="$files_to_scan build-logs/cmake/vcpkg-manifest-install.log" + fi + failed_logs=$(grep -A 1 -i "See logs for more information:" $files_to_scan 2>/dev/null | \ + sed -n -e 's/.*buildtrees[/\\]\(.*\)/\1/p' | \ + tr '\\' '/' | tr -d '\r' | sort -u) + + if [ -n "$failed_logs" ]; then + echo "=========================================================================" + echo " Content of failed package logs:" + echo "=========================================================================" + echo "$failed_logs" | while read -r logpath; do + if [ -f "build-logs/vcpkg/$logpath" ]; then + echo "--- File: vcpkg/$logpath ---" + cat "build-logs/vcpkg/$logpath" + echo "------------------------------------------------------------------------" + fi + done + fi + rm -rf build-logs fi echo "Cleaning up VM and source archive..." gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet || true From 05a09dffb0f09240631c80b8c67fe5b6952640cf Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 11:12:43 -0400 Subject: [PATCH 18/24] dynamically select vm zone --- ci/cloudbuild/windows.yaml | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index e8a1e8e4d5c9c..c11155739aeb8 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -25,6 +25,18 @@ steps: gcloud storage cp "source-${BUILD_ID}.tar.gz" "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" rm "source-${BUILD_ID}.tar.gz" + # Step 1.5: Select US zone with most available N2 CPU quota + - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' + id: 'select-zone' + entrypoint: 'bash' + args: + - '-c' + - | + if ! python3 ci/cloudbuild/select_zone.py; then + echo "Warning: failed to dynamically select zone. Falling back to ${_ZONE}." + echo "${_ZONE}" > selected_zone.txt + fi + # Step 2: Create ephemeral GCE Windows Instance and run startup script - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' id: 'create-vm' @@ -32,10 +44,11 @@ steps: args: - '-c' - | + selected_zone=$(cat selected_zone.txt) vcpkg_version=$(cat ci/etc/vcpkg-version.txt) gcloud compute instances create "wincmake-${BUILD_ID}" \ --project="${PROJECT_ID}" \ - --zone="${_ZONE}" \ + --zone="$$selected_zone" \ --machine-type="${_MACHINE_TYPE}" \ --image-family="${_IMAGE_FAMILY}" \ --image-project="${_IMAGE_PROJECT}" \ @@ -51,6 +64,12 @@ steps: args: - '-c' - | + selected_zone="${_ZONE}" + if [ -f selected_zone.txt ]; then + selected_zone=$(cat selected_zone.txt) + fi + echo "Using zone: $$selected_zone" + log_lines=0 cleanup() { echo "Fetching final logs..." @@ -94,7 +113,7 @@ steps: rm -rf build-logs fi echo "Cleaning up VM and source archive..." - gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="${_ZONE}" --quiet || true + gcloud compute instances delete "wincmake-${BUILD_ID}" --zone="$$selected_zone" --quiet || true gcloud storage rm "gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz" || true } trap cleanup EXIT From db5950addf9d70217908013600897bf9780217ec Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 11:18:51 -0400 Subject: [PATCH 19/24] inline python script --- ci/cloudbuild/windows.yaml | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index c11155739aeb8..a2ba4d8a10d74 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -32,7 +32,37 @@ steps: args: - '-c' - | - if ! python3 ci/cloudbuild/select_zone.py; then + if ! python3 -c ' + import json, subprocess, sys + STANDARD_US_REGIONS = {"us-central1", "us-east1", "us-east4", "us-east5", "us-south1", "us-west1", "us-west2", "us-west3", "us-west4"} + try: + result = subprocess.run(["gcloud", "compute", "regions", "list", "--filter=name ~ ^us-", "--format=json(name,quotas)"], capture_output=True, text=True, check=True) + regions = json.loads(result.stdout) + best_region, max_available = None, -1 + for region in regions: + name = region.get("name") + if name not in STANDARD_US_REGIONS: continue + for quota in region.get("quotas", []): + if quota.get("metric") == "N2_CPUS": + available = quota.get("limit", 0.0) - quota.get("usage", 0.0) + print(f"Region: {name}, Available: {available}", file=sys.stderr) + if available > max_available: + max_available = available + best_region = name + break + if not best_region or max_available < 64: + print(f"Warning: No standard region found with at least 64 N2_CPUS available.", file=sys.stderr) + sys.exit(1) + print(f"Selected region: {best_region} with {max_available} available N2_CPUS", file=sys.stderr) + zones_result = subprocess.run(["gcloud", "compute", "zones", "list", f"--filter=region ~ /regions/{best_region} AND status=UP", "--format=value(name)"], capture_output=True, text=True, check=True) + zones = [line.strip() for line in zones_result.stdout.splitlines() if line.strip()] + if not zones: raise Exception(f"No UP zones found in region {best_region}") + print(f"Selected zone: {zones[0]}", file=sys.stderr) + with open("selected_zone.txt", "w") as f: f.write(zones[0] + "\n") + except Exception as e: + print(f"Error selecting zone: {e}", file=sys.stderr) + sys.exit(1) + '; then echo "Warning: failed to dynamically select zone. Falling back to ${_ZONE}." echo "${_ZONE}" > selected_zone.txt fi From 1b05384dd5ddb9824c861b05fc9babf86b730843 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 11:28:02 -0400 Subject: [PATCH 20/24] update select-zone to check for machine type --- ci/cloudbuild/windows.yaml | 61 ++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 13 deletions(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index a2ba4d8a10d74..5cbaefb1297f8 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -35,30 +35,65 @@ steps: if ! python3 -c ' import json, subprocess, sys STANDARD_US_REGIONS = {"us-central1", "us-east1", "us-east4", "us-east5", "us-south1", "us-west1", "us-west2", "us-west3", "us-west4"} + + def is_machine_type_available(zone, machine_type): + try: + res = subprocess.run([ + "gcloud", "compute", "machine-types", "list", + f"--filter=zone:{zone} AND name:{machine_type}", + "--format=value(name)" + ], capture_output=True, text=True, check=True) + return machine_type in res.stdout + except Exception as e: + print(f"Error checking machine type availability in zone {zone}: {e}", file=sys.stderr) + return False + try: result = subprocess.run(["gcloud", "compute", "regions", "list", "--filter=name ~ ^us-", "--format=json(name,quotas)"], capture_output=True, text=True, check=True) regions = json.loads(result.stdout) - best_region, max_available = None, -1 + + regions_quota = [] for region in regions: name = region.get("name") if name not in STANDARD_US_REGIONS: continue for quota in region.get("quotas", []): if quota.get("metric") == "N2_CPUS": available = quota.get("limit", 0.0) - quota.get("usage", 0.0) - print(f"Region: {name}, Available: {available}", file=sys.stderr) - if available > max_available: - max_available = available - best_region = name + regions_quota.append((name, available)) + break + + regions_quota.sort(key=lambda x: x[1], reverse=True) + + selected_zone = None + for region_name, available in regions_quota: + print(f"Checking region {region_name} (Available N2_CPUS: {available})...", file=sys.stderr) + if available < 64: + print(f"Skipping region {region_name}: not enough available N2_CPUS.", file=sys.stderr) + continue + + zones_result = subprocess.run([ + "gcloud", "compute", "zones", "list", + f"--filter=region ~ /regions/{region_name} AND status=UP", + "--format=value(name)" + ], capture_output=True, text=True, check=True) + zones = [line.strip() for line in zones_result.stdout.splitlines() if line.strip()] + + for zone in zones: + print(f"Checking machine type availability in zone {zone}...", file=sys.stderr) + if is_machine_type_available(zone, "${_MACHINE_TYPE}"): + selected_zone = zone break - if not best_region or max_available < 64: - print(f"Warning: No standard region found with at least 64 N2_CPUS available.", file=sys.stderr) + + if selected_zone: + print(f"Selected zone: {selected_zone}", file=sys.stderr) + break + + if not selected_zone: + print("Error: No suitable zone with enough quota and machine type support was found.", file=sys.stderr) sys.exit(1) - print(f"Selected region: {best_region} with {max_available} available N2_CPUS", file=sys.stderr) - zones_result = subprocess.run(["gcloud", "compute", "zones", "list", f"--filter=region ~ /regions/{best_region} AND status=UP", "--format=value(name)"], capture_output=True, text=True, check=True) - zones = [line.strip() for line in zones_result.stdout.splitlines() if line.strip()] - if not zones: raise Exception(f"No UP zones found in region {best_region}") - print(f"Selected zone: {zones[0]}", file=sys.stderr) - with open("selected_zone.txt", "w") as f: f.write(zones[0] + "\n") + + with open("selected_zone.txt", "w") as f: + f.write(selected_zone + "\n") except Exception as e: print(f"Error selecting zone: {e}", file=sys.stderr) sys.exit(1) From 8f7ff41a62eb1979996cbf5b4177c026358efdce Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 11:34:04 -0400 Subject: [PATCH 21/24] create zone list for creating vm --- ci/cloudbuild/windows.yaml | 70 ++++++++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 5cbaefb1297f8..784acf4124009 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -64,11 +64,10 @@ steps: regions_quota.sort(key=lambda x: x[1], reverse=True) - selected_zone = None + candidate_zones = [] for region_name, available in regions_quota: - print(f"Checking region {region_name} (Available N2_CPUS: {available})...", file=sys.stderr) if available < 64: - print(f"Skipping region {region_name}: not enough available N2_CPUS.", file=sys.stderr) + print(f"Skipping region {region_name}: not enough available N2_CPUS ({available}).", file=sys.stderr) continue zones_result = subprocess.run([ @@ -81,25 +80,22 @@ steps: for zone in zones: print(f"Checking machine type availability in zone {zone}...", file=sys.stderr) if is_machine_type_available(zone, "${_MACHINE_TYPE}"): - selected_zone = zone - break - - if selected_zone: - print(f"Selected zone: {selected_zone}", file=sys.stderr) - break - - if not selected_zone: - print("Error: No suitable zone with enough quota and machine type support was found.", file=sys.stderr) + candidate_zones.append(zone) + + if not candidate_zones: + print("Error: No suitable zones with enough quota and machine type support found.", file=sys.stderr) sys.exit(1) - with open("selected_zone.txt", "w") as f: - f.write(selected_zone + "\n") + print(f"Found candidate zones: {candidate_zones}", file=sys.stderr) + with open("candidate_zones.txt", "w") as f: + for zone in candidate_zones: + f.write(zone + "\n") except Exception as e: print(f"Error selecting zone: {e}", file=sys.stderr) sys.exit(1) '; then echo "Warning: failed to dynamically select zone. Falling back to ${_ZONE}." - echo "${_ZONE}" > selected_zone.txt + echo "${_ZONE}" > candidate_zones.txt fi # Step 2: Create ephemeral GCE Windows Instance and run startup script @@ -109,18 +105,40 @@ steps: args: - '-c' - | - selected_zone=$(cat selected_zone.txt) vcpkg_version=$(cat ci/etc/vcpkg-version.txt) - gcloud compute instances create "wincmake-${BUILD_ID}" \ - --project="${PROJECT_ID}" \ - --zone="$$selected_zone" \ - --machine-type="${_MACHINE_TYPE}" \ - --image-family="${_IMAGE_FAMILY}" \ - --image-project="${_IMAGE_PROJECT}" \ - --service-account="${_SERVICE_ACCOUNT}" \ - --scopes="https://www.googleapis.com/auth/cloud-platform" \ - --metadata="source-archive=gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz,build-type=${_BUILD_TYPE},features=${_FEATURES},logs-bucket=gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID},vcpkg-version=${vcpkg_version}" \ - --metadata-from-file="windows-startup-script-ps1=ci/cloudbuild/builds/windows-startup.ps1" + created=false + + # Read candidate zones + if [ -f candidate_zones.txt ]; then + mapfile -t zones < candidate_zones.txt + else + zones=("${_ZONE}") + fi + + for zone in "$${zones[@]}"; do + echo "Attempting to create VM in zone: $$zone..." + if gcloud compute instances create "wincmake-${BUILD_ID}" \ + --project="${PROJECT_ID}" \ + --zone="$$zone" \ + --machine-type="${_MACHINE_TYPE}" \ + --image-family="${_IMAGE_FAMILY}" \ + --image-project="${_IMAGE_PROJECT}" \ + --service-account="${_SERVICE_ACCOUNT}" \ + --scopes="https://www.googleapis.com/auth/cloud-platform" \ + --metadata="source-archive=gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz,build-type=${_BUILD_TYPE},features=${_FEATURES},logs-bucket=gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID},vcpkg-version=${vcpkg_version}" \ + --metadata-from-file="windows-startup-script-ps1=ci/cloudbuild/builds/windows-startup.ps1"; then + echo "$$zone" > selected_zone.txt + created=true + break + else + echo "Warning: failed to create VM in zone $$zone, trying next candidate." + fi + done + + if [ "$$created" = false ]; then + echo "Error: Failed to create VM in all candidate zones." + exit 1 + fi # Step 3: Poll GCS for status file and stream build logs, then clean up GCE VM - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk' From a58e58d9298638444bef5067871b3e5f14789909 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 13:01:18 -0400 Subject: [PATCH 22/24] stream logs and two hour timeout --- ci/cloudbuild/builds/windows-startup.ps1 | 16 ++++++++++++++++ ci/cloudbuild/windows.yaml | 1 + 2 files changed, 17 insertions(+) diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index b4bd1053af6dc..41ad82e30e273 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -13,6 +13,18 @@ try { $LogsBucket = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/logs-bucket" $VcpkgVersion = Invoke-RestMethod -Headers $Headers -Uri "$MetadataUrl/vcpkg-version" + # Start background job to periodically upload build.log to GCS for streaming logs + $LogUploadJob = Start-Job -ScriptBlock { + param($LogPath, $LogsBucket) + while ($true) { + if (Test-Path $LogPath) { + # Use Out-Null to suppress output to avoid writing back to the transcript log + & gcloud storage cp $LogPath "$LogsBucket/build.log" 2>&1 | Out-Null + } + Start-Sleep -Seconds 20 + } + } -ArgumentList $LogPath, $LogsBucket + Write-Host "Source Archive: $SourceArchive" Write-Host "Build Type: $BuildType" Write-Host "Features: $Features" @@ -135,6 +147,10 @@ catch { $Status | ConvertTo-Json | Out-File -FilePath "C:\status.json" -Encoding ascii } finally { + if ($LogUploadJob) { + Stop-Job $LogUploadJob -ErrorAction SilentlyContinue + Remove-Job $LogUploadJob -ErrorAction SilentlyContinue + } Stop-Transcript if (Test-Path "C:\vcpkg\buildtrees") { Get-ChildItem -Path "C:\vcpkg\buildtrees" -Filter "*.log" -Recurse | ForEach-Object { diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 784acf4124009..746034efb0276 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -1,6 +1,7 @@ options: dynamic_substitutions: true substitutionOption: 'ALLOW_LOOSE' + timeout: '7200s' # 2 hours substitutions: _ZONE: 'us-east1-b' From 33a1809f091ae76ac8b59312e4036e3e4d326765 Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 13:05:38 -0400 Subject: [PATCH 23/24] fix timeout --- ci/cloudbuild/windows.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index 746034efb0276..f28cd83d349ef 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -1,7 +1,7 @@ +timeout: '7200s' # 2 hours options: dynamic_substitutions: true substitutionOption: 'ALLOW_LOOSE' - timeout: '7200s' # 2 hours substitutions: _ZONE: 'us-east1-b' From b8d5724b0e4b5d3ed7c650c44ad67a4d09492cee Mon Sep 17 00:00:00 2001 From: Scott Hart Date: Wed, 17 Jun 2026 15:42:17 -0400 Subject: [PATCH 24/24] use custom image with larger disk --- ci/cloudbuild/builds/image-provision.ps1 | 96 ++++++++++++++++++++++++ ci/cloudbuild/builds/windows-startup.ps1 | 82 ++++---------------- ci/cloudbuild/windows.yaml | 6 +- 3 files changed, 116 insertions(+), 68 deletions(-) create mode 100644 ci/cloudbuild/builds/image-provision.ps1 diff --git a/ci/cloudbuild/builds/image-provision.ps1 b/ci/cloudbuild/builds/image-provision.ps1 new file mode 100644 index 0000000000000..8fd15cf7c28a4 --- /dev/null +++ b/ci/cloudbuild/builds/image-provision.ps1 @@ -0,0 +1,96 @@ +# Setup log output redirection +$LogPath = "C:\image-provision.log" +Start-Transcript -Path $LogPath + +try { + # 1. Ensure Chocolatey is installed + if (-not (Get-Command choco -ErrorAction SilentlyContinue)) { + if (-not (Test-Path "C:\ProgramData\chocolatey\bin\choco.exe")) { + Write-Host "Installing Chocolatey..." + Set-ExecutionPolicy Bypass -Scope Process -Force + [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 + Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) + } + $env:Path += ";C:\ProgramData\chocolatey\bin" + } + + # 2. Ensure Git is installed and in the PATH + if (-not (Get-Command git -ErrorAction SilentlyContinue)) { + Write-Host "Installing Git..." + choco install -y git --no-progress + $env:Path += ";C:\Program Files\Git\cmd" + } + + # 3. Ensure CMake is installed and in the PATH + if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { + Write-Host "Installing CMake..." + choco install -y cmake --version 3.31.6 --no-progress + $env:Path += ";C:\Program Files\CMake\bin" + } + + # 4. Ensure Ninja is installed and in the PATH + if (-not (Get-Command ninja -ErrorAction SilentlyContinue)) { + Write-Host "Installing Ninja..." + $NinjaDir = "C:\ninja" + New-Item -ItemType Directory -Force -Path $NinjaDir + Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-win.zip" -OutFile "$NinjaDir\ninja.zip" + Expand-Archive -Path "$NinjaDir\ninja.zip" -DestinationPath $NinjaDir -Force + Remove-Item "$NinjaDir\ninja.zip" + $env:Path += ";$NinjaDir" + } + + # 5. Download and Install sccache + if (-not (Get-Command sccache -ErrorAction SilentlyContinue)) { + Write-Host "Installing sccache..." + $SccacheDir = "C:\sccache" + New-Item -ItemType Directory -Force -Path $SccacheDir + $SccacheUrl = "https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-pc-windows-msvc.tar.gz" + Invoke-WebRequest -Uri $SccacheUrl -OutFile "$SccacheDir\sccache.tar.gz" + tar -xzf "$SccacheDir\sccache.tar.gz" -C $SccacheDir --strip-components=1 + $env:Path += ";$SccacheDir" + } + + # Set machine-level persistent PATH for Git, CMake, Ninja, sccache + [Environment]::SetEnvironmentVariable("Path", $env:Path, [EnvironmentVariableTarget]::Machine) + + # 6. Download and bootstrap vcpkg + Write-Host "Setting up vcpkg..." + $VcpkgDir = "C:\vcpkg" + New-Item -ItemType Directory -Force -Path $VcpkgDir + # Default version to bake in: matching the repository version in ci/etc/vcpkg-version.txt + $VcpkgVersion = "3895230f38e498525f2560a281223d12066fa74a" + $VcpkgUrl = "https://github.com/microsoft/vcpkg/archive/$VcpkgVersion.tar.gz" + Invoke-WebRequest -Uri $VcpkgUrl -OutFile "$VcpkgDir\vcpkg.tar.gz" + tar -xzf "$VcpkgDir\vcpkg.tar.gz" -C $VcpkgDir --strip-components=1 + & "$VcpkgDir\bootstrap-vcpkg.sh" -disableMetrics + + # Save the baked vcpkg version to a file + $VcpkgVersion | Out-File -FilePath "C:\vcpkg_version.txt" -Encoding ascii + [Environment]::SetEnvironmentVariable("VCPKG_ROOT", $VcpkgDir, [EnvironmentVariableTarget]::Machine) + + # 7. Install Visual Studio 2022 Build Tools + if (-not (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe")) { + Write-Host "Installing Visual Studio 2022 Build Tools..." + $VsBootstrapperPath = "C:\vs_buildtools.exe" + Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vs_buildtools.exe" -OutFile $VsBootstrapperPath + + Write-Host "Running Visual Studio Installer..." + $Process = Start-Process -FilePath $VsBootstrapperPath -ArgumentList "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --passive --norestart --wait" -Wait -NoNewWindow -PassThru + + if ($Process.ExitCode -ne 0 -and $Process.ExitCode -ne 3010) { + throw "Visual Studio Build Tools installation failed with exit code: $($Process.ExitCode)" + } + Write-Host "Visual Studio Build Tools installed successfully." + } + + # 8. Run Sysprep generalization and shutdown + Write-Host "Running Sysprep generalization and shutdown..." + & $env:SystemRoot\System32\Sysprep\Sysprep.exe /oobe /generalize /shutdown /quiet +} +catch { + Write-Error "Error occurred during image provisioning: $_" + exit 1 +} +finally { + Stop-Transcript +} diff --git a/ci/cloudbuild/builds/windows-startup.ps1 b/ci/cloudbuild/builds/windows-startup.ps1 index 41ad82e30e273..6943b783dffd9 100644 --- a/ci/cloudbuild/builds/windows-startup.ps1 +++ b/ci/cloudbuild/builds/windows-startup.ps1 @@ -30,60 +30,25 @@ try { Write-Host "Features: $Features" Write-Host "Vcpkg Version: $VcpkgVersion" - # 2. Ensure Chocolatey is installed - if (-not (Get-Command choco -ErrorAction SilentlyContinue)) { - if (-not (Test-Path "C:\ProgramData\chocolatey\bin\choco.exe")) { - Write-Host "Installing Chocolatey..." - Set-ExecutionPolicy Bypass -Scope Process -Force - [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072 - Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1')) - } - $env:Path += ";C:\ProgramData\chocolatey\bin" - } - - # 3. Ensure Git is installed and in the PATH - if (-not (Get-Command git -ErrorAction SilentlyContinue)) { - Write-Host "Installing Git..." - choco install -y git --no-progress - $env:Path += ";C:\Program Files\Git\cmd" - } - - # 4. Ensure CMake is installed and in the PATH - if (-not (Get-Command cmake -ErrorAction SilentlyContinue)) { - Write-Host "Installing CMake..." - choco install -y cmake --version 3.31.6 --no-progress - $env:Path += ";C:\Program Files\CMake\bin" + # 2. Check if the pre-baked vcpkg version matches the requested version + $VcpkgDir = "C:\vcpkg" + $BakedVersion = "" + if (Test-Path "C:\vcpkg_version.txt") { + $BakedVersion = (Get-Content "C:\vcpkg_version.txt").Trim() } - - # 5. Ensure Ninja is installed and in the PATH - if (-not (Get-Command ninja -ErrorAction SilentlyContinue)) { - Write-Host "Installing Ninja..." - $NinjaDir = "C:\ninja" - New-Item -ItemType Directory -Force -Path $NinjaDir - Invoke-WebRequest -Uri "https://github.com/ninja-build/ninja/releases/download/v1.12.1/ninja-win.zip" -OutFile "$NinjaDir\ninja.zip" - Expand-Archive -Path "$NinjaDir\ninja.zip" -DestinationPath $NinjaDir -Force - Remove-Item "$NinjaDir\ninja.zip" - $env:Path += ";$NinjaDir" + if ($BakedVersion -ne $VcpkgVersion) { + Write-Host "Vcpkg version mismatch! Baked: $BakedVersion, Requested: $VcpkgVersion. Re-setting up vcpkg..." + Remove-Item -Recurse -Force $VcpkgDir -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Force -Path $VcpkgDir + $VcpkgUrl = "https://github.com/microsoft/vcpkg/archive/$VcpkgVersion.tar.gz" + Invoke-WebRequest -Uri $VcpkgUrl -OutFile "$VcpkgDir\vcpkg.tar.gz" + tar -xzf "$VcpkgDir\vcpkg.tar.gz" -C $VcpkgDir --strip-components=1 + & "$VcpkgDir\bootstrap-vcpkg.sh" -disableMetrics + $VcpkgVersion | Out-File -FilePath "C:\vcpkg_version.txt" -Encoding ascii + } else { + Write-Host "Using pre-baked vcpkg version: $VcpkgVersion" } - # 6. Download and Install sccache - Write-Host "Installing sccache..." - $SccacheDir = "C:\sccache" - New-Item -ItemType Directory -Force -Path $SccacheDir - $SccacheUrl = "https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-pc-windows-msvc.tar.gz" - Invoke-WebRequest -Uri $SccacheUrl -OutFile "$SccacheDir\sccache.tar.gz" - tar -xzf "$SccacheDir\sccache.tar.gz" -C $SccacheDir --strip-components=1 - $env:Path += ";$SccacheDir" - - # 7. Download and bootstrap vcpkg - Write-Host "Setting up vcpkg..." - $VcpkgDir = "C:\vcpkg" - New-Item -ItemType Directory -Force -Path $VcpkgDir - $VcpkgUrl = "https://github.com/microsoft/vcpkg/archive/$VcpkgVersion.tar.gz" - Invoke-WebRequest -Uri $VcpkgUrl -OutFile "$VcpkgDir\vcpkg.tar.gz" - tar -xzf "$VcpkgDir\vcpkg.tar.gz" -C $VcpkgDir --strip-components=1 - & "$VcpkgDir\bootstrap-vcpkg.sh" -disableMetrics - # 8. Extract workspace source codebase Write-Host "Extracting source..." $Workspace = "C:\workspace" @@ -99,21 +64,6 @@ try { $env:EXECUTE_INTEGRATION_TESTS = "false" # 10. Run MSVC Developer Environment Config - # Ensure Visual Studio 2022 Build Tools with C++ workload is installed - if (-not (Test-Path "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe")) { - Write-Host "Installing Visual Studio 2022 Build Tools..." - $VsBootstrapperPath = "C:\vs_buildtools.exe" - Invoke-WebRequest -Uri "https://aka.ms/vs/17/release/vs_buildtools.exe" -OutFile $VsBootstrapperPath - - Write-Host "Running Visual Studio Installer..." - $Process = Start-Process -FilePath $VsBootstrapperPath -ArgumentList "--add Microsoft.VisualStudio.Workload.VCTools --includeRecommended --passive --norestart --wait" -Wait -NoNewWindow -PassThru - - if ($Process.ExitCode -ne 0 -and $Process.ExitCode -ne 3010) { - throw "Visual Studio Build Tools installation failed with exit code: $($Process.ExitCode)" - } - Write-Host "Visual Studio Build Tools installed successfully." - Remove-Item $VsBootstrapperPath - } # Locates and runs vcvarsall.bat to configure compile paths Write-Host "Locating VS / MSVC compiler..." diff --git a/ci/cloudbuild/windows.yaml b/ci/cloudbuild/windows.yaml index f28cd83d349ef..dac7e29aabb3d 100644 --- a/ci/cloudbuild/windows.yaml +++ b/ci/cloudbuild/windows.yaml @@ -6,13 +6,14 @@ options: substitutions: _ZONE: 'us-east1-b' _MACHINE_TYPE: 'n2-standard-64' # 64 vCPUs, 256 GB RAM for fast compilation - _IMAGE_FAMILY: 'windows-2022' # Public image family - _IMAGE_PROJECT: 'windows-cloud' + _IMAGE_FAMILY: 'windows-cmake-builder' # Custom builder image family + _IMAGE_PROJECT: 'cloud-cpp-testing-resources' _SERVICE_ACCOUNT: 'windows-builder-sa@cloud-cpp-testing-resources.iam.gserviceaccount.com' _CACHE_BUCKET: 'cloud-cpp-testing-resources_cloudbuild' _LOGS_BUCKET: 'cloud-cpp-testing-resources_cloudbuild' _BUILD_TYPE: 'Release' _FEATURES: 'storage' + _BOOT_DISK_SIZE: '200GB' steps: # Step 1: Compress and upload workspace source code to GCS @@ -124,6 +125,7 @@ steps: --machine-type="${_MACHINE_TYPE}" \ --image-family="${_IMAGE_FAMILY}" \ --image-project="${_IMAGE_PROJECT}" \ + --boot-disk-size="${_BOOT_DISK_SIZE}" \ --service-account="${_SERVICE_ACCOUNT}" \ --scopes="https://www.googleapis.com/auth/cloud-platform" \ --metadata="source-archive=gs://${_CACHE_BUCKET}/source/source-${BUILD_ID}.tar.gz,build-type=${_BUILD_TYPE},features=${_FEATURES},logs-bucket=gs://${_LOGS_BUCKET}/logs/wincmake-${BUILD_ID},vcpkg-version=${vcpkg_version}" \