diff --git a/duties.py b/duties.py index 904dfdb..1dc6f7c 100644 --- a/duties.py +++ b/duties.py @@ -13,6 +13,7 @@ from urllib.request import urlopen from duty import duty PACKAGE_NAME = "tembo" +REPO_URL = "https://github.com/tembo-pages/tembo-core" @duty(post=["export"]) @@ -66,22 +67,21 @@ def coverage(ctx): @duty -def version(ctx, bump: str = "patch"): +def bump(ctx, version: str = "patch"): """ Bump the version using Poetry and update _version.py. Args: ctx: The context instance (passed automatically). - bump (str, optional) = poetry version flag. Available options are: - patch, minor, major, prepatch, preminor, premajor, prerelease. - Defaults to patch. + version (str, optional) = poetry version flag. Available options are: + patch, minor, major. Defaults to patch. Example: - `duty version bump=major` + `duty bump version=major` """ # bump with poetry - result = ctx.run(["poetry", "version", bump]) + result = ctx.run(["poetry", "version", version]) new_version = re.search(r"(?:.*)(?:\s)(\d+\.\d+\.\d+)$", result) print(new_version.group(0)) @@ -126,6 +126,26 @@ def build(ctx): shutil.rmtree(extracted_path) +@duty +def release(ctx, version: str = "patch") -> None: + """ + Prepare package for a new release. + + Will run bump, build, export. Manual running of publish is required afterwards. + + Args: + ctx: The context instance (passed automatically). + version (str): poetry version flag. Available options are: patch, minor, major. + """ + print(ctx.run(["duty", "bump", f"version={version}"])) + ctx.run(["duty", "build"]) + ctx.run(["duty", "export"]) + print( + "✔ Check generated files. Run `duty changelog planned_release= previous_release=` and `duty publish password=`" + " when ready to publish." + ) + + @duty def export(ctx): """ @@ -308,82 +328,36 @@ def check_dependencies(ctx): ) -def _latest(lines: List[str], regex: Pattern) -> Optional[str]: - for line in lines: - match = regex.search(line) - if match: - return match.groupdict()["version"] - return None - - -def _unreleased(versions, last_release): - for index, version in enumerate(versions): - if version.tag == last_release: - return versions[:index] - return versions - - -def update_changelog( - inplace_file: str, - marker: str, - version_regex: str, - commit_style: str, -) -> None: - """ - Update the given changelog file in place. - Arguments: - inplace_file: The file to update in-place. - marker: The line after which to insert new contents. - version_regex: A regular expression to find currently documented versions in the file. - template_url: The URL to the Jinja template used to render contents. - commit_style: The style of commit messages to parse. - """ - from git_changelog.build import Changelog - from jinja2.sandbox import SandboxedEnvironment - - env = SandboxedEnvironment(autoescape=False) - template = env.from_string(changelog_template()) - changelog = Changelog(".", style=commit_style) - - if len(changelog.versions_list) == 1: - last_version = changelog.versions_list[0] - if last_version.planned_tag is None: - planned_tag = "0.1.0" - last_version.tag = planned_tag - last_version.url += planned_tag - last_version.compare_url = last_version.compare_url.replace("HEAD", planned_tag) - - with open(inplace_file, "r") as changelog_file: - lines = changelog_file.read().splitlines() - - last_released = _latest(lines, re.compile(version_regex)) - if last_released: - changelog.versions_list = _unreleased(changelog.versions_list, last_released) - rendered = template.render(changelog=changelog, inplace=True) - lines[lines.index(marker)] = rendered - - with open(inplace_file, "w") as changelog_file: # noqa: WPS440 - changelog_file.write("\n".join(lines).rstrip("\n") + "\n") - - @duty -def changelog(ctx): +def changelog(ctx, planned_release: Optional[str] = None, previous_release: Optional[str] = None): """ - Update the changelog in-place with latest commits. - Arguments: + Generate a changelog with git-cliff. + + Args: ctx: The context instance (passed automatically). + planned_release (str, optional): The planned release version. Example: v1.0.2 + previous_release (str, optional): The previous release version. Example: v1.0.1 """ - ctx.run( - update_changelog, - kwargs={ - "inplace_file": "CHANGELOG.md", - "marker": "", - "version_regex": r"^## \[v?(?P[^\]]+)", - "commit_style": "angular", - }, - title="Updating changelog", - pty=True, - ) + generated_changelog: str = ctx.run(["git", "cliff", "-u", "-t", planned_release, "-s", "header"])[:-1] + if previous_release is not None: + generated_changelog: list = generated_changelog.splitlines() + generated_changelog.insert( + 1, + f"[Compare with {previous_release}]({REPO_URL}/compare/{previous_release}..{planned_release})", + ) + generated_changelog: str = "\n".join([line for line in generated_changelog]) + "\n" + new_changelog = [] + + changelog_file = pathlib.Path(".") / "CHANGELOG.md" + with changelog_file.open("r", encoding="utf-8") as changelog_contents: + all_lines = changelog_contents.readlines() + for line_string in all_lines: + regex_string = re.search(r"()", line_string) + new_changelog.append(line_string) + if isinstance(regex_string, re.Match): + new_changelog.append(generated_changelog) + with changelog_file.open("w", encoding="utf-8") as changelog_contents: + changelog_contents.writelines(new_changelog) def rm_tree(directory: pathlib.Path): @@ -399,51 +373,3 @@ def rm_tree(directory: pathlib.Path): else: rm_tree(child) directory.rmdir() - - -def changelog_template() -> str: - return """ -{% if not inplace -%} -# Changelog -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). - -{% endif %} -{% macro render_commit(commit) -%} -- {{ commit.style.subject|default(commit.subject) }} ([{{ commit.hash|truncate(7, True, '') }}]({{ commit.url }}) by {{ commit.author_name }}). -{%- if commit.text_refs.issues_not_in_subject %} References: {% for issue in commit.text_refs.issues_not_in_subject -%} -{% if issue.url %}[{{ issue.ref }}]({{ issue.url }}){%else %}{{ issue.ref }}{% endif %}{% if not loop.last %}, {% endif -%} -{%- endfor -%}{%- endif -%} -{%- endmacro -%} - -{%- macro render_section(section) -%} -### {{ section.type or "Misc" }} -{% for commit in section.commits|sort(attribute='author_date',reverse=true)|unique(attribute='subject') -%} -{{ render_commit(commit) }} -{% endfor %} -{%- endmacro -%} - -{%- macro render_version(version) -%} -{%- if version.tag or version.planned_tag -%} -## [{{ version.tag or version.planned_tag }}]({{ version.url }}){% if version.date %} - {{ version.date }}{% endif %} - -[Compare with {{ version.previous_version.tag|default("first commit") }}]({{ version.compare_url }}) -{%- else -%} -## Unrealeased - -[Compare with latest]({{ version.compare_url }}) -{%- endif %} - -{% for type, section in version.sections_dict|dictsort -%} -{%- if type and type in changelog.style.DEFAULT_RENDER -%} -{{ render_section(section) }} -{% endif -%} -{%- endfor -%} -{%- endmacro -%} - -{% for version in changelog.versions_list -%} -{{ render_version(version) }} -{%- endfor -%} - """