Some checks failed
Axolotl desktop CI / guardrails (push) Has been cancelled
Axolotl desktop CI / desktop (macos-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (ubuntu-latest) (push) Has been cancelled
Axolotl desktop CI / desktop (windows-latest) (push) Has been cancelled
Axolotl desktop CI / website (push) Has been cancelled
Repository checks / typos (push) Has been cancelled
Repository checks / tombi (push) Has been cancelled
Rust checks / shear (push) Has been cancelled
Sync source to CNB / Sync Git ref (push) Has been cancelled
410 lines
16 KiB
YAML
410 lines
16 KiB
YAML
name: Axolotl release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
concurrency:
|
|
group: axolotl-release-${{ github.ref }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
preflight:
|
|
name: Release preflight
|
|
runs-on: ubuntu-24.04
|
|
env:
|
|
SQLX_OFFLINE: true
|
|
steps:
|
|
- name: Check out source
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 0
|
|
submodules: recursive
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: pnpm
|
|
|
|
- name: Set up Rust
|
|
uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Install Blockbench skin editor dependencies
|
|
run: npm ci
|
|
working-directory: third-party/blockbench
|
|
|
|
- name: Run release guardrails
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
node scripts/axolotl/check-migrations.mjs --release
|
|
node scripts/axolotl/brand-guard.mjs
|
|
node scripts/axolotl/i18n-check.mjs
|
|
cargo fmt --all --check
|
|
|
|
- name: Prepare draft release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
release_notes="${RUNNER_TEMP}/axolotl-release-notes.md"
|
|
node scripts/axolotl/create-release-notes.mjs "${GITHUB_REF_NAME}" "$release_notes"
|
|
existing_release="$(
|
|
gh release list --limit 100 --json tagName \
|
|
--jq ".[] | select(.tagName == \"${GITHUB_REF_NAME}\") | .tagName"
|
|
)"
|
|
if [[ -n "$existing_release" ]]; then
|
|
echo "Release ${GITHUB_REF_NAME} already exists"
|
|
gh release edit "${GITHUB_REF_NAME}" --notes-file "$release_notes"
|
|
exit 0
|
|
fi
|
|
|
|
release_args=(
|
|
--draft
|
|
--notes-file "$release_notes"
|
|
--title "Axolotl Launcher ${GITHUB_REF_NAME}"
|
|
)
|
|
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
|
|
release_args+=(--prerelease)
|
|
fi
|
|
gh release create "${GITHUB_REF_NAME}" "${release_args[@]}"
|
|
|
|
build:
|
|
name: Build (${{ matrix.name }})
|
|
needs: preflight
|
|
strategy:
|
|
fail-fast: true
|
|
max-parallel: 4
|
|
matrix:
|
|
include:
|
|
- name: Linux x64
|
|
runner: ubuntu-24.04
|
|
args: --config tauri-release.conf.json --config tauri-updater.conf.json
|
|
- name: Linux arm64
|
|
runner: ubuntu-24.04-arm
|
|
args: --config tauri-release.conf.json --config tauri-updater.conf.json
|
|
- name: Windows x64
|
|
runner: windows-2025
|
|
args: --config tauri-release.conf.json --config tauri-modern.conf.json --config tauri-updater.conf.json
|
|
- name: macOS universal
|
|
runner: macos-15
|
|
args: --target universal-apple-darwin --config tauri-release.conf.json --config tauri-updater.conf.json
|
|
runs-on: ${{ matrix.runner }}
|
|
env:
|
|
SQLX_OFFLINE: true
|
|
steps:
|
|
- name: Check out source
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 0
|
|
submodules: recursive
|
|
|
|
- name: Set up pnpm
|
|
uses: pnpm/action-setup@008330803749db0355799c700092d9a85fd074e9 # v6.0.9
|
|
|
|
- name: Set up Node.js
|
|
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6
|
|
with:
|
|
node-version-file: .nvmrc
|
|
cache: pnpm
|
|
|
|
- name: Set up Rust
|
|
uses: dtolnay/rust-toolchain@4be7066ada62dd38de10e7b70166bc74ed198c30 # stable
|
|
|
|
- name: Set up Rust compiler cache
|
|
if: runner.os == 'Windows'
|
|
uses: mozilla-actions/sccache-action@2df7dbab909c49ab7d3382d05da469f3f975c2d6 # v0.0.7
|
|
|
|
- name: Check Rust compiler cache availability
|
|
id: sccache
|
|
if: runner.os == 'Windows'
|
|
continue-on-error: true
|
|
shell: bash
|
|
env:
|
|
SCCACHE_GHA_ENABLED: 'true'
|
|
run: ${SCCACHE_PATH} rustc -vV
|
|
|
|
- name: Enable Rust compiler cache
|
|
if: runner.os == 'Windows' && steps.sccache.outcome == 'success'
|
|
shell: bash
|
|
run: |
|
|
echo 'RUSTC_WRAPPER=sccache' >> "$GITHUB_ENV"
|
|
echo 'SCCACHE_GHA_ENABLED=true' >> "$GITHUB_ENV"
|
|
echo 'SCCACHE_CACHE_SIZE=4G' >> "$GITHUB_ENV"
|
|
|
|
- name: Add macOS universal targets
|
|
if: runner.os == 'macOS'
|
|
run: rustup target add aarch64-apple-darwin x86_64-apple-darwin
|
|
|
|
- name: Install Linux dependencies
|
|
if: runner.os == 'Linux'
|
|
run: sudo apt-get -o Acquire::ForceIPv4=true update && sudo apt-get -o Acquire::ForceIPv4=true install -y libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf xdg-utils
|
|
|
|
- name: Install dependencies
|
|
run: pnpm install --frozen-lockfile
|
|
|
|
- name: Install Blockbench skin editor dependencies
|
|
run: npm ci
|
|
working-directory: third-party/blockbench
|
|
|
|
- uses: ./.github/actions/replace-gradle-mirror
|
|
|
|
- name: Set release version
|
|
run: node scripts/axolotl/set-version.mjs "${{ github.ref_name }}"
|
|
|
|
- name: Build and upload release assets
|
|
uses: tauri-apps/tauri-action@1ddc7b49b13c3038297360482fcb3e058764d7c9 # v0.6.2
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
|
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
|
TAURI_BUNDLER_DMG_IGNORE_CI: ${{ runner.os == 'macOS' && 'true' || '' }}
|
|
with:
|
|
projectPath: apps/app
|
|
tauriScript: pnpm tauri
|
|
args: ${{ matrix.args }}
|
|
tagName: ${{ github.ref_name }}
|
|
releaseName: Axolotl Launcher ${{ github.ref_name }}
|
|
releaseDraft: true
|
|
prerelease: ${{ contains(github.ref_name, '-') }}
|
|
generateReleaseNotes: false
|
|
includeUpdaterJson: false
|
|
updaterJsonPreferNsis: true
|
|
retryAttempts: 2
|
|
|
|
- name: Show Rust compiler cache statistics
|
|
if: runner.os == 'Windows' && steps.sccache.outcome == 'success' && always()
|
|
shell: bash
|
|
run: ${SCCACHE_PATH} --show-stats
|
|
|
|
- name: Publish Windows distribution variants
|
|
if: runner.os == 'Windows'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
CURSEFORGE_API_KEY: ${{ secrets.CURSEFORGE_API_KEY }}
|
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
|
shell: pwsh
|
|
run: |
|
|
$version = "${{ github.ref_name }}" -replace '^v', ''
|
|
$appName = (Get-Content apps/app/tauri.conf.json -Raw | ConvertFrom-Json).mainBinaryName
|
|
$outDir = "target/release/bundle/nsis"
|
|
$buildDir = "target/portable-build"
|
|
$publishDir = Join-Path $env:RUNNER_TEMP "windows-assets"
|
|
|
|
New-Item -ItemType Directory -Force -Path $publishDir | Out-Null
|
|
|
|
$modernInstallers = @(Get-ChildItem $outDir -Filter '*-setup.exe' -File)
|
|
if ($modernInstallers.Count -ne 1) {
|
|
throw "Expected one modern installer, found $($modernInstallers.Count)"
|
|
}
|
|
|
|
$modernName = "Axolotl_Launcher_${version}_x64_modern-setup.exe"
|
|
$modernPath = Join-Path $publishDir $modernName
|
|
Copy-Item -Force $modernInstallers[0].FullName $modernPath
|
|
gh release upload "${{ github.ref_name }}" $modernPath --clobber
|
|
|
|
$modernSignature = "$($modernInstallers[0].FullName).sig"
|
|
if (Test-Path $modernSignature) {
|
|
$modernSignaturePath = "$modernPath.sig"
|
|
Copy-Item -Force $modernSignature $modernSignaturePath
|
|
gh release upload "${{ github.ref_name }}" $modernSignaturePath --clobber
|
|
gh release delete-asset "${{ github.ref_name }}" "$($modernInstallers[0].Name).sig" --yes
|
|
}
|
|
gh release delete-asset "${{ github.ref_name }}" $modernInstallers[0].Name --yes
|
|
|
|
pnpm --filter @modrinth/app tauri build --config tauri-release.conf.json --config tauri-native.conf.json
|
|
|
|
$nativeInstallers = @(Get-ChildItem $outDir -Filter '*-setup.exe' -File)
|
|
if ($nativeInstallers.Count -ne 1) {
|
|
throw "Expected one native NSIS installer, found $($nativeInstallers.Count)"
|
|
}
|
|
|
|
$nativeName = "Axolotl_Launcher_${version}_x64_nsis-setup.exe"
|
|
$nativePath = Join-Path $publishDir $nativeName
|
|
Copy-Item -Force $nativeInstallers[0].FullName $nativePath
|
|
gh release upload "${{ github.ref_name }}" $nativePath --clobber
|
|
|
|
$nativeSignature = "$($nativeInstallers[0].FullName).sig"
|
|
if (Test-Path $nativeSignature) {
|
|
$nativeSignaturePath = "$nativePath.sig"
|
|
Copy-Item -Force $nativeSignature $nativeSignaturePath
|
|
gh release upload "${{ github.ref_name }}" $nativeSignaturePath --clobber
|
|
}
|
|
|
|
# Reuse the binary already built by tauri-action
|
|
$appExe = "target/release/${appName}.exe"
|
|
if (Test-Path $appExe) {
|
|
New-Item -ItemType Directory -Force -Path "$buildDir\Axolotl" | Out-Null
|
|
Copy-Item -Force $appExe "$buildDir\Axolotl\"
|
|
|
|
$editorResources = "target/release/resources/blockbench-skin"
|
|
foreach ($requiredFile in @('index.html', 'css/setup.css', 'dist/skin.bundle.js.gz')) {
|
|
if (!(Test-Path -LiteralPath (Join-Path $editorResources $requiredFile) -PathType Leaf)) {
|
|
throw "Missing skin editor resource: $requiredFile"
|
|
}
|
|
}
|
|
New-Item -ItemType Directory -Force -Path "$buildDir\Axolotl\resources" | Out-Null
|
|
Copy-Item -LiteralPath $editorResources -Destination "$buildDir\Axolotl\resources" -Recurse -Force
|
|
|
|
# Create empty .Axolotl folder to trigger portable mode
|
|
New-Item -ItemType Directory -Force -Path "$buildDir\Axolotl\.Axolotl" | Out-Null
|
|
|
|
# Create portable zip (for manual download)
|
|
$zipName = "Axolotl_Launcher_${version}_x64_portable.zip"
|
|
$zipPath = Join-Path $publishDir $zipName
|
|
Compress-Archive -Path "$buildDir\Axolotl" -DestinationPath $zipPath -Force
|
|
Write-Output "Created portable zip: $zipPath"
|
|
|
|
# Upload portable zip (for manual download only)
|
|
gh release upload "${{ github.ref_name }}" "$zipPath" --clobber
|
|
} else {
|
|
throw "Binary not found at $appExe"
|
|
}
|
|
|
|
verify-and-publish:
|
|
name: Verify and publish
|
|
needs: build
|
|
runs-on: ubuntu-24.04
|
|
steps:
|
|
- name: Check out source
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 0
|
|
ref: main
|
|
|
|
- name: Download updater signatures
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: gh release download "${GITHUB_REF_NAME}" --pattern '*.sig' --dir release-check/signatures
|
|
|
|
- name: Download release metadata
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
release_id="$(
|
|
gh api "repos/${GITHUB_REPOSITORY}/releases" \
|
|
--paginate \
|
|
--jq ".[] | select(.tag_name == \"${GITHUB_REF_NAME}\") | .id"
|
|
)"
|
|
if [[ -z "$release_id" ]]; then
|
|
echo "Release ${GITHUB_REF_NAME} was not found"
|
|
exit 1
|
|
fi
|
|
gh api "repos/${GITHUB_REPOSITORY}/releases/${release_id}" > release-check/release.json
|
|
|
|
- name: Generate update manifest
|
|
run: node scripts/axolotl/create-update-manifest.mjs release-check/release.json release-check/signatures "${GITHUB_REF_NAME}" release-check/latest.json
|
|
|
|
- name: Verify update manifest
|
|
run: node scripts/axolotl/verify-update-manifest.mjs release-check/latest.json "${GITHUB_REF_NAME}"
|
|
|
|
- name: Upload update manifest
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: gh release upload "${GITHUB_REF_NAME}" release-check/latest.json --clobber
|
|
|
|
- name: Publish release
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
if [[ "${GITHUB_REF_NAME}" == *-* ]]; then
|
|
gh release edit "${GITHUB_REF_NAME}" --draft=false --prerelease
|
|
else
|
|
gh release edit "${GITHUB_REF_NAME}" --draft=false --latest
|
|
fi
|
|
|
|
- name: Refresh published GitHub release metadata
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
release_id="$(
|
|
gh api "repos/${GITHUB_REPOSITORY}/releases" \
|
|
--paginate \
|
|
--jq ".[] | select(.tag_name == \"${GITHUB_REF_NAME}\") | .id"
|
|
)"
|
|
if [[ -z "$release_id" ]]; then
|
|
echo "Published release ${GITHUB_REF_NAME} was not found"
|
|
exit 1
|
|
fi
|
|
gh api "repos/${GITHUB_REPOSITORY}/releases/${release_id}" > release-check/release.json
|
|
|
|
- name: Build Update Server artifact catalog
|
|
run: |
|
|
node scripts/axolotl/create-update-server-catalog.mjs \
|
|
release-check/release.json \
|
|
"${GITHUB_REF_NAME}" \
|
|
release-check/update-server-catalog.json
|
|
node scripts/axolotl/create-update-server-catalog.test.mjs
|
|
|
|
- name: Notify Update Server to publish release assets
|
|
env:
|
|
UPDATE_SERVER_URL: ${{ secrets.UPDATE_SERVER_URL }}
|
|
UPDATE_SERVER_WEBHOOK_SECRET: ${{ secrets.UPDATE_SERVER_WEBHOOK_SECRET }}
|
|
UPDATE_SERVER_FORCE_UPDATE: 'false'
|
|
run: |
|
|
node scripts/axolotl/publish-update-server.mjs \
|
|
release-check/update-server-catalog.json \
|
|
release-check/release.json \
|
|
"${GITHUB_REF_NAME}"
|
|
|
|
- name: Publish website download metadata
|
|
if: ${{ !contains(github.ref_name, '-') }}
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
node scripts/axolotl/create-website-release-metadata.mjs \
|
|
release-check/release.json \
|
|
apps/website/releases/latest.json
|
|
node scripts/axolotl/create-website-release-catalog.mjs \
|
|
apps/website/releases/catalog.json
|
|
|
|
git config user.name "Axolotl Release Bot"
|
|
git config user.email "release@axolotl.local"
|
|
git add apps/website/releases/latest.json apps/website/releases/catalog.json
|
|
if git diff --cached --quiet; then
|
|
echo "Website metadata is unchanged"
|
|
else
|
|
git commit -m "chore(website): update download metadata to ${GITHUB_REF_NAME} [skip ci]"
|
|
git push origin main
|
|
fi
|
|
|
|
- name: Mirror published release to CNB
|
|
env:
|
|
CNB_REPO_URL_HTTPS: ${{ secrets.CNB_REPO_URL_HTTPS }}
|
|
CNB_TOKEN: ${{ secrets.CNB_TOKEN }}
|
|
CNB_TOKEN_USER_NAME: ${{ secrets.CNB_TOKEN_USER_NAME }}
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [[ -z "${CNB_TOKEN:-}" ]]; then
|
|
echo "CNB_TOKEN is not configured"
|
|
exit 1
|
|
fi
|
|
|
|
cnb_url="${CNB_REPO_URL_HTTPS:-https://cnb.cool/axlmc/Axolotl.git}"
|
|
token_user="${CNB_TOKEN_USER_NAME:-cnb}"
|
|
auth="$(printf '%s:%s' "$token_user" "$CNB_TOKEN" | base64 -w0)"
|
|
git_cnb() {
|
|
git -c "http.extraHeader=Authorization: Basic $auth" "$@"
|
|
}
|
|
|
|
git fetch origin "refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}"
|
|
git_cnb push --force "$cnb_url" \
|
|
"refs/tags/${GITHUB_REF_NAME}:refs/tags/${GITHUB_REF_NAME}"
|
|
|
|
node scripts/axolotl/cnb-release.mjs finalize "${GITHUB_REF_NAME}" cnb-release/final
|
|
node scripts/axolotl/verify-update-manifest.mjs \
|
|
cnb-release/final/latest.json "${GITHUB_REF_NAME}" cnb
|