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

Add {{git_creation_date_localized}} #50

Merged
merged 8 commits into from
Apr 12, 2021
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
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ plugins:
timezone: Europe/Amsterdam
locale: en
fallback_to_build_date: false
enable_creation_date: true
exclude:
- index.md
```
Expand Down Expand Up @@ -152,6 +153,10 @@ Default is `None`. Specify a two letter [ISO639](https://en.wikipedia.org/wiki/L

Default is `false`. If set to `true` the plugin will use the time at `mkdocs build` instead of the file's last git revision date *when git is not available*. This means the revision date can be incorrect, but this can be acceptable if you want your project to also successfully build in environments with no access to GIT.

### `enable_creation_date`

Default is `false`. If set to `true`, you will be able to use `{{git_creation_date_localized}}` in markdown files and `page.meta.git_creation_date_localized` in page templates.

### `exclude`

Default is empty. Specify a list of page source paths (one per line) that should not have a revision date included (excluded from processing by this plugin). This can be useful for example to remove the revision date 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:
Expand Down
37 changes: 34 additions & 3 deletions mkdocs_git_revision_date_localized_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class GitRevisionDateLocalizedPlugin(BasePlugin):
("type", config_options.Type(str, default="date")),
("timezone", config_options.Type(str, default="UTC")),
("exclude", config_options.Type(list, default=[])),
("enable_creation_date", config_options.Type(bool, default=False)),
)

def on_config(self, config: config_options.Config, **kwargs) -> Dict[str, Any]:
Expand Down Expand Up @@ -147,11 +148,15 @@ def on_page_markdown(
logging.debug("Excluding page " + page.file.src_path)
return markdown

# revision date
revision_dates = self.util.get_revision_date_for_file(
path=page.file.abs_src_path,
commit_timestamp=self.util.get_git_commit_timestamp(
path=page.file.abs_src_path,
is_first_commit=False,
fallback_to_build_date=self.config.get("fallback_to_build_date"),
),
locale=self.config.get("locale", "en"),
time_zone=self.config.get("time_zone", "UTC"),
fallback_to_build_date=self.config.get("fallback_to_build_date"),
)
revision_date = revision_dates[self.config["type"]]

Expand All @@ -162,13 +167,39 @@ def on_page_markdown(
revision_date += revision_dates["iso_date"]

page.meta["git_revision_date_localized"] = revision_date
return re.sub(
markdown = re.sub(
r"\{\{\s*[page\.meta\.]*git_revision_date_localized\s*\}\}",
revision_date,
markdown,
flags=re.IGNORECASE,
)

# Creation date
if self.config.get("enable_creation_date"):
creation_dates = self.util.get_creation_date_for_file(
commit_timestamp=self.util.get_git_commit_timestamp(
path=page.file.abs_src_path,
is_first_commit=True,
fallback_to_build_date=self.config.get("fallback_to_build_date"),
),
locale=self.config.get("locale", "en"),
time_zone=self.config.get("time_zone", "UTC"),
)
creation_date = creation_dates[self.config["type"]]

if self.config["type"] == "timeago":
creation_date += creation_dates["iso_date"]

page.meta["git_creation_date_localized"] = creation_date
markdown = re.sub(
r"\{\{\s*[page\.meta\.]*git_creation_date_localized\s*\}\}",
creation_date,
markdown,
flags=re.IGNORECASE,
)

return markdown

def on_post_build(self, config: Dict[str, Any], **kwargs) -> None:
"""
Run on post build.
Expand Down
96 changes: 77 additions & 19 deletions mkdocs_git_revision_date_localized_plugin/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from babel.dates import format_date, get_timezone
from git import (
Repo,
Git,
GitCommandError,
GitCommandNotFound,
InvalidGitRepositoryError,
Expand All @@ -32,7 +33,7 @@ def __init__(self, config={}):
self.config = config
self.repo_cache = {}

def _get_repo(self, path: str):
def _get_repo(self, path: str) -> Git:
if not os.path.isdir(path):
path = os.path.dirname(path)

Expand Down Expand Up @@ -78,35 +79,41 @@ def _date_formats(
% (loc_revision_date.isoformat(), locale),
}

def get_revision_date_for_file(
self,
path: str,
locale: str = "en",
time_zone: str = "UTC",
fallback_to_build_date: bool = False,
) -> Dict[str, str]:
def get_git_commit_timestamp(
self,
path: str,
is_first_commit: bool,
fallback_to_build_date: bool = False,
) -> int:
"""
Determine localized date variants for a given file.
Get a list of commit dates in unix timestamp, starts with the most recent commit.

Args:
is_first_commit (bool): if true, get the timestamp of the first commit,
else, get that of the most recent commit.
path (str): Location of a markdown file that is part of a Git repository.
locale (str, optional): Locale code of language to use. Defaults to 'en'.
timezone (str): Timezone database name (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).

Returns:
dict: Localized date variants.
list: commit dates in unix timestamp, starts with the most recent commit.
"""
unix_timestamp = None

commit_timestamp = ""

# perform git log operation
try:
if not self.fallback_enabled:
# Retrieve author date in UNIX format (%at)
# https://git-scm.com/docs/git-log#Documentation/git-log.txt-ematem
realpath = os.path.realpath(path)
unix_timestamp = self._get_repo(realpath).log(
realpath, n=1, date="short", format="%at"
)
git = self._get_repo(realpath)
if is_first_commit:
commit_timestamp = git.log(
realpath, date="short", format="%at", diff_filter="A"
)
else:
commit_timestamp = git.log(
realpath, date="short", format="%at", n=1
)
except (InvalidGitRepositoryError, NoSuchPathError) as err:
if fallback_to_build_date:
logger.warning(
Expand Down Expand Up @@ -147,16 +154,36 @@ def get_revision_date_for_file(
raise err

# create timestamp
if not unix_timestamp:
unix_timestamp = time.time()
if commit_timestamp == "":
commit_timestamp = time.time()
if not self.fallback_enabled:
logger.warning(
"[git-revision-date-localized-plugin] '%s' has no git logs, using current timestamp"
% path
)

return int(commit_timestamp)

def get_revision_date_for_file(
self,
commit_timestamp: int,
locale: str = "en",
time_zone: str = "UTC",
) -> Dict[str, str]:
"""
Determine localized date variants for a given file.

Args:
commit_timestamp (int): most recent commit date in unix timestamp.
locale (str, optional): Locale code of language to use. Defaults to 'en'.
time_zone (str): Timezone database name (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).

Returns:
dict: Localized date variants.
"""

date_formats = self._date_formats(
unix_timestamp=unix_timestamp, time_zone=time_zone, locale=locale
unix_timestamp=commit_timestamp, time_zone=time_zone, locale=locale
)

# Wrap in <span> for styling
Expand All @@ -167,3 +194,34 @@ def get_revision_date_for_file(
)

return date_formats

def get_creation_date_for_file(
self,
commit_timestamp: int,
locale: str = "en",
time_zone: str = "UTC",
) -> Dict[str, str]:
"""
Determine localized date variants for a given file.

Args:
commit_timestamp (int): the first commit date in unix timestamp.
locale (str, optional): Locale code of language to use. Defaults to 'en'.
time_zone (str): Timezone database name (https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).

Returns:
dict: Localized date variants.
"""

date_formats = self._date_formats(
unix_timestamp=commit_timestamp, time_zone=time_zone, locale=locale
)

# Wrap in <span> for styling
for date_type, date_string in date_formats.items():
date_formats[date_type] = (
'<span class="git-revision-date-localized-plugin git-revision-date-localized-plugin-%s">%s</span>'
% (date_type, date_string)
)

return date_formats
2 changes: 2 additions & 0 deletions tests/fixtures/basic_project/docs/page_with_tag.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# test page

Tag <mark>\{\{ git_revision_date_localized \}\}</mark> renders as: {{ git_revision_date_localized }}

Tag <mark>\{\{ git_creation_date_localized \}\}</mark> renders as: {{ git_creation_date_localized }}
7 changes: 7 additions & 0 deletions tests/fixtures/basic_project/mkdocs_creation_date.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
site_name: test gitrevisiondatelocalized_plugin
use_directory_urls: true

plugins:
- search
- git-revision-date-localized:
enable_creation_date: True
38 changes: 34 additions & 4 deletions tests/test_builds.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ def setup_commit_history(testproject_path):
os.chdir(testproject_path)

try:
repo.git.add("docs/page_with_tag.md")
repo.git.commit(message="add homepage", author=author, date="1500854705 -0700")

repo.git.add("mkdocs.yml")
repo.git.commit(message="add mkdocs", author=author)

Expand All @@ -139,8 +142,12 @@ def setup_commit_history(testproject_path):
repo.git.commit(message="second page", author=author)
repo.git.add("docs/index.md")
repo.git.commit(message="homepage", author=author)

file_name = os.path.join(testproject_path, "docs/page_with_tag.md")
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="homepage", author=author)
repo.git.commit(message="update homepage", author=author)
os.chdir(cwd)
except:
os.chdir(cwd)
Expand Down Expand Up @@ -195,13 +202,31 @@ def validate_build(testproject_path, plugin_config: dict = {}):

repo = Util(str(testproject_path / "docs"))
date_formats = repo.get_revision_date_for_file(
path=str(testproject_path / "docs/page_with_tag.md"),
commit_timestamp=repo.get_git_commit_timestamp(
path=str(testproject_path / "docs/page_with_tag.md"),
is_first_commit=False,
fallback_to_build_date=plugin_config.get("fallback_to_build_date"),
),
locale=plugin_config.get("locale"), # type: ignore
fallback_to_build_date=plugin_config.get("fallback_to_build_date"), # type: ignore
)

searches = [x in contents for x in date_formats.values()]
assert any(searches), "No correct date formats output was found"
assert any(searches), "No correct revision date formats output was found"

if plugin_config.get("enable_creation_date"):
commit_timestamp=repo.get_git_commit_timestamp(
path=str(testproject_path / "docs/page_with_tag.md"),
is_first_commit=True,
fallback_to_build_date=plugin_config.get("fallback_to_build_date"),
)
assert commit_timestamp == 1500854705
date_formats = repo.get_revision_date_for_file(
commit_timestamp=commit_timestamp,
locale=plugin_config.get("locale"), # type: ignore
)

searches = [x in contents for x in date_formats.values()]
assert any(searches), "No correct creation date formats output was found"


def validate_mkdocs_file(temp_path: str, mkdocs_yml_file: str):
Expand Down Expand Up @@ -270,6 +295,11 @@ def test_build_no_options(tmp_path):
validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs.yml")


def test_build_creation_date(tmp_path):
# Enable plugin with no extra options set
validate_mkdocs_file(tmp_path, "tests/fixtures/basic_project/mkdocs_creation_date.yml")


def test_build_locale_plugin(tmp_path):
# Enable plugin with plugin locale set to 'nl'
validate_mkdocs_file(
Expand Down