amont_runtime/hooks/post_commit.rs
1//! post-commit — bind the pre-commit gate marker to the commit that now
2//! exists.
3//!
4//! The commit object does not exist while pre-commit runs, so this is the
5//! earliest moment "the checks ran" can be attached to a hash. git invokes
6//! post-commit even for `--no-verify` (the flag skips only pre-commit and
7//! commit-msg), which is exactly what makes the stamp trustworthy: a commit
8//! that dodged the checks arrives here with no marker and gets no stamp.
9//!
10//! Notification-only, like the hook itself: git ignores its exit code, so
11//! this never blocks, and it prints nothing — a bookkeeping step that talked
12//! on every commit would be noise nobody asked for. That includes the bypass
13//! ledger: a commit that dodged its gate is COUNTED here, silently — the
14//! number's whole value is that it is collected without a lecture. The
15//! mechanisms live in [`crate::gate_stamp`] and [`crate::bypass`]; this is
16//! only the hook-shaped door to them.
17
18use crate::check::Verdict;
19
20pub fn run(settings: &crate::config::Settings, ctx: &crate::registry::Ctx) -> Verdict {
21 let stamped = crate::gate_stamp::bind_to_head();
22 crate::bypass::note_unverified(ctx.settings, ctx.manifest, &stamped);
23 rehearse(settings, false);
24 Verdict::Proceed
25}
26
27/// The one thing post-commit says: that a background rehearsal of the push
28/// gate has started — only in a repository that asked for it
29/// (`amont.rehearseOnCommit`), and only outside a rebase or cherry-pick,
30/// where the commit being made is not the one that will be pushed and the
31/// next replay would cancel this run anyway. The worker itself decides
32/// whether there is anything to run; this only pays the spawn.
33///
34/// post-rewrite calls it too, once a rebase has FINISHED — the moment the
35/// rebased branch, which no stamp covers any more, first exists. It passes
36/// `after_rebase`: git runs post-rewrite with the branch already updated but
37/// BEFORE it removes `rebase-merge/`, so the in-progress guard would stand
38/// down on exactly the call it exists for.
39pub(crate) fn rehearse(settings: &crate::config::Settings, after_rebase: bool) {
40 if !crate::rehearsal::on_commit_enabled(settings)
41 || !crate::gate_stamp::push_stamps_enabled(settings)
42 {
43 return;
44 }
45 if !after_rebase && !crate::git_states_in_progress().is_empty() {
46 return;
47 }
48 match crate::rehearsal::spawn_detached() {
49 Ok(_) => println!("rehearsing the push gate in the background (`amont rehearse --status`)"),
50 Err(e) => crate::hooks::common::warn(&format!("could not start the rehearsal: {e}")),
51 }
52}