Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/quality_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ jobs:
quality-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: actions/setup-python@v6
- uses: actions/checkout@v7
- uses: actions/setup-python@v7
with:
python-version: "3.11"
- name: Install dependencies
Expand Down
16 changes: 10 additions & 6 deletions .github/workflows/status_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,23 @@ jobs:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
steps:
- uses: actions/checkout@v6
- uses: actions/checkout@v7
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
- uses: actions/setup-python@v6
- uses: actions/setup-python@v7
with:
python-version: "3.11"
- name: Get the commit message
run: |
echo 'commit_message<<EOF' >> $GITHUB_ENV
git log --format=%B -n 1 ${{ github.event.after }} >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV
delimiter="$(python -c 'import uuid; print(uuid.uuid4())')"
{
echo "commit_message<<${delimiter}"
git log --format=%B -n 1 HEAD
echo "${delimiter}"
} >> "$GITHUB_ENV"
shell: bash
- uses: ccdc-opensource/commit-hooks@main
- uses: ./
with:
commitMessage: ${{ env.commit_message }}
licenseCheck: true
108 changes: 66 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
This repository contains files that can be used as a github action and local
git hooks.
This repository provides code quality and compliance tooling for CCDC repositories:

It does a few checks on source code to ensure compliance with some general
CCDC coding standard.
1. **Native Git Hooks** (`main/`): Local hooks configured globally (`commit-msg`, `pre-commit`, `pre-merge-commit`) for standard Git workflows.
2. **GitHub Action** (`action.yml`): Composite GitHub Action for CI workflows to validate copyright headers and repository compliance on PRs/commits.

It does a few checks on source code to ensure compliance with general CCDC coding standards.

The commit will be flagged if it includes certain text files with:

Expand All @@ -12,59 +13,82 @@ The commit will be flagged if it includes certain text files with:
* Tabs
* Missing terminating newline for certain files
* Certain C++ #include patterns and std::exception
* Missing or non-compliant CCDC copyright and license headers (when using the GitHub Action or local copywrite integration)

The commit will also be flagged if the commit message does not include a Jira
ID (unless marked with NO_JIRA or a Copilot Autofix co-author line), or if the
size of new or modified files exceeds a threshold.


# Github action
# GitHub Actions

This repository provides a composite GitHub Action for validating copyright
headers and file compliance rules in CI.

## Usage

```yaml
Comment thread
mmaharjan-ccdc marked this conversation as resolved.
- uses: ccdc-opensource/commit-hooks@v7
- name: Checkout repository
uses: actions/checkout@v7
with:
commitMessage: 'The commit message'
```
ref: ${{ github.event_name == 'pull_request' && github.head_ref || github.ref }}
fetch-depth: 0

## Scenarios
### Check files in pull request for merge to main
```yaml
name: Check pull request files
on:
pull_request
branches: [ main ]
jobs:
Pull-request-files-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
ref: ${{ github.head_ref }}
fetch-depth: 0
- uses: actions/setup-python@v6
with:
python-version: "3.11"
- name: Get the commit message
run: |
echo "commit_message=$(git log --format=%B -n 1 ${{ github.event.after }})" >> $GITHUB_ENV
shell: bash
- uses: ccdc-opensource/commit-hooks@v7
with:
commitMessage: ${{ env.commit_message }}
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: "3.11"

- name: Extract commit message
shell: bash
run: |
delimiter="$(python -c 'import uuid; print(uuid.uuid4())')"
{
echo "commit_message<<${delimiter}"
git log --format=%B -n 1 HEAD
echo "${delimiter}"
} >> "$GITHUB_ENV"

- uses: ccdc-opensource/commit-hooks@v8
with:
commitMessage: ${{ env.commit_message }}
# Optional: enable CCDC license header validation on PR changed files
licenseCheck: true # default: false (opt-in)
```

# commit-hooks
You can use this as git hooks for local repositories.
A complete workflow template for CI is available in [templates/compliance.yml](templates/compliance.yml).

# Native Git Hooks

To enable CCDC commit checks (Jira ID, CRLF, line endings, DO NOT COMMIT, file size, and automatic copyright headers) globally for all repositories on your machine:

1. Clone this repository.
2. Run:
```bash
git config --global core.hooksPath <path-to-cloned-repo>/main
```
3. (Optional) Install `copywrite` to automatically add and format CCDC copyright headers on commit:
* **Windows:** `choco install copywrite`
* **macOS:** `brew install hashicorp/tap/copywrite`
* **Linux:** `go install github.com/hashicorp/copywrite@latest`

> **Note:** If `copywrite` is not installed on your machine, native hooks will continue to run all other standard checks and display a gentle warning without failing your commit.

## Configuring Copywrite Behavior

Developers can customise the copywrite hook using Git configuration:

A set of hooks include:
* commit-msg
* pre-commit
* pre-merge-commit
* **Enable / Disable Copywrite:**
```bash
git config --global hooks.copywrite true # opt-in: enable copywrite integration
git config --global hooks.copywrite false # default: disabled
```

