-
-
Notifications
You must be signed in to change notification settings - Fork 45
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
Add ignored commits feature #114
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -17,6 +17,7 @@ You can customize the plugin by setting options in `mkdocs.yml`. For example: | |
- index.md | ||
enabled: true | ||
strict: true | ||
ignored_commits_file: .git-blame-ignore-revs | ||
``` | ||
|
||
## `type` | ||
|
@@ -147,3 +148,18 @@ Default is `true`. When enabled, the logs will show warnings when something is w | |
- git-revision-date-localized: | ||
strict: true | ||
``` | ||
|
||
## `ignored_commits_file` | ||
|
||
Default is `None`. When specified, contains a file that contains a list of commit hashes to ignore | ||
when determining the most recent updated time. The format of the file is the same as the format of | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sometime we use |
||
git `blame.ignoreRevsFile`. This can be useful to ignore formatting updates or other mass changes to the documents. | ||
|
||
|
||
=== ":octicons-file-code-16: mkdocs.yml" | ||
|
||
```yaml | ||
plugins: | ||
- git-revision-date-localized: | ||
ignored_commits_file: .git-blame-ignore-revs | ||
``` |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,7 @@ | |
NoSuchPathError, | ||
) | ||
|
||
from typing import Any, Dict | ||
from typing import Any, Dict, List | ||
|
||
logger = logging.getLogger("mkdocs.plugins") | ||
|
||
|
@@ -32,6 +32,9 @@ def __init__(self, config={}): | |
self.config = config | ||
self.repo_cache = {} | ||
|
||
ignore_commits_file = self.config.get("ignored_commits_file") | ||
self.ignored_commits = self.parse_git_ignore_revs(ignore_commits_file) if ignore_commits_file else [] | ||
|
||
def _get_repo(self, path: str) -> Git: | ||
if not os.path.isdir(path): | ||
path = os.path.dirname(path) | ||
|
@@ -117,6 +120,7 @@ def get_git_commit_timestamp( | |
realpath = os.path.realpath(path) | ||
git = self._get_repo(realpath) | ||
|
||
# Ignored commits are only considered for the most recent update, not for creation | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With 150k downloads per month, someone is bound to stumble on this. It should ignore those commits everywhere. Best to refactor, using a separate function that takes in a list of commits and return the last or first one that is not in the ignored commits list. You can use that function for both creation and most recent update. We also need a proper fallback inside that function. What if all commits are ignored (f.e. because there is only 1)? You would think that never happens, but it could happen for new repos. Or, some users, f.e. when using CI, use a shallow clone, that only retrieves the last commit. If that commits happens to be an ignored commit -- there are no more commits left to determine the build date. Probably the best fallback for that scenario is to then use ignored commits anyway. We'd need to document that. And we probably want to inform the user that that happened. It should log a warning when the |
||
if is_first_commit: | ||
# diff_filter="A" will select the commit that created the file | ||
commit_timestamp = git.log( | ||
|
@@ -128,10 +132,21 @@ def get_git_commit_timestamp( | |
if commit_timestamp != "": | ||
commit_timestamp = commit_timestamp.split()[-1] | ||
else: | ||
# Latest commit touching a specific file | ||
commit_timestamp = git.log( | ||
realpath, date="unix", format="%at", n=1, no_show_signature=True | ||
) | ||
# Retrieve the history for the file in the format <hash> <timestamp> | ||
# The maximum number of commits we will ever need to examine is 1 more than the number of ignored commits. | ||
lines = git.log( | ||
realpath, date="unix", format="%H %at", n=len(self.ignored_commits)+1, no_show_signature=True, | ||
).split("\n") | ||
# process the commits for the file in reverse-chronological order. Ignore any commit that is on the | ||
# ignored list. If the line is empty, we've reached the end and need to use the fallback behavior | ||
for line in lines: | ||
if not line: | ||
commit_timestamp = "" | ||
break | ||
commit, commit_timestamp = line.split(" ") | ||
if not any(commit.startswith(x) for x in self.ignored_commits): | ||
break | ||
|
||
except (InvalidGitRepositoryError, NoSuchPathError) as err: | ||
if self.config.get('fallback_to_build_date'): | ||
log( | ||
|
@@ -224,3 +239,19 @@ def add_spans(date_formats: Dict[str, str]) -> Dict[str, str]: | |
% (date_type, date_string) | ||
) | ||
return date_formats | ||
|
||
@staticmethod | ||
def parse_git_ignore_revs(filename: str) -> List[str]: | ||
""" | ||
Parses a file that is the same format as git's blame.ignoreRevsFile and return the list of commit hashes. | ||
|
||
Whitespace, blanklines and comments starting with # are all ignored. | ||
""" | ||
result = [] | ||
with open(filename, "rt") as f: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. perhaps we should specify UTF-8 encoding. This is standard for mkdocs. See f.e. https://github.com/mkdocs/mkdocs/blob/df3739d51903ab56771ac071a05b5aa9cdf9e129/mkdocs/commands/new.py#L43 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, what if this file is not found, because a user specified the wrong path? Can we give a helpful error, showing with path was tried and which parameter in mkdocs.yml should be changed? |
||
for line in f: | ||
line = line.split("#", 1)[0].strip() | ||
if not line: | ||
continue | ||
result.append(line) | ||
return result |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
site_name: test gitrevisiondatelocalized_plugin | ||
use_directory_urls: true | ||
|
||
plugins: | ||
- search | ||
- git-revision-date-localized: | ||
enable_creation_date: True | ||
ignored_commits_file: ignored-commits.txt |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -158,10 +158,15 @@ def setup_commit_history(testproject_path): | |
repo.git.commit(message="add homepage", author=author, date="1500854705") # Mon Jul 24 2017 00:05:05 GMT+0000 | ||
|
||
file_name = os.path.join(testproject_path, "docs/page_with_tag.md") | ||
with open(file_name, "a") as the_file: | ||
the_file.write("test\n") | ||
repo.git.add("docs/page_with_tag.md") | ||
repo.git.commit(message="update homepage #1", author=author, date="1525475836") # Fri May 04 2018 23:17:16 GMT+0000 | ||
|
||
with open(file_name, "a") as the_file: | ||
the_file.write("awa\n") | ||
repo.git.add("docs/page_with_tag.md") | ||
repo.git.commit(message="update homepage", author=author, date="1642911026") # Sun Jan 23 2022 04:10:26 GMT+0000 | ||
repo.git.commit(message="update homepage #2", author=author, date="1642911026") # Sun Jan 23 2022 04:10:26 GMT+0000 | ||
|
||
if os.path.exists("docs/page_with_renamed.md"): | ||
bf_file_name = os.path.join(testproject_path, "docs/page_with_renamed.md") | ||
|
@@ -382,10 +387,10 @@ def test_tags_are_replaced(tmp_path, mkdocs_file): | |
pytest.skip("Not necessary to test the JS library") | ||
|
||
# Make sure count_commits() works | ||
# We created 10 commits in setup_commit_history() | ||
# We created 11 commits in setup_commit_history() | ||
with working_directory(testproject_path): | ||
u = Util() | ||
assert commit_count(u._get_repo("docs/page_with_tag.md")) == 10 | ||
assert commit_count(u._get_repo("docs/page_with_tag.md")) == 11 | ||
|
||
|
||
# the revision date was in 'setup_commit_history' was set to 1642911026 (Sun Jan 23 2022 04:10:26 GMT+0000) | ||
|
@@ -672,3 +677,37 @@ def test_mkdocs_genfiles_plugin(tmp_path): | |
validate_build( | ||
testproject_path, plugin_config | ||
) | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well done on writing these unit tests! |
||
|
||
def test_ignored_commits(tmp_path): | ||
testproject_path = setup_clean_mkdocs_folder( | ||
"tests/fixtures/basic_project/mkdocs_ignored_commits.yml", tmp_path | ||
) | ||
repo = setup_commit_history(testproject_path) | ||
|
||
# First test that the middle commit doesn't show up by default | ||
# January 23, 2022 is the date of the most recent commit | ||
with open(str(testproject_path / "ignored-commits.txt"), "wt") as fp: | ||
fp.write("") | ||
|
||
result = build_docs_setup(testproject_path) | ||
assert result.exit_code == 0 | ||
|
||
page_with_tag = testproject_path / "site/page_with_tag/index.html" | ||
contents = page_with_tag.read_text(encoding="utf8") | ||
assert "January 23, 2022" in contents | ||
|
||
# Now mark the most recent change to page_with_tag as ignored | ||
# May 4, 2018 is the date of the second most recent commit | ||
hash = repo.git.log("docs/page_with_tag.md", format="%H", n=1) | ||
|
||
with open(str(testproject_path / "ignored-commits.txt"), "wt") as fp: | ||
fp.write(hash) | ||
|
||
# should not raise warning | ||
result = build_docs_setup(testproject_path) | ||
assert result.exit_code == 0 | ||
|
||
page_with_tag = testproject_path / "site/page_with_tag/index.html" | ||
contents = page_with_tag.read_text(encoding="utf8") | ||
assert "May 4, 2018" in contents |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
from mkdocs_git_revision_date_localized_plugin.util import Util | ||
import pytest | ||
import tempfile | ||
|
||
TEST_PARAMS = [ | ||
(b"abc123\n", ["abc123"]), | ||
(b"abc123 # comments are ignored\n", ["abc123"]), | ||
(b"\n\n\n\n\nabc123\n\n\n\n\n", ["abc123"]), | ||
] | ||
|
||
@pytest.mark.parametrize("test_input,expected", TEST_PARAMS) | ||
def test_parse_git_ignore_revs(test_input, expected): | ||
with tempfile.NamedTemporaryFile() as fp: | ||
fp.write(test_input) | ||
fp.flush() | ||
assert Util.parse_git_ignore_revs(fp.name) == expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'When specified, contains a file that contains a list' -- That sentence is a bit weird. Explain it needs a path, and relative to the projects root (mkdocs.yml file?).