Prevents 'HTTP 404: Not Found' and '502 Bad Gateway' errors from GitHub API when attempting to upload many assets simultaneously using the gh cli.
241 lines
7.8 KiB
YAML
241 lines
7.8 KiB
YAML
name: Publish Release
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows: ['Release']
|
|
types: [completed]
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry_run:
|
|
description: 'Build artifacts only, skip uploading to GitHub Release'
|
|
required: false
|
|
type: boolean
|
|
default: true
|
|
allow_update_published_release:
|
|
description: 'Allow uploading assets to an already published release'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
jobs:
|
|
check-release:
|
|
name: Check for new release
|
|
runs-on: ubuntu-latest
|
|
if: github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success'
|
|
permissions:
|
|
contents: read
|
|
outputs:
|
|
tag: ${{ steps.get_tag.outputs.tag }}
|
|
has_release: ${{ steps.get_tag.outputs.has_release }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Get latest release tag
|
|
id: get_tag
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
|
version="$(node -e "process.stdout.write(require('./package.json').version)")"
|
|
tag="v$version"
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
echo "has_release=true" >> "$GITHUB_OUTPUT"
|
|
else
|
|
tag=$(gh release list --limit 1 --json tagName --jq '.[0].tagName // empty')
|
|
if [ -n "$tag" ]; then
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
echo "has_release=true" >> "$GITHUB_OUTPUT"
|
|
echo "Found release: $tag"
|
|
else
|
|
echo "has_release=false" >> "$GITHUB_OUTPUT"
|
|
echo "No release found, skipping build."
|
|
fi
|
|
fi
|
|
|
|
build:
|
|
needs: check-release
|
|
if: needs.check-release.outputs.has_release == 'true'
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: windows-latest
|
|
platform: win32
|
|
arch: x64
|
|
- os: windows-11-arm
|
|
platform: win32
|
|
arch: arm64
|
|
- os: macos-15-intel
|
|
platform: darwin
|
|
arch: x64
|
|
- os: macos-14
|
|
platform: darwin
|
|
arch: arm64
|
|
- os: ubuntu-latest
|
|
platform: linux
|
|
arch: x64
|
|
- os: ubuntu-24.04-arm
|
|
platform: linux
|
|
arch: arm64
|
|
|
|
runs-on: ${{ matrix.os }}
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
steps:
|
|
- name: Checkout git repo
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Install pnpm
|
|
uses: pnpm/action-setup@v4
|
|
|
|
- name: Install Node and NPM
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: 20
|
|
cache: 'pnpm'
|
|
|
|
- name: Install Linux dependencies
|
|
if: matrix.platform == 'linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y fakeroot rpm libsecret-1-dev pkg-config
|
|
|
|
- name: Ensure WiX Toolset
|
|
if: matrix.platform == 'win32' && matrix.arch == 'x64'
|
|
shell: powershell
|
|
run: |
|
|
$installed = choco list --local-only wixtoolset --exact --limit-output
|
|
if (-not $installed) {
|
|
choco install wixtoolset --version=3.14.0 -y
|
|
} elseif ($installed -match '^wixtoolset\|3\.14(\.|$)') {
|
|
Write-Host "WiX Toolset already compatible: $installed"
|
|
} else {
|
|
Write-Host "Incompatible WiX Toolset detected: $installed"
|
|
choco upgrade wixtoolset --version=3.14.0 --allow-downgrade -y
|
|
}
|
|
# Ensure 7zip is available for Squirrel.Windows zip operations
|
|
choco install 7zip -y
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Make Artifacts
|
|
if: matrix.platform != 'darwin'
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=8192
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
|
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
|
run: pnpm run make -- --platform=${{ matrix.platform }} --arch=${{ matrix.arch }}
|
|
|
|
# DMG creation may be flaky on GitHub macOS runners, so retry the full darwin make.
|
|
- name: Make Artifacts (darwin with retry)
|
|
if: matrix.platform == 'darwin'
|
|
uses: nick-fields/retry@v3
|
|
with:
|
|
max_attempts: 3
|
|
timeout_minutes: 20
|
|
retry_wait_seconds: 20
|
|
command: pnpm run make -- --platform=${{ matrix.platform }} --arch=${{ matrix.arch }}
|
|
env:
|
|
NODE_OPTIONS: --max-old-space-size=8192
|
|
SENTRY_DSN: ${{ secrets.SENTRY_DSN }}
|
|
SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }}
|
|
SENTRY_ORG: ${{ secrets.SENTRY_ORG }}
|
|
SENTRY_PROJECT: ${{ secrets.SENTRY_PROJECT }}
|
|
|
|
- name: Upload Build Artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: make-${{ matrix.platform }}-${{ matrix.arch }}
|
|
path: |
|
|
out/make/**/*.exe
|
|
out/make/**/*.dmg
|
|
out/make/**/*.zip
|
|
out/make/**/*.AppImage
|
|
out/make/**/*.deb
|
|
out/make/**/*.rpm
|
|
out/make/**/*.msi
|
|
out/make/**/*.yml
|
|
out/make/**/*.txt
|
|
if-no-files-found: error
|
|
retention-days: 14
|
|
|
|
- name: Dry-run summary
|
|
if: github.event_name == 'workflow_dispatch' && github.event.inputs.dry_run == 'true'
|
|
run: |
|
|
echo "Dry run enabled: build artifacts generated and uploaded; release publish step will be skipped."
|
|
|
|
publish:
|
|
name: Publish Release
|
|
needs: [check-release, build]
|
|
runs-on: ubuntu-latest
|
|
if: needs.build.result == 'success' && (github.event_name != 'workflow_dispatch' || github.event.inputs.dry_run != 'true')
|
|
permissions:
|
|
contents: write
|
|
|
|
steps:
|
|
- name: Checkout git repo
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download Build Artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
pattern: make-*
|
|
merge-multiple: true
|
|
path: release-assets
|
|
|
|
- name: Resolve release tag
|
|
id: release_tag
|
|
run: |
|
|
tag="${{ needs.check-release.outputs.tag }}"
|
|
if [ -z "$tag" ]; then
|
|
version="$(node -e "process.stdout.write(require('./package.json').version)")"
|
|
tag="v$version"
|
|
fi
|
|
echo "tag=$tag" >> "$GITHUB_OUTPUT"
|
|
echo "Using release tag: $tag"
|
|
|
|
- name: Upload assets to release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
RELEASE_TAG: ${{ steps.release_tag.outputs.tag }}
|
|
run: |
|
|
mapfile -t files < <(find release-assets -type f \( \
|
|
-name '*.exe' -o \
|
|
-name '*.dmg' -o \
|
|
-name '*.zip' -o \
|
|
-name '*.AppImage' -o \
|
|
-name '*.deb' -o \
|
|
-name '*.rpm' -o \
|
|
-name '*.msi' -o \
|
|
-name '*.yml' -o \
|
|
-name '*.txt' \
|
|
\) | sort)
|
|
|
|
if [ "${#files[@]}" -eq 0 ]; then
|
|
echo "::error::No release assets found under release-assets/"
|
|
exit 1
|
|
fi
|
|
|
|
printf 'Uploading %s assets to %s\n' "${#files[@]}" "$RELEASE_TAG"
|
|
|
|
# Upload files sequentially with retries to prevent GitHub API rate limits and 404/502 errors
|
|
for file in "${files[@]}"; do
|
|
echo "Uploading $file..."
|
|
if ! gh release upload "$RELEASE_TAG" "$file" --clobber; then
|
|
echo "::warning::Failed to upload $file. Retrying in 5 seconds..."
|
|
sleep 5
|
|
if ! gh release upload "$RELEASE_TAG" "$file" --clobber; then
|
|
echo "::error::Failed to upload $file after retry."
|
|
exit 1
|
|
fi
|
|
fi
|
|
done
|