Skip to content

Releases: yantonov/krok

Release list

0.3.0

Choose a tag to compare

@github-actions github-actions released this 20 Aug 13:36

krok 0.3.0

Two fixes, both about hook installation surviving the way repositories are
actually set up: a build step that repoints core.hooksPath, and a bootstrap
script that runs more than once.

The preserved hook now lives under the git directory

When krok takes over a hook that already exists, it keeps a copy and registers
it as the first job so it keeps running. That copy used to go beside the hook it
replaced, under whatever git rev-parse --git-path hooks answered, and the job
resolved it through KROK_HOOKS_DIR at run time. Both follow core.hooksPath —
which is not krok's to set: husky sets it, from a build step, on every fresh
checkout. Installing before that happened left the copy in .git/hooks while
the job looked in .husky, and every commit then failed on the reserved job
with the preserved hook reported missing. A gerrit commit-msg hook is one of
the ones lost that way, which takes the whole repository with it.

The copy now goes to .git/krok/<hook>/existing, named through a new
KROK_GIT_DIR. Nothing outside git moves the git directory, and it is where the
config naming the copy already lives, so the two cannot come apart. It also
keeps krok out of a hooks directory that may be tracked — .husky is, and a
copy written there is untracked noise in every clone.

Upgrading is safe: a file an earlier krok left is still looked for where it was
left, so an upgrade does not read a hook it already installed as unfinished and
preserve it a second time.

add answers instead of refusing when the job is already registered

Registering a job krok already holds was an error. It did not need to be — the
job list already says what the caller asked for, and the command is the same, so
there is nothing ambiguous to report and nothing to write.

The refusal cost more than it looked. Scripts that register hooks run when a
checkout is set up, and again every time it is set up again; under set -e the
refusal fails them, and in a workspace holding several repositories it fails at
the first one that had been set up before, so none of the later ones get their
hooks. Re-running the bootstrap — the obvious move when hooks look wrong — became
the reason the rest of the workspace had none.

krok now reports that the job is already there and succeeds. The wrapper is
still seen to before the answer, so a re-run remains the way a hook file someone
deleted comes back. A different command whose derived key is already taken is
unaffected: it is numbered, as before.

New job variable

Variable Value
KROK_GIT_DIR The git directory shared by every worktree

KROK_REPO_ROOT and KROK_HOOKS_DIR are unchanged.

0.2.0

Choose a tag to compare

@github-actions github-actions released this 18 Aug 15:07

krok 0.2.0

First release since 0.1.0. Several fixes here change behaviour you may be relying on — read Before upgrading first.

Before upgrading

Jobs now run under sh, not under $SHELL. Previously each job was handed to whatever interactive shell you happen to use. If a registered command uses bash-only syntax — [[ ... ]], arrays, &> — it will now fail. Wrap it (bash -c '...') or rewrite it in POSIX syntax.

Asset names now carry the architecture. krok-linux-0.2.0.tar.gz is now krok-linux-x86_64-0.2.0.tar.gz, and so on. If you script the download URL, update it.

The install command changed:

curl -fsSL https://raw.githubusercontent.com/yantonov/krok/master/bin/install/install.sh | sh

Existing hooks report as outdated. The wrapper krok writes into .git/hooks/ changed (its shebang is now sh). Old wrappers keep working, so nothing breaks, but krok recover <hook-name> brings them in step. Any krok add for a hook rewrites its wrapper anyway.

Fixed

  • A job holding a path relative to the repository, such as ./scripts/check.sh, never ran. krok rewrote any command whose first word looked like a relative path into .git/hooks/, so the form the README suggests failed at every commit with a path pointing into the wrong directory. Commands now reach the shell exactly as written.
  • Hook arguments containing a space arrived split. They were pasted into the command as text, so a commit-msg path like my file.txt reached the job as two arguments. They are now passed as positional parameters, which also means nothing git puts in an argument is read as shell syntax.
  • krok add failed outright in a linked worktree or a submodule with "not inside a git repository". krok now asks git where things are instead of looking for a .git directory.
  • core.hooksPath was ignored, so hooks were written where git would not look for them.
  • Two different commands that derive the same key — cargo clippy -- -D warnings and cargo clippy -D warnings — could not both be registered; the second was refused as already registered. The second is now numbered. Registering the same command twice is still refused, and the message names the command.
  • The installer could ask for a release that was not published yet. It read the newest tag, but the release built from a tag stays a draft until published, so its assets 404. It now follows the latest published release.
  • The installer required jq, which is not present by default on macOS or a minimal Linux.
  • The README's install command was a guaranteed 404 — it named the old repository and a script path that predated the bin/install/ split.
  • install-from-source.sh printed a literal ${INSTALL_DIR} in its PATH hint, so the line it told you to copy put nothing on PATH.
  • The config was written in place, so an interrupted write could leave a half-written config. It is now written beside the config and moved onto it.

Added

  • krok config path prints the path of the config file in use.
  • Checksums. Each release asset is published with a .sha256 beside it, and the installer verifies the archive before unpacking it. The pair can also be checked by hand with sha256sum -c.
  • Builds for more architectures: linux aarch64, and both arm64 and x86_64 macOS. The macOS asset previously published was arm64 only, under a name that did not say so, so it could not run on an Intel Mac.
  • KROK_REPO_ROOT and KROK_HOOKS_DIR are exported to every job.
  • Jobs can read the arguments git passed individually, as $1, $2.
  • bin/install/install.sh, which resolves the release and then takes the installer script from that same release, so the script and the binary always come from one place.
  • bin/dev/tag-release.sh and bin/dev/release.sh.
  • A LICENSE file (Apache 2.0) and the author, description, repository and license fields in Cargo.toml. The project previously stated no terms at all.

Changed

  • Jobs start at the top level of the working tree, which is where git fires hooks from, whichever directory krok run was invoked from.
  • The binary is 47% smaller (1,142,272 → 606,208 bytes on Windows), built for size rather than speed.
  • Binaries install to ~/.local/bin rather than ~/bin.
  • Every script in bin/ is POSIX sh; none require bash.
  • The minimum supported Rust version is declared as 1.85 and checked on every build.
  • Preserved foreign hooks name themselves through $KROK_HOOKS_DIR in the config. Configs written by 0.1.0 keep working.

Internal

  • CI builds, lints and tests on Linux, Windows and macOS, and enforces clippy -D warnings and cargo fmt --check on each. Previously it built and tested on Linux only.
  • The archived actions-rs/toolchain, actions/checkout@v2 and a third-party tar action are gone; what remains is pinned.
  • 72 tests, up from 24: the integration suite grew, and the functions that only compute — key derivation, hook-name validation, wrapper state, path handling, command quoting — now have unit tests.