Skip to content

Release

Release #157

Workflow file for this run

name: "Release"
on:
push:
tags:
- "v[0-9]+.[0-9]+.[0-9]+"
workflow_dispatch:
permissions:
contents: write
id-token: write
jobs:
continuous-integration:
uses: ./.github/workflows/ci.yml
get-version:
needs: continuous-integration
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get-version.outputs.result }}
steps:
- uses: actions/checkout@v4
- name: Get version
id: get-version
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'));
return packageJson.version;
create-release:
needs: get-version
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
release_id: ${{ steps.create-release.outputs.result }}
steps:
- uses: actions/checkout@v4
- name: Create release (draft)
id: create-release
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const version = ${{ needs.get-version.outputs.version }};
const changelogContent = fs.readFileSync('changelog.md', 'utf-8');
const regex = new RegExp(`(?<=\\[${version}\\]\\s)([\\s\\S]*?)(?=\\s## \\[)`, 'g');
const releaseNotes = changelogContent.match(regex)?.[0].trim() || '';
const { data } = await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: `v${version}`,
name: `Seelen UI v${version}`,
body: releaseNotes,
generate_release_notes: true,
draft: true,
prerelease: false,
});
return data.id;
build-binaries:
needs: create-release
strategy:
fail-fast: false
matrix:
include:
- platform: windows-2025
target: x86_64-pc-windows-msvc
- platform: windows-2025
target: aarch64-pc-windows-msvc
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/setup
with:
rust-targets: ${{ matrix.target }}
cache-key-prefix: rust-build-${{ matrix.target }}
- name: Install frontend dependencies
run: npm install
- name: Build Hook DLL
run: cargo build --release --target ${{ matrix.target }} -p sluhk
- name: Build (no bundle)
env:
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: npx tauri build --ci --verbose --no-bundle --target ${{ matrix.target }}
- name: Upload binaries to artifacts
uses: actions/upload-artifact@v4
with:
name: binaries-${{ matrix.target }}
path: |
target/${{ matrix.target }}/release/static/**/*
target/${{ matrix.target }}/release/*.exe
target/${{ matrix.target }}/release/*.dll
target/${{ matrix.target }}/release/SHA256SUMS
target/${{ matrix.target }}/release/SHA256SUMS.sig
target/${{ matrix.target }}/release/seelen_ui.pdb
merge-binaries:
needs: build-binaries
runs-on: ubuntu-latest
outputs:
artifact-id: ${{ steps.merge-binaries.outputs.artifact-id }}
steps:
- name: Merge binaries artifacts
id: merge-binaries
uses: actions/upload-artifact/merge@v4
with:
name: binaries
pattern: binaries-*
separate-directories: true
delete-merged: true
sign-binaries:
needs: merge-binaries
runs-on: ubuntu-latest
steps:
- name: Sign binaries with SignPath
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: 1a9e9b37-229a-4540-a639-137deebee4e1
project-slug: seelen-ui
signing-policy-slug: release-signing
artifact-configuration-slug: binaries
github-artifact-id: ${{ needs.merge-binaries.outputs.artifact-id }}
output-artifact-directory: signed-binaries
wait-for-completion: true
- name: Upload signed binaries by target
uses: actions/upload-artifact@v4
with:
name: signed-binaries-x86_64-pc-windows-msvc
path: signed-binaries/binaries-x86_64-pc-windows-msvc/**/*
- name: Upload signed binaries by target
uses: actions/upload-artifact@v4
with:
name: signed-binaries-aarch64-pc-windows-msvc
path: signed-binaries/binaries-aarch64-pc-windows-msvc/**/*
bundle:
needs:
- get-version
- sign-binaries
strategy:
fail-fast: false
matrix:
include:
- platform: windows-2025
target: x86_64-pc-windows-msvc
- platform: windows-2025
target: aarch64-pc-windows-msvc
runs-on: ${{ matrix.platform }}
steps:
- uses: actions/checkout@v4
with:
lfs: true # needed to fetch fixed runtimes (.cab) files
- uses: ./.github/actions/setup
with:
rust-targets: ${{ matrix.target }}
cache-key-prefix: rust-bundle-${{ matrix.target }}
- name: Install frontend dependencies
run: npm install
- name: Install MSIX dependencies
shell: pwsh
run: |
winget upgrade winget --accept-package-agreements --accept-source-agreements --disable-interactivity --force || Write-Output "Ignoring winget update failure"
winget install --id Microsoft.DotNet.AspNetCore.8 --accept-package-agreements --accept-source-agreements --force
winget install --id Microsoft.DotNet.DesktopRuntime.8 --accept-package-agreements --accept-source-agreements --force
winget install --id MarcinOtorowski.MSIXHero --accept-package-agreements --accept-source-agreements --force
- name: Download signed binaries
uses: actions/download-artifact@v4
with:
name: signed-binaries-${{ matrix.target }}
path: target/${{ matrix.target }}/release
- name: Clean bundle folder from cache
shell: pwsh
run: |
$bundlePath = "target/${{ matrix.target }}/release/bundle"
if (Test-Path $bundlePath) {
Remove-Item -Path $bundlePath -Recurse -Force
Write-Output "Old bundles files deleted: $bundlePath"
}
- name: Bundle
run: npx tauri bundle --ci --verbose --target ${{ matrix.target }} --no-sign
- name: Rename normal bundle to temp
shell: pwsh
run: |
$arch = "${{ matrix.target }}".Contains("aarch64") ? "arm64" : "x64"
$version = ${{ needs.get-version.outputs.version }}
$bundlePath = "target/${{ matrix.target }}/release/bundle/nsis"
$setupFile = "$bundlePath/Seelen UI_${version}_${arch}-setup.exe"
$tempFile = "$bundlePath/Seelen UI_${version}_${arch}-setup_temp.exe"
if (Test-Path $setupFile) {
Move-Item -Path $setupFile -Destination $tempFile
Write-Output "Renamed $setupFile to $tempFile"
} else {
Write-Error "Setup file not found: $setupFile"
exit 1
}
- name: Set Fixed Runtime
shell: pwsh
run: |
$arch = "${{ matrix.target }}".Contains("aarch64") ? "arm64" : "x64"
./scripts/SetFixedRuntime.ps1 -Architecture $arch
- name: Copy Runtime to target directory
shell: pwsh
run: |
$runtimeSource = Get-ChildItem -Path "src/runtime" -Directory | Where-Object { $_.Name -match '^\d+\.\d+\.\d+\.\d+$' } | Select-Object -First 1
if ($runtimeSource) {
$targetRuntimeDir = "target/${{ matrix.target }}/release/runtime"
New-Item -ItemType Directory -Force -Path $targetRuntimeDir | Out-Null
Copy-Item -Path $runtimeSource.FullName -Destination "$targetRuntimeDir/$($runtimeSource.Name)" -Recurse -Force
Write-Output "Copied runtime from $($runtimeSource.FullName) to $targetRuntimeDir/$($runtimeSource.Name)"
} else {
Write-Error "Runtime version directory not found in src/runtime"
exit 1
}
- name: Bundle with Fixed Runtime
run: npx tauri bundle --ci --verbose --target ${{ matrix.target }} --no-sign
- name: Rename bundles
shell: pwsh
run: |
$arch = "${{ matrix.target }}".Contains("aarch64") ? "arm64" : "x64"
$version = ${{ needs.get-version.outputs.version }}
$bundlePath = "target/${{ matrix.target }}/release/bundle/nsis"
$tempFile = "$bundlePath/Seelen UI_${version}_${arch}-setup_temp.exe"
$normalFile = "$bundlePath/Seelen UI_${version}_${arch}-setup.exe"
$fixedFile = "$bundlePath/Seelen UI_${version}_${arch}-setup-fixed.exe"
Write-Output "Checking files in $bundlePath"
Get-ChildItem -Path $bundlePath -Filter "*.exe" | ForEach-Object { Write-Output " Found: $($_.Name)" }
if (Test-Path $normalFile) {
Move-Item -Path $normalFile -Destination $fixedFile -Force
Write-Output "Renamed fixed runtime bundle to $fixedFile"
} else {
Write-Output "Warning: $normalFile does not exist"
}
if (Test-Path $tempFile) {
Move-Item -Path $tempFile -Destination $normalFile -Force
Write-Output "Renamed normal bundle back to $normalFile"
} else {
Write-Output "Warning: $tempFile does not exist"
}
- name: Bundle MSIX
run: npx tsx scripts/bundle.msix.ts --target ${{ matrix.target }}
- name: Upload bundles to artifacts
uses: actions/upload-artifact@v4
with:
name: bundles-${{ matrix.target }}
path: target/${{ matrix.target }}/release/bundle
merge-bundles:
needs: bundle
runs-on: ubuntu-latest
outputs:
artifact-id: ${{ steps.upload-merged.outputs.artifact-id }}
steps:
- name: Merge artifacts
id: upload-merged
uses: actions/upload-artifact/merge@v4
with:
name: bundles
pattern: bundles-*
delete-merged: true
sign-bundles:
needs:
- get-version
- create-release
- merge-bundles
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Submit to SignPath
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: ${{ secrets.SIGNPATH_API_TOKEN }}
organization-id: 1a9e9b37-229a-4540-a639-137deebee4e1
project-slug: seelen-ui
signing-policy-slug: release-signing
artifact-configuration-slug: bundles
github-artifact-id: ${{ needs.merge-bundles.outputs.artifact-id }}
output-artifact-directory: bundles
- name: File Tree
run: |-
tree bundles
- name: Tauri Updater Signature
env:
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
run: |
npm install -g @tauri-apps/cli
echo "Removing existing .sig files to regenerate with Tauri updater keys..."
find ./bundles -name "*.sig" -type f -delete
echo "Existing signatures removed"
VERSION=${{ needs.get-version.outputs.version }}
PATH1="bundles/nsis/Seelen UI_${VERSION}_arm64-setup.exe"
PATH2="bundles/nsis/Seelen UI_${VERSION}_x64-setup.exe"
echo "Signing ${PATH1}..."
tauri signer sign --verbose "$PATH1"
echo "Signing ${PATH2}..."
tauri signer sign --verbose "$PATH2"
- name: Remove self-signed MSIX files (store-signed handled elsewhere)
run: |
echo "Removing self-signed .msix files from bundles..."
find ./bundles -name "*.msix" -type f -delete || true
echo "Self-signed .msix files removed (Store-signed MSIX will be added later by msix.yml workflow)"
- name: Upload Signed Installers to release
uses: svenstaro/upload-release-action@v2
with:
release_id: ${{ needs.create-release.outputs.release_id }}
file: bundles/**/*
file_glob: true
publish-release:
needs: [create-release, sign-bundles]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- name: Publish release (un-draft)
uses: actions/github-script@v7
env:
releaseId: ${{ needs.create-release.outputs.release_id }}
with:
github-token: "${{ secrets.GITHUB_TOKEN }}"
script: |
await github.rest.repos.updateRelease({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: process.env.releaseId,
draft: false,
});
microsoft-store-submission:
needs: [publish-release, merge-bundles]
runs-on: windows-2025
steps:
- uses: actions/checkout@v4
- name: Download merged bundles (unsigned)
uses: actions/download-artifact@v4
with:
name: bundles
path: target/release/bundle
# Use Store Broker to publish to Microsoft Store
- name: Submit to Partner Center (aka DevCenter)
shell: pwsh
run: |
./scripts/SubmitToStore.ps1
env:
PartnerCenterStoreId: ${{ secrets.MS_PRODUCT_ID }}
PartnerCenterTenantId: ${{ secrets.MS_TENANT_ID }}
PartnerCenterClientId: ${{ secrets.MS_CLIENT_ID }}
PartnerCenterClientSecret: ${{ secrets.MS_CLIENT_SECRET }}
SBDisableTelemetry: true
generate-update-file:
needs: [get-version, create-release, publish-release]
permissions:
contents: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/generate-update-manifest
with:
release-id: ${{ needs.create-release.outputs.release_id }}
version: ${{ needs.get-version.outputs.version }}
github-token: ${{ secrets.GITHUB_TOKEN }}
discord:
needs: publish-release
name: Send Announcement To Discord Server
runs-on: ubuntu-latest
steps:
- name: Discord notification
uses: LeGitHubDeTai/github-to-discord@main
env:
DISCORD_WEBHOOK: ${{ secrets.DISCORD_WEBHOOK }}
DISCORD_USERNAME: Seelen
DISCORD_AVATAR: https://raw.githubusercontent.com/eythaann/Seelen-UI/master/documentation/images/logo_with_margins.png
AUTHOR_NAME: eythaann
AUTHOR_URL: "https://github.com/eythaann"
AUTHOR_AVATAR: "https://avatars.githubusercontent.com/u/76607907?v=4"
MESSAGE_TITLE: Seelen UI
MESSAGE_DESCRIPTION: A new release of Seelen UI has been published
MESSAGE_COLOR: 5814783
SECTION_NAME: "ChangeLog"
FOOTER_TEXT: "Seelen Inc."
FOOTER_URL: "https://github.com/eythaann/seelen-ui"
publish-core-library:
needs: publish-release
uses: ./.github/workflows/publish-core.yml
secrets: inherit