diff --git a/.github/workflows/commits.yml b/.github/workflows/commits.yml new file mode 100644 index 000000000..a8ffae010 --- /dev/null +++ b/.github/workflows/commits.yml @@ -0,0 +1,28 @@ +name: Check Commits + +on: + pull_request: + branches: master + +jobs: + signed-commits: + name: Check signed commits in PR + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Check signed commits in PR + uses: 1Password/check-signed-commits-action@v1 + conventional-commits: + name: Conventional Commits + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + # needs the full log + fetch-depth: 0 + # pick the pr HEAD instead of the merge commit + ref: ${{ github.event.pull_request.head.sha }} + - name: Check conventional commits in PR + uses: cocogitto/cocogitto-action@v3 + with: + check-latest-tag-only: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6a83ccf57..cf54d8ec1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -48,15 +48,42 @@ hesitate to split it into multiple small, focused PRs. The Minimal Supported Rust Version is **1.57.0** (enforced by our CI). -Commits should cover both the issue fixed and the solution's rationale. -These [guidelines](https://chris.beams.io/posts/git-commit/) should be kept in mind. Commit messages should follow the ["Conventional Commits 1.0.0"](https://www.conventionalcommits.org/en/v1.0.0/) to make commit histories easier to read by humans and automated tools. - To facilitate communication with other contributors, the project is making use of GitHub's "assignee" field. First check that no one is assigned and then comment suggesting that you're working on it. If someone is already assigned, don't hesitate to ask if the assigned party or previous commenter are still working on it if it has been awhile. +Commit policy +------------- + +Commits should be signed with GPG using a key with a valid email address. +Commits should cover both the issue fixed and the solution's rationale. +These [guidelines](https://chris.beams.io/posts/git-commit/) should be kept in mind. +Commit messages should follow the ["Conventional Commits 1.0.0"](https://www.conventionalcommits.org/en/v1.0.0/) +to make commit histories easier to read by humans and automated tools. +Commits starting with `Merge ...` which GitHub automatically generates +are exempt from this rule. +You can use tools like [`cocogitto`](https://github.com/cocogitto/cocogitto) +to check if your commit messages follow the convention. + +[Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) can be used +to automate some of the above checks. +There are hooks provided in the `ci/git-hooks` directory that can be installed: + +```bash +cp ci/git-hooks/signed-commits.sh .git/hooks/pre-push +cp ci/git-hooks/conventional-commits.sh .git/hooks/commit-msg +``` + +`signed-commits.sh` hook (a `pre-push` hook) +will not allow the user to push to remote if the last commit is not signed. +This is a good sanity test, +if the last commit is signed then there is a high chance +of any other previous are also signed. +`conventional-commits.sh` hook (a `commit-msg` hook) will not allow the user to commit +if the commit message does not satisfy the Conventional Commits template. + Deprecation policy ------------------ diff --git a/ci/git-hooks/conventional-commits.sh b/ci/git-hooks/conventional-commits.sh new file mode 100755 index 000000000..9bdefda78 --- /dev/null +++ b/ci/git-hooks/conventional-commits.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Conventional commit regex pattern +# bash regex do not support \w \d \s etc +pattern="^(build|ci|docs|feat|fix|perf|refactor|style|test|chore|revert)(\([[:alnum:]\-]+\))?:[[:space:]].*" + +# Read the commit message from the file +commit_file="$1" +commit_head_message=$(head -n1 "$commit_file") + +# Check if the commit message matches the pattern +if ! [[ "$commit_head_message" =~ $pattern ]]; then + echo "Error: Invalid commit message format. Please use a conventional commit message." + echo "Commit message should match the pattern: $pattern." + echo "Please refer to https://www.conventionalcommits.org/en/v1.0.0/ for more details." + exit 1 +fi + +# If the commit message matches the pattern, the hook exits successfully +exit 0 diff --git a/ci/git-hooks/signed-commits.sh b/ci/git-hooks/signed-commits.sh new file mode 100755 index 000000000..ca77afdd2 --- /dev/null +++ b/ci/git-hooks/signed-commits.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Function to verify the signature of the last commit +verify_signature() { + local commit_hash=$(git rev-parse HEAD) + if ! git verify-commit "$commit_hash"; then + echo "Error: Last commit ($commit_hash) is not signed." + exit 1 + fi +} + +# Verify the signature of the last commit +verify_signature + +# Allow the push to proceed if the signature is valid +exit 0 diff --git a/cog.toml b/cog.toml new file mode 100644 index 000000000..ff35ebd0b --- /dev/null +++ b/cog.toml @@ -0,0 +1 @@ +ignore_merge_commits = true