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
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ and best practices for agents to follow.

## Standards

- Conventional Commits: app/usage-rules.md — enforced by the `commit-msg` hook
at `githooks/commit-msg` (run `git config core.hooksPath githooks` once per
clone to activate it).
- Conventional Commits: app/usage-rules.md — enforced by the `commit-msg`
and `pre-push` hooks at `githooks/` (run `mix setup` once per clone to
activate them).

<!-- usage-rules-start -->
<!-- ash-start -->
Expand Down
5 changes: 2 additions & 3 deletions Readme.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,11 @@ $ lproj list --mine
== Development

First, activate the repo's git hooks (enforces conventional-commit subjects
before you even push):
on every commit, and again on every commit about to be pushed):
Comment on lines 333 to +334

[source,sh]
----
$ cd app
$ mise exec -- mix githooks.install
$ mix setup
----

The project uses ExUnit and `mix format`. Run tests with:
Expand Down
21 changes: 0 additions & 21 deletions app/lib/mix/tasks/githooks.install.ex

This file was deleted.

15 changes: 9 additions & 6 deletions app/usage-rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,12 @@
- Use the imperative, present tense in the description (`add`, not `added`/`adds`).
- Mark breaking changes with `!` before the colon (e.g. `feat!: ...`).
- Bare `Merge branch ...` subjects are rejected — reword as `chore: Merge branch ...`.
- Enforced locally by the `commit-msg` hook at `githooks/commit-msg`, which
delegates to `ci/validate_conventional_commit.sh` — run
`git config core.hooksPath githooks` once per clone to activate it.
- Enforced in CI across a whole PR's commit range by `ci/conventional_commits.sh`
(same validator, run per-commit; skips GitHub's own auto-generated
update-branch merge commits).
- Enforced locally by the `commit-msg` hook at `githooks/commit-msg` (each
commit's own subject, via `ci/validate_conventional_commit.sh`) and the
`pre-push` hook at `githooks/pre-push` (every commit about to be pushed,
via `ci/conventional_commits.sh` - catches anything that slipped past
`commit-msg`, e.g. a commit made before the hooks were installed) — run
`mix setup` once per clone to activate both.
- Enforced in CI across a whole PR's commit range by the same
`ci/conventional_commits.sh` the `pre-push` hook uses (skips GitHub's own
auto-generated update-branch merge commits).
9 changes: 9 additions & 0 deletions githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
# Enforces Conventional Commits on every commit about to be pushed, not
# just whatever commit-msg already checked at commit time (catches a
# commit made before this hook was installed, an amend, a rebase, etc.).
# See app/usage-rules.md for the rule. Activate with:
# git config core.hooksPath githooks
Comment on lines +5 to +6

repo_top=$(git rev-parse --show-toplevel) || exit 1
exec "$repo_top/ci/conventional_commits.sh"
28 changes: 28 additions & 0 deletions lib/mix/tasks/git_hooks.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Mix.Tasks.GitHooks do
@shortdoc "Installs this repo's git hooks (commit-msg, pre-push - Conventional Commits)"

@moduledoc """
#{@shortdoc}.

mix git_hooks

Sets `core.hooksPath` to `githooks/` (this repo's own `commit-msg` and
`pre-push` hooks, both enforcing Conventional Commits via
`ci/validate_conventional_commit.sh`/`ci/conventional_commits.sh`) -
the same one-line `git config` this repo's docs already told you to run
by hand, just idempotent and easy to re-run. Safe to run repeatedly:
setting the same git config value twice is a no-op. Wired into
`mix setup` - see that task.
"""

use Mix.Task

alias RepoTasks.Shell

@impl Mix.Task
def run(_argv) do
Shell.run!("git", ["config", "core.hooksPath", "githooks"])
Mix.shell().info("==> Git hooks installed (core.hooksPath = githooks)")
:ok
end
end
21 changes: 21 additions & 0 deletions lib/mix/tasks/setup.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule Mix.Tasks.Setup do
@shortdoc "Sets up this repo for development"

@moduledoc """
#{@shortdoc}.

mix setup

Runs every one-time/idempotent setup step this repo needs. Currently
just `mix git_hooks` - expected to grow (e.g. app/'s own `mix deps.get`)
as more repo-management tasks land here.
"""

use Mix.Task

@impl Mix.Task
def run(_argv) do
Mix.Task.run("git_hooks")
:ok
end
end