Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/reuse 2.0 implementation #17

Merged
merged 23 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
6ce4d76
fixed implementation of add_license_headers for reuse 2.0
klmcadams Jul 28, 2023
d736190
style fix
klmcadams Jul 28, 2023
1f60ab0
adjusted unit tests for add_license_headers
klmcadams Jul 28, 2023
a0f935c
made reuse dependency >=2
klmcadams Jul 28, 2023
ab28647
make gitpython dependency flexible - pyproject.toml
klmcadams Jul 31, 2023
bbcce8a
set specific dependencies for testing - pyproject.toml
klmcadams Jul 31, 2023
cb6ab35
fixed docstrings
klmcadams Jul 31, 2023
adf4a48
Merge branch 'fix/reuse-2.0-implementation' of https://github.com/ans…
klmcadams Jul 31, 2023
9178903
changed sphinx & sphinx-theme back to newer versions
klmcadams Jul 31, 2023
4a9ae69
changing ansys-sphinx-theme to 9.7
klmcadams Jul 31, 2023
a6551ef
changed sphinx to 5.3.0
klmcadams Jul 31, 2023
7cdfec1
updated sphinx versions
klmcadams Jul 31, 2023
052d822
added linkcheck_ignore for time being
klmcadams Jul 31, 2023
efe2c13
fixed style for conf.py
klmcadams Jul 31, 2023
b911cff
added wget code - ci_cd.yml
klmcadams Aug 1, 2023
c1fb5c4
revert ci_cd.yml
klmcadams Aug 1, 2023
1cb9188
changed regex - conf.py
klmcadams Aug 1, 2023
6dd914c
add reminder to doc/source/conf.py
klmcadams Aug 1, 2023
a00d582
adjusted return sections in docstrings
klmcadams Aug 1, 2023
3ba557b
Merge branch 'main' into fix/reuse-2.0-implementation
RobPasMue Aug 3, 2023
dee262f
feat: genearl improvements
RobPasMue Aug 3, 2023
22d5211
feat: documenting API
RobPasMue Aug 3, 2023
b3cbe1c
feat: add ignored files
RobPasMue Aug 3, 2023
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
9 changes: 5 additions & 4 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,20 @@ classifiers = [
]
dependencies = [
"importlib-metadata >=4.0",
"reuse <2",
"reuse>=2",
"GitPython==3.1.32",
klmcadams marked this conversation as resolved.
Show resolved Hide resolved
]

[project.optional-dependencies]
tests = [
"pytest==7.3.0",
"pytest-cov==4.0.0",
"reuse <2",
"reuse>=2",
klmcadams marked this conversation as resolved.
Show resolved Hide resolved
]
doc = [
"ansys-sphinx-theme==0.10.0",
"ansys-sphinx-theme==0.9.7",
"numpydoc==1.5.0",
"sphinx==7.1.1",
"sphinx==5.3.0",
"sphinx-copybutton==0.5.1",
klmcadams marked this conversation as resolved.
Show resolved Hide resolved
]

Expand Down
193 changes: 127 additions & 66 deletions src/ansys/pre_commit_hooks/add_license_headers.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/usr/bin/env python

# Copyright (C) 2023 ANSYS, Inc. and/or its affiliates.
# SPDX-License-Identifier: MIT
#
Expand All @@ -25,97 +24,159 @@
"""Run reuse for files missing license headers."""
import argparse
import datetime
import json
import os
import subprocess
import sys
from tempfile import NamedTemporaryFile

from reuse import lint
from reuse.project import Project
from reuse.report import ProjectReport
import git
from reuse import header, lint, project


def set_lint_args(parser):
"""
Add arguments to parser for reuse lint.

Args:
parser (argparse.ArgumentParser): Parser without any arguments.

def get_args(args):
"""Retrieve value of --loc argument."""
parser = argparse.ArgumentParser(description="Get repository location.")
Returns:
parser.parse_args (argparse.Namespace): Parser Namespace containing lint arguments.
"""
parser.add_argument(
"--loc", type=str, required=True, help="Path to repository location", default="src"
)
return parser.parse_args(args).loc
parser.add_argument(
"--parser",
)
parser.add_argument("--no_multiprocessing", action="store_true")
lint.add_arguments(parser)

return parser.parse_args([sys.argv[1]])

def get_files(loc):

def list_noncompliant_files(args, proj):
"""
Generate report containing files without the license header.
Retrieve list of noncompliant files.

Args:
args (argparse.Namespace): Namespace of arguments with their values.
proj (project.Project): Project reuse runs on.

Parameters
----------
loc : str
Path to repository location.
Returns:
missing_headers (list): List of files without license headers.
"""
project = Project(loc)
report = ProjectReport.generate(project)
# Create a temporary file containing lint.run json output
with NamedTemporaryFile(mode="w", delete=False) as tmp:
args.json = True
lint.run(args, proj, tmp)

