Skip to content

Commit fa00f9a

Browse files
committed
ci: add local pre-commit DCO hook and setup command
Enforce the DCO sign-off locally so contributors catch a missing Signed-off-by before CI, alongside the existing black/isort/ruff formatting hooks. - .pre-commit-config.yaml: install the commit-msg hook by default (default_install_hook_types) and add a local DCO check hook. - .github/hooks/check-dco.sh: commit-msg hook that fails when the Signed-off-by line is missing. - runtests.sh: new --setup option that runs 'pre-commit install'. - CONTRIBUTING.md: document installing the hooks and the DCO check. Related to #9058 and #8683. Signed-off-by: R. Garcia-Dias <rafaelagd@gmail.com>
1 parent c0d1ec1 commit fa00f9a

4 files changed

Lines changed: 78 additions & 2 deletions

File tree

.github/hooks/check-dco.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/usr/bin/env bash
2+
# DCO sign-off check for the pre-commit commit-msg stage.
3+
#
4+
# Mirrors the GitHub DCO app requirement: every commit must carry a
5+
# "Signed-off-by:" line identifying the author.
6+
#
7+
# Usage: check-dco.sh <commit-message-file>
8+
9+
set -euo pipefail
10+
11+
msg_file="${1:-}"
12+
13+
if [[ -z "${msg_file}" || ! -f "${msg_file}" ]]; then
14+
echo "DCO check: no commit message file supplied." >&2
15+
exit 1
16+
fi
17+
18+
if grep -qE '^Signed-off-by: .+ <[^@ ]+@[^@ ]+>$' "${msg_file}"; then
19+
exit 0
20+
fi
21+
22+
cat >&2 <<'EOF'
23+
DCO check failed: commit message is missing a "Signed-off-by:" line.
24+
25+
Add a sign-off using one of:
26+
git commit -s # sign as you create the commit
27+
git commit --amend -s # sign the most recent commit
28+
29+
The line must identify the commit author, for example:
30+
Signed-off-by: Your Name <you@example.com>
31+
EOF
32+
33+
exit 1

.pre-commit-config.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
default_language_version:
22
python: python3
33

4+
default_install_hook_types: [pre-commit, commit-msg]
5+
46
ci:
57
autofix_prs: true
68
autoupdate_commit_msg: '[pre-commit.ci] pre-commit suggestions'
@@ -62,3 +64,10 @@ repos:
6264
^versioneer.py|
6365
^monai/_version.py
6466
)
67+
- repo: local
68+
hooks:
69+
- id: dco
70+
name: DCO sign-off
71+
entry: .github/hooks/check-dco.sh
72+
language: script
73+
stages: [commit-msg]

CONTRIBUTING.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,19 @@ To collaborate efficiently, please read through this section and follow them.
5151

5252
#### Checking the coding style
5353

54-
Coding style is checked and enforced by black, isort, and ruff.
54+
Coding style is checked and enforced by black, isort, and ruff, and every commit must carry a DCO sign-off.
55+
To catch formatting and DCO failures before they reach CI, install the git pre-commit hooks once per checkout:
56+
57+
```bash
58+
# install the git hooks: black, isort, ruff, and the DCO sign-off check
59+
pre-commit install
60+
61+
# or, via the test runner:
62+
./runtests.sh --setup
63+
```
64+
65+
These hooks run automatically on every `git commit`: `black`, `isort`, and `ruff` reformat the staged files, and the `commit-msg` hook blocks a commit that is missing a `Signed-off-by` line.
66+
5567
Before submitting a pull request, we recommend that all linting should pass, by running the following command locally:
5668

5769
```bash
@@ -247,6 +259,8 @@ Git has a `-s` (or `--signoff`) command-line option to append this automatically
247259
git commit -s -m 'a new commit'
248260
```
249261

262+
If the git pre-commit hooks are installed (`pre-commit install` or `./runtests.sh --setup`), the local `commit-msg` hook blocks any commit that is missing this line, so the DCO check fails locally rather than in CI.
263+
250264
The commit message will be:
251265

252266
```

runtests.sh

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ doPyreflyFormat=false
5353
doCleanup=false
5454
doDistTests=false
5555
doPrecommit=false
56+
doSetup=false
5657
testTimeout=0
5758

5859
NUM_PARALLEL=1
@@ -61,7 +62,7 @@ PY_EXE=${MONAI_PY_EXE:-$(which python)}
6162

6263
function print_usage {
6364
echo "runtests.sh [--codeformat] [--autofix] [--black] [--isort] [--pylint] [--ruff]"
64-
echo " [--clangformat] [--precommit] [--pytype] [-j number] [--pyrefly]"
65+
echo " [--clangformat] [--precommit] [--pytype] [-j number] [--pyrefly] [--setup]"
6566
echo " [--unittests] [--disttests] [--coverage] [--quick] [--min] [--net] [--build] [--list_tests]"
6667
echo " [--dryrun] [--copyright] [--clean] [--help] [--version] [--path] [--formatfix]"
6768
echo ""
@@ -103,6 +104,7 @@ function print_usage {
103104
echo ""
104105
echo "Misc. options:"
105106
echo " --dryrun : display the commands to the screen without running"
107+
echo " --setup : install git pre-commit hooks (black, isort, ruff, DCO sign-off)"
106108
echo " --copyright : check whether every source code has a copyright header"
107109
echo " -f, --codeformat : shorthand to run all code style and static analysis tests"
108110
echo " -c, --clean : clean temporary files from tests and exit"
@@ -320,6 +322,9 @@ do
320322
--precommit)
321323
doPrecommit=true
322324
;;
325+
--setup)
326+
doSetup=true
327+
;;
323328
--pytype)
324329
echo "${yellow}WARNING: --pytype is deprecated and may be removed in a future release.${noColor}"
325330
doPytypeFormat=true
@@ -429,6 +434,21 @@ then
429434
echo "${green}done!${noColor}"
430435
fi
431436

437+
if [ $doSetup = true ]
438+
then
439+
echo "${separator}${blue}setup${noColor}"
440+
441+
# ensure pre-commit is available
442+
if ! is_pip_installed pre_commit
443+
then
444+
install_deps
445+
fi
446+
447+
${cmdPrefix}"${PY_EXE}" -m pre_commit install
448+
449+
echo "${green}done! git hooks installed (black, isort, ruff, DCO sign-off).${noColor}"
450+
fi
451+
432452
# unconditionally report on the state of monai
433453
print_version
434454

0 commit comments

Comments
 (0)