646 lines
24 KiB
YAML
646 lines
24 KiB
YAML
name: build desktop
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
channel:
|
|
description: Channel to build (stable or canary)
|
|
required: false
|
|
type: choice
|
|
options:
|
|
- stable
|
|
- canary
|
|
default: stable
|
|
ref:
|
|
description: Git ref to build (branch, tag, or commit SHA)
|
|
required: false
|
|
default: ''
|
|
type: string
|
|
skip_windows:
|
|
description: Skip Windows builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_macos:
|
|
description: Skip macOS builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_linux:
|
|
description: Skip Linux builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_windows_x64:
|
|
description: Skip Windows x64 builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_windows_arm64:
|
|
description: Skip Windows ARM64 builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_macos_x64:
|
|
description: Skip macOS x64 builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_macos_arm64:
|
|
description: Skip macOS ARM64 builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_linux_x64:
|
|
description: Skip Linux x64 builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
skip_linux_arm64:
|
|
description: Skip Linux ARM64 builds
|
|
required: false
|
|
default: false
|
|
type: boolean
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
concurrency:
|
|
group: desktop-${{ inputs.channel }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
CHANNEL: ${{ inputs.channel }}
|
|
BUILD_CHANNEL: ${{ inputs.channel == 'canary' && 'canary' || 'stable' }}
|
|
SOURCE_REF: ${{ inputs.ref && inputs.ref || (inputs.channel == 'canary' && 'canary' || 'main') }}
|
|
|
|
jobs:
|
|
meta:
|
|
name: Resolve build metadata
|
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
outputs:
|
|
version: ${{ steps.meta.outputs.version }}
|
|
pub_date: ${{ steps.meta.outputs.pub_date }}
|
|
channel: ${{ steps.meta.outputs.channel }}
|
|
build_channel: ${{ steps.meta.outputs.build_channel }}
|
|
source_ref: ${{ steps.meta.outputs.source_ref }}
|
|
steps:
|
|
- name: Set metadata
|
|
id: meta
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
VERSION="0.0.${GITHUB_RUN_NUMBER}"
|
|
PUB_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
|
|
echo "pub_date=${PUB_DATE}" >> "$GITHUB_OUTPUT"
|
|
echo "channel=${{ inputs.channel }}" >> "$GITHUB_OUTPUT"
|
|
echo "build_channel=${{ inputs.channel == 'canary' && 'canary' || 'stable' }}" >> "$GITHUB_OUTPUT"
|
|
echo "source_ref=${{ (inputs.ref && inputs.ref) || (inputs.channel == 'canary' && 'canary' || 'main') }}" >> "$GITHUB_OUTPUT"
|
|
|
|
matrix:
|
|
name: Resolve build matrix
|
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
steps:
|
|
- name: Build platform matrix
|
|
id: set-matrix
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
PLATFORMS='[
|
|
{"platform":"windows","arch":"x64","os":"windows-latest","electron_arch":"x64"},
|
|
{"platform":"windows","arch":"arm64","os":"windows-11-arm","electron_arch":"arm64"},
|
|
{"platform":"macos","arch":"x64","os":"macos-15-intel","electron_arch":"x64"},
|
|
{"platform":"macos","arch":"arm64","os":"macos-15","electron_arch":"arm64"},
|
|
{"platform":"linux","arch":"x64","os":"ubuntu-24.04","electron_arch":"x64"},
|
|
{"platform":"linux","arch":"arm64","os":"ubuntu-24.04-arm","electron_arch":"arm64"}
|
|
]'
|
|
|
|
FILTERED="$(echo "$PLATFORMS" | jq -c \
|
|
--argjson skipWin '${{ inputs.skip_windows }}' \
|
|
--argjson skipWinX64 '${{ inputs.skip_windows_x64 }}' \
|
|
--argjson skipWinArm '${{ inputs.skip_windows_arm64 }}' \
|
|
--argjson skipMac '${{ inputs.skip_macos }}' \
|
|
--argjson skipMacX64 '${{ inputs.skip_macos_x64 }}' \
|
|
--argjson skipMacArm '${{ inputs.skip_macos_arm64 }}' \
|
|
--argjson skipLinux '${{ inputs.skip_linux }}' \
|
|
--argjson skipLinuxX64 '${{ inputs.skip_linux_x64 }}' \
|
|
--argjson skipLinuxArm '${{ inputs.skip_linux_arm64 }}' '
|
|
[.[] | select(
|
|
(
|
|
((.platform == "windows") and (
|
|
$skipWin or
|
|
((.arch == "x64") and $skipWinX64) or
|
|
((.arch == "arm64") and $skipWinArm)
|
|
)) or
|
|
((.platform == "macos") and (
|
|
$skipMac or
|
|
((.arch == "x64") and $skipMacX64) or
|
|
((.arch == "arm64") and $skipMacArm)
|
|
)) or
|
|
((.platform == "linux") and (
|
|
$skipLinux or
|
|
((.arch == "x64") and $skipLinuxX64) or
|
|
((.arch == "arm64") and $skipLinuxArm)
|
|
))
|
|
) | not
|
|
)]
|
|
')"
|
|
|
|
echo "matrix={\"include\":$FILTERED}" >> "$GITHUB_OUTPUT"
|
|
|
|
build:
|
|
name: Build ${{ matrix.platform }} (${{ matrix.arch }})
|
|
needs:
|
|
- meta
|
|
- matrix
|
|
runs-on: ${{ matrix.os }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJson(needs.matrix.outputs.matrix) }}
|
|
env:
|
|
APP_WORKDIR: fluxer_app
|
|
CHANNEL: ${{ needs.meta.outputs.channel }}
|
|
BUILD_CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
|
SOURCE_REF: ${{ needs.meta.outputs.source_ref }}
|
|
VERSION: ${{ needs.meta.outputs.version }}
|
|
PUB_DATE: ${{ needs.meta.outputs.pub_date }}
|
|
steps:
|
|
- name: Checkout source
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ env.SOURCE_REF }}
|
|
|
|
- name: Shorten Windows paths (workspace + temp for Squirrel) and pin pnpm store
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
subst W: "$env:GITHUB_WORKSPACE"
|
|
"APP_WORKDIR=W:\fluxer_app" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
New-Item -ItemType Directory -Force "C:\t" | Out-Null
|
|
New-Item -ItemType Directory -Force "C:\sq" | Out-Null
|
|
New-Item -ItemType Directory -Force "C:\ebcache" | Out-Null
|
|
"TEMP=C:\t" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
"TMP=C:\t" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
"SQUIRREL_TEMP=C:\sq" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
"ELECTRON_BUILDER_CACHE=C:\ebcache" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
New-Item -ItemType Directory -Force "C:\pnpm-store" | Out-Null
|
|
"NPM_CONFIG_STORE_DIR=C:\pnpm-store" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
"npm_config_store_dir=C:\pnpm-store" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
|
|
"store-dir=C:\pnpm-store" | Set-Content -Path "W:\.npmrc" -Encoding ascii
|
|
git config --global core.longpaths true
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@v4
|
|
with:
|
|
version: 10.26.0
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@v6
|
|
with:
|
|
node-version: 20
|
|
|
|
- name: Resolve pnpm store path (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
$store = pnpm store path --silent
|
|
"PNPM_STORE_PATH=$store" | Out-File -FilePath $env:GITHUB_ENV -Append -Encoding utf8
|
|
New-Item -ItemType Directory -Force $store | Out-Null
|
|
|
|
- name: Resolve pnpm store path (Unix)
|
|
if: runner.os != 'Windows'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
store="$(pnpm store path --silent)"
|
|
echo "PNPM_STORE_PATH=$store" >> "$GITHUB_ENV"
|
|
mkdir -p "$store"
|
|
|
|
- name: Cache pnpm store
|
|
uses: actions/cache@v4
|
|
with:
|
|
path: ${{ env.PNPM_STORE_PATH }}
|
|
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
|
restore-keys: |
|
|
${{ runner.os }}-pnpm-store-
|
|
|
|
- name: Install Python setuptools (Windows ARM64)
|
|
if: matrix.platform == 'windows' && matrix.arch == 'arm64'
|
|
shell: pwsh
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
python -m pip install "setuptools>=69" wheel
|
|
|
|
- name: Install Python setuptools (macOS)
|
|
if: matrix.platform == 'macos'
|
|
run: brew install python-setuptools
|
|
|
|
- name: Install Linux dependencies
|
|
if: matrix.platform == 'linux'
|
|
env:
|
|
DEBIAN_FRONTEND: noninteractive
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
libx11-dev libxtst-dev libxt-dev libxinerama-dev libxkbcommon-dev libxrandr-dev \
|
|
ruby ruby-dev build-essential rpm \
|
|
libpixman-1-dev libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
|
|
sudo gem install --no-document fpm
|
|
|
|
- name: Install dependencies
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Update version
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
run: pnpm version "${{ env.VERSION }}" --no-git-tag-version --allow-same-version
|
|
|
|
- name: Build Electron main process
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
env:
|
|
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
|
|
run: pnpm electron:compile
|
|
|
|
- name: Build Electron app (macOS)
|
|
if: matrix.platform == 'macos'
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
env:
|
|
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
|
|
CSC_LINK: ${{ secrets.APPLE_CERTIFICATE }}
|
|
CSC_KEY_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: pnpm exec electron-builder --config electron-builder.yaml --mac --${{ matrix.electron_arch }}
|
|
|
|
- name: Build Electron app (Windows)
|
|
if: matrix.platform == 'windows'
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
env:
|
|
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
|
|
TEMP: C:\t
|
|
TMP: C:\t
|
|
SQUIRREL_TEMP: C:\sq
|
|
ELECTRON_BUILDER_CACHE: C:\ebcache
|
|
run: pnpm exec electron-builder --config electron-builder.yaml --win --${{ matrix.electron_arch }}
|
|
|
|
- name: Analyze Squirrel nupkg for long paths
|
|
if: matrix.platform == 'windows'
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
shell: pwsh
|
|
env:
|
|
BUILD_VERSION: ${{ env.VERSION }}
|
|
MAX_WINDOWS_PATH_LEN: 260
|
|
PATH_HEADROOM: 10
|
|
run: |
|
|
$primaryDir = if ("${{ matrix.arch }}" -eq "arm64") { "dist-electron/squirrel-windows-arm64" } else { "dist-electron/squirrel-windows" }
|
|
$fallbackDir = if ("${{ matrix.arch }}" -eq "arm64") { "dist-electron/squirrel-windows" } else { "dist-electron/squirrel-windows-arm64" }
|
|
$dirs = @($primaryDir, $fallbackDir)
|
|
|
|
$nupkg = $null
|
|
foreach ($d in $dirs) {
|
|
if (Test-Path $d) {
|
|
$nupkg = Get-ChildItem -Path "$d/*.nupkg" -ErrorAction SilentlyContinue | Select-Object -First 1
|
|
if ($nupkg) { break }
|
|
}
|
|
}
|
|
|
|
if (-not $nupkg) {
|
|
throw "No Squirrel nupkg found in: $($dirs -join ', ')"
|
|
}
|
|
|
|
Write-Host "Analyzing Windows installer $($nupkg.FullName)"
|
|
$env:NUPKG_PATH = $nupkg.FullName
|
|
|
|
$lines = @(
|
|
'import os'
|
|
'import zipfile'
|
|
''
|
|
'path = os.environ["NUPKG_PATH"]'
|
|
'build_ver = os.environ["BUILD_VERSION"]'
|
|
'prefix = os.path.join(os.environ["LOCALAPPDATA"], "fluxer_app", f"app-{build_ver}", "resources", "app.asar.unpacked")'
|
|
'max_len = int(os.environ.get("MAX_WINDOWS_PATH_LEN", "260"))'
|
|
'headroom = int(os.environ.get("PATH_HEADROOM", "10"))'
|
|
'limit = max_len - headroom'
|
|
''
|
|
'with zipfile.ZipFile(path) as archive:'
|
|
' entries = []'
|
|
' for info in archive.infolist():'
|
|
' normalized = info.filename.lstrip("/\\\\")'
|
|
' total_len = len(os.path.join(prefix, normalized)) if normalized else len(prefix)'
|
|
' entries.append((total_len, info.filename))'
|
|
''
|
|
'if not entries:'
|
|
' raise SystemExit("nupkg archive contains no entries")'
|
|
''
|
|
'entries.sort(reverse=True)'
|
|
'print(f"Assumed install prefix: {prefix} ({len(prefix)} chars). Maximum allowed path length: {limit} (total reserve {max_len}, headroom {headroom}).")'
|
|
'print("Top 20 longest archived paths (length includes prefix):")'
|
|
'for length, name in entries[:20]:'
|
|
' print(f"{length:4d} {name}")'
|
|
''
|
|
'longest_len, longest_name = entries[0]'
|
|
'if longest_len > limit:'
|
|
' raise SystemExit(f"Longest path {longest_len} for {longest_name} exceeds limit {limit}")'
|
|
'print(f"Longest archived path {longest_len} is within the limit of {limit}.")'
|
|
)
|
|
|
|
$scriptPath = Join-Path $env:TEMP "nupkg-long-path-check.py"
|
|
Set-Content -Path $scriptPath -Value $lines -Encoding utf8
|
|
python $scriptPath
|
|
|
|
- name: Build Electron app (Linux)
|
|
if: matrix.platform == 'linux'
|
|
working-directory: ${{ env.APP_WORKDIR }}
|
|
env:
|
|
BUILD_CHANNEL: ${{ env.BUILD_CHANNEL }}
|
|
USE_SYSTEM_FPM: true
|
|
run: pnpm exec electron-builder --config electron-builder.yaml --linux --${{ matrix.electron_arch }}
|
|
|
|
- name: Prepare artifacts (Windows)
|
|
if: runner.os == 'Windows'
|
|
shell: pwsh
|
|
run: |
|
|
New-Item -ItemType Directory -Force upload_staging | Out-Null
|
|
|
|
$dist = Join-Path $env:APP_WORKDIR "dist-electron"
|
|
$sqDirName = if ("${{ matrix.arch }}" -eq "arm64") { "squirrel-windows-arm64" } else { "squirrel-windows" }
|
|
$sqFallbackName = if ($sqDirName -eq "squirrel-windows") { "squirrel-windows-arm64" } else { "squirrel-windows" }
|
|
|
|
$sq = Join-Path $dist $sqDirName
|
|
$sqFallback = Join-Path $dist $sqFallbackName
|
|
|
|
$picked = $null
|
|
if (Test-Path $sq) { $picked = $sq }
|
|
elseif (Test-Path $sqFallback) { $picked = $sqFallback }
|
|
|
|
if ($picked) {
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$picked\*.exe" "upload_staging\"
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$picked\*.exe.blockmap" "upload_staging\"
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$picked\RELEASES*" "upload_staging\"
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$picked\*.nupkg" "upload_staging\"
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$picked\*.nupkg.blockmap" "upload_staging\"
|
|
}
|
|
|
|
if (Test-Path $dist) {
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$dist\*.yml" "upload_staging\"
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$dist\*.zip" "upload_staging\"
|
|
Copy-Item -Force -ErrorAction SilentlyContinue "$dist\*.zip.blockmap" "upload_staging\"
|
|
}
|
|
|
|
if (-not (Get-ChildItem upload_staging -Filter *.exe -ErrorAction SilentlyContinue)) {
|
|
throw "No installer .exe staged. Squirrel outputs were not copied."
|
|
}
|
|
|
|
Get-ChildItem -Force upload_staging | Format-Table -AutoSize
|
|
|
|
- name: Prepare artifacts (Unix)
|
|
if: runner.os != 'Windows'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p upload_staging
|
|
DIST="${{ env.APP_WORKDIR }}/dist-electron"
|
|
|
|
cp -f "$DIST"/*.dmg upload_staging/ 2>/dev/null || true
|
|
cp -f "$DIST"/*.zip upload_staging/ 2>/dev/null || true
|
|
cp -f "$DIST"/*.zip.blockmap upload_staging/ 2>/dev/null || true
|
|
cp -f "$DIST"/*.yml upload_staging/ 2>/dev/null || true
|
|
|
|
cp -f "$DIST"/*.AppImage upload_staging/ 2>/dev/null || true
|
|
cp -f "$DIST"/*.deb upload_staging/ 2>/dev/null || true
|
|
cp -f "$DIST"/*.rpm upload_staging/ 2>/dev/null || true
|
|
cp -f "$DIST"/*.tar.gz upload_staging/ 2>/dev/null || true
|
|
|
|
ls -la upload_staging/
|
|
|
|
- name: Normalize updater YAML (arm64)
|
|
if: matrix.arch == 'arm64'
|
|
shell: bash
|
|
run: |
|
|
set -euo pipefail
|
|
cd upload_staging
|
|
[[ "${{ matrix.platform }}" == "macos" && -f latest-mac.yml && ! -f latest-mac-arm64.yml ]] && mv latest-mac.yml latest-mac-arm64.yml || true
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: fluxer-desktop-${{ env.BUILD_CHANNEL }}-${{ matrix.platform }}-${{ matrix.arch }}
|
|
path: |
|
|
upload_staging/*.exe
|
|
upload_staging/*.exe.blockmap
|
|
upload_staging/*.dmg
|
|
upload_staging/*.zip
|
|
upload_staging/*.zip.blockmap
|
|
upload_staging/*.AppImage
|
|
upload_staging/*.deb
|
|
upload_staging/*.rpm
|
|
upload_staging/*.tar.gz
|
|
upload_staging/*.yml
|
|
upload_staging/*.nupkg
|
|
upload_staging/*.nupkg.blockmap
|
|
upload_staging/RELEASES*
|
|
retention-days: 30
|
|
|
|
upload:
|
|
name: Upload to S3 (rclone)
|
|
needs:
|
|
- meta
|
|
- build
|
|
runs-on: blacksmith-2vcpu-ubuntu-2404
|
|
env:
|
|
CHANNEL: ${{ needs.meta.outputs.build_channel }}
|
|
DISPLAY_CHANNEL: ${{ needs.meta.outputs.channel }}
|
|
S3_ENDPOINT: https://s3.us-east-va.io.cloud.ovh.us
|
|
S3_BUCKET: fluxer-downloads
|
|
PUBLIC_DL_BASE: https://api.fluxer.app/dl
|
|
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
|
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: artifacts
|
|
pattern: fluxer-desktop-${{ needs.meta.outputs.build_channel }}-*
|
|
|
|
- name: Install rclone
|
|
run: |
|
|
set -euo pipefail
|
|
if ! command -v rclone >/dev/null 2>&1; then
|
|
curl -fsSL https://rclone.org/install.sh | sudo bash
|
|
fi
|
|
|
|
- name: Configure rclone (OVH S3)
|
|
run: |
|
|
set -euo pipefail
|
|
mkdir -p ~/.config/rclone
|
|
cat > ~/.config/rclone/rclone.conf <<'RCLONEEOF'
|
|
[ovh]
|
|
type = s3
|
|
provider = Other
|
|
env_auth = true
|
|
endpoint = https://s3.us-east-va.io.cloud.ovh.us
|
|
acl = private
|
|
RCLONEEOF
|
|
|
|
- name: Build S3 payload layout (+ manifest.json)
|
|
env:
|
|
VERSION: ${{ needs.meta.outputs.version }}
|
|
PUB_DATE: ${{ needs.meta.outputs.pub_date }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
mkdir -p s3_payload
|
|
|
|
shopt -s nullglob
|
|
for dir in artifacts/fluxer-desktop-${CHANNEL}-*; do
|
|
[ -d "$dir" ] || continue
|
|
|
|
base="$(basename "$dir")"
|
|
if [[ "$base" =~ ^fluxer-desktop-[a-z]+-([a-z]+)-([a-z0-9]+)$ ]]; then
|
|
platform="${BASH_REMATCH[1]}"
|
|
arch="${BASH_REMATCH[2]}"
|
|
else
|
|
echo "Skipping unrecognized artifact dir: $base"
|
|
continue
|
|
fi
|
|
|
|
case "$platform" in
|
|
windows) plat="win32" ;;
|
|
macos) plat="darwin" ;;
|
|
linux) plat="linux" ;;
|
|
*)
|
|
echo "Unknown platform: $platform"
|
|
continue
|
|
;;
|
|
esac
|
|
|
|
dest="s3_payload/desktop/${CHANNEL}/${plat}/${arch}"
|
|
mkdir -p "$dest"
|
|
cp -av "$dir"/* "$dest/" || true
|
|
|
|
if [[ "$plat" == "darwin" ]]; then
|
|
zip_file=""
|
|
for z in "$dest"/*.zip; do
|
|
zip_file="$z"
|
|
break
|
|
done
|
|
|
|
if [[ -z "$zip_file" ]]; then
|
|
echo "No .zip found for macOS $arch in $dest (auto-update requires zip artifacts)."
|
|
else
|
|
zip_name="$(basename "$zip_file")"
|
|
url="${PUBLIC_DL_BASE}/desktop/${CHANNEL}/${plat}/${arch}/${zip_name}"
|
|
|
|
cat > "$dest/RELEASES.json" <<EOF
|
|
{
|
|
"currentRelease": "${VERSION}",
|
|
"releases": [
|
|
{
|
|
"version": "${VERSION}",
|
|
"updateTo": {
|
|
"version": "${VERSION}",
|
|
"pub_date": "${PUB_DATE}",
|
|
"notes": "",
|
|
"name": "${VERSION}",
|
|
"url": "${url}"
|
|
}
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
cp -f "$dest/RELEASES.json" "$dest/releases.json"
|
|
fi
|
|
fi
|
|
|
|
setup_file=""
|
|
dmg_file=""
|
|
zip_file2=""
|
|
appimage_file=""
|
|
deb_file=""
|
|
rpm_file=""
|
|
targz_file=""
|
|
|
|
if [[ "$plat" == "win32" ]]; then
|
|
setup_file="$(ls -1 "$dest"/*.exe 2>/dev/null | grep -i 'setup' | head -n1 || true)"
|
|
if [[ -z "$setup_file" ]]; then
|
|
setup_file="$(ls -1 "$dest"/*.exe 2>/dev/null | head -n1 || true)"
|
|
fi
|
|
fi
|
|
|
|
if [[ "$plat" == "darwin" ]]; then
|
|
dmg_file="$(ls -1 "$dest"/*.dmg 2>/dev/null | head -n1 || true)"
|
|
zip_file2="$(ls -1 "$dest"/*.zip 2>/dev/null | head -n1 || true)"
|
|
fi
|
|
|
|
if [[ "$plat" == "linux" ]]; then
|
|
appimage_file="$(ls -1 "$dest"/*.AppImage 2>/dev/null | head -n1 || true)"
|
|
deb_file="$(ls -1 "$dest"/*.deb 2>/dev/null | head -n1 || true)"
|
|
rpm_file="$(ls -1 "$dest"/*.rpm 2>/dev/null | head -n1 || true)"
|
|
targz_file="$(ls -1 "$dest"/*.tar.gz 2>/dev/null | head -n1 || true)"
|
|
fi
|
|
|
|
jq -n \
|
|
--arg channel "${CHANNEL}" \
|
|
--arg platform "${plat}" \
|
|
--arg arch "${arch}" \
|
|
--arg version "${VERSION}" \
|
|
--arg pub_date "${PUB_DATE}" \
|
|
--arg setup "$(basename "${setup_file:-}")" \
|
|
--arg dmg "$(basename "${dmg_file:-}")" \
|
|
--arg zip "$(basename "${zip_file2:-}")" \
|
|
--arg appimage "$(basename "${appimage_file:-}")" \
|
|
--arg deb "$(basename "${deb_file:-}")" \
|
|
--arg rpm "$(basename "${rpm_file:-}")" \
|
|
--arg tar_gz "$(basename "${targz_file:-}")" \
|
|
'{
|
|
channel: $channel,
|
|
platform: $platform,
|
|
arch: $arch,
|
|
version: $version,
|
|
pub_date: $pub_date,
|
|
files: {
|
|
setup: $setup,
|
|
dmg: $dmg,
|
|
zip: $zip,
|
|
appimage: $appimage,
|
|
deb: $deb,
|
|
rpm: $rpm,
|
|
tar_gz: $tar_gz
|
|
}
|
|
}' > "$dest/manifest.json"
|
|
done
|
|
|
|
echo "Payload tree:"
|
|
find s3_payload -maxdepth 6 -type f | sort
|
|
|
|
- name: Upload payload to S3
|
|
run: |
|
|
set -euo pipefail
|
|
rclone copy s3_payload/desktop "ovh:${S3_BUCKET}/desktop" \
|
|
--transfers 32 \
|
|
--checkers 16 \
|
|
--fast-list \
|
|
--s3-upload-concurrency 8 \
|
|
--s3-chunk-size 16M \
|
|
-v
|
|
|
|
- name: Build summary
|
|
run: |
|
|
{
|
|
echo "## Desktop ${DISPLAY_CHANNEL^} Upload Complete"
|
|
echo ""
|
|
echo "**Version:** ${{ needs.meta.outputs.version }}"
|
|
echo ""
|
|
echo "**S3 prefix:** desktop/${CHANNEL}/"
|
|
echo ""
|
|
echo "**Redirect endpoint shape:** /dl/desktop/${CHANNEL}/{plat}/{arch}/{format}"
|
|
} >> "$GITHUB_STEP_SUMMARY"
|