Run Windows release orchestration on Forgejo desktop-release
Some checks failed
Windows Release / windows-x86_64 (push) Has been cancelled
Some checks failed
Windows Release / windows-x86_64 (push) Has been cancelled
Tower runner dispatches/waits on the private GitHub MSVC builder and verifies the public windows-continuous Forgejo release. Needs GH_BUILDER_TOKEN on the Forgejo repo. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
3140f9bb55
commit
166778d451
2 changed files with 111 additions and 164 deletions
|
|
@ -1,7 +1,8 @@
|
|||
name: Windows Release
|
||||
|
||||
# Continuous Windows portable build on every push to main.
|
||||
# Needs self-hosted runner label `windows-release` (MSVC 2022).
|
||||
# Forgejo-orchestrated Windows portable zip.
|
||||
# Tower `desktop-release` triggers the private GitHub builder (MSVC), then
|
||||
# verifies the public Forgejo release tag `windows-continuous`.
|
||||
# See docs/windows-runner.md
|
||||
|
||||
on:
|
||||
|
|
@ -18,30 +19,18 @@ concurrency:
|
|||
|
||||
jobs:
|
||||
windows-x86_64:
|
||||
runs-on: windows-release
|
||||
timeout-minutes: 240
|
||||
runs-on: desktop-release
|
||||
timeout-minutes: 360
|
||||
steps:
|
||||
- name: Checkout
|
||||
shell: bash
|
||||
env:
|
||||
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
rm -rf .git
|
||||
git init .
|
||||
origin_url="${GITHUB_SERVER_URL#https://}"
|
||||
origin_url="${origin_url#http://}"
|
||||
git remote add origin "https://oauth2:${FORGEJO_TOKEN}@${origin_url}/${GITHUB_REPOSITORY}.git"
|
||||
git -c http.sslVerify=false fetch --depth=1 origin "${GITHUB_SHA}"
|
||||
git checkout --force FETCH_HEAD
|
||||
git submodule update --init --recursive
|
||||
|
||||
- name: Resolve version
|
||||
- name: Resolve expected asset
|
||||
id: ver
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
ver="$(grep -E 'CURRENT_VERSION_STRING' src/VersionConstants.hpp | head -1 | sed -E 's/.*"([^"]+)".*/\1/')"
|
||||
# Shallow metadata from the triggering commit (no full Windows checkout).
|
||||
ver="$(curl -fsSL -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
|
||||
"${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/contents/src/VersionConstants.hpp?ref=${GITHUB_SHA}" \
|
||||
| python3 -c "import sys,json,base64,re; d=json.load(sys.stdin); t=base64.b64decode(d['content']).decode(); print(re.search(r'CURRENT_VERSION_STRING\s*=\s*\"([^\"]+)\"', t).group(1))")"
|
||||
short_sha="$(echo "${GITHUB_SHA}" | cut -c1-7)"
|
||||
asset_ver="${ver}+${short_sha}"
|
||||
zip_name="infinipaint-${asset_ver}-win-x86_64-portable.zip"
|
||||
|
|
@ -50,129 +39,87 @@ jobs:
|
|||
echo "tag=windows-continuous"
|
||||
echo "asset_ver=${asset_ver}"
|
||||
echo "zip_name=${zip_name}"
|
||||
echo "short_sha=${short_sha}"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
echo "Expect Forgejo asset: ${zip_name}"
|
||||
|
||||
- name: Ensure Conan
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
if (-not (Get-Command conan -ErrorAction SilentlyContinue)) {
|
||||
python -m pip install --user "conan>=2,<3"
|
||||
Get-ChildItem "$env:USERPROFILE\AppData\Roaming\Python" -Recurse -Filter conan.exe -ErrorAction SilentlyContinue |
|
||||
ForEach-Object { $env:Path = "$($_.DirectoryName);$env:Path" }
|
||||
}
|
||||
conan --version
|
||||
|
||||
- name: Build Windows x86_64
|
||||
shell: cmd
|
||||
run: |
|
||||
call windowsinstall\conan_init_x86_64.bat
|
||||
if errorlevel 1 exit /b 1
|
||||
call windowsinstall\build_x86_64.bat
|
||||
if errorlevel 1 exit /b 1
|
||||
|
||||
- name: Package portable zip
|
||||
id: pkg
|
||||
shell: pwsh
|
||||
env:
|
||||
ZIP_NAME: ${{ steps.ver.outputs.zip_name }}
|
||||
run: |
|
||||
$ErrorActionPreference = "Stop"
|
||||
$exe = Get-ChildItem -Path . -Recurse -Filter infinipaint.exe |
|
||||
Where-Object { $_.FullName -match 'Release' } |
|
||||
Select-Object -First 1
|
||||
if (-not $exe) { throw "infinipaint.exe not found under Release" }
|
||||
$outDir = Join-Path (Get-Location) "dist\portable"
|
||||
Remove-Item -Recurse -Force $outDir -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
|
||||
Copy-Item $exe.FullName (Join-Path $outDir "infinipaint.exe")
|
||||
$dllDir = Join-Path (Get-Location) "windowsinstall\dlls-x86_64"
|
||||
if (Test-Path $dllDir) {
|
||||
Copy-Item (Join-Path $dllDir "*.dll") $outDir -ErrorAction SilentlyContinue
|
||||
}
|
||||
$dataSrc = Join-Path (Get-Location) "assets\data"
|
||||
if (-not (Test-Path $dataSrc)) { $dataSrc = Join-Path (Get-Location) "data" }
|
||||
Copy-Item -Recurse $dataSrc (Join-Path $outDir "data")
|
||||
New-Item -ItemType Directory -Force -Path "dist" | Out-Null
|
||||
$zipPath = Join-Path (Get-Location) "dist\$env:ZIP_NAME"
|
||||
if (Test-Path $zipPath) { Remove-Item $zipPath }
|
||||
Compress-Archive -Path (Join-Path $outDir "*") -DestinationPath $zipPath
|
||||
"zip_path=$zipPath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||
Get-Item $zipPath | Format-List FullName, Length
|
||||
|
||||
- name: Publish Forgejo release
|
||||
- name: Dispatch or reuse GitHub Windows build
|
||||
id: gh
|
||||
shell: bash
|
||||
env:
|
||||
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
VERSION_TAG: ${{ steps.ver.outputs.tag }}
|
||||
ASSET_VER: ${{ steps.ver.outputs.asset_ver }}
|
||||
VERSION: ${{ steps.ver.outputs.version }}
|
||||
ZIP_NAME: ${{ steps.ver.outputs.zip_name }}
|
||||
FORGEJO_CURL_INSECURE: "true"
|
||||
GH_BUILDER_TOKEN: ${{ secrets.GH_BUILDER_TOKEN }}
|
||||
WANT_SHA: ${{ github.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
zip_path="dist/${ZIP_NAME}"
|
||||
test -f "$zip_path"
|
||||
command -v jq >/dev/null
|
||||
command -v curl >/dev/null
|
||||
|
||||
curl_tls=()
|
||||
if [ "${FORGEJO_CURL_INSECURE}" = "true" ]; then
|
||||
curl_tls+=(--insecure)
|
||||
if [ -z "${GH_BUILDER_TOKEN:-}" ]; then
|
||||
echo "GH_BUILDER_TOKEN secret missing on Forgejo repo" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
api_base="${GITHUB_API_URL}/repos/${GITHUB_REPOSITORY}/releases"
|
||||
body=$(printf '%s\n' \
|
||||
"Continuous Windows build from \`main\`." \
|
||||
"" \
|
||||
"- Version: **${VERSION}**" \
|
||||
"- Commit: \`${GITHUB_SHA}\`" \
|
||||
"- Asset: \`${ZIP_NAME}\`" \
|
||||
"" \
|
||||
"Updated on every push to \`main\`. Requires runner label \`windows-release\` (see docs/windows-runner.md).")
|
||||
|
||||
payload=$(jq -n \
|
||||
--arg tag "$VERSION_TAG" \
|
||||
--arg name "Windows continuous (${ASSET_VER})" \
|
||||
--arg body "$body" \
|
||||
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:true}')
|
||||
|
||||
tag_enc=$(jq -nr --arg t "$VERSION_TAG" '$t|@uri')
|
||||
resp_file=$(mktemp)
|
||||
status=$(curl "${curl_tls[@]}" -sS -o "$resp_file" -w '%{http_code}' \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${api_base}/tags/${tag_enc}")
|
||||
|
||||
release_id=""
|
||||
if [ "$status" = "200" ]; then
|
||||
release_id=$(jq -r '.id' < "$resp_file")
|
||||
curl "${curl_tls[@]}" -sS -X PATCH \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
"${api_base}/${release_id}" >/dev/null
|
||||
jq -r --arg n "$ZIP_NAME" '.assets[]? | select(.name==$n) | .id' < "$resp_file" | while read -r aid; do
|
||||
[ -n "$aid" ] || continue
|
||||
curl "${curl_tls[@]}" -sS -X DELETE \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
"${api_base}/${release_id}/assets/${aid}" >/dev/null || true
|
||||
done
|
||||
elif [ "$status" = "404" ]; then
|
||||
status=$(curl "${curl_tls[@]}" -sS -o "$resp_file" -w '%{http_code}' -X POST \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
"$api_base")
|
||||
[ "$status" = "200" ] || [ "$status" = "201" ] || { cat "$resp_file"; exit 1; }
|
||||
release_id=$(jq -r '.id' < "$resp_file")
|
||||
else
|
||||
cat "$resp_file"; exit 1
|
||||
api="https://api.github.com/repos/littlecodedragon/infinipaint"
|
||||
auth=(-H "Authorization: Bearer ${GH_BUILDER_TOKEN}" -H "Accept: application/vnd.github+json")
|
||||
gh_sha=$(curl -fsSL "${auth[@]}" "${api}/commits/main" | python3 -c "import sys,json; print(json.load(sys.stdin)['sha'])")
|
||||
if [ "$gh_sha" != "$WANT_SHA" ]; then
|
||||
echo "WARN: GitHub main=${gh_sha:0:7} != Forgejo ${WANT_SHA:0:7} — keep remotes synced (push both)." >&2
|
||||
fi
|
||||
runs=$(curl -fsSL "${auth[@]}" "${api}/actions/workflows/windows_release.yml/runs?branch=main&per_page=15")
|
||||
run_id=$(echo "$runs" | python3 -c "
|
||||
import sys, json, os
|
||||
want = os.environ['WANT_SHA']
|
||||
runs = json.load(sys.stdin).get('workflow_runs', [])
|
||||
# Prefer live or successful run for this SHA.
|
||||
for r in runs:
|
||||
if r.get('head_sha') != want:
|
||||
continue
|
||||
st, conc = r.get('status'), r.get('conclusion')
|
||||
if st in ('queued', 'in_progress') or (st == 'completed' and conc == 'success'):
|
||||
print(r['id'])
|
||||
break
|
||||
")
|
||||
if [ -z "${run_id}" ]; then
|
||||
echo "No usable GitHub run for ${WANT_SHA:0:7} — dispatching workflow_dispatch"
|
||||
code=$(curl -sS -o /tmp/gh-dispatch.json -w '%{http_code}' -X POST "${auth[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"${api}/actions/workflows/windows_release.yml/dispatches" \
|
||||
-d '{"ref":"main"}')
|
||||
[ "$code" = "204" ] || { cat /tmp/gh-dispatch.json; exit 1; }
|
||||
sleep 8
|
||||
runs=$(curl -fsSL "${auth[@]}" "${api}/actions/workflows/windows_release.yml/runs?branch=main&per_page=5")
|
||||
run_id=$(echo "$runs" | python3 -c "import sys,json; print(json.load(sys.stdin)['workflow_runs'][0]['id'])")
|
||||
fi
|
||||
echo "run_id=${run_id}" >> "$GITHUB_OUTPUT"
|
||||
echo "Tracking GitHub run ${run_id}"
|
||||
|
||||
name_enc=$(jq -nr --arg n "$ZIP_NAME" '$n|@uri')
|
||||
curl "${curl_tls[@]}" -sS -X POST \
|
||||
-H "Authorization: token ${FORGEJO_TOKEN}" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @"${zip_path}" \
|
||||
"${api_base}/${release_id}/assets?name=${name_enc}" \
|
||||
| jq -r '.browser_download_url // .name // .'
|
||||
- name: Wait for GitHub build + Forgejo public release
|
||||
shell: bash
|
||||
env:
|
||||
GH_BUILDER_TOKEN: ${{ secrets.GH_BUILDER_TOKEN }}
|
||||
FORGEJO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
RUN_ID: ${{ steps.gh.outputs.run_id }}
|
||||
ZIP_NAME: ${{ steps.ver.outputs.zip_name }}
|
||||
ASSET_VER: ${{ steps.ver.outputs.asset_ver }}
|
||||
SHORT_SHA: ${{ steps.ver.outputs.short_sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
api="https://api.github.com/repos/littlecodedragon/infinipaint"
|
||||
auth=(-H "Authorization: Bearer ${GH_BUILDER_TOKEN}" -H "Accept: application/vnd.github+json")
|
||||
fj="https://forgejo.fsociety00.cc/api/v1/repos/copilot/infinipaint/releases/tags/windows-continuous"
|
||||
for i in $(seq 1 240); do
|
||||
g=$(curl -fsSL "${auth[@]}" "${api}/actions/runs/${RUN_ID}")
|
||||
status=$(echo "$g" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('status'), d.get('conclusion') or '-')")
|
||||
rel=$(curl -fsSL -H "Authorization: token ${FORGEJO_TOKEN}" "$fj" || echo '{}')
|
||||
rname=$(echo "$rel" | python3 -c "import sys,json;print(json.load(sys.stdin).get('name',''))" 2>/dev/null || true)
|
||||
assets=$(echo "$rel" | python3 -c "import sys,json;print([a.get('name') for a in json.load(sys.stdin).get('assets',[])])" 2>/dev/null || true)
|
||||
echo "$(date -u +%H:%M:%S) github=${status} forgejo=${rname} assets=${assets}"
|
||||
if echo "$assets" | grep -Fq "${ZIP_NAME}" || echo "$rname" | grep -Fq "${SHORT_SHA}"; then
|
||||
echo "Public Forgejo release is up to date."
|
||||
exit 0
|
||||
fi
|
||||
if echo "$status" | grep -q '^completed failure\|^completed cancelled\|^completed timed_out'; then
|
||||
echo "GitHub Windows build failed: ${status}" >&2
|
||||
echo "$g" | python3 -c "import sys,json;print(json.load(sys.stdin).get('html_url',''))"
|
||||
exit 1
|
||||
fi
|
||||
sleep 60
|
||||
done
|
||||
echo "Timed out waiting for Forgejo asset ${ZIP_NAME}" >&2
|
||||
exit 1
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue