Run Windows Electron builds on Linux with Wine.
Some checks failed
Some checks failed
This commit is contained in:
@@ -200,7 +200,7 @@ jobs:
|
|||||||
echo "GitHub release id: ${RELEASE_ID}"
|
echo "GitHub release id: ${RELEASE_ID}"
|
||||||
|
|
||||||
build-windows:
|
build-windows:
|
||||||
runs-on: windows
|
runs-on: ubuntu-latest
|
||||||
needs: [increment-version, prepare-release]
|
needs: [increment-version, prepare-release]
|
||||||
if: always() && needs.prepare-release.result == 'success'
|
if: always() && needs.prepare-release.result == 'success'
|
||||||
|
|
||||||
@@ -212,38 +212,35 @@ jobs:
|
|||||||
ref: ${{ github.ref_name }}
|
ref: ${{ github.ref_name }}
|
||||||
|
|
||||||
- name: Checkout submodules manually
|
- name: Checkout submodules manually
|
||||||
shell: powershell
|
|
||||||
run: |
|
run: |
|
||||||
$ErrorActionPreference = "Stop"
|
set -euo pipefail
|
||||||
# Use the same host/scheme the runner already used for origin (not public HTTPS).
|
# Use the same host/scheme the runner already used for origin (not public HTTPS).
|
||||||
$origin = (git remote get-url origin).Trim()
|
ORIGIN_URL=$(git remote get-url origin)
|
||||||
$origin = $origin.TrimEnd('/')
|
ORIGIN_URL=${ORIGIN_URL%/}
|
||||||
if ($origin.EndsWith('.git')) { $origin = $origin.Substring(0, $origin.Length - 4) }
|
ORIGIN_URL=${ORIGIN_URL%.git}
|
||||||
$base = $origin.Substring(0, $origin.LastIndexOf('/'))
|
BASE_URL=${ORIGIN_URL%/*}
|
||||||
$cinnyUrl = "$base/cinny.git"
|
CINNY_URL="${BASE_URL}/cinny.git"
|
||||||
Write-Host "Rewriting submodule URL to $cinnyUrl"
|
echo "Rewriting submodule URL to ${CINNY_URL}"
|
||||||
git config submodule.cinny.url $cinnyUrl
|
git config submodule.cinny.url "${CINNY_URL}"
|
||||||
git submodule sync --recursive
|
git submodule sync --recursive
|
||||||
|
|
||||||
git submodule update --init --recursive
|
if git submodule update --init --recursive; then
|
||||||
if ($LASTEXITCODE -eq 0) {
|
echo "Submodules checked out at pinned commits."
|
||||||
Write-Host "Submodules checked out at pinned commits."
|
|
||||||
exit 0
|
exit 0
|
||||||
}
|
fi
|
||||||
|
|
||||||
Write-Warning "Pinned submodule commit is unavailable on remote. Falling back to remote submodule HEAD."
|
echo "Pinned submodule commit is unavailable on remote. Falling back to remote submodule HEAD."
|
||||||
git submodule deinit -f --all
|
git submodule deinit -f --all || true
|
||||||
git config submodule.cinny.url $cinnyUrl
|
rm -rf cinny .git/modules/cinny
|
||||||
|
git config submodule.cinny.url "${CINNY_URL}"
|
||||||
git submodule sync --recursive
|
git submodule sync --recursive
|
||||||
git submodule update --init --recursive --remote
|
git submodule update --init --recursive --remote
|
||||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
|
||||||
|
|
||||||
Write-Host "Resolved submodule commit:"
|
echo "Resolved submodule commit:"
|
||||||
git -C cinny rev-parse HEAD
|
git -C cinny rev-parse HEAD
|
||||||
|
|
||||||
- name: Pull latest (after version bump)
|
- name: Pull latest (after version bump)
|
||||||
if: github.ref == 'refs/heads/main'
|
if: github.ref == 'refs/heads/main'
|
||||||
shell: powershell
|
|
||||||
run: git pull origin main
|
run: git pull origin main
|
||||||
|
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
@@ -251,6 +248,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: '20'
|
node-version: '20'
|
||||||
|
|
||||||
|
- name: Install Wine (NSIS cross-build)
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
sudo dpkg --add-architecture i386
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends wine64 wine32
|
||||||
|
|
||||||
- name: Install dependencies (root)
|
- name: Install dependencies (root)
|
||||||
run: npm ci --prefer-offline
|
run: npm ci --prefer-offline
|
||||||
|
|
||||||
@@ -259,107 +263,82 @@ jobs:
|
|||||||
run: npm ci --prefer-offline
|
run: npm ci --prefer-offline
|
||||||
|
|
||||||
- name: Clean previous builds
|
- name: Clean previous builds
|
||||||
shell: powershell
|
|
||||||
run: |
|
run: |
|
||||||
if (Test-Path cinny/dist) { Remove-Item -Recurse -Force cinny/dist }
|
rm -rf cinny/dist dist-electron
|
||||||
if (Test-Path dist-electron) { Remove-Item -Recurse -Force dist-electron }
|
|
||||||
|
|
||||||
- name: Build Electron app
|
- name: Build Electron app
|
||||||
run: npm run build:local -- --win
|
run: npm run build:local -- --win
|
||||||
env:
|
env:
|
||||||
GH_TOKEN: ${{ secrets.GHTOKEN }}
|
GH_TOKEN: ${{ secrets.GHTOKEN }}
|
||||||
|
CSC_IDENTITY_AUTO_DISCOVERY: 'false'
|
||||||
|
|
||||||
- name: Upload Windows assets to releases
|
- name: Upload Windows assets to releases
|
||||||
shell: powershell
|
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
GH_TOKEN: ${{ secrets.GHTOKEN }}
|
GH_TOKEN: ${{ secrets.GHTOKEN }}
|
||||||
run: |
|
run: |
|
||||||
$ErrorActionPreference = "Stop"
|
set -euo pipefail
|
||||||
$TAG_NAME = "${{ needs.prepare-release.outputs.tag }}"
|
TAG_NAME="${{ needs.prepare-release.outputs.tag }}"
|
||||||
$API_BASE = "${{ github.server_url }}/api/v1"
|
API_BASE="${{ github.server_url }}/api/v1"
|
||||||
$REPO = "${{ github.repository }}"
|
REPO="${{ github.repository }}"
|
||||||
$GITHUB_REPO = "Paarrot/Paarrot-Desktop"
|
GITHUB_REPO="Paarrot/Paarrot-Desktop"
|
||||||
|
|
||||||
function Invoke-JsonCurl([string[]]$CurlArgs) {
|
GITEA_RELEASE_ID=$(curl -fsS -H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
$raw = & curl.exe @CurlArgs
|
"${API_BASE}/repos/${REPO}/releases/tags/${TAG_NAME}" | jq -r '.id')
|
||||||
if ($LASTEXITCODE -ne 0) { throw "curl failed: $($CurlArgs -join ' ')" }
|
GH_RELEASE_ID=$(curl -fsS -H "Authorization: token ${GH_TOKEN}" \
|
||||||
return ($raw | ConvertFrom-Json)
|
"https://api.github.com/repos/${GITHUB_REPO}/releases/tags/${TAG_NAME}" | jq -r '.id')
|
||||||
|
GH_UPLOAD_URL=$(curl -fsS -H "Authorization: token ${GH_TOKEN}" \
|
||||||
|
"https://api.github.com/repos/${GITHUB_REPO}/releases/${GH_RELEASE_ID}" | jq -r '.upload_url' | sed 's/{?name,label}//')
|
||||||
|
|
||||||
|
upload_one() {
|
||||||
|
local FILE="$1"
|
||||||
|
local FILENAME
|
||||||
|
FILENAME=$(basename "$FILE")
|
||||||
|
echo "Uploading ${FILENAME} ($(du -h "$FILE" | cut -f1))..."
|
||||||
|
|
||||||
|
OLD_ID=$(curl -fsS -H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
"${API_BASE}/repos/${REPO}/releases/${GITEA_RELEASE_ID}/assets" \
|
||||||
|
| jq -r --arg n "$FILENAME" '.[] | select(.name == $n) | .id' || true)
|
||||||
|
if [ -n "${OLD_ID:-}" ]; then
|
||||||
|
curl -fsS -X DELETE -H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
"${API_BASE}/repos/${REPO}/releases/${GITEA_RELEASE_ID}/assets/${OLD_ID}" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -fsS --max-time 0 --retry 5 --retry-delay 10 \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"${FILE}" \
|
||||||
|
"${API_BASE}/repos/${REPO}/releases/${GITEA_RELEASE_ID}/assets?name=${FILENAME}" \
|
||||||
|
>/dev/null
|
||||||
|
echo " Gitea: ok"
|
||||||
|
|
||||||
|
OLD_GH=$(curl -fsS -H "Authorization: token ${GH_TOKEN}" \
|
||||||
|
"https://api.github.com/repos/${GITHUB_REPO}/releases/${GH_RELEASE_ID}/assets" \
|
||||||
|
| jq -r --arg n "$FILENAME" '.[] | select(.name == $n) | .id' || true)
|
||||||
|
if [ -n "${OLD_GH:-}" ]; then
|
||||||
|
curl -fsS -X DELETE -H "Authorization: token ${GH_TOKEN}" \
|
||||||
|
"https://api.github.com/repos/${GITHUB_REPO}/releases/assets/${OLD_GH}" >/dev/null
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl -fsS --max-time 0 --retry 5 --retry-delay 10 \
|
||||||
|
-X POST \
|
||||||
|
-H "Authorization: token ${GH_TOKEN}" \
|
||||||
|
-H "Content-Type: application/octet-stream" \
|
||||||
|
--data-binary @"${FILE}" \
|
||||||
|
"${GH_UPLOAD_URL}?name=${FILENAME}" \
|
||||||
|
>/dev/null
|
||||||
|
echo " GitHub: ok"
|
||||||
}
|
}
|
||||||
|
|
||||||
$giteaRelease = Invoke-JsonCurl @(
|
shopt -s nullglob
|
||||||
"-fsS", "-H", "Authorization: token $env:GITEA_TOKEN",
|
for FILE in dist-electron/Paarrot-*-win-x64.exe dist-electron/latest.yml; do
|
||||||
"$API_BASE/repos/$REPO/releases/tags/$TAG_NAME"
|
upload_one "$FILE"
|
||||||
)
|
done
|
||||||
$ghRelease = Invoke-JsonCurl @(
|
|
||||||
"-fsS", "-H", "Authorization: token $env:GH_TOKEN",
|
|
||||||
"https://api.github.com/repos/$GITHUB_REPO/releases/tags/$TAG_NAME"
|
|
||||||
)
|
|
||||||
# GitHub returns upload_url like .../assets{?name,label}
|
|
||||||
$ghUploadUrl = [string]$ghRelease.upload_url
|
|
||||||
if ([string]::IsNullOrWhiteSpace($ghUploadUrl)) {
|
|
||||||
throw "GitHub release $($ghRelease.id) has no upload_url"
|
|
||||||
}
|
|
||||||
$ghUploadUrl = $ghUploadUrl -replace '\{\?[^}]*\}', ''
|
|
||||||
Write-Host "GitHub upload base: $ghUploadUrl"
|
|
||||||
|
|
||||||
function Upload-One([string]$File) {
|
|
||||||
$filename = [System.IO.Path]::GetFileName($File)
|
|
||||||
$sizeMb = [math]::Round((Get-Item $File).Length / 1MB, 1)
|
|
||||||
Write-Host "Uploading $filename (${sizeMb} MB)..."
|
|
||||||
|
|
||||||
$giteaAssets = Invoke-JsonCurl @(
|
|
||||||
"-fsS", "-H", "Authorization: token $env:GITEA_TOKEN",
|
|
||||||
"$API_BASE/repos/$REPO/releases/$($giteaRelease.id)/assets"
|
|
||||||
)
|
|
||||||
foreach ($asset in @($giteaAssets)) {
|
|
||||||
if ($asset.name -eq $filename) {
|
|
||||||
& curl.exe -fsS -X DELETE -H "Authorization: token $env:GITEA_TOKEN" `
|
|
||||||
"$API_BASE/repos/$REPO/releases/$($giteaRelease.id)/assets/$($asset.id)" | Out-Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& curl.exe -fsS --max-time 0 --retry 5 --retry-delay 10 `
|
|
||||||
-X POST `
|
|
||||||
-H "Authorization: token $env:GITEA_TOKEN" `
|
|
||||||
-H "Content-Type: application/octet-stream" `
|
|
||||||
--data-binary "@$File" `
|
|
||||||
"$API_BASE/repos/$REPO/releases/$($giteaRelease.id)/assets?name=$filename" | Out-Null
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "Gitea upload failed for $filename" }
|
|
||||||
Write-Host " Gitea: ok"
|
|
||||||
|
|
||||||
$ghAssets = Invoke-JsonCurl @(
|
|
||||||
"-fsS", "-H", "Authorization: token $env:GH_TOKEN",
|
|
||||||
"https://api.github.com/repos/$GITHUB_REPO/releases/$($ghRelease.id)/assets"
|
|
||||||
)
|
|
||||||
foreach ($asset in @($ghAssets)) {
|
|
||||||
if ($asset.name -eq $filename) {
|
|
||||||
& curl.exe -fsS -X DELETE -H "Authorization: token $env:GH_TOKEN" `
|
|
||||||
"https://api.github.com/repos/$GITHUB_REPO/releases/assets/$($asset.id)" | Out-Null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Brace the variable — `$url?name=` is parsed as PowerShell's null-conditional.
|
|
||||||
$ghAssetUrl = "${ghUploadUrl}?name=$([uri]::EscapeDataString($filename))"
|
|
||||||
Write-Host " GitHub URL: $ghAssetUrl"
|
|
||||||
& curl.exe -fsS --max-time 0 --retry 5 --retry-delay 10 `
|
|
||||||
-X POST `
|
|
||||||
-H "Authorization: token $env:GH_TOKEN" `
|
|
||||||
-H "Content-Type: application/octet-stream" `
|
|
||||||
--data-binary "@$File" `
|
|
||||||
$ghAssetUrl | Out-Null
|
|
||||||
if ($LASTEXITCODE -ne 0) { throw "GitHub upload failed for $filename" }
|
|
||||||
Write-Host " GitHub: ok"
|
|
||||||
}
|
|
||||||
|
|
||||||
Get-ChildItem -Path dist-electron -File |
|
|
||||||
Where-Object { $_.Name -like 'Paarrot-*-win-x64.exe' -or $_.Name -eq 'latest.yml' } |
|
|
||||||
ForEach-Object { Upload-One $_.FullName }
|
|
||||||
|
|
||||||
- name: List build output
|
- name: List build output
|
||||||
shell: powershell
|
|
||||||
run: |
|
run: |
|
||||||
Get-ChildItem -Path dist-electron -Recurse | Select-Object FullName
|
find dist-electron -type f -printf '%p\n' | sort
|
||||||
|
|
||||||
build-linux:
|
build-linux:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
Reference in New Issue
Block a user