Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
1484104
feat(packaging): add AUR, Flathub, Scoop and Microsoft Store channels
kipavy Aug 19, 2026
e66df9c
feat(packaging): submit the Microsoft Store bundle from CI
kipavy Aug 19, 2026
05bf459
test(packaging): verify the Scoop and cask manifests on CI
kipavy Aug 19, 2026
75d3eaf
fix(packaging): style the cask from a Casks/ path, and share the audit
kipavy Aug 19, 2026
3d471d2
docs(packaging): homebrew-cask core is blocked on notarization
kipavy Aug 19, 2026
7741514
fix(ci): stop the packaging check and the release sharing an MSIX slot
kipavy Aug 19, 2026
494c183
fix(packaging): pack the MSIX from the workspace-root target dir
kipavy Aug 19, 2026
57b5751
feat(packaging): add the 300x300 Store app tile
kipavy Aug 19, 2026
bd5ff08
feat(packaging): collect the Store listing images in one directory
kipavy Aug 19, 2026
13001ff
feat(packaging): add the 2:3 Store poster art
kipavy Aug 19, 2026
d0fa647
fix(packaging): add the wide Start tile the MSIX manifest requires
kipavy Aug 19, 2026
54b7040
fix(packaging): warn when the MSIX packages a stale version
kipavy Aug 19, 2026
8564d22
fix(ci): only let the release job submit the MSIX to the Store
kipavy Aug 19, 2026
0b936ea
fix(ci): key the MSIX concurrency group on the ref being built
kipavy Aug 19, 2026
54ac64e
fix(ci): cache Rust against the workspace-root target dir
kipavy Aug 19, 2026
66460de
fix(packaging): stamp the MSIX bundle with the app version
kipavy Aug 19, 2026
1392056
fix(packaging): clear stale per-architecture MSIX packages before pac…
kipavy Aug 19, 2026
eb10838
fix(packaging): validate the Scoop manifest against the newest release
kipavy Aug 19, 2026
6c9d5b2
fix(packaging): check every capture before wiping the Store listing
kipavy Aug 19, 2026
477b861
docs(packaging): the Flathub bot leaves the metainfo releases alone
kipavy Aug 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions .github/actions/cask-audit/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Generate and audit the Homebrew cask
description: >
Generates the cask for a tag, styles it and audits it inside a throwaway tap.
Used both by the release job that publishes to VoltiusApp/homebrew-voltius and
by the packaging check that runs the stricter new-cask audit homebrew-cask
core applies to a submission.

inputs:
tag:
description: Release tag to generate the cask for
required: true
core:
description: >
Generate the homebrew-cask core variant (drops the --no-quarantine hint,
which core rejects) instead of the tap variant.
required: false
default: 'false'
audit-args:
description: Extra flags for `brew audit`, e.g. --new for a first submission
required: false
default: ''
tap:
description: Throwaway tap name to audit inside
required: false
default: voltiusapp/audit
github-token:
description: >
Token for the audit's GitHub API calls. Without one it uses the
unauthenticated 60 req/hr limit and flakes ("API rate limit exceeded") on
back-to-back runs.
required: true

outputs:
path:
description: Path of the generated cask file
value: out/Casks/voltius.rb

runs:
using: composite
steps:
- name: Generate cask
shell: bash
env:
GH_TOKEN: ${{ inputs.github-token }}
TAG: ${{ inputs.tag }}
CORE: ${{ inputs.core }}
run: |
# The path matters: `brew style` only applies the cask cops when the
# file sits under a Casks/ directory. On a bare .rb it falls back to
# generic Ruby cops and fails on Sorbet sigils and frozen_string_literal.
mkdir -p out/Casks
variant=""
[ "$CORE" = "true" ] && variant="--core"
bash scripts/gen-homebrew-cask.sh "$TAG" $variant > out/Casks/voltius.rb
cat out/Casks/voltius.rb

- name: Style and audit
shell: bash
env:
HOMEBREW_GITHUB_API_TOKEN: ${{ inputs.github-token }}
TAP: ${{ inputs.tap }}
AUDIT_ARGS: ${{ inputs.audit-args }}
run: |
brew style out/Casks/voltius.rb
brew tap-new "$TAP" --no-git
mkdir -p "$(brew --repository "$TAP")/Casks"
cp out/Casks/voltius.rb "$(brew --repository "$TAP")/Casks/voltius.rb"
brew audit --cask --online $AUDIT_ARGS "$TAP/voltius"
136 changes: 101 additions & 35 deletions .github/workflows/publish-installers.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
# Publishes the Homebrew cask (tap VoltiusApp/homebrew-voltius) and the winget
# manifest (microsoft/winget-pkgs) from a published GitHub release.
# Publishes the Homebrew cask (tap VoltiusApp/homebrew-voltius), the winget
# manifest (microsoft/winget-pkgs) and the AUR package (voltius-bin) from a
# published GitHub release.
#
# Scoop is deliberately absent: its manifest carries checkver + autoupdate, so
# once merged into ScoopInstaller/Extras their excavator bot follows releases on
# its own. See scripts/gen-scoop-manifest.sh.
#
# Required repository secrets:
# HOMEBREW_TAP_TOKEN PAT with push access to VoltiusApp/homebrew-voltius
# AUR_SSH_PRIVATE_KEY private key registered on the AUR account that owns
# voltius-bin. Absent: the AUR job warns and skips.
# WINGET_PKGS_TOKEN classic PAT (public_repo + workflow) for komac to fork
# winget-pkgs. Must be CLASSIC — winget-releaser does not
# support fine-grained PATs, which cannot authorize a PR
Expand Down Expand Up @@ -36,44 +43,38 @@ concurrency:
cancel-in-progress: false

