Skip to content

Tray app

Tray app #4

Workflow file for this run

name: Tray app
# Standalone from cargo-dist's release.yml on purpose: `dist generate` owns that file, so adding
# a job there would reintroduce the drift we just removed. This builds the menu-bar app's .app
# bundle and attaches it (zipped) to the GitHub Release.
#
# Chained off the "Release" workflow's completion (not `release: published`, not a bare tag push):
# - `release: published` never fires — cargo-dist creates the Release with the default
# GITHUB_TOKEN and GitHub suppresses events for token-made changes (anti-recursion).
# - `workflow_run` fires only AFTER Release finishes, so the Release already exists — no polling.
# The tag comes from `git tag --points-at HEAD` (reliable), not `workflow_run.head_branch` (which
# is often empty for tag-triggered upstreams).
#
# The .app is ad-hoc signed only (not notarized); first launch needs right-click → Open.
on:
workflow_run:
workflows: ["Release"]
types: [completed]
workflow_dispatch:
inputs:
tag:
description: "Existing release tag to attach the .app to (e.g. v0.2.1)"
required: true
permissions:
contents: write
jobs:
build:
# Manual dispatch always; otherwise only a successful Release that was triggered by a tag push
# (release.yml's only `push` trigger is tags, so event == 'push' means a version tag).
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.event == 'push')
runs-on: macos-14
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
# workflow_run checks out the default branch by default; for the auto path we want the exact
# commit that Release ran on (the tagged one). fetch-tags lets `git tag --points-at` see it.
- uses: actions/checkout@v6
with:
ref: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.tag || github.event.workflow_run.head_sha }}
fetch-depth: 0
fetch-tags: true
- name: Resolve tag
id: tag
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
tag="${{ github.event.inputs.tag }}"
else
# The tag on the checked-out commit; take the highest if a commit carries several.
tag="$(git tag --points-at HEAD --sort=-version:refname | head -n1)"
fi
if [ -z "$tag" ]; then
echo "no tag found on HEAD; nothing to attach to" >&2
exit 1
fi
echo "tag=$tag" >> "$GITHUB_OUTPUT"
echo "version=${tag#v}" >> "$GITHUB_OUTPUT"
- name: Add Rust targets
run: rustup target add aarch64-apple-darwin x86_64-apple-darwin
- name: Build FFI xcframework
run: apps/tray/Scripts/build-ffi.sh
# One single-arch .app per architecture (not a universal binary), so each user downloads
# only the slice they run — half the size. Matches how the CLI is split by arch.
- name: Build, zip, and attach per-arch .app
env:
CODEX_BUDDY_VERSION: ${{ steps.tag.outputs.version }}
run: |
for arch in arm64 x86_64; do
SWIFT_ARCH_FLAGS="--arch $arch" apps/tray/Scripts/build-app.sh
# -y preserves the symlinks inside the .app so the bundle stays valid after unzip.
( cd apps/tray/build && zip -r -y -q "Codex-Buddy-$arch-macOS.zip" "Codex Buddy.app" )
gh release upload "${{ steps.tag.outputs.tag }}" \
"apps/tray/build/Codex-Buddy-$arch-macOS.zip" --clobber
done