Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
141 changes: 141 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Release

# Builds installable artifacts (cargo-packager) for macOS / Linux / Windows and attaches them to a
# GitHub Release. Runs on a version tag `v*`; `workflow_dispatch` builds the artifacts without
# releasing (for dry-runs). Separate from ci.yml (which only tests).
on:
push:
tags: ["v*"]
workflow_dispatch:

concurrency:
group: release-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: package · ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# macos-14 = Apple Silicon (we lipo a universal binary on it); ubuntu-22.04 has libfuse2 for
# AppImage; windows-latest builds the .msi (cargo-packager fetches WiX itself).
os: [macos-14, ubuntu-22.04, windows-latest]
steps:
- uses: actions/checkout@v4

- name: Show toolchain
run: rustup show

# gpui links X11/Wayland/Vulkan/fontconfig (build) + libfuse2 (AppImage tooling needs FUSE2,
# absent on ubuntu-24.04 — hence pinning 22.04).
- name: Install Linux deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
build-essential pkg-config clang libfontconfig-dev \
libwayland-dev libxkbcommon-x11-dev libx11-xcb-dev libvulkan1 \
libfuse2

- uses: Swatinem/rust-cache@v2

- uses: cargo-bins/cargo-binstall@main
- name: Install cargo-packager
shell: bash
run: |
# binstall is fast but sometimes exits 0 without installing; verify the binary is really
# present and fall back to a source build, then assert it's runnable.
cargo binstall --no-confirm cargo-packager || true
command -v cargo-packager >/dev/null || cargo install cargo-packager --locked
cargo packager --version

# No before-packaging-command in the manifest, so build the release binary explicitly.
# (macOS builds its own universal binary via lipo in the step below.)
- name: Build release binary (Linux/Windows)
if: runner.os != 'macOS'
run: cargo build --release -p posel-app

# macOS: build both arches, lipo into target/release, then package. No build hook in the
# manifest, so `--release` simply bundles the universal binary already sitting there.
# (Do NOT pass `--config` — it REPLACES the manifest config, dropping product-name/binaries.)
- name: Package (macOS — universal .app + .dmg)
if: runner.os == 'macOS'
run: |
rustup target add aarch64-apple-darwin x86_64-apple-darwin
cargo build --release --target aarch64-apple-darwin -p posel-app
cargo build --release --target x86_64-apple-darwin -p posel-app
mkdir -p target/release
lipo -create -output target/release/posel \
target/aarch64-apple-darwin/release/posel \
target/x86_64-apple-darwin/release/posel
lipo -info target/release/posel
cargo packager --release --formats app,dmg --manifest-path crates/app/Cargo.toml --out-dir "${{ github.workspace }}/dist"
# Guard: the binary inside the bundle must be universal.
lipo -info "$(find dist -path '*Posel.app/Contents/MacOS/posel')"
# Signing is intentionally OFF (unsigned). To enable later, set these from secrets and add a
# conditional `--config` injecting macos.signing-identity — no other change needed:
# env:
# APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }}
# APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
# APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }}
# APPLE_API_KEY: ${{ secrets.APPLE_API_KEY }}
# APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
# APPLE_API_KEY_PATH: ${{ secrets.APPLE_API_KEY_PATH }}

- name: Package (Linux — AppImage + .deb)
if: runner.os == 'Linux'
run: |
cargo packager --release --formats appimage,deb \
--manifest-path crates/app/Cargo.toml --out-dir "${{ github.workspace }}/dist"

