Release client #11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release client | |
| on: | |
| push: | |
| tags: ["client-v*"] | |
| schedule: | |
| - cron: "7 18 * * 0" # Sundays 18:07 UTC (weekly pre-alpha snapshot of master) | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version core, e.g. 0.2.0 (blank = bump patch from latest)" | |
| required: false | |
| default: "" | |
| env: | |
| CARGO_TERM_COLOR: always | |
| MC_VERSION: "26.2" | |
| permissions: | |
| contents: write | |
| jobs: | |
| check: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_release: ${{ steps.check.outputs.should_release }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check for new commits since last release | |
| id: check | |
| shell: bash | |
| run: | | |
| # Only the weekly cron skips an unchanged master; manual/tag runs always release. | |
| if [ "${{ github.event_name }}" != "schedule" ]; then | |
| echo "should_release=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| git fetch --tags --force | |
| last_tag=$(git tag --list 'client-v*' --sort=-v:refname | head -n1) | |
| if [ -z "$last_tag" ] || [ -n "$(git rev-list "${last_tag}..HEAD")" ]; then | |
| echo "should_release=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "should_release=false" >> "$GITHUB_OUTPUT" | |
| echo "No new commits on master since ${last_tag}; skipping weekly release." | |
| fi | |
| build-client: | |
| needs: check | |
| if: needs.check.outputs.should_release == 'true' | |
| strategy: | |
| matrix: | |
| include: | |
| - os: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| artifact: pomme-client.exe | |
| name: pomme-client-windows-x64 | |
| - os: ubuntu-latest | |
| target: x86_64-unknown-linux-gnu | |
| artifact: pomme-client | |
| name: pomme-client-linux-x64-gnu | |
| - os: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact: pomme-client | |
| name: pomme-client-macos-arm64 | |
| runs-on: ${{ matrix.os }} | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@nightly | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install Vulkan SDK | |
| uses: jakoch/install-vulkan-sdk-action@37effcfa045411f8bfbbda26df2fd1b3bf3436fa | |
| with: | |
| vulkan_version: 1.4.341.0 | |
| install_runtime: false | |
| cache: true | |
| stripdown: true | |
| - name: Install Linux dependencies | |
| if: matrix.os == 'ubuntu-latest' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libvulkan-dev cmake libxkbcommon-dev libwayland-dev libasound2-dev libudev-dev | |
| - name: Build | |
| run: cargo build -p pomme-client --release --target ${{ matrix.target }} | |
| - name: Package (Unix) | |
| if: matrix.os != 'windows-latest' | |
| shell: bash | |
| run: | | |
| mkdir -p dist bundle | |
| cp "target/${{ matrix.target }}/release/${{ matrix.artifact }}" bundle/ | |
| # macOS has no system Vulkan, so ship the loader + MoltenVK + ICD next | |
| # to the binary (build.rs gives it an @executable_path rpath). | |
| if [ "${{ matrix.os }}" = "macos-latest" ]; then | |
| findlib() { find "$VULKAN_SDK" -name "$1" | head -n1; } | |
| loader=$(findlib libvulkan.1.dylib) | |
| mvk=$(findlib libMoltenVK.dylib) | |
| icd=$(findlib MoltenVK_icd.json) | |
| if [ -z "$loader" ] || [ -z "$mvk" ] || [ -z "$icd" ]; then | |
| echo "::error::Vulkan runtime not found under VULKAN_SDK=$VULKAN_SDK (loader='$loader' mvk='$mvk' icd='$icd')" | |
| exit 1 | |
| fi | |
| cp "$loader" "$mvk" bundle/ | |
| sed -E 's#("library_path"[[:space:]]*:[[:space:]]*)"[^"]*"#\1"./libMoltenVK.dylib"#' \ | |
| "$icd" > bundle/MoltenVK_icd.json | |
| fi | |
| (cd bundle && zip -j "../dist/${{ matrix.name }}.zip" ./*) | |
| - name: Package (Windows) | |
| if: matrix.os == 'windows-latest' | |
| shell: pwsh | |
| run: | | |
| New-Item -ItemType Directory -Force dist | Out-Null | |
| Compress-Archive -Path "target/${{ matrix.target }}/release/${{ matrix.artifact }}" -DestinationPath "dist/${{ matrix.name }}.zip" | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: ${{ matrix.name }} | |
| path: dist/ | |
| if-no-files-found: error | |
| release-client: | |
| needs: [check, build-client] | |
| if: needs.check.outputs.should_release == 'true' | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| with: | |
| fetch-depth: 0 | |
| - name: Resolve release tag | |
| id: rel | |
| shell: bash | |
| run: | | |
| git fetch --tags --force | |
| tags=$(git tag --list 'client-v*') | |
| if [ "${{ github.event_name }}" = "push" ]; then | |
| tag="${{ github.ref_name }}" | |
| else | |
| core="${{ inputs.version }}" | |
| if [ -z "$core" ]; then | |
| latest=$(echo "$tags" \ | |
| | sed -nE 's/^client-v([0-9]+\.[0-9]+\.[0-9]+).*$/\1/p' \ | |
| | sort -V | tail -n1) | |
| if [ -z "$latest" ]; then | |
| core="0.1.0" | |
| else | |
| IFS=. read -r ma mi pa <<< "$latest" | |
| core="$ma.$mi.$((pa + 1))" | |
| fi | |
| fi | |
| tag="client-v${core}+${MC_VERSION}" | |
| fi | |
| prev=$(echo "$tags" | grep -vFx "$tag" | sort -V | tail -n1 || true) | |
| echo "tag=$tag" >> "$GITHUB_OUTPUT" | |
| echo "prev=$prev" >> "$GITHUB_OUTPUT" | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| - name: Generate checksums | |
| run: | | |
| cd dist | |
| sha256sum *.zip > sha256sums.txt | |
| - uses: softprops/action-gh-release@v3 | |
| with: | |
| tag_name: ${{ steps.rel.outputs.tag }} | |
| prerelease: false | |
| # Keep the "Latest" badge on the launcher release, not the weekly client. | |
| make_latest: false | |
| previous_tag: ${{ steps.rel.outputs.prev }} | |
| files: dist/* | |
| generate_release_notes: ${{ steps.rel.outputs.prev != '' }} | |
| - name: Announce release on Discord | |
| if: steps.rel.outputs.prev != '' | |
| continue-on-error: true | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }} | |
| TAG: ${{ steps.rel.outputs.tag }} | |
| shell: bash | |
| run: | | |
| if [ -z "$DISCORD_WEBHOOK_URL" ]; then | |
| echo "No DISCORD_WEBHOOK_URL secret set; skipping Discord announcement." | |
| exit 0 | |
| fi | |
| body=$(gh release view "$TAG" --json body --jq .body) | |
| url=$(gh release view "$TAG" --json url --jq .url) | |
| # Discord embed descriptions cap at 4096 chars; trim and link to the full notes. | |
| max=3900 | |
| if [ "${#body}" -gt "$max" ]; then | |
| body="${body:0:$max}"$'\n\n'"…[full changelog]($url)" | |
| fi | |
| role_id="1513130412367675523" | |
| payload=$(jq -n \ | |
| --arg title "Pomme $TAG" \ | |
| --arg desc "$body" \ | |
| --arg url "$url" \ | |
| --arg content "<@&$role_id> New Pomme release is out!" \ | |
| --arg role "$role_id" \ | |
| '{ | |
| username: "Pomme Releases", | |
| content: $content, | |
| allowed_mentions: { roles: [$role] }, | |
| embeds: [{ title: $title, url: $url, description: $desc, color: 5763719 }] | |
| }') | |
| curl -fsS -X POST -H "Content-Type: application/json" -d "$payload" "$DISCORD_WEBHOOK_URL" |