From 7ae84db9217331147c43a8606206d4f23de09b54 Mon Sep 17 00:00:00 2001 From: Justin Chung <20733699+justin13888@users.noreply.github.com> Date: Mon, 21 Sep 2026 01:02:21 -0400 Subject: [PATCH 1/7] chore(tooling): add mise tasks and hk hooks as the single command source MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit mise.toml now holds every command Focale runs; hk.pkl decides only when each task fires and against which files, and scripts/determinism-hashes.sh makes the determinism render reproducible locally. hk's pre-commit stashes unstaged work and runs against the staged content, so formatting no longer rewrites files you deliberately left unstaged — verified against the old lefthook config, which reformatted them in the working tree. mise also provisions convco, which lefthook's commit-msg hook assumed was already on PATH. convco goes through the cargo backend rather than a direct release download: it publishes no x86_64-apple-darwin binary, so binstall takes the prebuilt artifact where one exists and falls back to a source build instead of hard-failing. The pre-push steps are unglobbed on purpose. Each runs a workspace-wide cargo command that ignores hk's file selection, so a glob would only decide whether the step runs — and a push touching only Cargo.toml or rust-toolchain.toml would skip a gate CI still enforces. --- .gitignore | 7 ++++ hk.pkl | 59 ++++++++++++++++++++++++++++ mise.toml | 73 +++++++++++++++++++++++++++++++++++ scripts/determinism-hashes.sh | 45 +++++++++++++++++++++ 4 files changed, 184 insertions(+) create mode 100644 hk.pkl create mode 100644 mise.toml create mode 100755 scripts/determinism-hashes.sh diff --git a/.gitignore b/.gitignore index e9921fd..30f8a80 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,13 @@ **/*.rs.bk *.pdb +# === Tooling === +# mise's local, uncommitted config override. +mise.local.toml +.mise.local.toml +# Default output of `mise run determinism`. +/hashes*.txt + # === Linux === *~ .fuse_hidden* diff --git a/hk.pkl b/hk.pkl new file mode 100644 index 0000000..891e716 --- /dev/null +++ b/hk.pkl @@ -0,0 +1,59 @@ +/// Git hooks for Focale. +/// +/// Every command lives in `mise.toml` — this file only decides when each task +/// runs and against which files. Install the hooks with `mise run hooks`. +/// +/// Keep the version below in sync with `hk` in `mise.toml`. +amends "package://github.com/jdx/hk/releases/download/v2.0.1/hk@2.0.1#/Config.pkl" + +min_hk_version = "2.0.1" +default_branch = "master" + +hooks { + ["pre-commit"] { + fix = true + // Run against the staged content, not the dirty worktree: hk saves unstaged + // work, formats, stages only the files it selected, then restores the rest. + stash = "git" + steps { + ["fmt"] { + glob = "**/*.rs" + fix = "mise run fmt" + } + } + } + + ["commit-msg"] { + steps { + // convco rather than hk's check_conventional_commit builtin: hk can only + // validate a single message, and pre-push and CI need a *range* checker, + // so convco is the one implementation of the rule. Merge and rebase + // commits are exempt; the task handles that. + ["conventional-commit"] { + check = "mise run commit-msg '{{commit_msg_file}}'" + } + } + } + + ["pre-push"] { + steps { + // All three are deliberately unglobbed. Each runs a workspace-wide cargo + // command that ignores hk's file selection, so a glob would only gate + // whether the step runs at all — and a push touching just Cargo.toml, + // rust-toolchain.toml or rustfmt.toml would then skip a gate CI still + // enforces. Matches the lefthook config this replaces. + ["fmt-check"] { + check = "mise run fmt-check" + } + ["lint"] { + check = "mise run lint" + } + ["test"] { + check = "mise run test" + } + ["commits"] { + check = "mise run commits" + } + } + } +} diff --git a/mise.toml b/mise.toml new file mode 100644 index 0000000..3882445 --- /dev/null +++ b/mise.toml @@ -0,0 +1,73 @@ +# Single source of truth for Focale's commands. +# +# The git hooks (hk.pkl) and every GitHub Actions job invoke these tasks; no +# command string is defined anywhere else. Run `mise tasks ls` to list them. + +[tools] +# Keep the version in sync with the `amends` URL at the top of hk.pkl. +hk = "2.0.1" +# convco publishes no x86_64-apple-darwin binary, so it goes through the cargo +# backend: binstall grabs the prebuilt release where one exists (Linux, Apple +# Silicon, Windows) and falls back to a source build rather than hard-failing. +cargo-binstall = "latest" +"cargo:convco" = "0.7.2" + +[tasks.fmt] +description = "Format all Rust sources" +run = "cargo fmt" + +[tasks.fmt-check] +description = "Verify formatting" +run = "cargo fmt --check" + +[tasks.lint] +description = "Clippy over the workspace, warnings denied" +run = "cargo clippy --workspace --all-targets -- -D warnings" + +[tasks.test] +description = "Workspace test suite" +run = "cargo test --workspace" + +[tasks.build] +description = "Build the workspace" +run = "cargo build --workspace" + +[tasks.run] +description = "Launch the desktop app (Wayland/X11)" +run = "cargo run -p focale-app --" + +[tasks.check] +description = "Everything CI runs" +# Sequential, like the justfile recipe this replaces: the three gates contend on +# cargo's target lock, so running them together buys nothing and interleaves the +# output. CI still runs them as independent parallel jobs. +run = ["mise run fmt-check", "mise run lint", "mise run test"] + +[tasks.commits] +description = "Validate conventional commits over a range" +usage = 'arg "[range]" help="Commit range to check" default="origin/master..HEAD"' +run = 'convco check "$usage_range"' + +[tasks.commit-msg] +description = "Validate a single commit message file" +usage = 'arg "" help="Path to the commit message file"' +run = ''' +# Merge and rebase commits are exempt (AGENTS.md); git is mid-operation then. +if git rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1; then exit 0; fi +if [ -d "$(git rev-parse --git-path rebase-merge)" ] \ + || [ -d "$(git rev-parse --git-path rebase-apply)" ]; then exit 0; fi +convco check --from-stdin < "$usage_file" +''' + +[tasks.determinism] +description = "Render the determinism fixture in every export format and hash it" +quiet = true +run = "./scripts/determinism-hashes.sh" + +[tasks.validate-hooks] +description = "Check hk.pkl parses and its steps resolve" +run = "hk validate" + +[tasks.hooks] +description = "Install the hk git hooks in this clone" +run = "hk install --mise" diff --git a/scripts/determinism-hashes.sh b/scripts/determinism-hashes.sh new file mode 100755 index 0000000..f102384 --- /dev/null +++ b/scripts/determinism-hashes.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# Render the committed determinism fixture in every export format and record +# "