# Open the temporary file, load the json, and find files missing copyright & licensing info.
file = open(tmp.name, "rb")
lint_json = json.load(file)
file.close()
missing_headers = list(
set(
lint_json["non_compliant"]["missing_copyright_info"]
+ lint_json["non_compliant"]["missing_licensing_info"]
)
)

with NamedTemporaryFile(mode="w") as tmp:
output = lint.lint_files_without_copyright_and_licensing(report, tmp)
# Remove temporary file
os.remove(tmp.name)

return output
return missing_headers


def get_files_missing_header(loc):
"""Retrieve files without license header."""
try:
# Run reuse lint command to find files without license header
return get_files(loc)
except NotADirectoryError as e: # When loc is an invalid path
return str(e) + " for a repository"
def find_files_missing_header():
"""
Retrieve files without license header.

Returns:
0: No files exist that are missing license header.
1: Files exist that are missing license header.
"""
# Set up argparse for location, parser, and lint
# Lint contains 4 args: quiet, json, plain, and no_multiprocessing
parser = argparse.ArgumentParser()
args = set_lint_args(parser)
proj = project.Project(rf"{args.loc}")

missing_headers = list_noncompliant_files(args, proj)

def run_reuse_cmd(file):
"""Run the reuse command for files missing the license header."""
# Get current year for license file
year = datetime.date.today().year
cmd = [
"reuse",
"annotate",
"--year",
rf"{year}",
"--copyright-style",
"string-c",
"--merge-copyright",
"--template=ansys",
"-l",
"MIT",
"-c",
"ANSYS, Inc. and/or its affiliates.",
"--skip-unrecognised",
rf"{file}",
]
subprocess.check_call(cmd, stdout=subprocess.PIPE)


def run_reuse_on_files(loc):
"""Run the reuse annotate command on all files without license header."""
missing_header = get_files_missing_header(loc)
if missing_header:
# Run reuse command for files without license header
for file in missing_header:
print(f"License header added to {file}")
if os.path.isfile(file):
run_reuse_cmd(file)
return 1

# Return zero if all files have license header
# If there are files missing headers, run reuse and return 1
if missing_headers != []:
# Returns 1 if reuse changes all noncompliant files
# Returns 2 if .reuse directory does not exist
return run_reuse(parser, year, args.loc, missing_headers)
return 0


def check_reuse_dir():
"""
Check .reuse directory exists in root of git repository.

Returns:
git_root (str): Root path of git repository.
"""
klmcadams marked this conversation as resolved.
Show resolved Hide resolved
# Get root directory of current git repository
git_repo = git.Repo(os.getcwd(), search_parent_directories=True)
git_root = git_repo.git.rev_parse("--show-toplevel")

# If .reuse folder does not exist in git repository root, return 1
if not os.path.isdir(os.path.join(git_root, ".reuse")):
print(f"Please ensure the .reuse directory is in {git_root}")
klmcadams marked this conversation as resolved.
Show resolved Hide resolved
return 1
return git_root


def run_reuse(parser, year, loc, missing_headers):
"""
Run reuse command on files without license headers.

Args:
parser (argparse.ArgumentParser): Parser containing previously set arguments.
year (int): Current year for license header.
loc (str): Location to search for files missing headers.
missing_headers (list): List of files that are missing headers.
Returns:
1: Fails pre-commit hook on return 1
"""
# Add header arguments to parser which include: copyright, license, contributor, year,
# style, copyright-style, template, exclude-year, merge-copyrights, single-line,
# multi-line, explicit-license, force-dot-license, recursive, no-replace,
# skip-unrecognized, skip-existing
header.add_arguments(parser)

git_root = check_reuse_dir()
if git_root == 1:
return 2
klmcadams marked this conversation as resolved.
Show resolved Hide resolved

# Add missing license header to each file in the list
for file in missing_headers:
args = parser.parse_args([rf"--loc={loc}", file])
args.year = [str(year)]
args.copyright_style = "string-c"
args.copyright = ["ANSYS, Inc. and/or its affiliates."]
args.merge_copyrights = True
args.template = "ansys"
args.license = ["MIT"]
args.skip_unrecognised = True
args.parser = parser

# Requires .reuse directory to be in git_root directory
proj = project.Project(git_root)
header.run(args, proj)

return 1


def main():
"""Run reuse on files without license headers."""
try:
# Get repository location argument
loc = get_args([sys.argv[1]])
return run_reuse_on_files(loc)
except IndexError as e:
print("Please provide the --loc argument. IndexError: " + str(e))
"""Find files missing license header & run reuse on them."""
return find_files_missing_header()


if __name__ == "__main__":
Expand Down
Loading
Loading