From 74711b66bd655836772377127141742c44db7930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Sat, 26 Oct 2019 12:25:38 +0200 Subject: [PATCH 1/3] add .flake8 --- .flake8 | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .flake8 diff --git a/.flake8 b/.flake8 new file mode 100644 index 00000000..1d36346c --- /dev/null +++ b/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 88 \ No newline at end of file From a57e03e36188cd22e4ad8ad46c293b151224947a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul=20=28ACSONE=29?= Date: Sat, 26 Oct 2019 12:26:21 +0200 Subject: [PATCH 2/3] [ADD] oca-towncrier --- setup.py | 3 + tests/test_towncrier.py | 43 +++++++++++++ tools/oca_towncrier.py | 118 +++++++++++++++++++++++++++++++++++ tools/towncrier-template.rst | 33 ++++++++++ 4 files changed, 197 insertions(+) create mode 100644 tests/test_towncrier.py create mode 100644 tools/oca_towncrier.py create mode 100644 tools/towncrier-template.rst diff --git a/setup.py b/setup.py index ba321ad8..62ed883e 100644 --- a/setup.py +++ b/setup.py @@ -38,6 +38,8 @@ 'polib', 'pygments', 'requests', + 'toml>=0.10.0', # for oca-towncrier + 'towncrier>=19.2', # for oca-towncrier 'twine', 'wheel', ], @@ -67,6 +69,7 @@ 'oca-pypi-upload = tools.pypi_upload:cli', 'oca-gen-addon-readme = tools.gen_addon_readme:gen_addon_readme', 'oca-gen-addon-icon = tools.gen_addon_icon:gen_addon_icon', + 'oca-towncrier = tools.oca_towncrier:oca_towncrier', ], }, ) diff --git a/tests/test_towncrier.py b/tests/test_towncrier.py new file mode 100644 index 00000000..3b7c11f8 --- /dev/null +++ b/tests/test_towncrier.py @@ -0,0 +1,43 @@ +# License AGPLv3 (http://www.gnu.org/licenses/agpl-3.0-standalone.html) +# Copyright (c) 2018 ACSONE SA/NV + +import toml + +from tools.oca_towncrier import ( + _make_issue_format, + _preserve_file, + _prepare_pyproject_toml, +) + + +def test_make_issue_format(): + assert ( + _make_issue_format("OCA", "repo") + == "`#{issue} `_" + ) + + +def test_preserve_file(tmp_path): + p = tmp_path / "dummy" + with _preserve_file(str(p)): + # path does not exist + p.write_text(u"abc") + assert not p.exists() + p.write_text(u"abc") + with _preserve_file(str(p)): + p.write_text(u"xyz") + assert p.read_text() == u"abc" + + +def test_prepare_pyproject_toml(tmp_path): + with _prepare_pyproject_toml(str(tmp_path), "OCA", "repo"): + with open(str(tmp_path / "pyproject.toml")) as f: + pyproject = toml.load(f) + assert set(pyproject["tool"]["towncrier"].keys()) == { + "template", + "underlines", + "title_format", + "issue_format", + "directory", + "filename", + } diff --git a/tools/oca_towncrier.py b/tools/oca_towncrier.py new file mode 100644 index 00000000..c01df495 --- /dev/null +++ b/tools/oca_towncrier.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python +# Copyright (c) 2019 ACSONE SA/NV +# License AGPLv3 (http://www.gnu.org/licenses/agpl-3.0-standalone.html) + +import contextlib +import datetime +import os +import shutil +import subprocess +import sys + +import click +import toml + +from .manifest import read_manifest + + +def _make_issue_format(org, repo): + return "`#{{issue}} `_".format( + org=org, repo=repo + ) + + +def _get_towncrier_template(): + return os.path.join(os.path.dirname(__file__), "towncrier-template.rst") + + +@contextlib.contextmanager +def _preserve_file(path): + if not os.path.exists(path): + try: + yield + finally: + os.unlink(path) + else: + save_path = path + ".save" + assert not os.path.exists(save_path) + try: + shutil.copy2(path, save_path) + yield + finally: + shutil.copy2(save_path, path) + os.unlink(save_path) + + +@contextlib.contextmanager +def _prepare_pyproject_toml(addon_dir, org, repo): + """Inject towncrier options in pyproject.toml""" + pyproject_path = os.path.join(addon_dir, "pyproject.toml") + with _preserve_file(pyproject_path): + pyproject = {} + if os.path.exists(pyproject_path): + with open(pyproject_path) as f: + pyproject = toml.load(f) + if "tool" not in pyproject: + pyproject["tool"] = {} + pyproject["tool"]["towncrier"] = { + "template": _get_towncrier_template(), + "underlines": ["~"], + "title_format": "{version} ({project_date})", + "issue_format": _make_issue_format(org, repo), + "directory": "readme/newsfragments", + "filename": "readme/HISTORY.rst", + } + with open(pyproject_path, "w") as f: + toml.dump(pyproject, f) + yield + + +@click.command( + help=( + "Generate readme/HISTORY.rst from towncrier newsfragments " + "stored in readme/newfragments/. This script is meant to be run " + "before oca-gen-addon-readme. See https://pypi.org/project/towncrier/ " + "for more information and the naming and format of newfragment files." + ) +) +@click.option( + "--addon-dir", + "addon_dirs", + type=click.Path(dir_okay=True, file_okay=False, exists=True), + multiple=True, + help="Directory where addon manifest is located. This option " "may be repeated.", +) +@click.option("--version") +@click.option("--date") +@click.option( + "--org", default="OCA", help="GitHub organization name", show_default=True +) +@click.option("--repo", required=True, help="GitHub repository name.") +def oca_towncrier(addon_dirs, version, date, org, repo): + if not date: + date = datetime.date.today().isoformat() + for addon_dir in addon_dirs: + news_dir = os.path.join(addon_dir, "readme", "newsfragments") + if not os.path.isdir(news_dir): + continue + 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_pyproject_toml(addon_dir, org, repo): + subprocess.call( + [ + sys.executable, + "-m", + "towncrier", + "--version", + addon_version, + "--date", + date, + "--yes", + ], + cwd=addon_dir, + ) + + +if __name__ == "__main__": + oca_towncrier() diff --git a/tools/towncrier-template.rst b/tools/towncrier-template.rst new file mode 100644 index 00000000..47aee2ad --- /dev/null +++ b/tools/towncrier-template.rst @@ -0,0 +1,33 @@ +{% for section, _ in sections.items() %} +{% if section %}{{section}} +{{ '~' * section|length }} + +{% 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 }} ({{ values|join(', ') }}) +{% endfor %} + +{% else %} +- {{ sections[section][category]['']|join(', ') }} + +{% endif %} +{% if sections[section][category]|length == 0 %} +No significant changes. + +{% else %} +{% endif %} + +{% endfor %} +{% else %} +No significant changes. + + +{% endif %} +{% endfor %} + From 8e435dfd83cf187d9853fe60781f3c6a2ce05fba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Bidoul?= Date: Wed, 25 Mar 2020 12:24:21 +0100 Subject: [PATCH 3/3] oca-towncrier: add --commit option --- tools/gitutils.py | 7 ++++--- tools/oca_towncrier.py | 14 ++++++++++++-- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/tools/gitutils.py b/tools/gitutils.py index c28846dd..c797de65 100644 --- a/tools/gitutils.py +++ b/tools/gitutils.py @@ -3,9 +3,10 @@ import subprocess -def commit_if_needed(paths, message): - cmd = ['git', 'add'] + paths - subprocess.check_call(cmd) +def commit_if_needed(paths, message, add=True): + if add: + cmd = ['git', 'add'] + paths + subprocess.check_call(cmd) cmd = ['git', 'diff', '--quiet', '--exit-code', '--cached', '--'] + paths r = subprocess.call(cmd) if r != 0: diff --git a/tools/oca_towncrier.py b/tools/oca_towncrier.py index c01df495..82dd48bb 100644 --- a/tools/oca_towncrier.py +++ b/tools/oca_towncrier.py @@ -12,6 +12,7 @@ import click import toml +from .gitutils import commit_if_needed from .manifest import read_manifest @@ -85,12 +86,17 @@ def _prepare_pyproject_toml(addon_dir, org, repo): @click.option("--version") @click.option("--date") @click.option( - "--org", default="OCA", help="GitHub organization name", show_default=True + "--org", default="OCA", help="GitHub organization name.", show_default=True ) @click.option("--repo", required=True, help="GitHub repository name.") -def oca_towncrier(addon_dirs, version, date, org, repo): +@click.option( + "--commit/--no-commit", + help="git commit changes, if any (a git add is done in any case).", +) +def oca_towncrier(addon_dirs, version, date, org, repo, commit): if not date: date = datetime.date.today().isoformat() + paths = [] for addon_dir in addon_dirs: news_dir = os.path.join(addon_dir, "readme", "newsfragments") if not os.path.isdir(news_dir): @@ -112,6 +118,10 @@ def oca_towncrier(addon_dirs, version, date, org, repo): ], cwd=addon_dir, ) + paths.append(news_dir) + paths.append(os.path.join(addon_dir, "readme", "HISTORY.rst")) + if commit: + commit_if_needed(paths, message="[UPD] changelog", add=False) if __name__ == "__main__":