mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 08:02:24 +00:00
The four platform jobs each ran softprops/action-gh-release, so the first one to finish published a release carrying only its own assets. That release immediately became /releases/latest, which the in-app update check polls — users were prompted to download a version whose assets were still being built, and macOS users in particular could open the page minutes before a .dmg existed. A permanently failed platform left the gap forever. Build jobs now hand their bundles to a single draft-release job via upload-artifact. It runs only after all four succeed, and assembles a draft: drafts are invisible to /releases/latest, so nothing is advertised until the release skill has verified the six assets, written the notes, and published it by hand. This mirrors the shape nightly.yml already used.
174 lines
7.3 KiB
YAML
174 lines
7.3 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags: ["v*"]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
build:
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- runner: macos-14
|
|
os: macos
|
|
arch: arm64
|
|
target: aarch64-apple-darwin
|
|
# macos-13 was retired; macos-15-intel is the remaining hosted x86_64 image.
|
|
- runner: macos-15-intel
|
|
os: macos
|
|
arch: x86_64
|
|
target: x86_64-apple-darwin
|
|
- runner: windows-latest
|
|
os: windows
|
|
arch: x86_64
|
|
target: x86_64-pc-windows-msvc
|
|
- runner: ubuntu-latest
|
|
os: linux
|
|
arch: x86_64
|
|
target: x86_64-unknown-linux-gnu
|
|
runs-on: ${{ matrix.runner }}
|
|
steps:
|
|
- name: Checkout tty7
|
|
uses: actions/checkout@v4
|
|
with:
|
|
path: tty7
|
|
|
|
# gpui-component is pulled as a git dependency (see Cargo.toml's patch
|
|
# section), so no sibling checkout is needed.
|
|
|
|
# gpui's Linux backends resolve the x11/wayland/xkb/font dev packages via
|
|
# pkg-config at build time — the same set the README documents for
|
|
# building from source on Linux.
|
|
- name: Install Linux system dependencies
|
|
if: matrix.os == 'linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y pkg-config cmake clang libxkbcommon-dev \
|
|
libxkbcommon-x11-dev libfontconfig1-dev libfreetype6-dev \
|
|
libwayland-dev libx11-dev libxcb1-dev libzstd-dev libssl-dev \
|
|
libkrb5-dev libfuse2 file imagemagick
|
|
echo "LIBGSSAPI_IMPL=mit" >> "$GITHUB_ENV"
|
|
|
|
- uses: dtolnay/rust-toolchain@stable
|
|
with:
|
|
targets: ${{ matrix.target }}
|
|
|
|
- uses: Swatinem/rust-cache@v2
|
|
with:
|
|
workspaces: tty7
|
|
|
|
# `--locked` because a release must ship the dependency set the tag
|
|
# recorded, not whatever cargo would re-resolve at build time. Safe here
|
|
# (unlike nightly) precisely because nothing rewrites Cargo.toml: this is
|
|
# a plain checkout of the tagged commit.
|
|
- name: Build
|
|
working-directory: tty7
|
|
run: cargo build --release --locked --target ${{ matrix.target }}
|
|
|
|
# ---- Packaging: one step per OS ----------------------------------------
|
|
# macOS gets a signed + notarized drag-to-Applications DMG. Windows gets
|
|
# an Inno Setup installer plus a portable zip; Linux a tarball — both
|
|
# unsigned, of the self-contained binary (fonts are embedded via
|
|
# include_bytes!; the Windows icon is compiled in via build.rs).
|
|
- name: Bundle macOS DMG
|
|
if: matrix.os == 'macos'
|
|
working-directory: tty7
|
|
env:
|
|
# macOS code signing — the cert is imported into a throwaway keychain.
|
|
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
|
|
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
|
APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
|
|
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
|
|
# Notarization — required for Developer ID builds to pass Gatekeeper.
|
|
APPLE_ID: ${{ secrets.APPLE_ID }}
|
|
APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
|
|
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
|
|
run: bash .github/scripts/bundle-macos.sh "${{ matrix.target }}" "${{ matrix.arch }}"
|
|
|
|
- name: Package Linux tarball
|
|
if: matrix.os == 'linux'
|
|
working-directory: tty7
|
|
run: bash .github/scripts/bundle-linux.sh "${{ matrix.target }}" "${{ matrix.arch }}"
|
|
|
|
# AppImage bundles the x11/wayland/xkb/font libs so it runs on Fedora/Arch/
|
|
# etc., not just Ubuntu. Kept separate from the tarball step so the tarball
|
|
# still ships even if AppImage tooling changes upstream.
|
|
- name: Package Linux AppImage
|
|
if: matrix.os == 'linux'
|
|
working-directory: tty7
|
|
run: bash .github/scripts/bundle-appimage.sh "${{ matrix.target }}" "${{ matrix.arch }}"
|
|
|
|
- name: Package Windows installer + zip
|
|
if: matrix.os == 'windows'
|
|
working-directory: tty7
|
|
shell: pwsh
|
|
run: '& ./.github/scripts/bundle-windows.ps1 "${{ matrix.target }}" "${{ matrix.arch }}"'
|
|
|
|
# Hand the artifacts to the assemble job rather than uploading them to the
|
|
# release here. Four parallel jobs each publishing their own slice would
|
|
# make the release "latest" the moment the *first* platform finished — the
|
|
# in-app update check (src/core/update.rs) reads /releases/latest, so users
|
|
# would be prompted to download a release that was still missing most of
|
|
# its assets. Same glob list as before: the bundle scripts leave
|
|
# intermediates in dist/ (tty7.app, entitlements.plist, the Windows staging
|
|
# dir) that must not reach the release assets.
|
|
- uses: actions/upload-artifact@v7
|
|
with:
|
|
name: release-${{ matrix.os }}-${{ matrix.arch }}
|
|
path: |
|
|
tty7/dist/*.dmg
|
|
tty7/dist/*.tar.gz
|
|
tty7/dist/*.zip
|
|
tty7/dist/*-setup.exe
|
|
tty7/dist/*.AppImage
|
|
if-no-files-found: error
|
|
|
|
# Single assembly step, after all four platforms succeed. The release object is
|
|
# created as a **draft** and left that way: a draft is invisible to both
|
|
# /releases/latest and the releases page, so nothing can prompt a user to
|
|
# download a version whose asset set is incomplete or whose notes are still
|
|
# empty. Publishing is the release skill's job — it verifies the six assets and
|
|
# writes the body first, then flips the draft. See .claude/skills/release/SKILL.md.
|
|
draft-release:
|
|
needs: build
|
|
if: startsWith(github.ref, 'refs/tags/')
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
steps:
|
|
- uses: actions/download-artifact@v8
|
|
with:
|
|
path: dist
|
|
merge-multiple: true
|
|
|
|
# Reuse an existing release rather than failing: re-triggering a tag
|
|
# (force-push after a fixed platform) must top up the same draft. If the
|
|
# release was already published, --clobber just replaces its assets and it
|
|
# stays published.
|
|
#
|
|
# Existence is probed with `release list`, not `release view`: GitHub's
|
|
# get-release-by-tag endpoint does not return drafts, so a view-based check
|
|
# could miss the very draft a previous run left behind and create a second
|
|
# one (GitHub happily allows duplicate drafts on one tag).
|
|
- name: Assemble the draft release
|
|
run: |
|
|
set -euo pipefail
|
|
# Captured into a variable, not piped into `grep -q`: -q exits on the
|
|
# first match, and the resulting SIGPIPE would make `pipefail` report
|
|
# the pipeline as failed — i.e. "found" would read as "not found".
|
|
# `release list` includes drafts (cf. its --exclude-drafts flag).
|
|
EXISTING=$(gh release list --repo "$GITHUB_REPOSITORY" --limit 100 \
|
|
--json tagName -q '.[].tagName')
|
|
if grep -Fxq "$GITHUB_REF_NAME" <<<"$EXISTING"; then
|
|
echo "release $GITHUB_REF_NAME already exists; reusing it"
|
|
else
|
|
gh release create "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY" \
|
|
--draft --title "$GITHUB_REF_NAME" --notes ""
|
|
fi
|
|
gh release upload "$GITHUB_REF_NAME" dist/* --clobber --repo "$GITHUB_REPOSITORY"
|