- name: Package (Windows — .msi)
if: runner.os == 'Windows'
run: |
cargo packager --release --formats wix `
--manifest-path crates/app/Cargo.toml --out-dir "${{ github.workspace }}/dist"

- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: posel-${{ matrix.os }}
# Bundle binaries/installers only — skip the loose unbundled exe/.app dirs.
path: |
dist/*.dmg
dist/*.AppImage
dist/*.deb
dist/*.msi
if-no-files-found: error

release:
name: publish GitHub Release
needs: build
runs-on: ubuntu-latest
# Only publish on a real version tag; workflow_dispatch stops after `build` (artifacts only).
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: actions/checkout@v4

# Fail loudly if the tag and the crate version disagree (tag v0.1.0 ⇔ version 0.1.0).
- name: Check tag matches crate version
run: |
TAG="${GITHUB_REF_NAME#v}"
VER=$(cargo metadata --no-deps --format-version 1 \
| jq -r '.packages[] | select(.name=="posel-app") | .version')
echo "tag=$TAG crate=$VER"
[ "$TAG" = "$VER" ] || { echo "::error::tag $TAG != crate version $VER"; exit 1; }

- uses: actions/download-artifact@v4
with:
path: artifacts

- name: Publish release
uses: softprops/action-gh-release@v2
with:
files: artifacts/**/*
fail_on_unmatched_files: true
generate_release_notes: true
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/target
/dist
**/*.rs.bk
*.pdb
.DS_Store
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ is the opposite corner of the design space:

## Status

Working, in active development. v1 targets **macOS**.
Working, in active development. Runs on **macOS, Linux, and Windows**.

- **REST** — request editor (method, query/headers/body), streaming response panel,
environments + variables, secrets in the OS keychain, request history.
Expand All @@ -36,6 +36,21 @@ Working, in active development. v1 targets **macOS**.

See [docs/PLAN.md](./docs/PLAN.md) for the phased roadmap and what's next.

## Install

Grab the latest build for your platform from the
[Releases](https://github.com/starvy/posel/releases) page:

- **macOS** — `.dmg` (universal: Apple Silicon + Intel)
- **Linux** — `.AppImage` (portable) or `.deb` (Debian/Ubuntu)
- **Windows** — `.msi` installer

> **Unsigned builds.** Releases aren't code-signed yet, so the OS warns on first launch:
> - **macOS** — right-click the app → **Open**, or `xattr -dr com.apple.quarantine /Applications/Posel.app`.
> - **Windows** — SmartScreen → **More info** → **Run anyway**.
>
> This goes away once signing/notarization is set up.

## Architecture

The domain logic is headless and unit-tested; GPUI is confined to the edge (`ui`/`app` only).
Expand All @@ -58,8 +73,9 @@ stays protocol-agnostic. See [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md).
## Build & run

Requires a current stable Rust toolchain (GPUI uses recently-stabilized std features; run
`rustup update stable` if a build fails with `E0658`). macOS only for now — secret storage uses
the macOS keychain.
`rustup update stable` if a build fails with `E0658`). Builds on macOS, Linux, and Windows;
secrets use the platform keychain (macOS Keychain, Windows Credential Manager, Linux
Secret Service).

```bash
cargo run -p posel-app # the desktop app (binary: posel)
Expand Down
19 changes: 19 additions & 0 deletions crates/app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,22 @@ gpui-component.workspace = true
gpui-component-assets.workspace = true
anyhow.workspace = true
tracing-subscriber.workspace = true

# Installer/bundle config for `cargo packager` (see .github/workflows/release.yml). `version` is read
# from [workspace.package]. GUI assets are embedded in the binary (with_assets), so no `resources`.
# `icons` is a single placeholder PNG — cargo-packager derives the per-platform .icns/.ico from it.
# No `before-packaging-command`: the release binary is built explicitly by the workflow first (the
# macOS leg lipos a universal binary), then `cargo packager --release` bundles target/release/posel.
[package.metadata.packager]
product-name = "Posel"
identifier = "com.starvy.posel"
category = "DeveloperTool"
icons = [
"../../packaging/icons/icon.icns",
"../../packaging/icons/icon.ico",
"../../packaging/icons/icon.png",
]

[package.metadata.packager.macos]
minimum-system-version = "11.0"
# signing-identity intentionally unset → unsigned (no failure); CI injects it once certs exist.
Binary file added packaging/icons/icon.icns
Binary file not shown.
Binary file added packaging/icons/icon.ico
Binary file not shown.
Binary file added packaging/icons/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading