Skip to content

Show date in tray reset timestamps #51

Show date in tray reset timestamps

Show date in tray reset timestamps #51

Workflow file for this run

name: Release
on:
push:
tags:
- 'v*'
branches:
- '**'
workflow_dispatch:
inputs:
dry_run:
description: 'Build without creating release'
required: false
default: false
type: boolean
permissions:
contents: write
jobs:
build:
name: Build (${{ matrix.target }})
# Run on: tags, workflow_dispatch, or commits containing [build] in message
if: >
startsWith(github.ref, 'refs/tags/v') ||
github.event_name == 'workflow_dispatch' ||
contains(github.event.head_commit.message, '[build]')
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
target: darwin-aarch64
- os: macos-15
target: darwin-x86_64
- os: ubuntu-latest
target: linux-x86_64
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Rust cache
uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri -> target
- name: Install dependencies
run: bun install --frozen-lockfile
- name: Install Linux build dependencies
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
libwebkit2gtk-4.1-dev \
libjavascriptcoregtk-4.1-dev \
libsoup-3.0-dev \
libappindicator3-dev \
librsvg2-dev \
libxss-dev \
libfuse2 \
patchelf \
pkg-config \
build-essential
sudo apt-get install -y libfuse2t64 || true
- name: Enable AppImage extract-and-run (no FUSE)
if: matrix.os == 'ubuntu-latest'
run: echo "APPIMAGE_EXTRACT_AND_RUN=1" >> "$GITHUB_ENV"
- name: Validate macOS signing secrets
if: startsWith(matrix.target, 'darwin')
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
set -euo pipefail
missing=0
require_secret() {
if [[ -z "${2:-}" ]]; then
echo "Missing required secret: $1"
missing=1
fi
}
require_secret "APPLE_CERTIFICATE" "${APPLE_CERTIFICATE:-}"
require_secret "APPLE_CERTIFICATE_PASSWORD" "${APPLE_CERTIFICATE_PASSWORD:-}"
require_secret "KEYCHAIN_PASSWORD" "${KEYCHAIN_PASSWORD:-}"
require_secret "APPLE_ID" "${APPLE_ID:-}"
require_secret "APPLE_ID_PASSWORD" "${APPLE_ID_PASSWORD:-}"
require_secret "APPLE_TEAM_ID" "${APPLE_TEAM_ID:-}"
if [[ "$missing" -ne 0 ]]; then exit 1; fi
- name: Import macOS signing certificate
if: startsWith(matrix.target, 'darwin')
env:
APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
set -euo pipefail
printf '%s' "$APPLE_CERTIFICATE" | base64 --decode > certificate.p12
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security set-keychain-settings -t 3600 -u build.keychain
security list-keychains -d user -s build.keychain
security import certificate.p12 -k build.keychain -P "$APPLE_CERTIFICATE_PASSWORD" -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
rm certificate.p12
cert_info="$(security find-identity -v -p codesigning build.keychain | grep -m 1 'Developer ID Application' || true)"
if [[ -z "${cert_info:-}" ]]; then
echo "Failed to find 'Developer ID Application' identity"
security find-identity -v -p codesigning build.keychain || true
exit 1
fi
cert_id="$(echo "$cert_info" | awk -F'\"' '{print $2}')"
echo "APPLE_SIGNING_IDENTITY=$cert_id" >> "$GITHUB_ENV"
- name: Build bundles
run: bunx tauri build --ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
APPLE_ID: ${{ startsWith(matrix.target, 'darwin') && secrets.APPLE_ID || '' }}
APPLE_ID_PASSWORD: ${{ startsWith(matrix.target, 'darwin') && secrets.APPLE_ID_PASSWORD || '' }}
APPLE_TEAM_ID: ${{ startsWith(matrix.target, 'darwin') && secrets.APPLE_TEAM_ID || '' }}
- name: Notarize + staple macOS artifacts
if: startsWith(matrix.target, 'darwin')
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
set -euo pipefail
app_path="$(find "src-tauri/target/release/bundle" -type d -name 'Claudometer.app' -print -quit || true)"
if [[ -z "${app_path:-}" ]]; then
echo "Failed to locate Claudometer.app"
exit 1
fi
dmg_path="$(find "src-tauri/target/release/bundle" -type f -name '*.dmg' -print -quit || true)"
if [[ -n "${dmg_path:-}" ]]; then
payload="$dmg_path"
else
payload_dir="$(mktemp -d)"
payload="$payload_dir/Claudometer.app.zip"
ditto -c -k --keepParent "$app_path" "$payload"
fi
xcrun notarytool submit "$payload" --wait \
--apple-id "$APPLE_ID" \
--password "$APPLE_ID_PASSWORD" \
--team-id "$APPLE_TEAM_ID"
xcrun stapler staple -v "$app_path"
if [[ -n "${dmg_path:-}" ]]; then
xcrun stapler staple -v "$dmg_path"
fi
- name: Verify macOS signing
if: startsWith(matrix.target, 'darwin')
run: |
set -euo pipefail
app_path="$(find "src-tauri/target/release/bundle" -type d -name 'Claudometer.app' -print -quit)"
codesign --verify --deep --strict --verbose=2 "$app_path"
spctl -a -vv --type exec "$app_path"
dmg_path="$(find "src-tauri/target/release/bundle" -type f -name '*.dmg' -print -quit || true)"
if [[ -n "${dmg_path:-}" ]]; then
xcrun stapler validate -v "$dmg_path"
fi
- name: Collect artifacts
run: |
set -euo pipefail
mkdir -p "artifacts/${{ matrix.target }}"
find "src-tauri/target/release/bundle" -type f \( \
-name '*.AppImage' -o -name '*.AppImage.sig' -o \
-name '*.deb' -o -name '*.deb.sig' -o \
-name '*.rpm' -o -name '*.rpm.sig' -o \
-name '*.dmg' -o -name '*.dmg.sig' -o \
-name '*.app.tar.gz' -o -name '*.app.tar.gz.sig' \
\) -exec cp {} "artifacts/${{ matrix.target }}/" \;
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: bundles-${{ matrix.target }}
path: artifacts/${{ matrix.target }}
retention-days: 7
create-release:
name: Create Release
needs: [build]
if: startsWith(github.ref, 'refs/tags/v') && !inputs.dry_run
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
set -euo pipefail
mkdir -p release-assets
for platform_dir in artifacts/bundles-*; do
platform=$(basename "$platform_dir" | sed 's/bundles-//')
for file in "$platform_dir"/*; do
filename=$(basename "$file")
if [[ "$filename" == "Claudometer.app.tar.gz" ]]; then
cp "$file" "release-assets/Claudometer-${platform}.app.tar.gz"
elif [[ "$filename" == "Claudometer.app.tar.gz.sig" ]]; then
cp "$file" "release-assets/Claudometer-${platform}.app.tar.gz.sig"
else
cp "$file" "release-assets/$filename"
fi
done
done
echo "Release assets:"
ls -la release-assets/
- name: Generate latest.json
env:
TAG: ${{ github.ref_name }}
REPO: ${{ github.repository }}
run: |
set -euo pipefail
linux_payload="$(ls -1 release-assets/*.AppImage | head -n 1)"
linux_sig="${linux_payload}.sig"
mac_arm_payload="release-assets/Claudometer-darwin-aarch64.app.tar.gz"
mac_arm_sig="${mac_arm_payload}.sig"
mac_x64_payload="release-assets/Claudometer-darwin-x86_64.app.tar.gz"
mac_x64_sig="${mac_x64_payload}.sig"
bun run scripts/generate-latest-json.ts \
--repo "$REPO" \
--tag "$TAG" \
--platform "linux-x86_64:${linux_payload}:${linux_sig}" \
--platform "darwin-aarch64:${mac_arm_payload}:${mac_arm_sig}" \
--platform "darwin-x86_64:${mac_x64_payload}:${mac_x64_sig}" \
--out latest.json
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ github.ref_name }}
name: Claudometer ${{ github.ref_name }}
draft: false
prerelease: ${{ contains(github.ref_name, '-') }}
files: |
release-assets/*
latest.json
body: |
## Claudometer ${{ github.ref_name }}
### Downloads
| Platform | Download |
|----------|----------|
| macOS (Apple Silicon) | `Claudometer-darwin-aarch64.dmg` |
| macOS (Intel) | `Claudometer-darwin-x86_64.dmg` |
| Linux (x86_64) | `Claudometer_*.AppImage` or `.deb` |
### Installation
**macOS**: Download the `.dmg`, open it, and drag Claudometer to Applications.
**Linux**: Download the `.AppImage` and make it executable (`chmod +x`), or install the `.deb` package.
build-summary:
name: Build Summary
needs: [build]
if: always() && needs.build.result != 'skipped'
runs-on: ubuntu-latest
steps:
- name: Summary
run: |
echo "## Build Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Platform | Status |" >> $GITHUB_STEP_SUMMARY
echo "|----------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| darwin-aarch64 | ${{ needs.build.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
echo "| darwin-x86_64 | ${{ needs.build.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
echo "| linux-x86_64 | ${{ needs.build.result == 'success' && '✅' || '❌' }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
echo "📦 **Release will be created** (tag detected)" >> $GITHUB_STEP_SUMMARY
else
echo "ℹ️ **No release** - push a tag (e.g., \`git tag v1.0.0 && git push --tags\`) to create a release" >> $GITHUB_STEP_SUMMARY
fi