Skip to content

chore(deps): update dependency dotnet-sdk to v10 #213

chore(deps): update dependency dotnet-sdk to v10

chore(deps): update dependency dotnet-sdk to v10 #213

Workflow file for this run

name: Build and package SyntaxLauncher
on:
push:
branches: [main]
tags: ["v*"]
pull_request:
workflow_dispatch:
inputs:
preview_channel:
description: Preview channel to publish from main
type: choice
options: [snapshot, dev]
default: snapshot
permissions:
contents: read
concurrency:
group: syntaxlauncher-ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs:
verify:
name: Verify core and desktop compilation
runs-on: ubuntu-26.04
timeout-minutes: 35
outputs:
launcher_version: ${{ steps.release.outputs.launcher_version }}
publish_release: ${{ steps.release.outputs.publish_release }}
preview_channel: ${{ steps.channel.outputs.preview_channel }}
build_channel: ${{ steps.channel.outputs.build_channel }}
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: "25"
- uses: gradle/actions/setup-gradle@v6
with:
gradle-version: "9.8.1"
- name: Verify canonical product version and release tag
run: python3 scripts/launcher_version.py --github-ref "$GITHUB_REF"
- name: Detect eligible stable version increment
id: release
shell: bash
env:
BEFORE_SHA: ${{ github.event.before }}
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
run: |
set -euo pipefail
args=()
if [[ "$GITHUB_EVENT_NAME" == push && "$GITHUB_REF" == refs/heads/main ]]; then
args+=(--before "$BEFORE_SHA")
fi
python3 scripts/auto_release.py "${args[@]}" --github-output "$GITHUB_OUTPUT"
# Never backfill a failed historical version from a newer main commit:
# the code may already belong to the next milestone. Recover the
# historical commit with the pinned recovery workflow instead.
if [[ "$GITHUB_REF" == refs/heads/main && "$GITHUB_EVENT_NAME" == push ]]; then
version="$(python3 scripts/launcher_version.py)"
if [[ "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] && ! gh release view "v$version" >/dev/null 2>&1; then
echo "::warning::Stable v$version is missing. Only a version-increment commit can publish automatically. For earlier versions, use a release recovery pinned to the original verified commit."
fi
fi
- name: Select publication channel
id: channel
shell: bash
env:
STABLE_RELEASE: ${{ steps.release.outputs.publish_release }}
REQUESTED_PREVIEW: ${{ inputs.preview_channel }}
run: |
set -euo pipefail
preview_channel=""
build_channel=stable
if [[ "$GITHUB_REF" == refs/heads/main && "$GITHUB_EVENT_NAME" == push ]]; then
preview_channel=dev
if [[ "$STABLE_RELEASE" != true ]]; then build_channel=dev; fi
elif [[ "$GITHUB_REF" == refs/heads/main && "$GITHUB_EVENT_NAME" == workflow_dispatch ]]; then
preview_channel="$REQUESTED_PREVIEW"
[[ "$preview_channel" == snapshot || "$preview_channel" == dev ]]
build_channel="$preview_channel"
fi
echo "preview_channel=$preview_channel" >> "$GITHUB_OUTPUT"
echo "build_channel=$build_channel" >> "$GITHUB_OUTPUT"
- name: Validate packaging shell scripts before building
run: |
bash -n packaging/smoke-linux.sh
bash -n packaging/smoke-macos.sh
- name: Compile and run tests
run: gradle --no-daemon --stacktrace "-PlauncherBuildNumber=$GITHUB_RUN_NUMBER" "-PlauncherCommit=$GITHUB_SHA" "-PlauncherUpdateChannel=${{ steps.channel.outputs.build_channel }}" test build
- name: Verify official NeoForge installer processors
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
timeout-minutes: 22
env:
SYNTAXLAUNCHER_NEOFORGE_LIVE_SMOKE: "1"
run: gradle --no-daemon --stacktrace :launcher-core:test --tests 'pl.syntaxdevteam.syntaxlauncher.core.loader.NeoForgeOfficialSmokeTest' --rerun-tasks
- name: Smoke-test official Forge V2 processor installation
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
timeout-minutes: 22
env:
SYNTAXLAUNCHER_FORGE_LIVE_SMOKE: "1"
run: gradle --no-daemon --stacktrace :launcher-core:test --tests 'pl.syntaxdevteam.syntaxlauncher.core.loader.ForgeOfficialSmokeTest' --rerun-tasks
- name: Test update packaging protocol
run: python3 -m unittest discover -s scripts -p "test_*.py"
- name: Test Build Explorer publisher
run: python3 -m unittest discover -s tests -p 'test_*.py'
- name: Summarize remaining release-readiness gates
shell: bash
run: python3 scripts/release_readiness.py --format markdown >> "$GITHUB_STEP_SUMMARY"
- name: Enforce final acceptance before Stable 1.0 and later
run: python3 scripts/release_readiness.py --enforce-production
- name: Upload test evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: syntaxlauncher-test-results
path: |
launcher-core/build/test-results/**
launcher-core/build/reports/tests/**
launcher-desktop/build/reports/**
launcher-desktop/build/test-results/**
if-no-files-found: ignore
retention-days: 14
distributables:
name: Application and installers (${{ matrix.os }})
needs: verify
runs-on: ${{ matrix.os }}
timeout-minutes: 50
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
artifact: linux-x64
- os: windows-2022
artifact: windows-x64
- os: macos-15
artifact: macos-arm64
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: temurin
java-version: "25"
- uses: gradle/actions/setup-gradle@v6
with:
gradle-version: "9.8.1"
- uses: actions/setup-python@v7
with:
python-version: "3.12"
- name: Verify official managed Java on this platform
shell: bash
timeout-minutes: 15
env:
SYNTAXLAUNCHER_JAVA_LIVE_SMOKE: "1"
run: gradle --no-daemon --stacktrace :launcher-core:test --tests '*ManagedJavaOfficialSmokeTest' --rerun-tasks
- name: Upload managed Java acceptance
if: always()
uses: actions/upload-artifact@v7
with:
name: managed-java-${{ matrix.artifact }}
path: launcher-core/build/test-results/test
if-no-files-found: warn
- name: Build runnable native app directory
shell: bash
run: |
version="$(python3 scripts/launcher_version.py --github-ref "$GITHUB_REF")"
gradle --no-daemon --stacktrace "-PlauncherBuildNumber=$GITHUB_RUN_NUMBER" "-PlauncherCommit=$GITHUB_SHA" "-PlauncherUpdateChannel=${{ needs.verify.outputs.build_channel }}" :launcher-desktop:createDistributable
python scripts/package_update.py --source launcher-desktop/build/compose/binaries/main/app --platform "${{ matrix.artifact }}" --version "$version" --output "launcher-desktop/build/updates/syntaxlauncher-update-${{ matrix.artifact }}.zip"
gradle --no-daemon --stacktrace "-PlauncherBuildNumber=$GITHUB_RUN_NUMBER" "-PlauncherCommit=$GITHUB_SHA" "-PlauncherUpdateChannel=${{ needs.verify.outputs.build_channel }}" "-PupdateBundle=build/updates/syntaxlauncher-update-${{ matrix.artifact }}.zip" :launcher-desktop:verifyUpdateBundle
- name: Verify portable Windows executable branding
if: runner.os == 'Windows'
shell: bash
run: python scripts/verify_windows_icon.py --exe launcher-desktop/build/compose/binaries/main/app/SyntaxLauncher/SyntaxLauncher.exe
- name: Verify Mojang HTTPS with the packaged runtime
shell: bash
run: |
image=launcher-desktop/build/compose/binaries/main/app/SyntaxLauncher
if [[ "$RUNNER_OS" == macOS ]]; then image="$image.app"; fi
python scripts/verify_native_network.py --image "$image" --platform "${{ matrix.artifact }}"
- name: Install Linux packaging tools
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y rpm fakeroot desktop-file-utils xvfb appstream
- uses: actions/setup-dotnet@v5
if: runner.os == 'Windows'
with:
dotnet-version: '10.0.x'
- name: Install pinned WiX v7
if: runner.os == 'Windows'
shell: pwsh
run: |
dotnet tool install --tool-path "$env:RUNNER_TEMP/wix7" wix --version 7.0.0
if ($LASTEXITCODE -ne 0) { throw 'WiX v7 installation failed' }
"$env:RUNNER_TEMP/wix7" | Out-File -FilePath $env:GITHUB_PATH -Append
# Maintainer explicitly accepted the WiX v7 OSMF EULA and confirmed eligibility on 2026-10-23.
& "$env:RUNNER_TEMP/wix7/wix.exe" eula accept wix7
if ($LASTEXITCODE -ne 0) { throw 'WiX v7 EULA acceptance failed' }
& "$env:RUNNER_TEMP/wix7/wix.exe" extension add --global WixToolset.UI.wixext/7.0.0
if ($LASTEXITCODE -ne 0) { throw 'WiX v7 UI extension installation failed' }
- name: Build native installers from the verified application image
shell: bash
run: |
image=launcher-desktop/build/compose/binaries/main/app/SyntaxLauncher
if [[ "$RUNNER_OS" == macOS ]]; then image="$image.app"; fi
python scripts/package_installers.py --image "$image" --platform "${{ matrix.artifact }}" --output launcher-desktop/build/installers
- name: Test Debian, Fedora RPM and AppImage lifecycle
if: runner.os == 'Linux'
run: bash packaging/smoke-linux.sh
- name: Test WiX v7 install, payload, repair and uninstall
if: runner.os == 'Windows'
shell: pwsh
run: ./packaging/smoke-windows.ps1
- name: Test DMG mount and application copy
if: runner.os == 'macOS'
run: bash packaging/smoke-macos.sh
- name: Upload tested installers
uses: actions/upload-artifact@v7
with:
name: native-installers-${{ matrix.artifact }}-${{ github.sha }}
path: launcher-desktop/build/installers/*
if-no-files-found: error
retention-days: 14
- name: Upload installer evidence
if: always()
uses: actions/upload-artifact@v7
with:
name: native-installer-evidence-${{ matrix.artifact }}-${{ github.sha }}
path: launcher-desktop/build/installer-evidence/
if-no-files-found: ignore
retention-days: 14
- name: Show jpackage diagnostics on failure
if: failure()
shell: bash
run: |
if [ -d launcher-desktop/build/compose/logs ]; then
find launcher-desktop/build/compose/logs -type f -name "*.txt" -print -exec tail -n 100 {} \;
else
echo "No Compose packaging logs found"
fi
- name: Upload jpackage diagnostic logs
if: failure()
uses: actions/upload-artifact@v7
with:
name: syntaxlauncher-packaging-logs-${{ matrix.artifact }}-${{ github.sha }}
path: launcher-desktop/build/compose/logs/
if-no-files-found: warn
retention-days: 14
- name: Archive portable application preserving POSIX permissions
shell: bash
run: |
test -d launcher-desktop/build/compose/binaries/main/app
tar -czf syntaxlauncher-${{ matrix.artifact }}.tar.gz -C launcher-desktop/build/compose/binaries/main/app .
- name: Upload portable app
uses: actions/upload-artifact@v7
with:
name: syntaxlauncher-${{ matrix.artifact }}-${{ github.sha }}
path: syntaxlauncher-${{ matrix.artifact }}.tar.gz
if-no-files-found: error
retention-days: 14
- name: Upload verified update bundle
uses: actions/upload-artifact@v7
with:
name: syntaxlauncher-update-${{ matrix.artifact }}
path: launcher-desktop/build/updates/*.zip
if-no-files-found: error
retention-days: 14
publish-release:
name: Publish complete verified stable version
if: (startsWith(github.ref, 'refs/tags/v') && !contains(github.ref_name, '-')) || needs.verify.outputs.publish_release == 'true'
needs: [verify, distributables]
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/download-artifact@v8
with:
pattern: syntaxlauncher-update-*
path: release-assets
merge-multiple: true
- uses: actions/download-artifact@v8
with:
pattern: syntaxlauncher-*-${{ github.sha }}
path: release-assets
merge-multiple: true
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/download-artifact@v8
with:
pattern: native-installers-*-${{ github.sha }}
path: release-assets
merge-multiple: true
- name: Verify complete installer set and write checksums
run: python3 scripts/verify_installers.py --directory release-assets --write
- name: Publish all platform updates together
env:
# A fine-grained PAT with repository Contents: write can be used
# when the workflow GITHUB_TOKEN is denied by repository policy.
GH_TOKEN: ${{ secrets.SYNTAXLAUNCHER_RELEASE_TOKEN || github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: v${{ needs.verify.outputs.launcher_version }}
shell: bash
run: |
set -euo pipefail
test -s release-assets/syntaxlauncher-update-linux-x64.zip
test -s release-assets/syntaxlauncher-update-windows-x64.zip
test -s release-assets/syntaxlauncher-update-macos-arm64.zip
test -s release-assets/syntaxlauncher-linux-x64.tar.gz
test -s release-assets/syntaxlauncher-windows-x64.tar.gz
test -s release-assets/syntaxlauncher-macos-arm64.tar.gz
# Refuse to publish this version from a commit different from its tag.
if gh api "repos/$GH_REPO/git/ref/tags/$RELEASE_TAG" > existing-tag.json 2>/dev/null; then
tag_type="$(python3 -c 'import json; print(json.load(open("existing-tag.json"))["object"]["type"])')"
tag_sha="$(python3 -c 'import json; print(json.load(open("existing-tag.json"))["object"]["sha"])')"
if [[ "$tag_type" == tag ]]; then
tag_sha="$(gh api "repos/$GH_REPO/git/tags/$tag_sha" --jq '.object.sha')"
elif [[ "$tag_type" != commit ]]; then
echo "Unsupported git tag object type: $tag_type" >&2
exit 1
fi
if [[ "$tag_sha" != "$GITHUB_SHA" ]]; then
echo "Tag $RELEASE_TAG does not reference verified commit $GITHUB_SHA" >&2
exit 1
fi
tag_exists=true
else
tag_exists=false
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
echo "Expected pushed tag $RELEASE_TAG is missing" >&2
exit 1
fi
fi
publish_release() {
if ! gh release create "$@"; then
echo "::error::Unable to create GitHub Release. If HTTP 403, authorize SYNTAXLAUNCHER_RELEASE_TOKEN for SyntaxDevTeam/SyntaxLauncher with Contents: Read and write and confirm organization approval. GITHUB_TOKEN may also be restricted by organization policy."
exit 1
fi
}
if gh release view "$RELEASE_TAG" --json isDraft > existing-release.json 2>/dev/null; then
python3 -c 'import json; assert json.load(open("existing-release.json"))["isDraft"], "Refusing to replace a published release"'
elif [[ "$tag_exists" == true ]]; then
publish_release "$RELEASE_TAG" --verify-tag --draft --generate-notes --notes "<!-- syntaxlauncher-build:$GITHUB_RUN_NUMBER.$GITHUB_RUN_ATTEMPT -->" --title "SyntaxLauncher $RELEASE_TAG"
else
# GITHUB_TOKEN-created tags do not invoke another workflow; publish from this verified run.
publish_release "$RELEASE_TAG" --target "$GITHUB_SHA" --draft --generate-notes --notes "<!-- syntaxlauncher-build:$GITHUB_RUN_NUMBER.$GITHUB_RUN_ATTEMPT -->" --title "SyntaxLauncher $RELEASE_TAG"
fi
gh release upload "$RELEASE_TAG" release-assets/*.zip release-assets/*.tar.gz release-assets/*.msi release-assets/*.dmg release-assets/*.deb release-assets/*.rpm release-assets/*.AppImage release-assets/SHA256SUMS-installers.txt --clobber
# Preview releases are published separately and never become latest stable.
gh release edit "$RELEASE_TAG" --draft=false --latest
publish-preview:
name: Publish verified DEV or SNAPSHOT channel
needs: [verify, distributables]
if: needs.verify.outputs.preview_channel != ''
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/download-artifact@v8
with:
pattern: syntaxlauncher-update-*
path: release-assets
merge-multiple: true
- uses: actions/download-artifact@v8
with:
pattern: syntaxlauncher-*-${{ github.sha }}
path: release-assets
merge-multiple: true
- uses: actions/download-artifact@v8
with:
pattern: native-installers-*-${{ github.sha }}
path: release-assets
merge-multiple: true
- name: Verify complete installer set and write checksums
run: python3 scripts/verify_installers.py --directory release-assets --write
- name: Publish complete applications and installers as an immutable preview
env:
GH_TOKEN: ${{ secrets.SYNTAXLAUNCHER_RELEASE_TOKEN || github.token }}
GH_REPO: ${{ github.repository }}
PREVIEW_CHANNEL: ${{ needs.verify.outputs.preview_channel }}
run: >-
python3 scripts/publish_preview.py --channel "$PREVIEW_CHANNEL"
--run "$GITHUB_RUN_NUMBER" --attempt "$GITHUB_RUN_ATTEMPT"
--commit "$GITHUB_SHA" --assets release-assets --installers
publish-build-explorer:
name: Publish all platforms to Build Explorer
needs: [verify, distributables]
if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
runs-on: ubuntu-24.04
timeout-minutes: 35
steps:
- uses: actions/checkout@v7
with:
persist-credentials: false
- uses: actions/download-artifact@v8
with:
pattern: syntaxlauncher-*-${{ github.sha }}
path: dist
merge-multiple: true
- name: Publish complete portable build set
env:
BUILD_EXPLORER_TOKEN: ${{ secrets.BUILD_EXPLORER_TOKEN }}
run: python3 scripts/publish_build_explorer.py