The dist branch existed to carry ~120 MB payloads that could not go on main. Once payloads became release attachments it held one 500-byte manifest.json, so it was a whole branch for a reason that no longer applied. The pointer is now a release asset too: each publish recreates a one-asset release naming the versioned build. Forgejo has no /releases/latest/download/ route (404), so a pointer is still required — but keeping it in a release means nothing about distribution lives in git: no payload branch, no bot commits on main, and no push that could retrigger the pipeline (which is why writing the manifest to main was not the answer either). Recreating the tag deletes the old release AND its tag; the tag outlives its release and would otherwise block recreation. Versioned releases are retained, so older builds stay downloadable. tools/publish-dist.ps1 is removed — publishing is CI's job now.
177 lines
8 KiB
YAML
177 lines
8 KiB
YAML
# Gitea Actions CI gate for the self-hosted runners.
|
|
#
|
|
# Deliberately does NOT use actions/setup-dotnet: data.forgejo.org (the mirror
|
|
# Gitea resolves actions from) does not host that action at all, and the
|
|
# self-hosted runners carry the pinned SDK band from global.json already.
|
|
# actions/checkout IS mirrored, so it is used normally.
|
|
#
|
|
# The suite runs through tools/run-release-gate.ps1 rather than a bare
|
|
# `dotnet test`: that script owns the xUnit trait-lane filter which excludes
|
|
# the InstalledDat / Live / Manual / OS-specific lanes. A bare `dotnet test`
|
|
# fails ~36 tests by design because those lanes assert their own preconditions.
|
|
name: CI
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
windows-gate:
|
|
runs-on: windows-latest
|
|
timeout-minutes: 45
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Verify the pinned SDK band resolves
|
|
shell: pwsh
|
|
run: |
|
|
dotnet --version
|
|
dotnet --list-sdks
|
|
|
|
# NOT tools/run-release-gate.ps1 here. That script redirects every child
|
|
# process to its own log file, so the step emits nothing for minutes at a
|
|
# time; Forgejo treats a task that stops reporting as a zombie and fails
|
|
# it while the work is still running (observed: job marked failed with 20
|
|
# dotnet processes still alive and a complete 8.7 MB TRX on disk). Running
|
|
# the projects directly keeps output streaming. The script stays the
|
|
# canonical LOCAL gate; the trait filter below is copied from its default.
|
|
- name: Build
|
|
shell: pwsh
|
|
run: dotnet build AcDream.slnx -c Release --nologo
|
|
|
|
- name: Test (lane-filtered, streaming)
|
|
shell: pwsh
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$filter = 'Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Lane!=Windows&Lane!=Linux&Lane!=SystemFont&Purpose!=Diagnostic&Status!=KnownFailure'
|
|
$failed = @()
|
|
foreach ($proj in Get-ChildItem tests -Directory | Sort-Object Name) {
|
|
$csproj = Join-Path $proj.FullName "$($proj.Name).csproj"
|
|
if (-not (Test-Path $csproj)) { continue }
|
|
Write-Host "::group::$($proj.Name)"
|
|
dotnet test $csproj -c Release --no-build --nologo --filter $filter
|
|
if ($LASTEXITCODE -ne 0) { $failed += $proj.Name }
|
|
Write-Host "::endgroup::"
|
|
}
|
|
if ($failed.Count) { throw "Failed test projects: $($failed -join ', ')" }
|
|
|
|
linux-portable:
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 45
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Portable closure (Linux lanes run here, not on Windows)
|
|
run: |
|
|
set -e
|
|
dotnet --version
|
|
for p in \
|
|
tests/AcDream.Platform.Tests \
|
|
tests/AcDream.Core.Tests \
|
|
tests/AcDream.Core.Net.Tests \
|
|
tests/AcDream.Content.Tests \
|
|
tests/AcDream.Runtime.Tests \
|
|
tests/AcDream.Headless.Tests \
|
|
tests/AcDream.Launcher.Core.Tests \
|
|
tests/AcDream.UI.Abstractions.Tests ; do
|
|
echo "::group::$p"
|
|
# MaxParallelThreads is capped because this runner is a small
|
|
# container. Under full-assembly parallel load
|
|
# FakeAceTransportTests.PausedSelector_SeededDroppedServerReady_
|
|
# RecoversOnIdleSweep took 37 s and missed its 2 s real-time wait,
|
|
# while passing 5/5 in ~350 ms in isolation. Timing-sensitive, not
|
|
# broken: starve it less rather than edit Campaign N transport code.
|
|
dotnet test "$p" -c Release --nologo \
|
|
--filter 'Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&Lane!=Manual&Lane!=Windows&Lane!=SystemFont&Purpose!=Diagnostic&Status!=KnownFailure' \
|
|
-- xUnit.MaxParallelThreads=2
|
|
echo "::endgroup::"
|
|
done
|
|
|
|
release:
|
|
# Same workflow rather than a workflow_run trigger: workflow_run is a
|
|
# GitHub feature whose Forgejo support is unreliable, while `needs` is
|
|
# guaranteed. A red gate therefore cannot publish.
|
|
needs: [windows-gate, linux-portable]
|
|
runs-on: windows-latest
|
|
timeout-minutes: 60
|
|
steps:
|
|
- uses: actions/checkout@v6
|
|
|
|
- name: Compute release version
|
|
id: ver
|
|
shell: pwsh
|
|
run: |
|
|
$v = '0.1.0-build.{0}' -f ([DateTime]::UtcNow.ToString('yyyyMMddHHmm'))
|
|
"version=$v" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
|
Write-Host "release version: $v"
|
|
|
|
- name: Build payloads with release-attachment URLs
|
|
shell: pwsh
|
|
env:
|
|
TAG: ${{ steps.ver.outputs.version }}
|
|
run: |
|
|
./tools/publish-bin.ps1 -Version $env:TAG -BaseUrl "${{ github.server_url }}/${{ github.repository }}/releases/download/$env:TAG"
|
|
|
|
- name: Create the release and upload payloads
|
|
shell: pwsh
|
|
env:
|
|
TAG: ${{ steps.ver.outputs.version }}
|
|
TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$api = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
|
$headers = @{ Authorization = "token $env:TOKEN" }
|
|
$body = @{
|
|
tag_name = $env:TAG
|
|
name = "acdream alpha $env:TAG"
|
|
body = "Automated alpha build from ${{ github.sha }}."
|
|
draft = $false
|
|
prerelease = $true
|
|
target_commitish = 'main'
|
|
} | ConvertTo-Json
|
|
$release = Invoke-RestMethod -Method Post -Uri "$api/releases" -Headers $headers -ContentType 'application/json' -Body $body
|
|
Write-Host "created release id=$($release.id)"
|
|
foreach ($f in Get-ChildItem bin -File) {
|
|
Write-Host ("uploading {0} ({1:N1} MB)" -f $f.Name, ($f.Length/1MB))
|
|
Invoke-RestMethod -Method Post -Headers $headers -Uri "$api/releases/$($release.id)/assets?name=$($f.Name)" -Form @{ attachment = Get-Item $f.FullName } | Out-Null
|
|
}
|
|
|
|
- name: Republish the `latest` pointer release
|
|
shell: pwsh
|
|
env:
|
|
TAG: ${{ steps.ver.outputs.version }}
|
|
TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
run: |
|
|
$ErrorActionPreference = 'Stop'
|
|
$api = "${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
|
|
$headers = @{ Authorization = "token $env:TOKEN" }
|
|
|
|
# Forgejo has no /releases/latest/download/ route, so the launcher
|
|
# needs a pointer at a URL that never changes. A one-asset release on
|
|
# the fixed `latest` tag is that pointer. Keeping it in a release
|
|
# rather than in git means no payload branch, no bot commits on main,
|
|
# and no push that would retrigger this workflow.
|
|
$existing = Invoke-RestMethod -Method Get -Headers $headers `
|
|
-Uri "$api/releases/tags/latest" -SkipHttpErrorCheck
|
|
if ($existing.id) {
|
|
Invoke-RestMethod -Method Delete -Headers $headers -Uri "$api/releases/$($existing.id)" | Out-Null
|
|
# The tag outlives its release and would block recreation.
|
|
Invoke-RestMethod -Method Delete -Headers $headers -Uri "$api/tags/latest" -SkipHttpErrorCheck | Out-Null
|
|
Write-Host "removed the previous latest pointer"
|
|
}
|
|
|
|
$body = @{
|
|
tag_name = 'latest'
|
|
name = "Update feed -> $env:TAG"
|
|
body = "Pointer the launcher polls. The downloads live in the ``$env:TAG`` release."
|
|
draft = $false
|
|
prerelease = $false
|
|
target_commitish = 'main'
|
|
} | ConvertTo-Json
|
|
$pointer = Invoke-RestMethod -Method Post -Uri "$api/releases" -Headers $headers `
|
|
-ContentType 'application/json' -Body $body
|
|
|
|
Invoke-RestMethod -Method Post -Headers $headers `
|
|
-Uri "$api/releases/$($pointer.id)/assets?name=manifest.json" `
|
|
-Form @{ attachment = Get-Item bin/manifest.json } | Out-Null
|
|
Write-Host "latest pointer now advertises $env:TAG"
|