commit f87d6bd4c8242eca92b03c6948e66e29820befd1 Author: Sven van Heugten Date: Fri Feb 20 15:55:21 2026 +0100 Initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..165238e --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Sven van Heugten + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..58f79f7 --- /dev/null +++ b/README.md @@ -0,0 +1,51 @@ +# git-check-assertions + +🚧 Merely a proof-of-concept right now. + +I recently wrote two blogs posts arguing that there might be some value in writing verifiable claims, i.e. assertions, inside of our commit messages: + +* [Should we start writing verifiable claims in commit message?](https://sven.memcmp.org/2026-02-19-should-we-start-writing-verifiable-claims-in-commit-messages/) +* [Writing the steps to validate a test in the commit message](https://sven.memcmp.org/2026-02-20-writing-the-steps-to-validate-a-test-in-the-commit-message/) + +This is a simple verifier for such assertions. + +You include a small bash script inside your commit messages, and `git-check-assertions` will then check out every commit (from the point that your branch diverged from `main`), and verify that the script in the commit message runs successfully. + +⚠️ Only run this on repositories and branches that you trust, since the `bash` scripts in the commit messages can do whatever they want. + +## Examples of commit messages + +Assert that a commit builds: + +~~~ +```git-check-assertions +dotnet build +``` +~~~ + +Assert that a commit builds and that the tests succeed: + +~~~ +```git-check-assertions +dotnet build +dotnet test --no-build +``` +~~~ + +Assert that a commit builds, but that the tests do not succeed (`assert_fails` is a helper function included in `git-check-assertions`): + +~~~ +```git-check-assertions +dotnet build +assert_fails dotnet test --no-build +``` +~~~ + +Assert that a commit builds, and that the tests fail with exactly the error that you expect: + +~~~ +```git-check-assertions +dotnet build +(assert_fails dotnet test --no-build) | grep "Invalid URL" +``` +~~~ diff --git a/git-check-assertions.sh b/git-check-assertions.sh new file mode 100755 index 0000000..1acab64 --- /dev/null +++ b/git-check-assertions.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +# Copyright (c) 2026 Sven van Heugten +# +# Repository: https://codeberg.org/svenvanheugten/git-check-assertions +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +set -euo pipefail + +assert_fails() { + ! "$@" || { echo "Expected command to fail, but it succeeded."; exit 1; } +} +export -f assert_fails + +orig_ref="$(git symbolic-ref --quiet --short HEAD || git rev-parse HEAD)" +base="$(git merge-base main HEAD)" +mapfile -t commits < <(git rev-list --reverse "${base}..HEAD") + +echo "Base: $base" +echo "Commits to visit: ${#commits[@]}" +echo + +for commit_hash in "${commits[@]}"; do + echo "Checking out $commit_hash" + git -c advice.detachedHead=false checkout -q "$commit_hash" + commit_msg="$(git log -1 --format=%B "$commit_hash")" + block="$(printf '%s\n' "$commit_msg" \ + | sed -n '/^```git-check-assertions[[:space:]]*$/,/^```[[:space:]]*$/p' \ + | sed '1d;$d')" + if [ -n "$block" ]; then + echo "git-check-assertions block in $commit_hash:" + printf '%s\n' "$block" | sed 's/^/> /' + if ! bash -euo pipefail -c "$block"; then + echo "git-check-assertions block failed in $commit_hash" >&2 + echo "Returning to $orig_ref" + git checkout -q "$orig_ref" + exit 1 + fi + fi + echo +done + +echo +echo "Returning to $orig_ref" +git checkout -q "$orig_ref"