forked from scylladb/scylladb
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.github: add check-license-header workflow
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
Showing
2 changed files
with
125 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.` | ||
}) |