fix(release): use GitHub-hosted runners (#685)
This commit is contained in:
1 parent
d79180fda2
commit
47e3838e0b
4 files changed
+119
-53
No files matched your search
@@ -10,8 +10,8 @@ permissions:
|
||||
|
||||
# 竖线分隔在任何错误(含网络错误)时回退到下一个源;默认的逗号只在
|
||||
# 404/410 时回退,proxy.golang.org 瞬时故障会直接让整个 job 失败。
|
||||
# 自托管 Runner 保留本机 Go 缓存;代码与编译参数变化由 Go 自动判定失效。
|
||||
# 不再下载/上传 setup-go 缓存,也无需 main push 预热。
|
||||
# CI 保留自托管 Runner 的本机 Go 缓存;Release 使用 GitHub 托管的临时 Runner。
|
||||
# 两条流程都不下载/上传 setup-go 缓存,也无需 main push 预热。
|
||||
env:
|
||||
GOPROXY: https://proxy.golang.org|direct
|
||||
|
||||
@@ -21,7 +21,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
validate-tag:
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -143,7 +143,7 @@ jobs:
|
||||
|
||||
verify-and-build-web:
|
||||
needs: validate-tag
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -165,7 +165,7 @@ jobs:
|
||||
|
||||
static-checks:
|
||||
needs: validate-tag
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -208,7 +208,7 @@ jobs:
|
||||
needs: validate-tag
|
||||
# 同一 commit 的 CI 已全绿时跳过;publication-preflight 接受 skipped 结果。
|
||||
if: ${{ needs.validate-tag.outputs.ci_verified != 'true' }}
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -228,7 +228,7 @@ jobs:
|
||||
race-cpa:
|
||||
needs: validate-tag
|
||||
if: ${{ needs.validate-tag.outputs.ci_verified != 'true' }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -250,7 +250,7 @@ jobs:
|
||||
name: Database contract (${{ matrix.driver }})
|
||||
needs: validate-tag
|
||||
if: ${{ needs.validate-tag.outputs.ci_verified != 'true' }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -328,23 +328,23 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
- goos: linux
|
||||
runner: [self-hosted, Linux, ARM64]
|
||||
runner: ubuntu-24.04
|
||||
goarch: amd64
|
||||
filename: gpt-load-linux-amd64
|
||||
- goos: linux
|
||||
runner: [self-hosted, Linux, ARM64]
|
||||
runner: ubuntu-24.04
|
||||
goarch: arm64
|
||||
filename: gpt-load-linux-arm64
|
||||
- goos: darwin
|
||||
runner: [self-hosted, macOS, ARM64]
|
||||
runner: macos-15
|
||||
goarch: amd64
|
||||
filename: gpt-load-macos-amd64
|
||||
- goos: darwin
|
||||
runner: [self-hosted, macOS, ARM64]
|
||||
runner: macos-15
|
||||
goarch: arm64
|
||||
filename: gpt-load-macos-arm64
|
||||
- goos: windows
|
||||
runner: [self-hosted, Windows, X64]
|
||||
runner: windows-2025
|
||||
goarch: amd64
|
||||
filename: gpt-load-windows-amd64.exe
|
||||
steps:
|
||||
@@ -389,7 +389,7 @@ jobs:
|
||||
|
||||
build-windows-setup:
|
||||
needs: build-binaries
|
||||
runs-on: [self-hosted, Windows, X64]
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -433,7 +433,7 @@ jobs:
|
||||
|
||||
package-metadata:
|
||||
needs: validate-tag
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -473,7 +473,7 @@ jobs:
|
||||
- build-binaries
|
||||
- build-windows-setup
|
||||
- package-metadata
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -533,15 +533,15 @@ jobs:
|
||||
max-parallel: 5
|
||||
matrix:
|
||||
include:
|
||||
- runner: [self-hosted, Linux, X64]
|
||||
- runner: ubuntu-24.04
|
||||
filename: gpt-load-linux-amd64
|
||||
- runner: [self-hosted, Linux, ARM64]
|
||||
- runner: ubuntu-24.04-arm
|
||||
filename: gpt-load-linux-arm64
|
||||
- runner: macos-15-intel
|
||||
filename: gpt-load-macos-amd64
|
||||
- runner: [self-hosted, macOS, ARM64]
|
||||
- runner: macos-15
|
||||
filename: gpt-load-macos-arm64
|
||||
- runner: [self-hosted, Windows, X64]
|
||||
- runner: windows-2025
|
||||
filename: gpt-load-windows-amd64.exe
|
||||
runs-on: ${{ matrix.runner }}
|
||||
steps:
|
||||
@@ -584,7 +584,7 @@ jobs:
|
||||
|
||||
windows-installer-smoke:
|
||||
needs: package-checksums
|
||||
runs-on: [self-hosted, Windows, X64]
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Checkout tag commit
|
||||
@@ -623,7 +623,7 @@ jobs:
|
||||
|
||||
docker-smoke:
|
||||
needs: validate-tag
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- name: Isolate Docker credentials
|
||||
@@ -660,9 +660,9 @@ jobs:
|
||||
# 路径 COPY 的是不同的二进制,必须各自验证。使用原生 arm64 runner 而非
|
||||
# QEMU:QEMU 模拟下的启动行为不能代表真实 arm64 运行时。
|
||||
- arch: amd64
|
||||
runner: [self-hosted, Linux, X64]
|
||||
runner: ubuntu-24.04
|
||||
- arch: arm64
|
||||
runner: [self-hosted, Linux, ARM64]
|
||||
runner: ubuntu-24.04-arm
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
@@ -714,7 +714,7 @@ jobs:
|
||||
# race-tests、race-cpa 与 database-contract 在 CI 已验证同一 commit 时为 skipped,
|
||||
# 这里只拒绝真正失败的 gate,不把 skipped 当作缺失的验证。
|
||||
if: ${{ !cancelled() && !contains(needs.*.result, 'failure') }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
# Draft Releases are visible only to identities with push access.
|
||||
@@ -977,7 +977,7 @@ jobs:
|
||||
# 间接祖先因 CI 结论复用而 skipped,publish-images 也会被默认条件连带跳过,
|
||||
# 即便这里列出的直接 needs 全部成功。显式条件只看直接 needs,绕开这个传播。
|
||||
if: ${{ !cancelled() && needs.validate-tag.result == 'success' && needs.publication-preflight.result == 'success' }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1007,7 +1007,7 @@ jobs:
|
||||
if: ${{ needs.publication-preflight.outputs.write_mode == 'publish' }}
|
||||
uses: docker/setup-qemu-action@1f40c72289eff860ee54a304f1438e3cff362e0a # v4.3.0
|
||||
with:
|
||||
platforms: amd64
|
||||
platforms: arm64
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4.3.0
|
||||
@@ -1093,7 +1093,7 @@ jobs:
|
||||
- publish-images
|
||||
# 同上:显式条件只看直接 needs,避免默认条件把间接祖先的 skip 传播下来。
|
||||
if: ${{ !cancelled() && needs.validate-tag.result == 'success' && needs.publication-preflight.result == 'success' && needs.publish-images.result == 'success' }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -1162,6 +1162,9 @@ jobs:
|
||||
make_latest: false
|
||||
generate_release_notes: true
|
||||
fail_on_unmatched_files: true
|
||||
# 串行上传避免单个 runner 的并发连接中断拖垮整组资产;重试时保留已成功资产。
|
||||
preserve_order: true
|
||||
overwrite_files: false
|
||||
# 目录内容已由上面的清单校验锁定为 .github/release-assets.txt 的全集。
|
||||
files: release/*
|
||||
body: |
|
||||
@@ -1180,7 +1183,7 @@ jobs:
|
||||
- publish-images
|
||||
# 同上:显式条件只看直接 needs,避免默认条件把间接祖先的 skip 传播下来。
|
||||
if: ${{ !cancelled() && needs.validate-tag.result == 'success' && needs.publish-images.result == 'success' }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1223,7 +1226,7 @@ jobs:
|
||||
- publish-images
|
||||
# 同上:显式条件只看直接 needs,避免默认条件把间接祖先的 skip 传播下来。
|
||||
if: ${{ !cancelled() && needs.validate-tag.result == 'success' && needs.publication-preflight.result == 'success' && needs.publish-github.result == 'success' && needs.publish-images.result == 'success' }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
# Draft Releases are visible only to identities with push access.
|
||||
@@ -1366,7 +1369,7 @@ jobs:
|
||||
group: gpt-load-v2-image-channels
|
||||
cancel-in-progress: false
|
||||
queue: max
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 20
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1436,7 +1439,7 @@ jobs:
|
||||
environment:
|
||||
name: render
|
||||
url: ${{ vars.RENDER_SERVICE_URL }}
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -1446,7 +1449,7 @@ jobs:
|
||||
RELEASE_VERSION: ${{ needs.validate-tag.outputs.version }}
|
||||
IMAGE: ghcr.io/tbphp/gpt-load:${{ needs.validate-tag.outputs.image_exact }}
|
||||
RENDER_CLI_VERSION: "2.25.0"
|
||||
RENDER_CLI_SHA256: "7c4dc66ded7acc75e2f828b02d3d6901e9f2e4175d25c4fe5fd6f3aaf66b071b"
|
||||
RENDER_CLI_SHA256: "3b3f1f839ef36b81f12d84ac7288f1c96f9f7519b39c53fe6f866612f704e7cd"
|
||||
steps:
|
||||
- name: Validate deployment inputs
|
||||
shell: bash
|
||||
@@ -1461,7 +1464,7 @@ jobs:
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
archive="cli_${RENDER_CLI_VERSION}_linux_arm64.zip"
|
||||
archive="cli_${RENDER_CLI_VERSION}_linux_amd64.zip"
|
||||
archive_path="${RUNNER_TEMP}/${archive}"
|
||||
extract_dir="${RUNNER_TEMP}/render-cli-${RENDER_CLI_VERSION}"
|
||||
url="https://github.com/render-oss/cli/releases/download/v${RENDER_CLI_VERSION}/${archive}"
|
||||
@@ -1556,7 +1559,7 @@ jobs:
|
||||
- post-publish-image-smoke
|
||||
- post-publish-verify
|
||||
- promote-image-channels
|
||||
runs-on: [self-hosted, Linux, ARM64]
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
# Draft Releases are visible only to identities with push access.
|
||||
|
||||
@@ -19,7 +19,7 @@ func TestWindowsInstallerKeepsPortableBinaryAndAddsSetupAsset(t *testing.T) {
|
||||
workflow := readRepositoryFile(t, ".github/workflows/release.yml")
|
||||
setupJob := workflowJobBlock(t, workflow, "build-windows-setup")
|
||||
for _, required := range []string{
|
||||
"runs-on: [self-hosted, Windows, X64]",
|
||||
"runs-on: windows-2025",
|
||||
"binary-gpt-load-windows-amd64.exe",
|
||||
"packaging/windows/gpt-load.iss",
|
||||
"ISCC.exe",
|
||||
|
||||
@@ -36,7 +36,7 @@ func TestSelfHostedCIKeepsPlatformGatesAndLocalCaches(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelfHostedReleaseIsolatesDockerCredentials(t *testing.T) {
|
||||
func TestReleaseIsolatesDockerCredentials(t *testing.T) {
|
||||
content := readRepositoryFile(t, ".github/workflows/release.yml")
|
||||
for _, job := range []string{
|
||||
"docker-smoke", "prebuilt-image-smoke", "publication-preflight", "publish-images",
|
||||
@@ -56,22 +56,85 @@ func TestSelfHostedReleaseIsolatesDockerCredentials(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestReleaseKeepsX64OnlyForNativeAMD64Validation(t *testing.T) {
|
||||
func TestReleaseUsesGitHubHostedRunners(t *testing.T) {
|
||||
content := readRepositoryFile(t, ".github/workflows/release.yml")
|
||||
const x64 = "[self-hosted, Linux, X64]"
|
||||
if strings.Count(content, x64) != 2 {
|
||||
t.Fatal("Linux X64 must only run the native binary and prebuilt image AMD64 gates")
|
||||
if strings.Contains(content, "self-hosted") {
|
||||
t.Fatal("release workflow must not route release-specific jobs to self-hosted runners")
|
||||
}
|
||||
for _, job := range []string{"native-artifact-smoke", "prebuilt-image-smoke"} {
|
||||
for _, job := range []string{
|
||||
"validate-tag", "verify-and-build-web", "static-checks", "race-tests", "race-cpa",
|
||||
"database-contract", "package-metadata", "package-checksums", "docker-smoke",
|
||||
"publication-preflight", "publish-images", "publish-github", "post-publish-image-smoke",
|
||||
"post-publish-verify", "promote-image-channels", "deploy-render", "reconcile-publication",
|
||||
} {
|
||||
block := workflowJobBlock(t, content, job)
|
||||
if !strings.Contains(block, x64) || !strings.Contains(block, "[self-hosted, Linux, ARM64]") {
|
||||
t.Errorf("%s must retain both native Linux architectures", job)
|
||||
if !strings.Contains(block, "runs-on: ubuntu-24.04") {
|
||||
t.Errorf("%s is not assigned to the GitHub-hosted Ubuntu runner", job)
|
||||
}
|
||||
}
|
||||
for _, job := range []string{"build-windows-setup", "windows-installer-smoke"} {
|
||||
block := workflowJobBlock(t, content, job)
|
||||
if !strings.Contains(block, "runs-on: windows-2025") {
|
||||
t.Errorf("%s is not assigned to the GitHub-hosted Windows runner", job)
|
||||
}
|
||||
}
|
||||
for _, test := range []struct {
|
||||
job string
|
||||
required []string
|
||||
}{
|
||||
{
|
||||
job: "build-binaries",
|
||||
required: []string{
|
||||
"runner: ubuntu-24.04\n goarch: amd64",
|
||||
"runner: ubuntu-24.04\n goarch: arm64",
|
||||
"runner: macos-15\n goarch: amd64",
|
||||
"runner: macos-15\n goarch: arm64",
|
||||
"runner: windows-2025\n goarch: amd64",
|
||||
},
|
||||
},
|
||||
{
|
||||
job: "native-artifact-smoke",
|
||||
required: []string{
|
||||
"runner: ubuntu-24.04\n filename: gpt-load-linux-amd64",
|
||||
"runner: ubuntu-24.04-arm\n filename: gpt-load-linux-arm64",
|
||||
"runner: macos-15-intel\n filename: gpt-load-macos-amd64",
|
||||
"runner: macos-15\n filename: gpt-load-macos-arm64",
|
||||
"runner: windows-2025\n filename: gpt-load-windows-amd64.exe",
|
||||
},
|
||||
},
|
||||
{
|
||||
job: "prebuilt-image-smoke",
|
||||
required: []string{
|
||||
"runner: ubuntu-24.04\n - arch: arm64",
|
||||
"runner: ubuntu-24.04-arm",
|
||||
},
|
||||
},
|
||||
} {
|
||||
block := workflowJobBlock(t, content, test.job)
|
||||
for _, required := range test.required {
|
||||
if !strings.Contains(block, required) {
|
||||
t.Errorf("%s does not include %s", test.job, required)
|
||||
}
|
||||
}
|
||||
}
|
||||
publish := workflowJobBlock(t, content, "publish-images")
|
||||
qemu := workflowStepBlock(t, publish, "Set up QEMU")
|
||||
if !strings.Contains(publish, "runs-on: [self-hosted, Linux, ARM64]") ||
|
||||
!strings.Contains(qemu, "platforms: amd64") {
|
||||
t.Fatal("ARM64 image publisher must enable AMD64 emulation for the other target")
|
||||
if !strings.Contains(qemu, "platforms: arm64") {
|
||||
t.Fatal("AMD64 hosted image publisher must enable ARM64 emulation for the other target")
|
||||
}
|
||||
publishGitHub := workflowStepBlock(t, workflowJobBlock(t, content, "publish-github"), "Create or update GitHub Release draft")
|
||||
for _, required := range []string{"preserve_order: true", "overwrite_files: false"} {
|
||||
if !strings.Contains(publishGitHub, required) {
|
||||
t.Errorf("GitHub Release asset upload does not contain %q", required)
|
||||
}
|
||||
}
|
||||
deployRender := workflowJobBlock(t, content, "deploy-render")
|
||||
for _, required := range []string{
|
||||
"cli_${RENDER_CLI_VERSION}_linux_amd64.zip",
|
||||
"3b3f1f839ef36b81f12d84ac7288f1c96f9f7519b39c53fe6f866612f704e7cd",
|
||||
} {
|
||||
if !strings.Contains(deployRender, required) {
|
||||
t.Errorf("Render deployment does not contain %q", required)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1394,7 +1394,7 @@ func TestReleaseWorkflowDeploysCurrentMajorChannelToRender(t *testing.T) {
|
||||
"RELEASE_VERSION: ${{ needs.validate-tag.outputs.version }}",
|
||||
"IMAGE: ghcr.io/tbphp/gpt-load:${{ needs.validate-tag.outputs.image_exact }}",
|
||||
`RENDER_CLI_VERSION: "2.25.0"`,
|
||||
`RENDER_CLI_SHA256: "7c4dc66ded7acc75e2f828b02d3d6901e9f2e4175d25c4fe5fd6f3aaf66b071b"`,
|
||||
`RENDER_CLI_SHA256: "3b3f1f839ef36b81f12d84ac7288f1c96f9f7519b39c53fe6f866612f704e7cd"`,
|
||||
} {
|
||||
if !strings.Contains(job, required) {
|
||||
t.Fatalf("Render deployment job does not contain %q:\n%s", required, job)
|
||||
@@ -1411,7 +1411,7 @@ func TestReleaseWorkflowDeploysCurrentMajorChannelToRender(t *testing.T) {
|
||||
"RENDER_CLI_VERSION",
|
||||
"RENDER_CLI_SHA256",
|
||||
"sha256sum --check",
|
||||
"cli_${RENDER_CLI_VERSION}_linux_arm64.zip",
|
||||
"cli_${RENDER_CLI_VERSION}_linux_amd64.zip",
|
||||
"--retry-all-errors",
|
||||
} {
|
||||
if !strings.Contains(install, required) {
|
||||
@@ -2144,11 +2144,11 @@ func TestReleaseWorkflowPostPublishVerifiesDraftAssetsAgainstCurrentRun(t *testi
|
||||
// 发布前的五平台原生 smoke 仍然是必须的门禁。
|
||||
nativeJob := workflowJobBlock(t, content, "native-artifact-smoke")
|
||||
for _, required := range []string{
|
||||
"[self-hosted, Linux, X64]",
|
||||
"[self-hosted, Linux, ARM64]",
|
||||
"ubuntu-24.04",
|
||||
"ubuntu-24.04-arm",
|
||||
"macos-15-intel",
|
||||
"[self-hosted, macOS, ARM64]",
|
||||
"[self-hosted, Windows, X64]",
|
||||
"macos-15",
|
||||
"windows-2025",
|
||||
"gpt-load-linux-amd64",
|
||||
"gpt-load-linux-arm64",
|
||||
"gpt-load-macos-amd64",
|
||||
|
||||
Reference in new issue
Block a user