Skip to content

Commit

Permalink
[FIX] oca-towncrier: Add support for Mardown format
Browse files Browse the repository at this point in the history
If readme fragments uses the md format, generate the history file into the same format
  • Loading branch information
lmignon committed Mar 11, 2024
1 parent 451de41 commit 3349f4b
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 16 deletions.
4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@
"requests",
"toml>=0.10.0", # for oca-towncrier
"tomli ; python_version < '3.11'", # from 3.11 tomllib is in stdlib
"towncrier>=21.3", # for oca-towncrier
"towncrier>=21.3; python_version < '3.8'", # for oca-towncrier
# for oca-towncrier with MarkDow support
"towncrier>=23.11; python_version >= '3.8'",
"selenium",
"twine",
"wheel",
Expand Down
48 changes: 45 additions & 3 deletions tests/test_towncrier.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
# License AGPLv3 (https://www.gnu.org/licenses/agpl-3.0-standalone.html)
# Copyright (c) 2018 ACSONE SA/NV

import sys
import textwrap

import pytest
import toml
from click.testing import CliRunner
from tools.oca_towncrier import _make_issue_format, _prepare_config, oca_towncrier


def test_make_issue_format():
assert (
_make_issue_format("OCA", "repo")
_make_issue_format("OCA", "repo", "rst")
== "`#{issue} <https://github.com/OCA/repo/issues/{issue}>`_"
)
assert (
_make_issue_format("OCA", "repo", "md")
== "[#{issue}](https://github.com/OCA/repo/issues/{issue})"
)