## Setting up
1. Clone this repo
1. `git config --global core.hooksPath <this repo location>/main`
* **Set Mode (`fix` vs `check`):**
```bash
git config --global hooks.copywriteMode fix # default: automatically inserts/updates headers on commit
git config --global hooks.copywriteMode check # read-only check (warns/fails if headers are missing)
```

## Recommended settings
### To ensure the line endings are correctly converted:
Expand Down
95 changes: 91 additions & 4 deletions action.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,104 @@
#
# This code is Copyright (C) 2026 The Cambridge Crystallographic Data Centre (CCDC)
# of 12 Union Road, Cambridge CB2 1EZ, UK and a proprietary work of CCDC. This
# code may not be used, reproduced, translated, modified, disassembled or
# copied, except in accordance with a valid licence agreement with CCDC and
# may NOT be disclosed or redistributed in any form, either in whole or in
# part, to any third party. All copies of this code made in accordance with a
# valid licence agreement as referred to above must contain this copyright
# notice.
#
# No representations, warranties, or liabilities are expressed or implied in
# the supply of this code by CCDC, its servants or agents, except where such
# exclusion or limitation is prohibited, void or unenforceable under governing
# law.
#
name: CCDC File Checks
author: CCDC
description: Check changed files for compliance
inputs:
commitMessage:
description: 'The commit message'
required: true
licenseCheck:
description: 'Validate CCDC copyright and license headers on changed files (true/false)'
required: false
default: 'false'
runs:
using: "composite"
using: composite
steps:
- run: python3 $GITHUB_ACTION_PATH/main.py
- name: Install copywrite
if: ${{ inputs.licenseCheck == 'true' }}
uses: hashicorp/setup-copywrite@v1.1.3

- name: Validate Header Compliance
if: ${{ inputs.licenseCheck == 'true' }}
shell: bash
env:
COPYWRITE_HOOK_ROOT: ${{ github.action_path }}
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
run: |
copywrite --version

CHANGED_FILES=()
if [ "${GITHUB_EVENT_NAME:-}" = "pull_request" ] && [ -n "${GITHUB_BASE_REF:-}" ]; then
DIFF_REF="origin/${GITHUB_BASE_REF}"
if ! git rev-parse --verify "$DIFF_REF" >/dev/null 2>&1; then
DIFF_REF="remotes/origin/${GITHUB_BASE_REF}"
fi
if ! git rev-parse --verify "$DIFF_REF" >/dev/null 2>&1; then
DIFF_REF="${GITHUB_BASE_REF}"
fi
if ! git rev-parse --verify "$DIFF_REF" >/dev/null 2>&1; then
echo "Unable to resolve pull request base ref: ${GITHUB_BASE_REF}" >&2
exit 1
fi
while IFS= read -r file; do
[ -n "$file" ] && CHANGED_FILES+=("$file")
done < <(git diff --name-only --diff-filter=d "${DIFF_REF}...HEAD")
elif [ "${GITHUB_EVENT_NAME:-}" = "push" ]; then
if [[ "${GITHUB_EVENT_BEFORE:-}" =~ ^0+$ ]]; then
while IFS= read -r file; do
[ -n "$file" ] && CHANGED_FILES+=("$file")
done < <(git diff-tree --root --no-commit-id --name-only --diff-filter=d -r HEAD)
else
if [ -z "${GITHUB_EVENT_BEFORE:-}" ] || ! git rev-parse --verify "${GITHUB_EVENT_BEFORE}^{commit}" >/dev/null 2>&1; then
echo "Unable to resolve push baseline: ${GITHUB_EVENT_BEFORE:-<empty>}" >&2
exit 1
fi
while IFS= read -r file; do
[ -n "$file" ] && CHANGED_FILES+=("$file")
done < <(git diff --name-only --diff-filter=d "${GITHUB_EVENT_BEFORE}..HEAD")
fi
elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then
while IFS= read -r file; do
[ -n "$file" ] && CHANGED_FILES+=("$file")
done < <(git diff --name-only --diff-filter=d HEAD^..HEAD)
else
while IFS= read -r file; do
[ -n "$file" ] && CHANGED_FILES+=("$file")
done < <(git diff-tree --root --no-commit-id --name-only --diff-filter=d -r HEAD)
fi

