Build App (Preview) / compute-version (pull_request) Successful in 3s
Build App (Preview) / create-release (pull_request) Successful in 1s
Build App (Preview) / build-macos (pull_request) Successful in 2m44s
Build App (Preview) / build-windows (pull_request) Successful in 5m27s
Build App (Preview) / build-linux (pull_request) Successful in 5m36s
Every push to the PR started two workflows on the same commit. build-app.yml ran on pull_request and compiled all three platforms — then published nothing, because every publishing step in it is gated on `gitea.event_name == 'push'`. build-app-preview.yml compiled the same three and published them. Six OS builds per push, half of them unreachable. So the PR trigger moves to the preview workflow, which was already doing the identical compilation and has something to show for it. build-app.yml is now push-to-main and manual dispatch only: releases. Two things a pull_request event changes, handled rather than inherited: `gitea.sha` can be the merge ref — not the commit anyone is testing, and not something to hang a tag on — so the release's target comes from `git rev-parse HEAD` in the checkout; and `gitea.ref_name` is the PR number, so the release body uses `gitea.head_ref` when there is one. The cost is one prerelease per PR commit touching app/**, which the existing Cleanup Old Releases sweep already prunes. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
525 lines
21 KiB
YAML
525 lines
21 KiB
YAML
name: Build App (Preview)
|
|
|
|
# Builds the Tauri app for branches other than main and publishes the bundles as
|
|
# a **prerelease**, so they are downloadable from the Releases page. No GitHub
|
|
# sync.
|
|
#
|
|
# This is also the **PR build check**: it compiles Linux, macOS and Windows, so
|
|
# a push that breaks any of them fails here. build-app.yml used to do that job
|
|
# in parallel and publish nothing, which meant six OS builds per push and one
|
|
# unreachable set of bundles; it is now releases-only.
|
|
#
|
|
# The cost of the swap, stated plainly: one prerelease per PR commit that
|
|
# touches `app/**`. They are pruned by Cleanup Old Releases (see Lifecycle).
|
|
#
|
|
# ## Why not workflow artifacts
|
|
#
|
|
# Two attempts failed before this one, and both failure modes are worth knowing:
|
|
#
|
|
# * `actions/upload-artifact@v4` cannot run here at all. It bundles
|
|
# `@actions/artifact` v2, whose `isGhes()` treats any GITHUB_SERVER_URL that
|
|
# is not github.com / *.ghe.com / *.localhost as GitHub Enterprise Server and
|
|
# throws before making a single request. act_runner sets that variable to this
|
|
# Gitea instance, so every platform died with "GHESNotSupportedError" — after
|
|
# the whole Tauri build had been paid for (run #265).
|
|
# * `@v3` uploads *succeed*, and the files are downloadable by direct URL — but
|
|
# Gitea does not **list** them: `/api/v1/…/runs/<id>/artifacts` reports
|
|
# `total_count: 0` and the run page shows nothing (verified on run #267).
|
|
# A build nobody can find is not a build.
|
|
#
|
|
# So previews publish the same way every other workflow here does: curl to the
|
|
# Gitea releases API. One release per preview, tagged `preview-<sha>`.
|
|
#
|
|
# ## Lifecycle
|
|
#
|
|
# The `preview-` tag prefix is deliberate. `cleanup-releases.yml` keeps the most
|
|
# recent `v<major>.<minor>.<patch>` releases and separately deletes every release
|
|
# whose tag does *not* start with `v[0-9]` — so previews are pruned by the
|
|
# cleanup that is already run, and never crowd the real release list.
|
|
#
|
|
# `sync-release.yml` is workflow_dispatch-only, so nothing here reaches GitHub.
|
|
|
|
env:
|
|
GITEA_URL: ${{ gitea.server_url }}
|
|
REPO: ${{ gitea.repository }}
|
|
|
|
on:
|
|
# Every push to an open PR: this *is* the branch's build check — it compiles
|
|
# Linux, macOS and Windows — and publishing the result costs nothing extra
|
|
# once they are built. build-app.yml deliberately no longer runs on PRs.
|
|
pull_request:
|
|
branches: [main]
|
|
paths:
|
|
- "app/**"
|
|
- "VERSION"
|
|
- ".gitea/workflows/build-app-preview.yml"
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
compute-version:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
version: ${{ steps.version.outputs.VERSION }}
|
|
sha: ${{ steps.version.outputs.SHA }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Compute preview version
|
|
id: version
|
|
run: |
|
|
MAJOR_MINOR=$(cat VERSION | tr -d '[:space:]')
|
|
SHORT_SHA=$(git rev-parse --short HEAD)
|
|
# From the checkout, not from `gitea.sha`: on a pull_request event
|
|
# that variable can be the merge ref, which is not the commit anyone
|
|
# is testing and not something to hang a tag on.
|
|
echo "SHA=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
|
|
|
|
# The patch number is computed exactly as build-app.yml does it, so a
|
|
# preview is labelled with the version the release it previews would
|
|
# carry. This used to be hard-coded `.0`, which made every preview
|
|
# installer claim to be x.y.0 no matter what it contained.
|
|
LATEST_TAG=$(git tag -l "v${MAJOR_MINOR}.*" --sort=-v:refname | grep -E "^v${MAJOR_MINOR}\.[0-9]+$" | head -1 || true)
|
|
if [ -n "$LATEST_TAG" ]; then
|
|
PATCH=$(git rev-list --count "${LATEST_TAG}..HEAD")
|
|
echo "Latest matching tag: ${LATEST_TAG} (+${PATCH} commits)"
|
|
else
|
|
echo "No v${MAJOR_MINOR}.* tag yet — starting this line at .0"
|
|
PATCH=0
|
|
fi
|
|
|
|
VERSION="${MAJOR_MINOR}.${PATCH}-preview.${SHORT_SHA}"
|
|
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
|
|
echo "Computed preview version: ${VERSION}"
|
|
|
|
# One release, created once. The three build jobs run concurrently, so
|
|
# get-or-create in each of them would race on the same tag: whoever loses gets
|
|
# a 409 and (the way the old build-app.yml parsed it) an empty release id that
|
|
# still reported success. Creating it in a job they all depend on removes the
|
|
# race rather than handling it.
|
|
create-release:
|
|
runs-on: ubuntu-latest
|
|
needs: [compute-version]
|
|
outputs:
|
|
release_id: ${{ steps.release.outputs.RELEASE_ID }}
|
|
tag: ${{ steps.release.outputs.TAG }}
|
|
steps:
|
|
- name: Create the preview release
|
|
id: release
|
|
env:
|
|
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
VERSION: ${{ needs.compute-version.outputs.version }}
|
|
SHA: ${{ needs.compute-version.outputs.sha }}
|
|
BRANCH: ${{ gitea.head_ref || gitea.ref_name }}
|
|
run: |
|
|
set -euo pipefail
|
|
TAG="preview-${VERSION##*.}"
|
|
echo "TAG=${TAG}" >> $GITHUB_OUTPUT
|
|
|
|
# Idempotent: re-dispatching the same commit must update the existing
|
|
# release rather than fail on the duplicate tag.
|
|
HTTP_CODE=$(curl -sS -o release.json -w '%{http_code}' \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/tags/${TAG}")
|
|
case "${HTTP_CODE}" in
|
|
200) echo "Release ${TAG} already exists, reusing" ;;
|
|
404)
|
|
echo "Creating release ${TAG}"
|
|
# prerelease: true keeps it off "latest" — this is a branch build,
|
|
# not something anyone should install by accident.
|
|
curl -fsS -X POST \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"tag_name\": \"${TAG}\", \"target_commitish\": \"${SHA}\", \"name\": \"Preview ${VERSION}\", \"prerelease\": true, \"body\": \"Unreleased build of \`${BRANCH}\` at ${SHA}. Not a release — pruned by Cleanup Old Releases.\"}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases" > release.json
|
|
;;
|
|
*)
|
|
echo "Unexpected HTTP ${HTTP_CODE} from get-release-by-tag" >&2
|
|
cat release.json >&2 || true
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
RELEASE_ID=$(grep -o '"id":[0-9]*' release.json | head -1 | grep -o '[0-9]*' || true)
|
|
if [ -z "${RELEASE_ID}" ]; then
|
|
echo "Failed to parse release id; response was:" >&2
|
|
cat release.json >&2
|
|
exit 1
|
|
fi
|
|
echo "RELEASE_ID=${RELEASE_ID}" >> $GITHUB_OUTPUT
|
|
echo "Release ${TAG} is id ${RELEASE_ID}"
|
|
|
|
build-linux:
|
|
runs-on: ubuntu-latest
|
|
needs: [compute-version, create-release]
|
|
steps:
|
|
- name: Install Node.js 22
|
|
run: |
|
|
NEED_INSTALL=false
|
|
if command -v node >/dev/null 2>&1; then
|
|
NODE_MAJOR=$(node --version | sed 's/v\([0-9]*\).*/\1/')
|
|
OLD_NODE_DIR=$(dirname "$(which node)")
|
|
echo "Found Node.js $(node --version) at $(which node) (major: ${NODE_MAJOR})"
|
|
if [ "$NODE_MAJOR" -lt 22 ]; then
|
|
echo "Node.js ${NODE_MAJOR} is too old, removing before installing 22..."
|
|
sudo rm -f "${OLD_NODE_DIR}/node" "${OLD_NODE_DIR}/npm" "${OLD_NODE_DIR}/npx" "${OLD_NODE_DIR}/corepack"
|
|
hash -r
|
|
NEED_INSTALL=true
|
|
fi
|
|
else
|
|
echo "Node.js not found, installing 22..."
|
|
NEED_INSTALL=true
|
|
fi
|
|
if [ "$NEED_INSTALL" = true ]; then
|
|
curl -fsSL https://deb.nodesource.com/setup_22.x | sudo -E bash -
|
|
sudo apt-get install -y nodejs
|
|
hash -r
|
|
fi
|
|
node --version
|
|
npm --version
|
|
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set app version
|
|
run: |
|
|
# Tauri / Cargo require a strict semver; strip the preview suffix for
|
|
# the bundle version but keep it in the artifact filename.
|
|
BASE_VERSION="$(echo '${{ needs.compute-version.outputs.version }}' | cut -d'-' -f1)"
|
|
sed -i "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/src-tauri/tauri.conf.json
|
|
sed -i "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/package.json
|
|
sed -i "s/^version = \".*\"/version = \"${BASE_VERSION}\"/" app/src-tauri/Cargo.toml
|
|
echo "Patched version to ${BASE_VERSION}"
|
|
|
|
- name: Install system dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y \
|
|
libgtk-3-dev \
|
|
libwebkit2gtk-4.1-dev \
|
|
libayatana-appindicator3-dev \
|
|
librsvg2-dev \
|
|
libsoup-3.0-dev \
|
|
libssl-dev \
|
|
libxdo-dev \
|
|
patchelf \
|
|
pkg-config \
|
|
build-essential \
|
|
curl \
|
|
wget \
|
|
file \
|
|
xdg-utils
|
|
|
|
- name: Install Rust stable
|
|
run: |
|
|
if command -v rustup >/dev/null 2>&1; then
|
|
rustup update stable
|
|
rustup default stable
|
|
else
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
|
fi
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
rustc --version
|
|
cargo --version
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: ./app
|
|
run: |
|
|
rm -rf node_modules package-lock.json
|
|
npm install
|
|
|
|
- name: Install Tauri CLI
|
|
working-directory: ./app
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
npx tauri --version || npm install @tauri-apps/cli
|
|
|
|
- name: Build Tauri app
|
|
working-directory: ./app
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
npx tauri build
|
|
|
|
- name: Collect artifacts
|
|
run: |
|
|
mkdir -p artifacts
|
|
cp app/src-tauri/target/release/bundle/appimage/*.AppImage artifacts/ 2>/dev/null || true
|
|
cp app/src-tauri/target/release/bundle/deb/*.deb artifacts/ 2>/dev/null || true
|
|
cp app/src-tauri/target/release/bundle/rpm/*.rpm artifacts/ 2>/dev/null || true
|
|
ls -la artifacts/
|
|
|
|
# Assets, not workflow artifacts — see the note at the top of this file.
|
|
# Delete-then-upload so a re-dispatch replaces rather than 409s, and the
|
|
# retry/http1.1 hardening that build-app.yml learned from real macOS
|
|
# upload failures (curl exit 92 and exit 28 mid-stream).
|
|
- name: Upload Linux bundles to the preview release
|
|
shell: bash
|
|
env:
|
|
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
run: |
|
|
set -euo pipefail
|
|
shopt -s nullglob
|
|
files=(artifacts/*)
|
|
if [ ${#files[@]} -eq 0 ]; then
|
|
echo "No Linux bundles were produced" >&2
|
|
exit 1
|
|
fi
|
|
for file in "${files[@]}"; do
|
|
filename=$(basename "$file")
|
|
EXISTING_ID=$(curl -sS \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets" \
|
|
| python3 -c "import json,sys; t=sys.argv[1]; print(next((a['id'] for a in json.load(sys.stdin) if a.get('name')==t), ''))" "${filename}" || true)
|
|
if [ -n "${EXISTING_ID}" ]; then
|
|
echo "Replacing existing asset ${filename}"
|
|
curl -fsS -X DELETE \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets/${EXISTING_ID}"
|
|
fi
|
|
echo "Uploading ${filename}..."
|
|
curl -fsS --http1.1 --retry 5 --retry-all-errors --retry-delay 5 --max-time 600 \
|
|
-X POST \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--data-binary "@${file}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${filename}"
|
|
done
|
|
|
|
build-macos:
|
|
runs-on: macos-latest
|
|
needs: [compute-version, create-release]
|
|
steps:
|
|
- name: Install Node.js 22
|
|
run: |
|
|
NEED_INSTALL=false
|
|
if command -v node >/dev/null 2>&1; then
|
|
NODE_MAJOR=$(node --version | sed 's/v\([0-9]*\).*/\1/')
|
|
if [ "$NODE_MAJOR" -lt 22 ]; then
|
|
NEED_INSTALL=true
|
|
fi
|
|
else
|
|
NEED_INSTALL=true
|
|
fi
|
|
if [ "$NEED_INSTALL" = true ]; then
|
|
brew install node@22
|
|
brew link --overwrite node@22
|
|
fi
|
|
node --version
|
|
npm --version
|
|
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set app version
|
|
run: |
|
|
BASE_VERSION="$(echo '${{ needs.compute-version.outputs.version }}' | cut -d'-' -f1)"
|
|
sed -i '' "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/src-tauri/tauri.conf.json
|
|
sed -i '' "s/\"version\": \".*\"/\"version\": \"${BASE_VERSION}\"/" app/package.json
|
|
sed -i '' "s/^version = \".*\"/version = \"${BASE_VERSION}\"/" app/src-tauri/Cargo.toml
|
|
echo "Patched version to ${BASE_VERSION}"
|
|
|
|
- name: Install Rust stable
|
|
run: |
|
|
if command -v rustup >/dev/null 2>&1; then
|
|
rustup update stable
|
|
rustup default stable
|
|
else
|
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable
|
|
fi
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
rustup target add aarch64-apple-darwin x86_64-apple-darwin
|
|
rustc --version
|
|
cargo --version
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: ./app
|
|
run: |
|
|
rm -rf node_modules
|
|
npm install
|
|
|
|
- name: Install Tauri CLI
|
|
working-directory: ./app
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
npx tauri --version || npm install @tauri-apps/cli
|
|
|
|
- name: Build Tauri app (universal)
|
|
working-directory: ./app
|
|
run: |
|
|
export PATH="$HOME/.cargo/bin:$PATH"
|
|
npx tauri build --target universal-apple-darwin
|
|
|
|
- name: Collect artifacts
|
|
run: |
|
|
mkdir -p artifacts
|
|
cp app/src-tauri/target/universal-apple-darwin/release/bundle/dmg/*.dmg artifacts/ 2>/dev/null || true
|
|
cp app/src-tauri/target/universal-apple-darwin/release/bundle/macos/*.app.tar.gz artifacts/ 2>/dev/null || true
|
|
ls -la artifacts/
|
|
|
|
# Assets, not workflow artifacts — see the note at the top of this file.
|
|
# Delete-then-upload so a re-dispatch replaces rather than 409s, and the
|
|
# retry/http1.1 hardening that build-app.yml learned from real macOS
|
|
# upload failures (curl exit 92 and exit 28 mid-stream).
|
|
- name: Upload macOS bundles to the preview release
|
|
shell: bash
|
|
env:
|
|
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
run: |
|
|
set -euo pipefail
|
|
shopt -s nullglob
|
|
files=(artifacts/*)
|
|
if [ ${#files[@]} -eq 0 ]; then
|
|
echo "No macOS bundles were produced" >&2
|
|
exit 1
|
|
fi
|
|
for file in "${files[@]}"; do
|
|
filename=$(basename "$file")
|
|
EXISTING_ID=$(curl -sS \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets" \
|
|
| python3 -c "import json,sys; t=sys.argv[1]; print(next((a['id'] for a in json.load(sys.stdin) if a.get('name')==t), ''))" "${filename}" || true)
|
|
if [ -n "${EXISTING_ID}" ]; then
|
|
echo "Replacing existing asset ${filename}"
|
|
curl -fsS -X DELETE \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets/${EXISTING_ID}"
|
|
fi
|
|
echo "Uploading ${filename}..."
|
|
curl -fsS --http1.1 --retry 5 --retry-all-errors --retry-delay 5 --max-time 600 \
|
|
-X POST \
|
|
-H "Authorization: token ${TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--data-binary "@${file}" \
|
|
"${GITEA_URL}/api/v1/repos/${REPO}/releases/${RELEASE_ID}/assets?name=${filename}"
|
|
done
|
|
|
|
build-windows:
|
|
runs-on: windows-latest
|
|
needs: [compute-version, create-release]
|
|
defaults:
|
|
run:
|
|
shell: cmd
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Set app version
|
|
shell: powershell
|
|
run: |
|
|
$raw = "${{ needs.compute-version.outputs.version }}"
|
|
$version = $raw.Split('-')[0]
|
|
(Get-Content app/src-tauri/tauri.conf.json) -replace '"version": ".*?"', "`"version`": `"$version`"" | Set-Content app/src-tauri/tauri.conf.json
|
|
(Get-Content app/package.json) -replace '"version": ".*?"', "`"version`": `"$version`"" | Set-Content app/package.json
|
|
(Get-Content app/src-tauri/Cargo.toml) -replace '^version = ".*?"', "version = `"$version`"" | Set-Content app/src-tauri/Cargo.toml
|
|
Write-Host "Patched version to $version"
|
|
|
|
- name: Install Rust stable
|
|
run: |
|
|
where rustup >nul 2>&1 && (
|
|
rustup update stable
|
|
rustup default stable
|
|
) || (
|
|
curl -fSL -o rustup-init.exe https://win.rustup.rs/x86_64
|
|
rustup-init.exe -y --default-toolchain stable
|
|
del rustup-init.exe
|
|
)
|
|
|
|
- name: Install Node.js
|
|
run: |
|
|
where node >nul 2>&1 && (
|
|
node --version
|
|
) || (
|
|
curl -fSL -o node-install.msi "https://nodejs.org/dist/v22.14.0/node-v22.14.0-x64.msi"
|
|
msiexec /i node-install.msi /quiet /norestart
|
|
del node-install.msi
|
|
)
|
|
|
|
- name: Verify tools
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
rustc --version
|
|
cargo --version
|
|
node --version
|
|
npm --version
|
|
|
|
- name: Install Tauri CLI via cargo
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
cargo install tauri-cli --version "^2"
|
|
|
|
- name: Fix npm platform detection
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
npm config set os win32
|
|
npm config list
|
|
|
|
- name: Install frontend dependencies
|
|
working-directory: ./app
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
if exist node_modules rmdir /s /q node_modules
|
|
npm ci
|
|
|
|
- name: Build frontend
|
|
working-directory: ./app
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
npm run build
|
|
|
|
- name: Build Tauri app
|
|
working-directory: ./app
|
|
env:
|
|
TAURI_CONFIG: "{\"build\":{\"beforeBuildCommand\":\"\"}}"
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
cargo tauri build
|
|
|
|
- name: Collect artifacts
|
|
run: |
|
|
set "PATH=%USERPROFILE%\.cargo\bin;C:\Program Files\nodejs;%PATH%"
|
|
mkdir artifacts
|
|
copy app\src-tauri\target\release\bundle\msi\*.msi artifacts\ 2>nul
|
|
copy app\src-tauri\target\release\bundle\nsis\*.exe artifacts\ 2>nul
|
|
dir artifacts\
|
|
|
|
# PowerShell, because this job's default shell is cmd. Same
|
|
# delete-then-upload shape as the other two.
|
|
- name: Upload Windows bundles to the preview release
|
|
shell: powershell
|
|
env:
|
|
TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
RELEASE_ID: ${{ needs.create-release.outputs.release_id }}
|
|
run: |
|
|
$ErrorActionPreference = "Stop"
|
|
$headers = @{ Authorization = "token $env:TOKEN" }
|
|
$api = "$env:GITEA_URL/api/v1/repos/$env:REPO"
|
|
$files = @(Get-ChildItem -File -Path artifacts\*)
|
|
if ($files.Count -eq 0) { throw "No Windows bundles were produced" }
|
|
|
|
$existing = Invoke-RestMethod -Method Get -Headers $headers -Uri "$api/releases/$env:RELEASE_ID/assets"
|
|
foreach ($file in $files) {
|
|
$name = $file.Name
|
|
$dupe = $existing | Where-Object { $_.name -eq $name }
|
|
if ($dupe) {
|
|
Write-Host "Replacing existing asset $name"
|
|
Invoke-RestMethod -Method Delete -Headers $headers -Uri "$api/releases/$env:RELEASE_ID/assets/$($dupe.id)" | Out-Null
|
|
}
|
|
Write-Host "Uploading $name..."
|
|
$uploadUri = "$api/releases/$env:RELEASE_ID/assets?name=$([uri]::EscapeDataString($name))"
|
|
curl.exe -fsS --retry 5 --retry-all-errors --retry-delay 5 --max-time 600 `
|
|
-X POST -H "Authorization: token $env:TOKEN" `
|
|
-H "Content-Type: application/octet-stream" `
|
|
--data-binary "@$($file.FullName)" $uploadUri
|
|
if ($LASTEXITCODE -ne 0) { throw "Upload of $name failed (curl exit $LASTEXITCODE)" }
|
|
}
|