def test_prepare_config(tmp_path):
with _prepare_config(str(tmp_path), "OCA", "repo") as fn:
with _prepare_config(str(tmp_path), "OCA", "repo") as (fn, result_file):
with open(fn) as f:
pyproject = toml.load(f)
assert set(pyproject["tool"]["towncrier"].keys()) == {
Expand Down Expand Up @@ -60,3 +65,40 @@ def test_oca_towncrier(tmp_path):
- Bugfix description. (`#50 <https://github.com/OCA/therepo/issues/50>`_)
"""
)


@pytest.mark.skipif(
sys.version_info < (3, 8), reason="MarkDow support requires python3.8 or higher"
)
def test_oca_towncrier_md(tmp_path):
addon_path = tmp_path / "addon_a"
readme_path = addon_path / "readme"
history_path = readme_path / "HISTORY.md"
news_path = readme_path / "newsfragments"
news_path.mkdir(parents=True)
(news_path / "50.bugfix").write_text("Bugfix description.")
(readme_path / "description.md").write_text("Some description")
runner = CliRunner()
runner.invoke(
oca_towncrier,
[
"--addon-dir",
str(addon_path),
"--version",
"14.0.1.0.1",
"--date",
"2021-12-31",
"--repo",
"therepo",
],
)
assert history_path.exists()
assert history_path.read_text() == textwrap.dedent(
"""\
## 14.0.1.0.1 (2021-12-31)
#### Bugfixes
- Bugfix description. ([#50](https://github.com/OCA/therepo/issues/50))
"""
)
52 changes: 40 additions & 12 deletions tools/oca_towncrier.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,34 +16,62 @@
from .manifest import read_manifest


def _make_issue_format(org, repo):
return "`#{{issue}} <https://github.com/{org}/{repo}/issues/{{issue}}>`_".format(
org=org, repo=repo
def _make_issue_format(org, repo, fragment_format):
if fragment_format == "md":
return f"[#{{issue}}](https://github.com/{org}/{repo}/issues/{{issue}})"
return f"`#{{issue}} <https://github.com/{org}/{repo}/issues/{{issue}}>`_"


def _get_towncrier_template(fragment_format):
return os.path.join(
os.path.dirname(__file__), f"towncrier-template.{fragment_format}"
)


def _get_towncrier_template():
return os.path.join(os.path.dirname(__file__), "towncrier-template.rst")
def _get_readme_fragment_format(addon_dir):
"""Detect the format of the readme fragment to generate (md or rst)"""
fragment_format = "rst"
readme_dir = os.path.join(addon_dir, "readme")
if not os.path.isdir(readme_dir):
return fragment_format
files = os.listdir(readme_dir)
files = [
f
for f in files
if not f.startswith(".") and os.path.isfile(os.path.join(readme_dir, f))
]
# The first file found with a .md or .rst extension will determine the format
for f in files:
if f.endswith(".md"):
fragment_format = "md"
break
if f.endswith(".rst"):
fragment_format = "rst"
break
return fragment_format


@contextlib.contextmanager
def _prepare_config(addon_dir, org, repo):
"""Inject towncrier options in pyproject.toml"""
# first detect expected format (we support both md and rst)
fragment_format = _get_readme_fragment_format(addon_dir)
with tempfile.NamedTemporaryFile(dir=addon_dir, mode="w") as config_file:
result_file = os.path.join("readme", f"HISTORY.{fragment_format}")
config = {
"tool": {
"towncrier": {
"template": _get_towncrier_template(),
"underlines": ["~"],
"issue_format": _make_issue_format(org, repo),
"template": _get_towncrier_template(fragment_format),
"underlines": ["~" if fragment_format == "rst" else ""],
"issue_format": _make_issue_format(org, repo, fragment_format),
"directory": "readme/newsfragments",
"filename": "readme/HISTORY.rst",
"filename": result_file,
}
}
}
toml.dump(config, config_file)
config_file.flush()
yield config_file.name
yield config_file.name, result_file


@click.command(
Expand Down Expand Up @@ -82,7 +110,7 @@ def oca_towncrier(addon_dirs, version, date, org, repo, commit):
if not any(not f.startswith(".") for f in os.listdir(news_dir)):
continue
addon_version = version or read_manifest(addon_dir)["version"]
with _prepare_config(addon_dir, org, repo) as config_file_name:
with _prepare_config(addon_dir, org, repo) as (config_file_name, result_file):
subprocess.call(
[
sys.executable,
Expand All @@ -99,7 +127,7 @@ def oca_towncrier(addon_dirs, version, date, org, repo, commit):
cwd=addon_dir,
)
paths.append(news_dir)
paths.append(os.path.join(addon_dir, "readme", "HISTORY.rst"))
paths.append(os.path.join(addon_dir, result_file))
if commit:
commit_if_needed(paths, message="[UPD] changelog", add=False)

Expand Down
65 changes: 65 additions & 0 deletions tools/towncrier-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{% if render_title %}
{% if versiondata.name %}
## {{ versiondata.name }} {{ versiondata.version }} ({{ versiondata.date }})
{% else %}
## {{ versiondata.version }} ({{ versiondata.date }})
{% endif %}
{% endif %}
{% for section, _ in sections.items() %}
{% if section %}

### {{section}}
{% endif %}

{% if sections[section] %}
{% for category, val in definitions.items() if category in sections[section] %}
#### {{ definitions[category]['name'] }}

{% if definitions[category]['showcontent'] %}
{% for text, values in sections[section][category].items() %}
- {{ text }}
{%- if values %}
{% if "\n - " in text or '\n * ' in text %}


(
{%- else %}
(
{%- endif -%}
{%- for issue in values %}
{{ issue.split(": ", 1)[0] }}{% if not loop.last %}, {% endif %}
{%- endfor %}
)
{% else %}

{% endif %}
{% endfor %}

{% else %}
- {% for issue in sections[section][category][''] %}
{{ issue.split(": ", 1)[0] }}{% if not loop.last %}, {% endif %}
{% endfor %}


{% endif %}
{% if issues_by_category[section][category] and "]: " in issues_by_category[section][category][0] %}
{% for issue in issues_by_category[section][category] %}
{{ issue }}
{% endfor %}

{% endif %}
{% if sections[section][category]|length == 0 %}
No significant changes.

{% else %}
{% endif %}
{% endfor %}
{% else %}
No significant changes.

{% endif %}
{% endfor +%}
{#
This comment adds one more newline at the end of the rendered newsfile content.
In this way the there are 2 newlines between the latest release and the previous release content.
#}

0 comments on commit 3349f4b

Please sign in to comment.