if [ ${#CHANGED_FILES[@]} -gt 0 ]; then
echo "Checking ${#CHANGED_FILES[@]} changed file(s) for header compliance..."
copywrite headers \
--config "$GITHUB_ACTION_PATH/main/copywrite/.copywrite.hcl" \
--plan \
-- \
"${CHANGED_FILES[@]}"
Comment thread
Copilot marked this conversation as resolved.
else
echo "No added or modified files found to check for header compliance."
fi

- name: Run file compliance check
shell: bash
env:
INPUT_COMMITMESSAGE: ${{ inputs.commitMessage }}
GITHUB_EVENT_BEFORE: ${{ github.event.before }}
run: |
python3 "$GITHUB_ACTION_PATH/main.py"

branding:
icon: 'check-square'
color: 'green'
icon: check-square
color: green
15 changes: 15 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
#!/usr/bin/env python3
#
# This code is Copyright (C) 2026 The Cambridge Crystallographic Data Centre (CCDC)
# of 12 Union Road, Cambridge CB2 1EZ, UK and a proprietary work of CCDC. This
# code may not be used, reproduced, translated, modified, disassembled or
# copied, except in accordance with a valid licence agreement with CCDC and
# may NOT be disclosed or redistributed in any form, either in whole or in
# part, to any third party. All copies of this code made in accordance with a
# valid licence agreement as referred to above must contain this copyright
# notice.
#
# No representations, warranties, or liabilities are expressed or implied in
# the supply of this code by CCDC, its servants or agents, except where such
# exclusion or limitation is prohibited, void or unenforceable under governing
# law.
#
'''
This is a github action entry point.

Expand Down
15 changes: 15 additions & 0 deletions main/commit-msg.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,19 @@
#!/usr/bin/env python3
#
# This code is Copyright (C) 2026 The Cambridge Crystallographic Data Centre (CCDC)
# of 12 Union Road, Cambridge CB2 1EZ, UK and a proprietary work of CCDC. This
# code may not be used, reproduced, translated, modified, disassembled or
# copied, except in accordance with a valid licence agreement with CCDC and
# may NOT be disclosed or redistributed in any form, either in whole or in
# part, to any third party. All copies of this code made in accordance with a
# valid licence agreement as referred to above must contain this copyright
# notice.
#
# No representations, warranties, or liabilities are expressed or implied in
# the supply of this code by CCDC, its servants or agents, except where such
# exclusion or limitation is prohibited, void or unenforceable under governing
# law.
#
'''
A hook to check commit massage.

Expand Down
37 changes: 37 additions & 0 deletions main/copywrite/.copywrite.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
schema_version = 1

project {
copyright_holder = "The Cambridge Crystallographic Data Centre (CCDC)"

header_ignore = [
".git/**",
".github/**",
"test/**",
"tests/**",
"templates/**",
"**/bin/**",
"**/obj/**",
"**/packages/**",
"**/node_modules/**",
"**/dist/**",
"**/build/**",
"**/.venv/**",
"**/venv/**",
"**/__pycache__/**",
"**/*.Designer.cs",
"**/*.g.cs",
"**/*.generated.*",
"**/*.min.js",
"**/*.lock",
]
}

rule {
paths = ["**/*.py", "**/*.sh", "**/*.bash", "**/*.yaml", "**/*.yml"]
license_header = "${COPYWRITE_HOOK_ROOT}/main/copywrite/headers/ccdc_hash.tmpl"
}

rule {
paths = ["**/*.js", "**/*.ts", "**/*.cs", "**/*.cpp", "**/*.cxx", "**/*.cc", "**/*.h", "**/*.hpp"]
license_header = "${COPYWRITE_HOOK_ROOT}/main/copywrite/headers/ccdc_slash.tmpl"
}
15 changes: 15 additions & 0 deletions main/copywrite/headers/ccdc_hash.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#
# This code is Copyright (C) {{ .Year }} The Cambridge Crystallographic Data Centre (CCDC)
# of 12 Union Road, Cambridge CB2 1EZ, UK and a proprietary work of CCDC. This
# code may not be used, reproduced, translated, modified, disassembled or
# copied, except in accordance with a valid licence agreement with CCDC and
# may NOT be disclosed or redistributed in any form, either in whole or in
Comment thread
mmaharjan-ccdc marked this conversation as resolved.
# part, to any third party. All copies of this code made in accordance with a
# valid licence agreement as referred to above must contain this copyright
# notice.
#
# No representations, warranties, or liabilities are expressed or implied in
# the supply of this code by CCDC, its servants or agents, except where such
# exclusion or limitation is prohibited, void or unenforceable under governing
# law.
#
15 changes: 15 additions & 0 deletions main/copywrite/headers/ccdc_slash.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//
// This code is Copyright (C) {{ .Year }} The Cambridge Crystallographic Data Centre (CCDC)
// of 12 Union Road, Cambridge CB2 1EZ, UK and a proprietary work of CCDC. This
// code may not be used, reproduced, translated, modified, disassembled or
// copied, except in accordance with a valid licence agreement with CCDC and
// may NOT be disclosed or redistributed in any form, either in whole or in
Comment thread
mmaharjan-ccdc marked this conversation as resolved.
// part, to any third party. All copies of this code made in accordance with a
// valid licence agreement as referred to above must contain this copyright
// notice.
//
// No representations, warranties, or liabilities are expressed or implied in
// the supply of this code by CCDC, its servants or agents, except where such
// exclusion or limitation is prohibited, void or unenforceable under governing
// law.
//
Loading
Loading