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
110 changes: 110 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: Release

on:
push:
tags: ['v*']

permissions:
contents: read

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

jobs:
build:
name: Build (${{ matrix.platform }})
runs-on: ${{ matrix.runner }}
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
include:
- platform: Linux
runner: ubuntu-26.04
asset: grr-linux-x86_64
extension: ''
- platform: macOS
runner: macos-15
asset: grr-macos-arm64
extension: ''
- platform: Windows
runner: windows-2025
asset: grr-windows-x86_64.exe
extension: .exe
defaults:
run:
shell: bash
env:
CARGO_BUILD_JOBS: 2
RUST_BACKTRACE: 1
steps:
- name: Check out source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
persist-credentials: false
- name: Set up Node
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1
with:
node-version: 22.22.2
- name: Check release version
env:
RELEASE_TAG: ${{ github.ref_name }}
run: node scripts/check-release-version.mjs "$RELEASE_TAG"
- name: Set up Linux development environment
if: runner.os == 'Linux'
uses: ./.github/actions/setup-linux
- name: Build Linux executable
if: runner.os == 'Linux'
run: npm run build:app
- name: Check system libgit2 linkage
if: runner.os == 'Linux'
run: npm run check:linux
- name: Check and build desktop executable
if: runner.os != 'Linux'
uses: ./.github/actions/check-desktop
env:
LIBGIT2_NO_PKG_CONFIG: '1'
- name: Stage executable
env:
RELEASE_ASSET: ${{ matrix.asset }}
EXECUTABLE_EXTENSION: ${{ matrix.extension }}
run: |
mkdir -p artifacts
cp "src-tauri/target/release/grr$EXECUTABLE_EXTENSION" "artifacts/$RELEASE_ASSET"
- name: Upload executable
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: release-${{ matrix.asset }}
path: artifacts/*
if-no-files-found: error
retention-days: 7

publish:
name: Publish release
needs: build
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
contents: write
steps:
- name: Download executables
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093
with:
pattern: release-*
path: artifacts
merge-multiple: true
- name: Write checksums
working-directory: artifacts
run: sha256sum grr-* > SHA256SUMS
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RELEASE_TAG: ${{ github.ref_name }}
run: |
args=(--verify-tag --generate-notes --title "grr $RELEASE_TAG")
if [[ "$RELEASE_TAG" == *-* ]]; then
args+=(--prerelease)
fi
gh release create "$RELEASE_TAG" artifacts/* "${args[@]}"
43 changes: 40 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,39 @@
# Contributing

Use Rust 1.90+, Node 22.20+ within Node 22, and the checked-in lockfiles. Native development currently targets Fedora Linux 44; see the system dependencies in [README.md](README.md).
Use Rust 1.90+, Node 22.20+ within Node 22, and the checked-in lockfiles. Native development currently targets Fedora Linux 44; see the [installation requirements](#installation-requirements).

## Installation requirements

The Linux release binary is built on Ubuntu 26.04 and requires compatible system libraries. On Fedora 44:

```sh
sudo dnf install webkit2gtk4.1 libgit2 openssl-libs libappindicator-gtk3 librsvg2 libxdo wl-clipboard
```

Clipboard copying on Wayland uses `wl-copy` from `wl-clipboard`. Windows needs WebView2, which is included with Windows 10 and 11. macOS native window chrome requires macOS 11 or later.

## Build from source

Requires Rust 1.90+, Node.js 22.20+ (Node 22), npm, and system libgit2 1.9.x.

```sh
sudo dnf install webkit2gtk4.1-devel libgit2-devel openssl-devel \
libappindicator-gtk3-devel librsvg2-devel libxdo-devel
sudo dnf group install "c-development"

npm ci
npm run install:local
```

Make sure Cargo's bin directory is on your `PATH`. Installation includes the Linux desktop icon. Clipboard copying requires `wl-copy` from `wl-clipboard`.

On macOS, install the Xcode command line tools (`xcode-select --install`) and libgit2 (`brew install libgit2`), then use the build commands below. On Windows, install the Visual Studio C++ build tools instead of the Fedora packages. libgit2 is built from source and WebView2 ships with Windows 10 and 11:

```sh
npm ci
npm run build
cargo install --path src-tauri --locked --features custom-protocol
```

## Development

Expand All @@ -12,7 +45,7 @@ npm run check

The Preact frontend lives in `ui/`. The Rust app, Tauri configuration, capabilities and icons live in `src-tauri/`. Git parsing uses libgit2; review data and window chrome are separate from the UI.

`npm run build:app` uses the Tauri CLI to build the executable. `npm run install:local` also installs the Linux desktop integration. macOS 11+ uses an AppKit toolbar for native window chrome. Packaged releases are not available yet.
`npm run build:app` uses the Tauri CLI to build the executable. `npm run install:local` also installs the Linux desktop integration. macOS 11+ uses an AppKit toolbar for native window chrome.

On macOS, Cargo uses a compatible system libgit2 when available and builds its bundled copy otherwise. For a direct production build on any platform, run `npm run build` at the project root, then `cargo build --release --locked` from `src-tauri`. The default `custom-protocol` feature embeds the frontend; rebuild it after frontend changes. `tauri dev` disables this feature to use the development server.

Expand Down Expand Up @@ -55,4 +88,8 @@ The native test stack overrides WebdriverIO's transitive Mocha, diff parser, Jav

CI has independent jobs for frontend checks, Rust tests and coverage, Windows and macOS Rust checks, native Linux tests, dependency audits, secret scanning and workflow validation. It runs on pushes, pull requests or manual dispatch with read-only permissions and no repository secrets. The Rust and native Linux jobs run directly on Ubuntu 26.04 and share the setup action in `.github/actions/setup-linux`. Windows and macOS share `.github/actions/check-desktop` for setup, formatting, Clippy, Rust tests and the release build. The macOS job uses an Apple Silicon runner on macOS 15.

Require `Frontend`, `Rust checks and coverage`, `Rust checks (Windows)`, `Rust checks (macOS)`, `Native tests (Linux)`, `Dependency audit`, `Secret scan` and `Workflow lint` checks for `main` after the first hosted run succeeds. CI does not publish releases. Native macOS window behavior still needs manual validation.
Require `Frontend`, `Rust checks and coverage`, `Rust checks (Windows)`, `Rust checks (macOS)`, `Native tests (Linux)`, `Dependency audit`, `Secret scan` and `Workflow lint` checks for `main` after the first hosted run succeeds. Version tags publish releases through `.github/workflows/release.yml` after Linux, Apple Silicon macOS, and Windows builds succeed.

## Release

Update the version in `package.json`, `package-lock.json`, `src-tauri/Cargo.toml`, `src-tauri/Cargo.lock`, and `src-tauri/tauri.conf.json` together. Commit the version change on `main`, then tag that commit with the matching `v` version (for example, `v0.6.2`) and push the tag. The release workflow rejects mismatched versions, builds all three executables, and publishes them with checksums and generated release notes. Tags containing a prerelease suffix publish a GitHub prerelease.
47 changes: 25 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,30 +1,39 @@
# grr

A small local Git review app. Browse a unified diff, add line comments, and send the review back to your terminal.
A small local Git review app. Browse diffs and commit history, add line comments, and send the review back to your terminal.

Currently tested on Fedora Linux 44 and Windows 10. Native macOS window chrome is available on macOS 11+, with broader platform validation still in progress.
Tested on Fedora Linux 44, Windows 10, and macOS.

## Install

Requires Rust 1.90+, Node.js 22.20+ (Node 22), npm, and system libgit2 1.9.x.
Download the [latest release](https://github.com/RubyElders/grr/releases/latest) for your platform:

```sh
sudo dnf install webkit2gtk4.1-devel libgit2-devel openssl-devel \
libappindicator-gtk3-devel librsvg2-devel libxdo-devel
sudo dnf group install "c-development"
### Linux (x86_64)

npm ci
npm run install:local
```sh
mkdir -p ~/.local/bin
curl -fL https://github.com/RubyElders/grr/releases/latest/download/grr-linux-x86_64 -o ~/.local/bin/grr
chmod +x ~/.local/bin/grr
```

Make sure Cargo's bin directory is on your `PATH`. Installation includes the Linux desktop icon. Clipboard copying requires `wl-copy` from `wl-clipboard`.
Requires WebKitGTK 4.1 and libgit2 1.9.x. See [Linux dependencies](CONTRIBUTING.md#installation-requirements).

On Windows, install the Visual Studio C++ build tools instead of the Fedora packages. libgit2 is built from source and WebView2 ships with Windows 10 and 11:
### macOS (Apple Silicon)

```sh
npm ci
npm run build
cargo install --path src-tauri --locked --features custom-protocol
mkdir -p ~/.local/bin
curl -fL https://github.com/RubyElders/grr/releases/latest/download/grr-macos-arm64 -o ~/.local/bin/grr
chmod +x ~/.local/bin/grr
```

Releases are unsigned. If blocked, allow the app in System Settings > Privacy & Security.

For Linux and macOS, make sure `~/.local/bin` is on your `PATH`.

### Windows (x86_64)

```powershell
Invoke-WebRequest https://github.com/RubyElders/grr/releases/latest/download/grr-windows-x86_64.exe -OutFile "$env:LOCALAPPDATA\Microsoft\WindowsApps\grr.exe"
```

## Use
Expand All @@ -36,14 +45,8 @@ grr log
grr -C ../another-project
```

`grr` (or `grr diff`) opens the changes and `grr log` opens the commit history; press `v` to switch between them. The app detects the base branch automatically; pass a revision such as `main` (or `--merge-base main`) to choose it. Like Git, `-C` opens another repository. Run `grr help` for all options. Uncommitted changes open as a separate virtual commit; use the commit picker to review individual commits or the whole branch.

Add comments with the line's `+` button. `Ctrl+Enter` approves or shares comments; `Ctrl+Alt+Enter` also copies the result. Press `?` for all shortcuts. Closing the window cancels the review.

Reviews stay local and results are printed to stdout. Use `npm run uninstall:local` to remove the app.

See [CONTRIBUTING.md](CONTRIBUTING.md) for development and tests.
Press `?` for shortcuts. Run `grr help` for options. Reviews stay local and results are printed to stdout.

## License
See [CONTRIBUTING.md](CONTRIBUTING.md) to build from source or contribute.

[MIT](LICENSE), including the app icon. Third-party dependencies retain their own licenses.
22 changes: 22 additions & 0 deletions scripts/check-release-version.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { readFileSync } from "node:fs";

const readJson = (path) => JSON.parse(readFileSync(path, "utf8"));
const packageVersion = readJson("package.json").version;
const lock = readJson("package-lock.json");
const tauriVersion = readJson("src-tauri/tauri.conf.json").version;
const cargo = readFileSync("src-tauri/Cargo.toml", "utf8");
const cargoVersion = cargo.match(/^\[package\]\s*\n[\s\S]*?^version\s*=\s*"([^"]+)"/m)?.[1];
const cargoLock = readFileSync("src-tauri/Cargo.lock", "utf8");
const cargoLockVersion = cargoLock.match(/^name = "grr"\nversion = "([^"]+)"/m)?.[1];
const versions = [packageVersion, lock.version, lock.packages[""].version, tauriVersion, cargoVersion, cargoLockVersion];
const tag = process.argv[2];

if (
!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(packageVersion)
|| versions.some((version) => version !== packageVersion)
|| tag !== `v${packageVersion}`
) {
throw new Error(`Release tag ${tag} must match all package versions: ${versions.join(", ")}`);
}

console.log(`Release ${tag} matches all package versions`);
Loading