Files
OpenZen/.github/workflows/build-loader.yml
T
Shirona1337 3263b0b4cb ci(loader): pin vcpkg baseline so the Qt cache stops missing
The vcpkg install was cloned at a floating HEAD while native/vcpkg.json
carried no builtin-baseline, so every run resolved the qtbase port afresh.
Its package ABI drifted whenever upstream vcpkg moved, the restored
actions/cache entry no longer matched, and qtbase was rebuilt from source
(~31 min) on every push. Because the cache key is static (hash of
vcpkg.json, unchanged since 05-23) the rebuilt tree was never saved back
either, so the miss repeated forever.

Pin both sides to vcpkg tag 2026.05.25
(d015e31e90838a4c9dfa3eed45979bc70d9357fc, qtbase 6.11.0):
  - native/vcpkg.json: add "builtin-baseline"
  - workflow: clone --branch 2026.05.25

Adding the baseline also changes the vcpkg.json hash, so this run gets a
fresh cache key, cold-builds Qt once, and saves it; subsequent runs match
the now-deterministic ABI and skip the qtbase build entirely.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 00:55:19 +08:00

233 lines
9.7 KiB
YAML

name: Build Loader
on:
push:
branches: [master]
# Only build when something that actually affects the output changed.
# README / docs / issue templates / .gitignore / .claude/ get to skip.
# Use workflow_dispatch (below) to force a run for anything else.
paths:
- 'src/**'
- 'native/**'
- 'build.gradle'
- 'settings.gradle'
- 'gradle.properties'
- 'gradle/wrapper/**'
- 'gradlew'
- 'gradlew.bat'
- '.github/workflows/build-loader.yml'
workflow_dispatch: {}
# contents: write so the [Release] commit-marker path can create a
# GitHub Release and upload the built artifacts.
# actions: write needed for vcpkg's GitHub Actions binary cache (x-gha backend).
permissions:
contents: write
actions: write
jobs:
build:
runs-on: windows-2022
timeout-minutes: 180
# Honour a [SKIP CI] marker (case-insensitive — GitHub's contains() is
# case-insensitive for string operands) anywhere in the head commit
# message. workflow_dispatch always runs since head_commit is null
# there and the !contains() short-circuits to true.
if: ${{ github.event_name != 'push' || !contains(github.event.head_commit.message, '[SKIP CI]') }}
env:
# NOTE: do not declare VCPKG_ROOT here. The windows-2022 runner
# ships VS Enterprise which pre-sets a system-wide VCPKG_ROOT
# pointing at its own (empty) vcpkg dir, and that pre-set value
# wins over a job-level env in PowerShell expansions. We export
# the right VCPKG_ROOT into $GITHUB_ENV inside the clone step
# so every later step sees our copy.
#
# We rely on actions/cache for the installed Qt artifacts; the
# vcpkg x-gha backend depends on the v1 GitHub Actions cache API
# which has been deprecated, and a fresh runner image often does
# not have ACTIONS_RESULTS_URL set for non-Node actions yet.
# Setting "files" as the binary source means vcpkg will still
# populate ${VCPKG_ROOT}/archives, which actions/cache then
# snapshots along with installed/.
VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}\\vcpkg-archives,readwrite"
# Opt every JavaScript action into the Node.js 24 runtime ahead of the
# 2026-06-02 forced switchover. The v4 / v1 pins below all still ship
# a Node 20 binary in their action.yml, and GitHub deprecated Node 20
# on 2025-09-19; setting this flag makes the runner execute them under
# Node 24 regardless, which silences the deprecation warning and
# de-risks the upcoming default flip.
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Resolve git revision
id: rev
shell: pwsh
run: |
$sha = git rev-parse --short=7 HEAD
"sha=$sha" | Out-File -FilePath $env:GITHUB_OUTPUT -Append
Write-Host "Build revision: $sha"
- name: Setup JDK 17
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
- name: Setup MSVC (x64)
uses: ilammy/msvc-dev-cmd@v1
with:
arch: x64
- name: Clone & bootstrap vcpkg
shell: pwsh
run: |
# Pin vcpkg to the SAME commit as native/vcpkg.json's
# "builtin-baseline". A floating HEAD clone made the qtbase port
# (and thus its package ABI) drift every time upstream vcpkg moved,
# so the restored Qt cache never matched and qtbase was rebuilt
# from source (~31 min) on every run. Tag 2026.05.25 ==
# d015e31e90838a4c9dfa3eed45979bc70d9357fc and ships qtbase 6.11.0.
# Keep this tag and the builtin-baseline in vcpkg.json in lockstep.
$vcpkgTag = '2026.05.25'
$vcpkg = Join-Path $env:GITHUB_WORKSPACE 'vcpkg'
if (Test-Path $vcpkg) {
Write-Host "Reusing existing $vcpkg"
} else {
git clone --depth=1 --branch $vcpkgTag https://github.com/microsoft/vcpkg.git $vcpkg
}
& "$vcpkg\bootstrap-vcpkg.bat" -disableMetrics
& "$vcpkg\vcpkg.exe" version
"VCPKG_ROOT=$vcpkg" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append
Write-Host "Exported VCPKG_ROOT=$vcpkg to GITHUB_ENV"
# Cache the resolved Qt install + the file-backed binary archive.
# Key is keyed on vcpkg.json so any dependency change invalidates;
# restore-keys lets a vcpkg.json bump still warm-start from the
# previous build's archives. installed/ alone makes CMake's manifest
# mode skip rebuilding qtbase; archives/ also fills back transitive
# deps if a partial rebuild is needed.
- name: Cache vcpkg installed + archives
uses: actions/cache@v4
with:
path: |
vcpkg\installed
vcpkg-archives
key: vcpkg-qt-${{ runner.os }}-${{ hashFiles('native/vcpkg.json') }}
restore-keys: |
vcpkg-qt-${{ runner.os }}-
- name: Install UPX
shell: pwsh
run: choco install upx -y --no-progress
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: gradle-${{ runner.os }}-${{ hashFiles('**/*.gradle', '**/gradle-wrapper.properties') }}
restore-keys: |
gradle-${{ runner.os }}-
- name: Build (clean dll upxCompress)
shell: pwsh
env:
OPENZEN_BUILD_REVISION: ${{ steps.rev.outputs.sha }}
run: |
Write-Host "VCPKG_ROOT = $env:VCPKG_ROOT"
Write-Host "JAVA_HOME = $env:JAVA_HOME"
Write-Host "OPENZEN_BUILD_REV = $env:OPENZEN_BUILD_REVISION"
.\gradlew.bat --no-daemon clean dll upxCompress
# Rename the two distributable artifacts so their final filenames carry
# the build sha. We rename rather than re-publish at build time so the
# local `./gradlew dll` workflow keeps producing stable filenames.
- name: Stage release artifacts
shell: pwsh
run: |
$sha = "${{ steps.rev.outputs.sha }}"
$exeSrc = "build\dist\OpenZenLoader.exe"
$jarSrc = "build\libs\hey-1.0.jar"
if (-not (Test-Path $exeSrc)) { throw "missing $exeSrc" }
if (-not (Test-Path $jarSrc)) { throw "missing $jarSrc" }
$release = "build\release"
New-Item -ItemType Directory -Force -Path $release | Out-Null
$exeDst = Join-Path $release "OpenZenLoader-$sha.exe"
$jarDst = Join-Path $release "OpenZen-$sha.jar"
Copy-Item -Force $exeSrc $exeDst
Copy-Item -Force $jarSrc $jarDst
$exeSz = (Get-Item $exeDst).Length
$jarSz = (Get-Item $jarDst).Length
Write-Host ("OpenZenLoader-{0}.exe : {1:N0} bytes ({2:N2} MB)" -f $sha, $exeSz, ($exeSz/1MB))
Write-Host ("OpenZen-{0}.jar : {1:N0} bytes ({2:N2} MB)" -f $sha, $jarSz, ($jarSz/1MB))
# NOTE: actions/upload-artifact always wraps its content in a zip; that
# is a platform limitation we cannot disable. By giving each artifact a
# single file whose name already encodes the sha, the download is
# OpenZenLoader-<sha>.exe.zip / OpenZen-<sha>.jar.zip, each containing
# just the named file (no nested directory). For raw exe/jar downloads
# without the zip wrapper, attach to a GitHub Release instead.
- name: Upload OpenZenLoader exe
uses: actions/upload-artifact@v4
with:
name: OpenZenLoader-${{ steps.rev.outputs.sha }}.exe
path: build/release/OpenZenLoader-${{ steps.rev.outputs.sha }}.exe
if-no-files-found: error
retention-days: 30
- name: Upload OpenZen jar
uses: actions/upload-artifact@v4
with:
name: OpenZen-${{ steps.rev.outputs.sha }}.jar
path: build/release/OpenZen-${{ steps.rev.outputs.sha }}.jar
if-no-files-found: error
retention-days: 30
# ===== Optional GitHub Release publish =====
# If the HEAD commit message contains the literal marker "[Release]",
# cut a GitHub Release tagged build-<sha> and attach the exe + jar.
# Without the marker, this step is skipped — every push still produces
# the Actions artifacts above, only tagged releases are gated.
- name: Detect [Release] marker
id: relmark
shell: pwsh
run: |
$msg = (git log -1 --pretty=%B HEAD | Out-String)
# Case-insensitive match so [release], [Release], [RELEASE] all
# qualify; .Contains in .NET is case-sensitive by default.
$isRelease = $msg.IndexOf("[Release]", [System.StringComparison]::OrdinalIgnoreCase) -ge 0
"is_release=$($isRelease.ToString().ToLower())" |
Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append
Write-Host "HEAD commit message:"
Write-Host $msg
Write-Host "[Release] marker present: $isRelease"
- name: Publish GitHub Release
if: steps.relmark.outputs.is_release == 'true'
shell: pwsh
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SHA: ${{ steps.rev.outputs.sha }}
run: |
$tag = "build-$env:SHA"
$title = "Build $env:SHA"
# Write notes via a file so quoting / [brackets] / newlines in the
# commit message can't corrupt the gh command line.
$notes = "release-notes.md"
git log -1 --pretty=%B HEAD | Out-File -FilePath $notes -Encoding utf8
gh release create $tag `
--title $title `
--notes-file $notes `
"build/release/OpenZenLoader-$env:SHA.exe" `
"build/release/OpenZen-$env:SHA.jar"