From 96fb712c9d5635613f39dfb086978236fbb3f13a Mon Sep 17 00:00:00 2001 From: rcg Date: Sun, 14 Apr 2024 19:34:30 +0200 Subject: [PATCH] Add support to ignore authors and/or commits --- docs/options.md | 11 ++ mkdocs_git_authors_plugin/git/page.py | 11 +- mkdocs_git_authors_plugin/plugin.py | 2 + setup.py | 2 +- tests/basic_setup/mkdocs_ignore_authors.yml | 8 ++ tests/test_basic.py | 17 +++ tests/test_util.py | 143 ++++++++++++++++++++ 7 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 tests/basic_setup/mkdocs_ignore_authors.yml diff --git a/docs/options.md b/docs/options.md index 8b31730..415e458 100644 --- a/docs/options.md +++ b/docs/options.md @@ -13,6 +13,9 @@ plugins: fallback_to_empty: false sort_authors_by: name authorship_threshold_percent: 10 + ignore_authors: + - john@doe.com + ignore_commits: .git-blame-ignore-revs exclude: - index.md enabled: true @@ -59,6 +62,14 @@ If this option is set to `true` (default: `false`) the plugin will work even out Default is empty. Specify a list of page source paths (one per line) that should not have author(s) included (excluded from processing by this plugin). This can be useful for example to remove the authors from the front page. The source path of a page is relative to your `docs/` folder. You can also use [globs](https://docs.python.org/3/library/glob.html) instead of full source paths. To exclude `docs/subfolder/page.md` specify in your `mkdocs.yml` a line under `exclude:` with `- subfolder/page.md`. Some examples: +## `ignore_authors` + +Default is empty. Specifies a list of emails for authors whose contributions should be ignored by this plugin. + +## `ignore_commits` + +Default is empty. Specifies a file containing a list of commit hashes (one per line) that should be ignored. Changes made in these commits will be attributed to the previous commit that changed the line. + ```yaml # mkdocs.yml plugins: diff --git a/mkdocs_git_authors_plugin/git/page.py b/mkdocs_git_authors_plugin/git/page.py index be7f465..d6663b9 100644 --- a/mkdocs_git_authors_plugin/git/page.py +++ b/mkdocs_git_authors_plugin/git/page.py @@ -146,7 +146,13 @@ def _process_git_blame(self): re_sha = re.compile(r"^\w{40}") - cmd = GitCommand("blame", ["--porcelain", str(self._path)]) + args = [] + if self.repo().config("ignore_commits"): + args.append("--ignore-revs-file") + args.append(self.repo().config("ignore_commits")) + args.append("--porcelain") + args.append(str(self._path)) + cmd = GitCommand("blame", args) cmd.run() lines = cmd.stdout() @@ -155,6 +161,7 @@ def _process_git_blame(self): if len(lines) == 0: raise GitCommandError + ignore_authors = self.repo().config("ignore_authors") commit_data = {} for line in lines: key = line.split(" ")[0] @@ -183,7 +190,7 @@ def _process_git_blame(self): author_tz=commit_data.get("author-tz"), summary=commit_data.get("summary"), ) - if len(line) > 1 or self.repo().config("count_empty_lines"): + if commit.author().email() not in ignore_authors and (len(line) > 1 or self.repo().config("count_empty_lines")): author = commit.author() if author not in self._authors: self._authors.append(author) diff --git a/mkdocs_git_authors_plugin/plugin.py b/mkdocs_git_authors_plugin/plugin.py index 4f093b5..fa24af1 100644 --- a/mkdocs_git_authors_plugin/plugin.py +++ b/mkdocs_git_authors_plugin/plugin.py @@ -21,6 +21,8 @@ class GitAuthorsPlugin(BasePlugin): ("count_empty_lines", config_options.Type(bool, default=True)), ("fallback_to_empty", config_options.Type(bool, default=False)), ("exclude", config_options.Type(list, default=[])), + ("ignore_commits", config_options.Type(str, default=None)), + ("ignore_authors", config_options.Type(list, default=[])), ("enabled", config_options.Type(bool, default=True)), ("enabled_on_serve", config_options.Type(bool, default=True)), ("sort_authors_by", config_options.Type(str, default="name")), diff --git a/setup.py b/setup.py index 2bd8c61..f69a2b6 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ setup( name="mkdocs-git-authors-plugin", - version="0.8.0", + version="0.9.0", description="Mkdocs plugin to display git authors of a page", long_description=long_description, long_description_content_type="text/markdown", diff --git a/tests/basic_setup/mkdocs_ignore_authors.yml b/tests/basic_setup/mkdocs_ignore_authors.yml new file mode 100644 index 0000000..f868ff9 --- /dev/null +++ b/tests/basic_setup/mkdocs_ignore_authors.yml @@ -0,0 +1,8 @@ +site_name: test gitauthors_plugin +use_directory_urls: true + +plugins: + - search + - git-authors: + ignore_authors: + - 'guts@users.noreply.github.com' diff --git a/tests/test_basic.py b/tests/test_basic.py index 878442c..4d3f6f9 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -146,6 +146,23 @@ def test_exclude_working(tmp_path): +def test_ignore_authors_working(tmp_path): + + result = build_docs_setup("tests/basic_setup/mkdocs_ignore_authors.yml", tmp_path) + assert result.exit_code == 0, ( + "'mkdocs build' command failed. Error: %s" % result.stdout + ) + + page_file = tmp_path / "page_with_tag/index.html" + assert page_file.exists(), "%s does not exist" % page_file + + contents = page_file.read_text() + assert re.search("Tim Vink", contents) + assert not re.search("Julien", contents) + + + def test_exclude_working_with_genfiles(tmp_path): """ A warning for uncommited files should not show up diff --git a/tests/test_util.py b/tests/test_util.py index 1e15efd..f2d570e 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -35,6 +35,7 @@ "sort_reverse": False, "sort_authors_by": "name", "authorship_threshold_percent": 0, + "ignore_authors": [], } #### Helpers #### @@ -275,6 +276,148 @@ def test_retrieve_authors(tmp_path): os.chdir(cwd) +def test_retrieve_authors_ignoring_commits(tmp_path): + """ + Builds a fake git project with some commits. + + Args: + tmp_path (PosixPath): Directory of a tempdir + """ + cwd = os.getcwd() + os.chdir(str(tmp_path)) + + # Create file + file_name = str(tmp_path / "new-file") + with open(file_name, "w") as the_file: + the_file.write("line 1\n") + the_file.write("line 2\n") + + # Create git repo and commit file + r = gitpython.Repo.init(tmp_path) + r.index.add([file_name]) + author = gitpython.Actor("Tim", "abc@abc.com") + r.index.commit("initial commit", author=author) + + # Update the file + with open(file_name, "w") as the_file: + the_file.write("line 1.1\n") + the_file.write("line 2.1\n") + r.index.add([file_name]) + author = gitpython.Actor("John", "john@abc.com") + commit = r.index.commit("second commit", author=author) + + repo_instance = repo.Repo() + repo_instance.set_config(DEFAULT_CONFIG) + repo_instance.page(file_name) + authors = repo_instance.get_authors() + authors = util.page_authors(authors, file_name) + authors[0]["last_datetime"] = None + + assert authors == [ + { + "name": "John", + "email": "john@abc.com", + "last_datetime": None, + "lines": 2, + "lines_all_pages": 2, + "contribution": "100.0%", + "contribution_all_pages": "100.0%", + } + ] + + # Get the authors while ignoring the last commit + ignored_commits_files = str(tmp_path / "ignored_commits.txt") + with open(ignored_commits_files, "w") as the_file: + the_file.write(commit.hexsha + "\n") + repo_instance = repo.Repo() + config = DEFAULT_CONFIG.copy() + config['ignore_commits'] = ignored_commits_files + repo_instance.set_config(config) + repo_instance.page(file_name) + authors = repo_instance.get_authors() + authors = util.page_authors(authors, file_name) + authors[0]["last_datetime"] = None + + assert authors == [ + { + "name": "Tim", + "email": "abc@abc.com", + "last_datetime": None, + "lines": 2, + "lines_all_pages": 2, + "contribution": "100.0%", + "contribution_all_pages": "100.0%", + }, + ] + + os.chdir(cwd) + + +def test_retrieve_authors_ignoring_emails(tmp_path): + """ + Builds a fake git project with some commits. + + Args: + tmp_path (PosixPath): Directory of a tempdir + """ + cwd = os.getcwd() + os.chdir(str(tmp_path)) + + # Create file + file_name = str(tmp_path / "new-file") + with open(file_name, "w") as the_file: + the_file.write("line 1\n") + the_file.write("line 2\n") + + # Create git repo and commit file + r = gitpython.Repo.init(tmp_path) + r.index.add([file_name]) + author = gitpython.Actor("Tim", "abc@abc.com") + r.index.commit("initial commit", author=author) + + # Add more content + with open(file_name, "a+") as the_file: + the_file.write("line 3\n") + the_file.write("line 4\n") + r.index.add([file_name]) + author = gitpython.Actor("John", "john@abc.com") + r.index.commit("second commit", author=author) + + # Get the authors while ignoring john@abc.com user + repo_instance = repo.Repo() + config = DEFAULT_CONFIG.copy() + config['ignore_authors'] = ['john@abc.com'] + repo_instance.set_config(config) + repo_instance.page(file_name) + authors = repo_instance.get_authors() + authors = util.page_authors(authors, file_name) + authors[0]["last_datetime"] = None + authors[1]["last_datetime"] = None + + assert authors == [ + { + "contribution": "0.0%", + "contribution_all_pages": "0.0%", + "email": "john@abc.com", + "last_datetime": None, + "lines": 0, + "lines_all_pages": 0, + "name": "John" + }, + { + "name": "Tim", + "email": "abc@abc.com", + "last_datetime": None, + "lines": 2, + "lines_all_pages": 2, + "contribution": "100.0%", + "contribution_all_pages": "100.0%", + }, + ] + + os.chdir(cwd) + + def test_mkdocs_in_git_subdir(tmp_path): """ Sometimes `mkdocs.yml` is not in the root of the repo.