Skip to content

Commit

Permalink
.github: add check-license-header workflow
Browse files Browse the repository at this point in the history
this workflow checks the first 10 lines for
"LicenseRef-ScyllaDB-Source-Available-1.0" in newly introduced files
when a new pull request is created against "master" or "next".

if "LicenseRef-ScyllaDB-Source-Available-1.0" is not found, the
workflow fails. for the sake of simplicity, instead of parsing the
header for SPDX License ID, we just check to see if the
"LicenseRef-ScyllaDB-Source-Available-1.0" is included.

Signed-off-by: Kefu Chai <[email protected]>
  • Loading branch information
tchaikov committed Dec 27, 2024
1 parent 3e22998 commit 1d1fdd2
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 0 deletions.
74 changes: 74 additions & 0 deletions .github/scripts/check-license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env python3

import argparse
import sys
from pathlib import Path
from typing import Set


def parse_args() -> argparse.Namespace:
"""Parses command-line arguments."""
parser = argparse.ArgumentParser(description='Check license headers in files')
parser.add_argument('--files', required=True, nargs="+", type=Path,
help='List of files to check')
parser.add_argument('--license', required=True,
help='License to check for')
parser.add_argument('--check-lines', type=int, default=10,
help='Number of lines to check (default: %(default)s)')
parser.add_argument('--extensions', required=True, nargs="+",
help='List of file extensions to check')
parser.add_argument('--verbose', action='store_true',
help='Print verbose output (default: %(default)s)')
return parser.parse_args()


def should_check_file(file_path: Path, allowed_extensions: Set[str]) -> bool:
return file_path.suffix in allowed_extensions


def check_license_header(file_path: Path, license_header: str, check_lines: int) -> bool:
try:
with open(file_path, 'r', encoding='utf-8') as f:
for _ in range(check_lines):
line = f.readline()
if license_header in line:
return True
return False
except (UnicodeDecodeError, StopIteration):
# Handle files that can't be read as text or have fewer lines
return False


def main() -> int:
args = parse_args()

if not args.files:
print("No files to check")
return 0

num_errors = 0

for file_path in args.files:
# Skip non-existent files
if not file_path.exists():
continue

# Skip files with non-matching extensions
if not should_check_file(file_path, args.extensions):
print(f"ℹ️ Skipping file with unchecked extension: {file_path}")
continue

# Check license header
if check_license_header(file_path, args.license, args.check_lines):
if args.verbose:
print(f"✅ License header found in: {file_path}")
else:
print(f"❌ Missing license header in: {file_path}")
num_errors += 1

if num_errors > 0:
sys.exit(1)


if __name__ == '__main__':
main()
51 changes: 51 additions & 0 deletions .github/workflows/check-license-header.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: License Header Check

on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- master
- next

env:
HEADER_CHECK_LINES: 10
LICENSE: "LicenseRef-ScyllaDB-Source-Available-1.0"
CHECKED_EXTENSIONS: ".cc .hh .py"

jobs:
check-license-headers:
name: Check License Headers
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get changed files
id: changed-files
run: |
# Get list of added files comparing with base branch
echo "files=$(git diff --name-only --diff-filter=A ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | tr '\n' ' ')" >> $GITHUB_OUTPUT
- name: Check license headers
run: |
.github/scripts/check-license.py \
--files ${{ steps.changed-files.outputs.files }} \
--license "${{ env.LICENSE }}" \
--check-lines "${{ env.HEADER_CHECK_LINES }}" \
--extensions ${{ env.CHECKED_EXTENSIONS }}
- name: Comment on PR if check fails
if: failure()
uses: actions/github-script@v7
with:
script: |
const licenseHeader = '${{ env.LICENSE_HEADER }}';
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.name,
body: `❌ License header check failed. Please ensure all new files include the header within the first ${{ env.HEADER_CHECK_LINES }} lines:\n\`\`\`\n${licenseHeader}\n\`\`\`\nSee action logs for details.`
})

0 comments on commit 1d1fdd2

Please sign in to comment.