diff --git a/README.md b/README.md index ef5e3e2..d8933b8 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # rust-vmm-ci - The `rust-vmm-ci` repository contains [integration tests](#integration-tests) and [Buildkite pipeline](#buildkite-pipeline) definitions that are used for -running the CI for all rust-vmm crates. +running the CI for all rust-vmm crates, as well as [git hooks](#git-hooks) +to ensure quality and consistency with the rust-vmm commit message standards. CI tests are executed on the container image maintained at [rust-vmm/rust-vmm-container repo](https://github.com/rust-vmm/rust-vmm-container) with builds available on [Docker Hub](https://hub.docker.com/r/rustvmm/dev/tags). @@ -15,6 +15,7 @@ To run the integration tests defined in the pipeline as part of the CI: 1. Add rust-vmm-ci as a git submodule to your repository +Adding rust-vmm-ci to new repos: ```bash # Add rust-vmm-ci as a submodule. This will point to the latest rust-vmm-ci # commit from the main branch. The following command will also add a @@ -25,6 +26,12 @@ git submodule add https://github.com/rust-vmm/rust-vmm-ci.git git commit -s -m "Added rust-vmm-ci as submodule" ``` +Initializing rust-vmm-ci in cloned rust-vmm repos with existing +uninitialized rust-vmm-ci submodule: +```bash +git submodule update --init +``` + 2. Create the coverage test configuration file named `coverage_config_ARCH.json` in the root of the repository, where `ARCH` is the architecture of the machine. @@ -122,6 +129,33 @@ triggering the CI on and [push](https://developer.github.com/v3/activity/events/types/#pushevent) events. +## Git Hooks +To ensure consistency and quality across commit messages in your repository, rust-vmm-ci +includes git hooks located at `rust-vmm-ci/git-hooks/`. Hooks are programs +that trigger actions at certain points in git's execution. + +### Commit-Msg +This hook is designed to automatically check your commit messages against with the +rust-vmm commit message standards. + +To utilize this hook for checking commit messages in your local repository, follow +these steps: + +1. Copy the Hook +After adding rust-vmm-ci as a submodule, copy the commit-msg hook from the submodule's +git-hooks directory to your repository's .git/hooks directory. You can do this with +the following command from the root of your repository: + +```shell +cp rust-vmm-ci/git-hooks/commit-msg .git/hooks/ +``` + +2. Make the Hook Executable +For the hook to run, it must be executable. Change its permissions accordingly: +```shell +chmod +x .git/hooks/commit-msg +``` + ## Buildkite Pipeline The [Buildkite](https://buildkite.com) pipeline is the definition of tests to diff --git a/githooks/commit-msg b/githooks/commit-msg new file mode 100755 index 0000000..b6ab4cd --- /dev/null +++ b/githooks/commit-msg @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +""" +Commit-msg hook to check the commit message format. +Ensures commit messages do not have exceedingly long titles (maximum 60 characters for the title) +and that commits are signed. +""" + +import sys + +COMMIT_TITLE_MAX_LEN = 60 +COMMIT_BODY_LINE_MAX_LEN = 75 + +def get_commit_message(commit_msg_filepath): + """Retrieve the commit message from the provided file path.""" + with open(commit_msg_filepath, 'r') as file: + return file.read() + +def main(commit_msg_filepath): + message = get_commit_message(commit_msg_filepath) + message_lines = message.split("\n") + + # Check for long commit title + if not message_lines or len(message_lines[0]) > COMMIT_TITLE_MAX_LEN: + print(f"Error: Commit title is too long (maximum {COMMIT_TITLE_MAX_LEN} characters allowed). Title: '{message_lines[0]}'") + sys.exit(1) + + # Ensure there is a blank line following the title + if len(message_lines) < 3 or message_lines[1] != "": + error_line = "None" if len(message_lines) < 2 else message_lines[1] + print(f"Error: The commit message should contain at least 3 lines: title, blank line, and description/sign-off. Problematic line: '{error_line}'") + sys.exit(1) + + # Check for a signed-off message + found_signed_off = False + for line in message_lines[2:]: + if line.startswith("Signed-off-by: "): + found_signed_off = True + break + if len(line) > COMMIT_BODY_LINE_MAX_LEN: + print(f"Error: Line in commit body exceeds {COMMIT_BODY_LINE_MAX_LEN} characters. Line: '{line}'") + sys.exit(1) + + if not found_signed_off: + print("Error: Commit is not signed. Please sign off your commit by running 'git commit -s'.") + sys.exit(1) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Error: No commit message file path provided.") + sys.exit(1) + main(sys.argv[1]) +