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
27 changes: 27 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: 'lint'

# Lints the Python code with ruff, configured in pyproject.toml, and checks the license
# headers of the source files.

on:
push:
pull_request:
workflow_dispatch:

jobs:

lint:
runs-on: ubuntu-24.04
name: '馃Ч ruff 路 license headers'
steps:

- name: '馃О Checkout'
uses: actions/checkout@v4

- name: '馃Ч ruff check'
run: pipx run ruff==0.17.0 check --output-format=github

# Also when ruff fails, so that one run reports both
- name: '馃摐 License headers'
if: ${{ !cancelled() }}
run: python3 tools/check_license_headers.py
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,14 @@ vunit_python_bridge = [
[tool.black]
line-length = 120

[tool.ruff]
line-length = 120

[tool.ruff.lint]
# pyflakes and pycodestyle errors and warnings. Listed explicitly so that a new ruff release
# doesn't change the rules.
select = ["E", "F", "W"]

[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
2 changes: 1 addition & 1 deletion src/vunit_python_bridge/native/vhpi/python_pkg.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com
// Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com

#include "python_pkg.h"

Expand Down
2 changes: 1 addition & 1 deletion src/vunit_python_bridge/native/vhpi/python_pkg.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com
// Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com

#include <stdbool.h>
#include <stdio.h>
Expand Down
2 changes: 1 addition & 1 deletion src/vunit_python_bridge/native/vhpi/python_pkg_vhpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at http://mozilla.org/MPL/2.0/.
//
// Copyright (c) 2014-2023, Lars Asplund lars.anders.asplund@gmail.com
// Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com

#include <aldecpli.h>
#include <stdbool.h>
Expand Down
58 changes: 58 additions & 0 deletions tools/check_license_headers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this file,
# You can obtain one at http://mozilla.org/MPL/2.0/.
#
# Copyright (c) 2014-2026, Lars Asplund lars.anders.asplund@gmail.com

"""
Check that every Python, VHDL and C source file starts with the MPL 2.0 notice and a copyright
line ending with the current year. Lists the files that don't and exits with 1.
"""

import datetime
import re
import subprocess
import sys
from pathlib import Path

ROOT = Path(__file__).parent.parent
SUFFIXES = (".py", ".vhd", ".vhd.in", ".c", ".h")
# The header is within the first lines, after an optional description line
HEADER_LINES = 15
NOTICE = [
"This Source Code Form is subject to the terms of the Mozilla Public",
"License, v. 2.0. If a copy of the MPL was not distributed with this file,",
"You can obtain one at http://mozilla.org/MPL/2.0/.",
]
COPYRIGHT = re.compile(r"Copyright \(c\) 2014-(\d{4}), Lars Asplund lars\.anders\.asplund@gmail\.com")


def header_problem(text: str, year: int):
"""
What is wrong with the header of a file, or None.
"""
header = "\n".join(text.splitlines()[:HEADER_LINES])
if not all(line in header for line in NOTICE):
return "no MPL 2.0 notice"
match = COPYRIGHT.search(header)
if match is None:
return "no copyright line 'Copyright (c) 2014-<year>, Lars Asplund lars.anders.asplund@gmail.com'"
if int(match.group(1)) != year:
return f"copyright ends with {match.group(1)}, not {year}"
return None


def main() -> int:
files = subprocess.run(["git", "ls-files"], cwd=ROOT, capture_output=True, text=True, check=True).stdout.split()
year = datetime.date.today().year
problems = []
for name in sorted(name for name in files if name.endswith(SUFFIXES)):
problem = header_problem((ROOT / name).read_text(encoding="utf-8"), year)
if problem:
problems.append(f"{name}: {problem}")
print("\n".join(problems) or "All license headers are in place.")
return 1 if problems else 0


if __name__ == "__main__":
sys.exit(main())
Loading