jobs:
homebrew:
runs-on: macos-latest
# One place resolves the tag for every channel below. It used to be repeated
# per job, which meant each new channel copied the same three lines.
tag:
runs-on: ubuntu-latest
outputs:
tag: ${{ steps.tag.outputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Resolve tag
id: tag
env:
DISPATCH_TAG: ${{ inputs.tag }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: echo "tag=${DISPATCH_TAG:-$RELEASE_TAG}" >> "$GITHUB_OUTPUT"

- name: Generate cask
env:
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p out/Casks
bash scripts/gen-homebrew-cask.sh "${{ steps.tag.outputs.tag }}" > out/Casks/voltius.rb
cat out/Casks/voltius.rb
homebrew:
needs: tag
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Audit cask
# brew audit --online calls the GitHub API; without a token it uses the
# unauthenticated 60 req/hr limit and flakes ("API rate limit exceeded")
# on back-to-back runs. The default token lifts this to 5000/hr.
env:
HOMEBREW_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
brew style out/Casks/voltius.rb
brew tap-new voltiusapp/voltius --no-git
mkdir -p "$(brew --repository voltiusapp/voltius)/Casks"
cp out/Casks/voltius.rb "$(brew --repository voltiusapp/voltius)/Casks/voltius.rb"
brew audit --cask --online voltiusapp/voltius/voltius
- name: Generate and audit the cask
uses: ./.github/actions/cask-audit
with:
tag: ${{ needs.tag.outputs.tag }}
tap: voltiusapp/voltius
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Push cask to tap
env:
TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
TAG: ${{ steps.tag.outputs.tag }}
TAG: ${{ needs.tag.outputs.tag }}
run: |
git clone "https://x-access-token:${TAP_TOKEN}@github.com/VoltiusApp/homebrew-voltius" tap
mkdir -p tap/Casks
Expand All @@ -89,15 +90,9 @@ jobs:
git push origin HEAD:main

winget:
needs: tag
runs-on: ubuntu-latest
steps:
- name: Resolve tag
id: tag
env:
DISPATCH_TAG: ${{ inputs.tag }}
RELEASE_TAG: ${{ github.event.release.tag_name }}
run: echo "tag=${DISPATCH_TAG:-$RELEASE_TAG}" >> "$GITHUB_OUTPUT"

# komac branches the fork from upstream, and once kipavy/winget-pkgs falls
# behind microsoft/winget-pkgs it fails with "kipavy does not have the
# correct permissions to execute `CreateRef`" — a misleading message that
Expand Down Expand Up @@ -133,11 +128,82 @@ jobs:
uses: vedantmgoyal9/winget-releaser@v2
with:
identifier: Voltius.Voltius
release-tag: ${{ steps.tag.outputs.tag }}
release-tag: ${{ needs.tag.outputs.tag }}
installers-regex: '_(x64|arm64)-setup\.exe$'
token: ${{ secrets.WINGET_PKGS_TOKEN }}
# The winget-pkgs fork lives under the token account (kipavy), not
# the org that owns this repo. Without this, komac defaults
# KOMAC_FORK_OWNER to github.repository_owner (VoltiusApp) and fails
# with "Could not resolve to a Repository VoltiusApp/winget-pkgs".
fork-user: kipavy

# Publishes the `voltius-bin` AUR package. The AUR is a plain git remote over
# ssh: pushing a commit that carries PKGBUILD + .SRCINFO IS the release.
#
# .SRCINFO must come from `makepkg --printsrcinfo`, and makepkg refuses to run
# as root, hence the throwaway user inside the arch container. The container
# is only used for that one command — the PKGBUILD itself is generated on the
# runner, where `gh` is already authenticated.
aur:
needs: tag
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7

- name: Skip when the AUR key is not configured
id: guard
env:
KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
run: |
if [ -z "$KEY" ]; then
echo "::warning::AUR_SSH_PRIVATE_KEY is not set — skipping the AUR push."
echo "ok=false" >> "$GITHUB_OUTPUT"
else
echo "ok=true" >> "$GITHUB_OUTPUT"
fi

- name: Generate PKGBUILD
if: steps.guard.outputs.ok == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
mkdir -p out/aur
bash scripts/gen-aur-pkgbuild.sh "${{ needs.tag.outputs.tag }}" > out/aur/PKGBUILD
cat out/aur/PKGBUILD

- name: Generate .SRCINFO
if: steps.guard.outputs.ok == 'true'
run: |
docker run --rm -v "$PWD/out/aur:/w" archlinux:base-devel bash -euc '
useradd -m b && chown -R b /w
su b -c "cd /w && makepkg --printsrcinfo > .SRCINFO"
'
cat out/aur/.SRCINFO

- name: Push to the AUR
if: steps.guard.outputs.ok == 'true'
env:
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
TAG: ${{ needs.tag.outputs.tag }}
run: |
install -d -m 700 ~/.ssh
printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > ~/.ssh/aur
chmod 600 ~/.ssh/aur
ssh-keyscan -H aur.archlinux.org >> ~/.ssh/known_hosts 2>/dev/null
export GIT_SSH_COMMAND="ssh -i ~/.ssh/aur -o IdentitiesOnly=yes"

git clone ssh://aur@aur.archlinux.org/voltius-bin.git aur
cp out/aur/PKGBUILD out/aur/.SRCINFO aur/
cd aur
git config user.name 'voltius-bot'
git config user.email 'bot@voltius.app'
git add PKGBUILD .SRCINFO
# --cached, after `git add`: on the very first push the files are
# untracked, and an unstaged `git diff` would report no change and
# skip the push that creates the package.
if git diff --cached --quiet; then
echo "AUR package already up to date for ${TAG}"; exit 0
fi
git commit -m "Update to ${TAG#v}"
git push origin HEAD:master
Loading
Loading