diff --git a/.github/workflows/commit-messages.yml b/.github/workflows/commit-messages.yml index 3a1abfaffd1..1ab2cf2bfe4 100644 --- a/.github/workflows/commit-messages.yml +++ b/.github/workflows/commit-messages.yml @@ -30,13 +30,15 @@ jobs: git fetch origin ${{ github.event.pull_request.head.sha }}:${{ github.event.pull_request.head.ref }} git checkout ${{ github.event.pull_request.head.ref }} - - name: Set up Node.js - uses: actions/setup-node@v3 - with: - node-version: '21' - - - name: Install Commitlint - run: npm install @commitlint/config-conventional @commitlint/cli + - name: Create virtual environment + run: | + cd tools/check-commit-messages + python3 -m venv .venv + source .venv/bin/activate + pip install -r requirements.txt - - name: Run Commitlint - run: npx commitlint --from=origin/master --to=HEAD --config .commitlintrc.yml + - name: Lint commit messages + run: | + cd tools/check-commit-messages + source .venv/bin/activate + python check_commit_messages.py diff --git a/tools/check-commit-messages/.gitignore b/tools/check-commit-messages/.gitignore new file mode 100644 index 00000000000..5ceb3864c29 --- /dev/null +++ b/tools/check-commit-messages/.gitignore @@ -0,0 +1 @@ +venv diff --git a/tools/check-commit-messages/check_commit_messages.py b/tools/check-commit-messages/check_commit_messages.py new file mode 100644 index 00000000000..40650f1a052 --- /dev/null +++ b/tools/check-commit-messages/check_commit_messages.py @@ -0,0 +1,63 @@ +""" +This script checks the commit messages in the current branch to ensure they follow the +recommended format. The recommended format is as follows: +* Commit message should have a subject and body +* An empty line should separate the subject and body +* The body should not be empty (it should contain more than just "Signed-off-by") +""" + +import git +import sys + +def check_commit_message(commit): + message_lines = commit.message.strip().splitlines() + + if len(message_lines) < 2: + return False, f"Commit {commit.hexsha} has no body." + + subject = message_lines[0].strip() + second_line = message_lines[1].strip() + + if not subject: + return False, f"Commit {commit.hexsha} has no subject." + + # Check if the second line is empty (indicating a blank line between subject and body) + if second_line: + return False, f"Commit {commit.hexsha} does not have an empty line between the subject and body." + + # Remove the subject and empty line to get the body + body_lines = [line.strip() for line in message_lines[2:] if line.strip()] + + # Remove lines that are just "Signed-off-by" + body_lines = [line for line in body_lines if not line.lower().startswith("signed-off-by")] + + if not body_lines: + return False, f"Commit {commit.hexsha} has a body but only contains Signed-off-by." + + return True, None + + +def main(): + repo = git.Repo(search_parent_directories=True) + + # Fetch the latest from origin/master to ensure we are comparing correctly + repo.remotes.origin.fetch('master') + + commits = list(repo.iter_commits('origin/master..HEAD')) + + if not commits: + print("No commits between origin/master and HEAD.") + sys.exit(1) + + print(f"Checking {len(commits)} commits between origin/master and HEAD...") + + for commit in commits: + valid, error_message = check_commit_message(commit) + if not valid: + print(error_message) + sys.exit(1) + + print("All commits are valid.") + +if __name__ == "__main__": + main() diff --git a/tools/check-commit-messages/requirements.txt b/tools/check-commit-messages/requirements.txt new file mode 100644 index 00000000000..dba1edf678b --- /dev/null +++ b/tools/check-commit-messages/requirements.txt @@ -0,0 +1,3 @@ +gitdb==4.0.11 +GitPython==3.1.43 +smmap==5.0.1