ci: update github action workflows for CI and release (#633)

Co-authored-by: Kalvin Chau <kalvin@squareup.com>

- combines the release workflow for CLI and Desktop App
    - "Build CLI" step only builds 'goose' artifacts; it skips 'goosed' artifacts
    - we no longer release desktop app run on pull requests speeds up PR builds a lot. however, i created a separate PR comment trigger which we can trigger with "/bundle-desktop" comment cause it can be useful in select PRs.
    - system deps in Cross.toml had to be updated (possible due to the recent Ubuntu update from 22 -> 24 in Github runners)

- versioned and stable release

- adds a PR comment trigger workflow to bundle desktop app and comment on PR with the download link

- only download 'goose' artifacts in download_cli.sh, improve error msgs

- combines the CI workflows for rust and electron app to a single workflow

- adds canary release workflow
This commit is contained in:
Salman Mohammed
2025-01-17 14:36:08 -05:00
committed by GitHub
parent 41912a909d
commit c331a146f5
12 changed files with 678 additions and 478 deletions
+69
View File
@@ -0,0 +1,69 @@
# This is a **reuseable** workflow that bundles the Desktop App for macOS.
# It doesn't get triggered on its own. It gets used in multiple workflows:
# - release.yml
# - canary.yml
on:
workflow_call:
inputs:
# Let's allow overriding the OSes and architectures in JSON array form:
# e.g. '["ubuntu-latest","macos-latest"]'
# If no input is provided, these defaults apply.
operating-systems:
type: string
required: false
default: '["ubuntu-latest","macos-latest"]'
architectures:
type: string
required: false
default: '["x86_64","aarch64"]'
name: "Reusable workflow to build CLI"
jobs:
build-cli:
name: Build CLI
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: ${{ fromJson(inputs.operating-systems) }}
architecture: ${{ fromJson(inputs.architectures) }}
include:
- os: ubuntu-latest
target-suffix: unknown-linux-gnu
- os: macos-latest
target-suffix: apple-darwin
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
target: ${{ matrix.architecture }}-${{ matrix.target-suffix }}
- name: Install cross
run: cargo install cross --git https://github.com/cross-rs/cross
- name: Build CLI
env:
CROSS_NO_WARNINGS: 0
run: |
export TARGET="${{ matrix.architecture }}-${{ matrix.target-suffix }}"
rustup target add "${TARGET}"
# 'cross' is used to cross-compile for different architectures (see Cross.toml)
cross build --release --target ${TARGET} -p goose-cli
# tar the goose binary as goose-<TARGET>.tar.bz2
cd target/${TARGET}/release
tar -cjf goose-${TARGET}.tar.bz2 goose
echo "ARTIFACT=target/${TARGET}/release/goose-${TARGET}.tar.bz2" >> $GITHUB_ENV
- name: Upload CLI artifact
uses: actions/upload-artifact@v4
with:
name: goose-${{ matrix.architecture }}-${{ matrix.target-suffix }}
path: ${{ env.ARTIFACT }}
+141
View File
@@ -0,0 +1,141 @@
# This is a **reuseable** workflow that bundles the Desktop App for macOS.
# It doesn't get triggered on its own. It gets used in multiple workflows:
# - release.yml
# - canary.yml
# - pr-comment-bundle-desktop.yml
on:
workflow_call:
secrets:
CERTIFICATE_OSX_APPLICATION:
required: true
CERTIFICATE_PASSWORD:
required: true
APPLE_ID:
required: true
APPLE_ID_PASSWORD:
required: true
APPLE_TEAM_ID:
required: true
name: Reusable workflow to bundle desktop app
jobs:
bundle-desktop:
runs-on: macos-latest
name: Bundle Desktop App on macOS
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache Cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache Cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/index
key: ${{ runner.os }}-cargo-index
restore-keys: |
${{ runner.os }}-cargo-index
- name: Cache Cargo build
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-
- name: Build goosed
run: cargo build --release -p goose-server
- name: Copy binary into Electron folder
run: cp target/release/goosed ui/desktop/src/bin/goosed
- name: Add MacOS certs for signing and notarization
run: ./add-macos-cert.sh
working-directory: ui/desktop
env:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm ci
working-directory: ui/desktop
- name: Make default Goose App
run: |
attempt=0
max_attempts=2
until [ $attempt -ge $max_attempts ]; do
npm run bundle:default && break
attempt=$((attempt + 1))
echo "Attempt $attempt failed. Retrying..."
sleep 5
done
if [ $attempt -ge $max_attempts ]; then
echo "Action failed after $max_attempts attempts."
exit 1
fi
working-directory: ui/desktop
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- name: Upload Desktop artifact
uses: actions/upload-artifact@v4
with:
name: Goose-darwin-arm64
path: ui/desktop/out/Goose-darwin-arm64/Goose.zip
- name: Quick launch test (macOS)
run: |
# Ensure no quarantine attributes (if needed)
xattr -cr "ui/desktop/out/Goose-darwin-arm64/Goose.app"
echo "Opening Goose.app..."
open -g "ui/desktop/out/Goose-darwin-arm64/Goose.app"
# Give the app a few seconds to start and write logs
sleep 5
# Check if it's running
if pgrep -f "Goose.app/Contents/MacOS/Goose" > /dev/null; then
echo "App appears to be running."
else
echo "App did not stay open. Possible crash or startup error."
exit 1
fi
LOGFILE="$HOME/Library/Application Support/Goose/logs/main.log"
# Print the log and verify "ChatWindow loaded" is in the logs
if [ -f "$LOGFILE" ]; then
echo "===== Log file contents ====="
cat "$LOGFILE"
echo "============================="
if grep -F "ChatWindow loaded" "$LOGFILE"; then
echo "Confirmed: 'ChatWindow loaded' found in logs!"
else
echo "Did not find 'ChatWindow loaded' in logs. Failing..."
exit 1
fi
else
echo "No log file found at $LOGFILE. Exiting with failure."
exit 1
fi
# Kill the app to clean up
pkill -f "Goose.app/Contents/MacOS/Goose"
+80
View File
@@ -0,0 +1,80 @@
# This workflow is for canary releases, automatically triggered by push to v1.0 branch.
# This workflow is identical to "release.yml" with these exceptions:
# - Triggered by push to v1.0 branch
# - Github Release tagged as "canary"
on:
push:
paths-ignore:
- 'docs/**'
branches:
- v1.0
name: Canary
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ------------------------------------
# 1) Build CLI for multiple OS/Arch
# ------------------------------------
build-cli:
uses: ./.github/workflows/build-cli.yml
# ------------------------------------
# 2) Upload Install CLI Script (we only need to do this once)
# ------------------------------------
install-script:
name: Upload Install Script
runs-on: ubuntu-latest
needs: [ build-cli ]
steps:
- uses: actions/checkout@v4
- uses: actions/upload-artifact@v4
with:
name: download_cli.sh
path: download_cli.sh
# ------------------------------------------------------------
# 3) Bundle Desktop App (macOS only) - builds goosed and Electron app
# ------------------------------------------------------------
bundle-desktop:
uses: ./.github/workflows/bundle-desktop.yml
secrets:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# ------------------------------------
# 4) Create/Update GitHub Release
# ------------------------------------
release:
name: Release
runs-on: ubuntu-latest
needs: [ build-cli, install-script, bundle-desktop ]
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
# Create/update the canary release
- name: Release canary
uses: ncipollo/release-action@v1
with:
tag: canary
name: Canary
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: |
goose-*.tar.bz2
Goose*.zip
download_cli.sh
allowUpdates: true
omitBody: true
omitPrereleaseDuringUpdate: true
-30
View File
@@ -1,30 +0,0 @@
name: Desktop App Lint
on:
push:
branches:
- v1.0
pull_request:
branches:
- v1.0
jobs:
build:
runs-on: macos-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm ci
working-directory: ui/desktop
- name: Run Lint check
run: npm run lint:check
working-directory: ui/desktop
-103
View File
@@ -1,103 +0,0 @@
name: Rust Build and Test
on:
push:
branches:
- v1.0
pull_request:
branches:
- v1.0
jobs:
format:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Set up Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: check format
run: |
cargo fmt --check
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
- name: Install Libs
run: |
sudo apt update -y
sudo apt install -y libdbus-1-dev gnome-keyring libxcb1-dev
- name: Start gnome-keyring
# run gnome-keyring with 'foobar' as password for the login keyring
# this will create a new login keyring and unlock it
# the login password doesn't matter, but the keyring must be unlocked for the tests to work
run: gnome-keyring-daemon --components=secrets --daemonize --unlock <<< 'foobar'
- name: Set up Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
- name: Cache Cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache Cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/index
key: ${{ runner.os }}-cargo-index
restore-keys: |
${{ runner.os }}-cargo-index
- name: Cache Cargo build
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-
- name: Install Ollama
run: curl -fsSL https://ollama.com/install.sh | sh
- name: Start Ollama
run: |
# Run the background, in a way that survives to the next step
nohup ollama serve > ollama.log 2>&1 &
# Block using the ready endpoint
time curl --retry 5 --retry-connrefused --retry-delay 1 -sf http://localhost:11434
- name: Test Ollama model
run: ollama run qwen2.5 hello || cat ollama.log
- name: Build the Rust project
run: cargo build
- name: Run Tests
run: cargo test --verbose
env:
OLLAMA_MODEL: "qwen2.5"
- name: check lint
run: |
cargo clippy
+122
View File
@@ -0,0 +1,122 @@
on:
push:
paths-ignore:
- 'docs/**'
branches:
- v1.0
pull_request:
paths-ignore:
- 'docs/**'
branches:
- v1.0
name: CI
jobs:
rust-format:
name: Check Rust Code Format
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Run cargo fmt
run: cargo fmt --check
rust-build-and-test:
name: Build and Test Rust Project
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Install Dependencies
run: |
sudo apt update -y
sudo apt install -y libdbus-1-dev gnome-keyring libxcb1-dev
- name: Start gnome-keyring
# run gnome-keyring with 'foobar' as password for the login keyring
# this will create a new login keyring and unlock it
# the login password doesn't matter, but the keyring must be unlocked for the tests to work
run: |
gnome-keyring-daemon --components=secrets --daemonize --unlock <<< 'foobar'
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Cache Cargo Registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache Cargo Index
uses: actions/cache@v3
with:
path: ~/.cargo/index
key: ${{ runner.os }}-cargo-index
restore-keys: |
${{ runner.os }}-cargo-index
- name: Cache Cargo Build
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-
- name: Install Ollama
run: curl -fsSL https://ollama.com/install.sh | sh
- name: Start Ollama
run: |
# Run the background, in a way that survives to the next step
nohup ollama serve > ollama.log 2>&1 &
# Block using the ready endpoint
time curl --retry 5 --retry-connrefused --retry-delay 1 -sf http://localhost:11434
- name: Test Ollama Model
run: ollama run qwen2.5 hello || cat ollama.log
- name: Build Rust Project
run: cargo build
- name: Run Tests
run: cargo test --verbose
env:
OLLAMA_MODEL: "qwen2.5"
## TODO: Need to decide if we wanna error out on clippy warnings. It was not being used before.
# - name: Run Cargo Clippy (Lint)
# run: cargo clippy -- -D warnings
desktop-lint:
name: Lint Electron Desktop App
runs-on: macos-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 'lts/*'
- name: Install Dependencies
run: npm ci
working-directory: ui/desktop
- name: Run Lint
run: npm run lint:check
working-directory: ui/desktop
-71
View File
@@ -1,71 +0,0 @@
on:
push:
tags:
- "v1.*"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
name: Release CLI
jobs:
build:
name: Build ${{ matrix.os }}-${{ matrix.architecture }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-latest ]
architecture: [ aarch64, x86_64 ]
include:
- os: ubuntu-latest
target-suffix: unknown-linux-gnu
- os: macos-latest
target-suffix: apple-darwin
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Rust toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: stable
- name: build
run: |
export TARGET=${{ matrix.architecture }}-${{ matrix.target-suffix }}
rustup target add "${TARGET}"
cargo install cross --git https://github.com/cross-rs/cross
CROSS_NO_WARNINGS=0 cross build --release --target ${TARGET}
cd target/${TARGET}/release
tar -cjf goose-${TARGET}.tar.bz2 goose goosed
echo "ARTIFACT=target/${TARGET}/release/goose-${TARGET}.tar.bz2" >> $GITHUB_ENV
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: goose-${{ matrix.architecture }}-${{ matrix.target-suffix }}
path: ${{ env.ARTIFACT }}
release:
name: Release
runs-on: ubuntu-latest
needs: [ build ]
permissions:
contents: write
steps:
# Step 1: Download all build artifacts
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
# Step 2: Create GitHub release with artifacts
- name: Create GitHub release
uses: ncipollo/release-action@v1
with:
artifacts: "goose-*.tar.bz2"
token: ${{ secrets.GITHUB_TOKEN }}
-214
View File
@@ -1,214 +0,0 @@
name: Desktop App Build
on:
push:
tags:
- "v1.*"
pull_request:
branches:
- v1.0
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: macos-latest
permissions:
contents: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Rust
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
toolchain: stable
- name: Cache Cargo registry
uses: actions/cache@v3
with:
path: ~/.cargo/registry
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-registry-
- name: Cache Cargo index
uses: actions/cache@v3
with:
path: ~/.cargo/index
key: ${{ runner.os }}-cargo-index
restore-keys: |
${{ runner.os }}-cargo-index
- name: Cache Cargo build
uses: actions/cache@v3
with:
path: target
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-build-
# Build Rust Binary
- name: Build Release Binary
run: cargo build --release
- name: copy binary
run: cp target/release/goosed ui/desktop/src/bin/goosed
# Desktop App Steps
- name: Add MacOS certs for signing and notarization
run: ./add-macos-cert.sh
working-directory: ui/desktop
env:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 'lts/*'
- name: Install dependencies
run: npm ci
working-directory: ui/desktop
- name: Make default Goose App
run: |
attempt=0
max_attempts=2
until [ $attempt -ge $max_attempts ]; do
npm run bundle:default && break
attempt=$((attempt + 1))
echo "Attempt $attempt failed. Retrying..."
sleep 5
done
if [ $attempt -ge $max_attempts ]; then
echo "Action failed after $max_attempts attempts."
exit 1
fi
working-directory: ui/desktop
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: Goose-darwin-arm64
path: ui/desktop/out/Goose-darwin-arm64/Goose.zip
- name: Quick launch test (macOS)
run: |
# Ensure no quarantine attributes (if needed)
xattr -cr "ui/desktop/out/Goose-darwin-arm64/Goose.app"
echo "Opening Goose.app..."
open -g "ui/desktop/out/Goose-darwin-arm64/Goose.app"
# Give the app a few seconds to start and write logs
sleep 5
# Check if it's running
if pgrep -f "Goose.app/Contents/MacOS/Goose" > /dev/null; then
echo "App appears to be running."
else
echo "App did not stay open. Possible crash or startup error."
exit 1
fi
LOGFILE="$HOME/Library/Application Support/Goose/logs/main.log"
# Print the log and verify "Starting goosed"
if [ -f "$LOGFILE" ]; then
echo "===== Log file contents ====="
cat "$LOGFILE"
echo "============================="
# Check for evidence it ran in the logs:
if grep -F "ChatWindow loaded" "$LOGFILE"; then
echo "Confirmed: 'Starting goosed' found in logs!"
else
echo "Did not find 'Starting goosed' in logs. Failing..."
exit 1
fi
else
echo "No log file found at $LOGFILE. Exiting with failure."
exit 1
fi
# Kill the app to clean up
pkill -f "Goose.app/Contents/MacOS/Goose"
release:
name: Release
runs-on: ubuntu-latest
needs: [build]
permissions:
contents: write
pull-requests: write
if: github.event_name != 'pull_request'
steps:
# Download all artifacts
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
# Create or update release
- name: Create/Update Release
uses: ncipollo/release-action@v1
with:
artifacts: "*.zip"
token: ${{ secrets.GITHUB_TOKEN }}
allowUpdates: true
omitBody: true
omitPrereleaseDuringUpdate: true
pr-comment:
name: Add PR Comment
runs-on: ubuntu-latest
needs: [build]
permissions:
pull-requests: write
if: github.event_name == 'pull_request'
steps:
# Download all artifacts
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
# Create comment with download links
- name: Find Comment
uses: peter-evans/find-comment@v2
id: fc
with:
issue-number: ${{ github.event.pull_request.number }}
comment-author: 'github-actions[bot]'
body-includes: Desktop App build artifacts
- name: Create or update comment
uses: peter-evans/create-or-update-comment@v3
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Desktop App for this PR
The following build is available for testing:
- [📱 macOS Desktop App (Universal, signed)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/Goose-darwin-arm64.zip)
The app is signed and notarized for macOS. After downloading, unzip the file and drag the Goose.app to your Applications folder.
This link is provided by nightly.link and will work even if you're not logged into GitHub.
edit-mode: replace
@@ -0,0 +1,71 @@
# This workflow is triggered by a comment on an issue or PR with the text "/bundle-desktop".
# It bundles the Desktop App, then creates a PR comment with a link to download the app.
on:
issue_comment:
types: [created]
workflow_dispatch:
# permissions needed for reacting to IssueOps commands on issues and PRs
permissions:
pull-requests: write
issues: write
checks: read
name: Workflow to Bundle Desktop App
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
trigger-on-command:
name: Trigger on "/bundle-desktop" PR comment
runs-on: ubuntu-latest
steps:
- uses: github/command@v1.3.0
id: command
with:
command: "/bundle-desktop"
reaction: "eyes"
allowed_contexts: pull_request
bundle-desktop:
# Only run this if "/bundle-desktop" command is detected.
if: ${{ steps.command.outputs.continue == 'true' }}
uses: ./.github/workflows/bundle-desktop.yml
secrets:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
pr-comment:
name: PR Comment with Desktop App
runs-on: ubuntu-latest
needs: [ bundle-desktop ]
permissions:
pull-requests: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
- name: Comment on PR with download link
uses: peter-evans/create-or-update-comment@v3
with:
comment-id: ${{ steps.command.outputs.comment_id }}
issue-number: ${{ github.event.pull_request.number }}
body: |
### Desktop App for this PR
The following build is available for testing:
- [📱 macOS Desktop App (arm64, signed)](https://nightly.link/${{ github.repository }}/actions/runs/${{ github.run_id }}/Goose-darwin-arm64.zip)
After downloading, unzip the file and drag the Goose.app to your Applications folder. The app is signed and notarized for macOS.
This link is provided by nightly.link and will work even if you're not logged into GitHub.
edit-mode: replace
+89
View File
@@ -0,0 +1,89 @@
# This workflow is main release, needs to be manually tagged & pushed.
on:
push:
tags:
- "v1.*"
name: Release
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
# ------------------------------------
# 1) Build CLI for multiple OS/Arch
# ------------------------------------
build-cli:
uses: ./.github/workflows/build-cli.yml
# ------------------------------------
# 2) Upload Install CLI Script (we only need to do this once)
# ------------------------------------
install-script:
name: Upload Install Script
runs-on: ubuntu-latest
needs: [ build-cli ]
steps:
- uses: actions/checkout@v4
- uses: actions/upload-artifact@v4
with:
name: download_cli.sh
path: download_cli.sh
# ------------------------------------------------------------
# 3) Bundle Desktop App (macOS only) - builds goosed and Electron app
# ------------------------------------------------------------
bundle-desktop:
uses: ./.github/workflows/bundle-desktop.yml
secrets:
CERTIFICATE_OSX_APPLICATION: ${{ secrets.CERTIFICATE_OSX_APPLICATION }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
# ------------------------------------
# 4) Create/Update GitHub Release
# ------------------------------------
release:
name: Release
runs-on: ubuntu-latest
needs: [ build-cli, install-script, bundle-desktop ]
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
merge-multiple: true
# Create/update the versioned release
- name: Release versioned
uses: ncipollo/release-action@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
# This pattern will match both goose tar.bz2 artifacts and the Goose.zip
artifacts: |
goose-*.tar.bz2
Goose*.zip
download_cli.sh
allowUpdates: true
omitBody: true
omitPrereleaseDuringUpdate: true
# Create/update the stable release
- name: Release stable
uses: ncipollo/release-action@v1
with:
tag: stable
name: Stable
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: |
goose-*.tar.bz2
Goose*.zip
download_cli.sh
allowUpdates: true
omitBody: true
omitPrereleaseDuringUpdate: true
+20 -10
View File
@@ -1,19 +1,29 @@
# Configuration for cross-compiling using cross
[target.aarch64-unknown-linux-gnu]
xargo = false
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH && apt-get update --fix-missing && apt-get install --assume-yes libxcb1-dev:$CROSS_DEB_ARCH libdbus-1-dev:$CROSS_DEB_ARCH",
# Add the ARM64 architecture and install necessary dependencies
"dpkg --add-architecture arm64",
"""\
apt-get update --fix-missing && apt-get install -y \
pkg-config \
libssl-dev:arm64 \
libdbus-1-dev:arm64 \
libxcb1-dev:arm64
"""
]
env = { PKG_CONFIG_PATH = "/usr/lib/aarch64-linux-gnu/pkgconfig" }
# If you run the build on your local machine,
# This is a workaround for the missing pkg-config path on aarch64
# You also need to add pkg-config:$CROSS_DEB_ARCH to the apt-get install command above
#[target.aarch64-unknown-linux-gnu.env]
#passthrough = ["PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig"]
# If you run the build on your local machine,
# You need to add pkg-config:$CROSS_DEB_ARCH to the apt-get install command below
[target.x86_64-unknown-linux-gnu]
xargo = false
pre-build = [
"dpkg --add-architecture $CROSS_DEB_ARCH && apt-get update --fix-missing && apt-get install --assume-yes libxcb1-dev:$CROSS_DEB_ARCH libdbus-1-dev:$CROSS_DEB_ARCH",
# Install necessary dependencies for x86_64
# We don't need architecture-specific flags because x86_64 dependencies are installable on Ubuntu system
"""\
apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
libdbus-1-dev \
libxcb1-dev \
"""
]
+86 -50
View File
@@ -1,39 +1,76 @@
#!/usr/bin/env sh
#!/usr/bin/env bash
set -euo pipefail
##############################################################################
# Goose CLI Install Script
#
# This script downloads the latest 'goose' CLI binary from GitHub releases
# and installs it to your system.
#
# Supported OS: macOS (darwin), Linux
# Supported Architectures: x86_64, arm64
#
# Usage:
# curl -H 'Accept: application/vnd.github.v3.raw' "https://api.github.com/repos/block/goose/contents/download_cli.sh?ref=v1.0" | bash
#
# Environment variables:
# GOOSE_BIN_DIR - Directory to which Goose will be installed (default: $HOME/.local/bin)
# GOOSE_PROVIDER - Optional: provider for goose (passed to "goose configure")
# GOOSE_MODEL - Optional: model for goose (passed to "goose configure")
##############################################################################
# --- 1) Check for curl ---
if ! command -v curl >/dev/null 2>&1; then
echo "Error: 'curl' is required to download Goose. Please install curl and try again."
exit 1
fi
# --- 2) Variables ---
REPO="block/goose"
OUT_FILE="goose"
GITHUB_API_ENDPOINT="api.github.com"
GOOSE_BIN_DIR="${GOOSE_BIN_DIR:-"$HOME/.local/bin"}"
function gh_curl() {
curl -sL -H "Accept: application/vnd.github.v3.raw" $@
# Helper function to fetch JSON from GitHub
gh_curl() {
curl -sL -H "Accept: application/vnd.github.v3.raw" "$@"
}
# Determine the operating system and architecture
OS=$(uname | tr '[:upper:]' '[:lower:]')
# --- 3) Detect OS/Architecture ---
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
case "$OS" in
linux|darwin) ;;
*)
echo "Error: Unsupported OS '$OS'. Goose only supports Linux and macOS."
exit 1
;;
esac
case "$ARCH" in
x86_64)
ARCH="x86_64"
;;
arm64)
arm64|aarch64)
# Some systems use 'arm64' and some 'aarch64' standardize to 'aarch64'
ARCH="aarch64"
;;
*)
echo "ERROR: Unsupported architecture: $ARCH"
echo "Error: Unsupported architecture '$ARCH'."
exit 1
;;
esac
FILE="goose-$ARCH-unknown-linux-gnu.tar.bz2"
# Build the filename we expect in the release assets
if [ "$OS" = "darwin" ]; then
FILE="goose-$ARCH-apple-darwin.tar.bz2"
else
FILE="goose-$ARCH-unknown-linux-gnu.tar.bz2"
fi
# Find the goose binary asset id
# --- 4) Fetch GitHub Releases and locate the correct asset ID ---
echo "Looking up the most recent goose binary release..."
echo ""
RELEASES=$(gh_curl https://$GITHUB_API_ENDPOINT/repos/$REPO/releases)
# Parse JSON to find the asset ID
@@ -52,58 +89,57 @@ ASSET_ID=$(echo "$RELEASES" | awk -v file="$FILE" '
')
if [ -z "$ASSET_ID" ]; then
echo "ERROR: $FILE asset not found"
echo "Error: Could not find a release asset named '$FILE' in the latest releases."
exit 1
fi
# Download the goose binary
# --- 5) Download & extract 'goose' binary ---
echo "Downloading $FILE..."
echo ""
curl -sL --header 'Accept: application/octet-stream' https://$GITHUB_API_ENDPOINT/repos/$REPO/releases/assets/$ASSET_ID > $FILE
tar -xjf $FILE
echo "Cleaning up $FILE..."
rm $FILE
chmod +x goose goosed
curl -sL --header 'Accept: application/octet-stream' \
"https://$GITHUB_API_ENDPOINT/repos/$REPO/releases/assets/$ASSET_ID" \
--output "$FILE"
LOCAL_BIN="$HOME/.local/bin"
if [ ! -d "$LOCAL_BIN" ]; then
echo "Directory $LOCAL_BIN does not exist. Creating it now..."
mkdir -p "$LOCAL_BIN"
echo "Directory $LOCAL_BIN created successfully."
echo "Extracting $FILE..."
tar -xjf "$FILE"
rm "$FILE" # clean up the downloaded tarball
# Make binaries executable
chmod +x goose
# --- 6) Install to $GOOSE_BIN_DIR ---
if [ ! -d "$GOOSE_BIN_DIR" ]; then
echo "Creating directory: $GOOSE_BIN_DIR"
mkdir -p "$GOOSE_BIN_DIR"
fi
echo "Moving goose to $GOOSE_BIN_DIR/$OUT_FILE"
mv goose "$GOOSE_BIN_DIR/$OUT_FILE"
# --- 7) Check PATH and give instructions if needed ---
if [[ ":$PATH:" != *":$GOOSE_BIN_DIR:"* ]]; then
echo ""
echo "Warning: $GOOSE_BIN_DIR is not in your PATH."
echo "Add it to your PATH by editing ~/.bashrc, ~/.zshrc, or similar:"
echo " export PATH=\"$GOOSE_BIN_DIR:\$PATH\""
echo "Then reload your shell (e.g. 'source ~/.bashrc', 'source ~/.zshrc') to apply changes."
echo ""
fi
echo "Sending goose to $LOCAL_BIN/$OUT_FILE"
echo ""
mv goose $LOCAL_BIN/$OUT_FILE
mv goosed $LOCAL_BIN
# Check if the directory is in the PATH
if [[ ":$PATH:" != *":$LOCAL_BIN:"* ]]; then
echo "The directory $LOCAL_BIN is not in your PATH."
echo "To add it, append the following line to your shell configuration file (e.g., ~/.bashrc or ~/.zshrc):"
echo ""
echo " export PATH=\"$LOCAL_BIN:\$PATH\""
echo ""
echo "Then reload your shell configuration file by running:"
echo ""
echo " source ~/.bashrc # or source ~/.zshrc"
fi
# Initialize config args with the default name
# --- 8) Auto-configure Goose (Optional) ---
CONFIG_ARGS="-n default"
# Check for GOOSE_PROVIDER environment variable
if [ -n "${GOOSE_PROVIDER:-}" ]; then
CONFIG_ARGS="$CONFIG_ARGS -p $GOOSE_PROVIDER"
CONFIG_ARGS="$CONFIG_ARGS -p $GOOSE_PROVIDER"
fi
# Check for GOOSE_MODEL environment variable
if [ -n "${GOOSE_MODEL:-}" ]; then
CONFIG_ARGS="$CONFIG_ARGS -m $GOOSE_MODEL"
CONFIG_ARGS="$CONFIG_ARGS -m $GOOSE_MODEL"
fi
$LOCAL_BIN/$OUT_FILE configure $CONFIG_ARGS
echo ""
echo "You can now run Goose using: $OUT_FILE session"
echo "Configuring Goose with: '$CONFIG_ARGS'"
echo ""
"$GOOSE_BIN_DIR/$OUT_FILE" configure $CONFIG_ARGS
echo ""
echo "Goose installed successfully! Run '$OUT_FILE session' to get started."
echo ""