From 37412ee1af5fbda9108f4096d0a08800058214d8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 16 Sep 2024 16:44:31 +0200 Subject: [PATCH 01/66] Refactor cli calls --- action.yml | 9 +--- github_query.py | 112 ++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 96 insertions(+), 25 deletions(-) diff --git a/action.yml b/action.yml index c50d6d4..32a38dc 100644 --- a/action.yml +++ b/action.yml @@ -55,12 +55,7 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - label_list=$(python -c 'import github_query; print(github_query.get_labels(github_query.parse_args()))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - if [[ "$label_list" == '[]' ]]; then - echo "label_list=''" >> $GITHUB_OUTPUT - exit 0 - fi - + label_list=$(python github_query.py pr-labels "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") echo "label_list=$label_list" >> $GITHUB_OUTPUT - name: Get version increment @@ -68,7 +63,7 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + increment=$(python github_query.py version-increment "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") echo "increment=$increment" >> $GITHUB_OUTPUT # disabled until fixed diff --git a/github_query.py b/github_query.py index cec0841..a297869 100644 --- a/github_query.py +++ b/github_query.py @@ -4,7 +4,7 @@ Additonally it's test suite relies mainly on putest and therefore the functions need to be importable to the pytest script. """ -import argparse +import click import json import logging import re @@ -13,24 +13,34 @@ logger = logging.getLogger(__name__) -def parse_args() -> dict: - """Parse command-line arguments and store them in a global variable.""" +def query_merged_prs(latest_release_date, query_tags, repo_name): + """Run gh pull request query. - parser = argparse.ArgumentParser(description="A python script to convert GitHub PR information to a more simple format.") - parser.add_argument("repo", type=str, help="Repository name consisting of 'repo-owner/repo-name'") - parser.add_argument("query_parameters", type=str, help="Keys to query for.") - parser.add_argument("date", type=str, default="2024-07-08T09:48:33Z", help="Latest release date.") - parsed_args = parser.parse_args() + Args: + latest_release_date (str): datatime string + query_tags (str): csv string + repo_name (str): repo name as - repo_name = parsed_args.repo - query_tags = parsed_args.query_parameters.split(',') - latest_release_date = parsed_args.date + Returns: + dict: json-dictionary. + """ - command = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" - pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + pr_list = subprocess.run( + [ + "gh", "pr", "list", + "--state", "merged", + "--search", f'merged:>={latest_release_date}', + "--json", ','.join(query_tags), + "--repo", repo_name + ], + capture_output=True, + text=True, + check=True + ) - return json.loads(pr_json.stdout) + return json.loads(pr_list.stdout) +# INFO not in use def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): """Get list of changes from a PRs changelog. @@ -60,6 +70,7 @@ def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): return changelog_lines +# INFO not in use def changelog_per_label(json_dict): # TODO replace with labels fetched from repo variables changelog_labels = ["bugfix", "enhancement", "feature"] @@ -69,6 +80,7 @@ def changelog_per_label(json_dict): if any(item in changelog_labels for item in labels): pass +# INFO not in use def prepare_changelog_markdown(pr_query, minor_bump_list, patch_bump_list): # ? should version bump labels also be filter for changelog ? label_list = minor_bump_list + patch_bump_list @@ -96,19 +108,22 @@ def get_labels(pr_data: dict) -> list: pr_data (dict): Github PR query result Returns: - [str]: Liste of unique labels strings found or `None`. + list: Liste of unique labels strings found or `None`. """ labels = set() for item in pr_data: if not item.get("labels"): + logger.warning("No PR label data found.") return [] for label in item["labels"]: if not label.get("name"): + logger.warning("No PR label names found.") return [] labels.add(label["name"]) + logger.debug("PR labels found.") return list(labels) @@ -120,7 +135,7 @@ def get_repo_var(repo: str, var_name: str) -> list: var_name (str): Repo variable name Returns: - str: Comma separated value string. + str: csv-string. """ labels = subprocess.run( ["gh", "variable", "get", var_name, "--repo", repo], @@ -129,9 +144,18 @@ def get_repo_var(repo: str, var_name: str) -> list: check=True ) - return csv_string_to_list(labels.stdout) + return labels.stdout def csv_string_to_list(input: str) -> list: + """Covnert string to list. + + Args: + input (str): Expected csv string. + + Returns: + list: List of strings. + """ + if input: return re.split(r',\s*', input.strip()) @@ -143,7 +167,7 @@ def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label Args: patch_bump_list ([str]): Labels for bumping patch version minor_bump_list ([str]): Labels for bumping minor version - label_list([str]): Labels found in PRs + label_list ([str]): Labels found in PRs Returns: str: version increment @@ -159,4 +183,56 @@ def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label if any(label in pr_label_list for label in patch_bump_list): return "patch" + logger.warning("No relevant labels found for version increment.") return "" + +# CLI using Click + +@click.group() +def cli(): + pass + +@cli.command() +@click.argument('repo_name', type=click.STRING) +@click.argument('query_tags', type=click.STRING) +@click.argument('latest_release_date', type=click.STRING) +def pr_labels(latest_release_date, query_tags, repo_name): + """Get a list of all version relevant PR labels. + + latest_release_date (str): datatime string\n + query_tags (str): csv string\n + repo_name (str): repo name as \n + """ + + pr_result = query_merged_prs(latest_release_date, query_tags, repo_name) + pr_labels = get_labels(pr_data=pr_result) + + if not pr_labels: + click.echo("") + + click.echo(pr_labels) + + +@cli.command() +@click.argument('repo_name', type=click.STRING) +@click.argument('query_tags', type=click.STRING) +@click.argument('latest_release_date', type=click.STRING) +def version_increment(latest_release_date, query_tags, repo_name): + """Output a calculated version increment suggestion. + + latest_release_date (str): datatime string\n + query_tags (str): csv string\n + repo_name (str): repo name as \n + """ + + pr_result = query_merged_prs(latest_release_date, query_tags, repo_name) + pr_labels = get_labels(pr_data=pr_result) + patch_repo_var_list = csv_string_to_list(get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) + minor_repo_var_list = csv_string_to_list(get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) + increment = get_version_increment(patch_bump_list=patch_repo_var_list, minor_bump_list=minor_repo_var_list, pr_label_list=pr_labels) + + click.echo(increment) + + +if __name__ == '__main__': + cli() \ No newline at end of file From 19044f60436b6a8857f4c6abfde9c0ae5c6efaa1 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 17 Sep 2024 13:00:07 +0200 Subject: [PATCH 02/66] Move logic into dedicated files --- github_query.py | 195 ++----------------------------------- src/__init__.py | 0 src/conversion_logic.py | 132 +++++++++++++++++++++++++ src/queries.py | 50 ++++++++++ tests/test_github_query.py | 27 +++-- 5 files changed, 203 insertions(+), 201 deletions(-) create mode 100644 src/__init__.py create mode 100644 src/conversion_logic.py create mode 100644 src/queries.py diff --git a/github_query.py b/github_query.py index a297869..f5c1316 100644 --- a/github_query.py +++ b/github_query.py @@ -5,186 +5,7 @@ """ import click -import json -import logging -import re -import subprocess - - -logger = logging.getLogger(__name__) - -def query_merged_prs(latest_release_date, query_tags, repo_name): - """Run gh pull request query. - - Args: - latest_release_date (str): datatime string - query_tags (str): csv string - repo_name (str): repo name as - - Returns: - dict: json-dictionary. - """ - - pr_list = subprocess.run( - [ - "gh", "pr", "list", - "--state", "merged", - "--search", f'merged:>={latest_release_date}', - "--json", ','.join(query_tags), - "--repo", repo_name - ], - capture_output=True, - text=True, - check=True - ) - - return json.loads(pr_list.stdout) - -# INFO not in use -def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): - """Get list of changes from a PRs changelog. - - Args: - pr_body (list(str)): List of PR body contents. - changelog_start (str, optional): Indicates markdown changelog section. Defaults to "## Changes". - heading (str, optional): Markdown heading. Defaults to "##". - - Returns: - list(str): List of changes found. - """ - - lines = pr_data.splitlines() - changelog_section = None - changelog_lines = [] - - for line in lines: - if line.startswith(changelog_start): - changelog_section = True - continue - - if changelog_section and line.startswith(heading): - break - - if changelog_section and line.startswith("* "): - changelog_lines.append(line.strip("* ").strip()) - - return changelog_lines - -# INFO not in use -def changelog_per_label(json_dict): - # TODO replace with labels fetched from repo variables - changelog_labels = ["bugfix", "enhancement", "feature"] - labels = [] - for item in json_dict: - labels.append(item["labels"]) - if any(item in changelog_labels for item in labels): - pass - -# INFO not in use -def prepare_changelog_markdown(pr_query, minor_bump_list, patch_bump_list): - # ? should version bump labels also be filter for changelog ? - label_list = minor_bump_list + patch_bump_list - changelog = "" - - for pr in pr_query: - # get all label names in a list - pr_label_list = [label["name"] for label in pr["labels"]] - fitlered_label = list(set(label_list).intersection(pr_label_list))[0] - - if fitlered_label: - change_list = get_changelog(pr_data=pr["body"]) - - changelog += f"## {fitlered_label.capitalize()}\n" - changelog += "".join([f"* {change}\n" for change in change_list]) - changelog += "\n" - - return changelog - - -def get_labels(pr_data: dict) -> list: - """Filter all unique labels from dictionary. - - Args: - pr_data (dict): Github PR query result - - Returns: - list: Liste of unique labels strings found or `None`. - """ - - labels = set() - - for item in pr_data: - if not item.get("labels"): - logger.warning("No PR label data found.") - return [] - for label in item["labels"]: - if not label.get("name"): - logger.warning("No PR label names found.") - return [] - - labels.add(label["name"]) - logger.debug("PR labels found.") - - return list(labels) - -def get_repo_var(repo: str, var_name: str) -> list: - """Query labels from repository variables. - - Args: - repo (str): Repository name `owner/repo-name` - var_name (str): Repo variable name - - Returns: - str: csv-string. - """ - labels = subprocess.run( - ["gh", "variable", "get", var_name, "--repo", repo], - capture_output=True, - text=True, - check=True - ) - - return labels.stdout - -def csv_string_to_list(input: str) -> list: - """Covnert string to list. - - Args: - input (str): Expected csv string. - - Returns: - list: List of strings. - """ - - if input: - return re.split(r',\s*', input.strip()) - - return [] - -def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label_list: list): - """Figure out version increment based on PR labels. - - Args: - patch_bump_list ([str]): Labels for bumping patch version - minor_bump_list ([str]): Labels for bumping minor version - label_list ([str]): Labels found in PRs - - Returns: - str: version increment - """ - - if not pr_label_list: - return "" - - # TODO add major bump option - if any(label in pr_label_list for label in minor_bump_list): - return "minor" - - if any(label in pr_label_list for label in patch_bump_list): - return "patch" - - logger.warning("No relevant labels found for version increment.") - return "" +from src import conversion_logic, queries # CLI using Click @@ -204,8 +25,8 @@ def pr_labels(latest_release_date, query_tags, repo_name): repo_name (str): repo name as \n """ - pr_result = query_merged_prs(latest_release_date, query_tags, repo_name) - pr_labels = get_labels(pr_data=pr_result) + pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + pr_labels = conversion_logic.get_labels(pr_data=pr_result) if not pr_labels: click.echo("") @@ -225,11 +46,11 @@ def version_increment(latest_release_date, query_tags, repo_name): repo_name (str): repo name as \n """ - pr_result = query_merged_prs(latest_release_date, query_tags, repo_name) - pr_labels = get_labels(pr_data=pr_result) - patch_repo_var_list = csv_string_to_list(get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) - minor_repo_var_list = csv_string_to_list(get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) - increment = get_version_increment(patch_bump_list=patch_repo_var_list, minor_bump_list=minor_repo_var_list, pr_label_list=pr_labels) + pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + pr_labels = conversion_logic.get_labels(pr_data=pr_result) + patch_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) + minor_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_repo_var_list, minor_bump_list=minor_repo_var_list, pr_label_list=pr_labels) click.echo(increment) diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/conversion_logic.py b/src/conversion_logic.py new file mode 100644 index 0000000..d734bd2 --- /dev/null +++ b/src/conversion_logic.py @@ -0,0 +1,132 @@ +import logging +import re + + +logger = logging.getLogger(__name__) + +# INFO not in use +def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): + """Get list of changes from a PRs changelog. + + Args: + pr_body (list(str)): List of PR body contents. + changelog_start (str, optional): Indicates markdown changelog section. Defaults to "## Changes". + heading (str, optional): Markdown heading. Defaults to "##". + + Returns: + list(str): List of changes found. + """ + + lines = pr_data.splitlines() + changelog_section = None + changelog_lines = [] + + for line in lines: + if line.startswith(changelog_start): + changelog_section = True + continue + + if changelog_section and line.startswith(heading): + break + + if changelog_section and line.startswith("* "): + changelog_lines.append(line.strip("* ").strip()) + + return changelog_lines + +# INFO not in use +def changelog_per_label(json_dict): + # TODO replace with labels fetched from repo variables + changelog_labels = ["bugfix", "enhancement", "feature"] + labels = [] + for item in json_dict: + labels.append(item["labels"]) + if any(item in changelog_labels for item in labels): + pass + +# INFO not in use +def prepare_changelog_markdown(pr_query, minor_bump_list, patch_bump_list): + # ? should version bump labels also be filter for changelog ? + label_list = minor_bump_list + patch_bump_list + changelog = "" + + for pr in pr_query: + # get all label names in a list + pr_label_list = [label["name"] for label in pr["labels"]] + fitlered_label = list(set(label_list).intersection(pr_label_list))[0] + + if fitlered_label: + change_list = get_changelog(pr_data=pr["body"]) + + changelog += f"## {fitlered_label.capitalize()}\n" + changelog += "".join([f"* {change}\n" for change in change_list]) + changelog += "\n" + + return changelog + + +def get_labels(pr_data: dict) -> list: + """Filter all unique labels from dictionary. + + Args: + pr_data (dict): Github PR query result + + Returns: + list: Liste of unique labels strings found or `None`. + """ + + labels = set() + + for item in pr_data: + if not item.get("labels"): + logger.warning("No PR label data found.") + return [] + for label in item["labels"]: + if not label.get("name"): + logger.warning("No PR label names found.") + return [] + + labels.add(label["name"]) + logger.debug("PR labels found.") + + return list(labels) + +def csv_string_to_list(input: str) -> list: + """Covnert string to list. + + Args: + input (str): Expected csv string. + + Returns: + list: List of strings. + """ + + if input: + return re.split(r',\s*', input.strip()) + + return [] + +def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label_list: list): + """Figure out version increment based on PR labels. + + Args: + patch_bump_list ([str]): Labels for bumping patch version + minor_bump_list ([str]): Labels for bumping minor version + label_list ([str]): Labels found in PRs + + Returns: + str: version increment + """ + + if not pr_label_list: + return "" + + # TODO add major bump option + if any(label in pr_label_list for label in minor_bump_list): + return "minor" + + if any(label in pr_label_list for label in patch_bump_list): + return "patch" + + logger.warning("No relevant labels found for version increment.") + return "" \ No newline at end of file diff --git a/src/queries.py b/src/queries.py new file mode 100644 index 0000000..9bbcabb --- /dev/null +++ b/src/queries.py @@ -0,0 +1,50 @@ +import json +import subprocess + + +def query_merged_prs(latest_release_date, query_tags, repo_name): + """Run gh pull request query. + + Args: + latest_release_date (str): datatime string + query_tags (str): csv string + repo_name (str): repo name as + + Returns: + dict: json-dictionary. + """ + + pr_list = subprocess.run( + [ + "gh", "pr", "list", + "--state", "merged", + "--search", f'merged:>={latest_release_date}', + "--json", ','.join(query_tags), + "--repo", repo_name + ], + capture_output=True, + text=True, + check=True + ) + + return json.loads(pr_list.stdout) + + +def get_repo_var(repo: str, var_name: str) -> list: + """Query labels from repository variables. + + Args: + repo (str): Repository name `owner/repo-name` + var_name (str): Repo variable name + + Returns: + str: csv-string. + """ + labels = subprocess.run( + ["gh", "variable", "get", var_name, "--repo", repo], + capture_output=True, + text=True, + check=True + ) + + return labels.stdout diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 2948f8d..d1fe6c6 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -1,7 +1,6 @@ import pytest -from unittest.mock import patch -import github_query +from src import conversion_logic @pytest.fixture def pr_api_output(): @@ -109,13 +108,13 @@ def csv_string_empty(): # Get PR Label test-cases def test_get_labels(pr_api_output): - labels = github_query.get_labels(pr_data=pr_api_output) + labels = conversion_logic.get_labels(pr_data=pr_api_output) assert isinstance(labels, list) assert set(labels) == {"bugfix", "enhancement"} def test_get_labels_missing_input(pr_api_output_missing_label): - labels = github_query.get_labels(pr_data=pr_api_output_missing_label) + labels = conversion_logic.get_labels(pr_data=pr_api_output_missing_label) assert labels == [] @@ -123,22 +122,22 @@ def test_get_labels_missing_input(pr_api_output_missing_label): # Convert repo label list def test_csv_string_to_list_spaces(csv_string_spaces): - string_list = github_query.csv_string_to_list(csv_string_spaces) + string_list = conversion_logic.csv_string_to_list(csv_string_spaces) assert string_list == ["bugfix", "enhancement", "feature"] def test_csv_string_to_list_no_spaces(csv_string_no_spaces): - string_list = github_query.csv_string_to_list(csv_string_no_spaces) + string_list = conversion_logic.csv_string_to_list(csv_string_no_spaces) assert string_list == ["bugfix", "enhancement", "feature"] def test_csv_string_to_list_no_comma(csv_string_no_comma): - string_list = github_query.csv_string_to_list(csv_string_no_comma) + string_list = conversion_logic.csv_string_to_list(csv_string_no_comma) assert string_list == ["bugfix"] def test_csv_string_to_list_empty(csv_string_empty): - string_list = github_query.csv_string_to_list(csv_string_empty) + string_list = conversion_logic.csv_string_to_list(csv_string_empty) assert string_list == [] @@ -146,26 +145,26 @@ def test_csv_string_to_list_empty(csv_string_empty): # Version Increment test-cases def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_bug) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_bug) assert increment == "patch" def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhancement): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_enhancement) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_enhancement) assert increment == "minor" def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wrong_labels): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_wrong_labels) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_wrong_labels) assert increment == "" def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_none) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_none) assert increment == "" -def test_get_version_increment_ampty_list(minor_bump, patch_bump, pr_labels_empty_list): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_empty_list) +def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empty_list): + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_empty_list) assert increment == "" From 172207bd492f2462f0d4675b626377f3f78b7b02 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 17 Sep 2024 13:00:54 +0200 Subject: [PATCH 03/66] Fix typo --- github_query.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/github_query.py b/github_query.py index f5c1316..3bfb2bc 100644 --- a/github_query.py +++ b/github_query.py @@ -5,9 +5,7 @@ """ import click -from src import conversion_logic, queries - -# CLI using Click +from src import conversion_logic, queries @click.group() def cli(): From c06979aa88bdcfc8c0fb54af783fa8e80bda1a5c Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 30 Sep 2024 16:42:48 +0200 Subject: [PATCH 04/66] Add major bump Upgrade tests --- src/conversion_logic.py | 17 ++++++++------ tests/test_github_query.py | 48 ++++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index d734bd2..81af801 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -53,12 +53,12 @@ def prepare_changelog_markdown(pr_query, minor_bump_list, patch_bump_list): for pr in pr_query: # get all label names in a list pr_label_list = [label["name"] for label in pr["labels"]] - fitlered_label = list(set(label_list).intersection(pr_label_list))[0] + filtered_label = list(set(label_list).intersection(pr_label_list))[0] - if fitlered_label: + if filtered_label: change_list = get_changelog(pr_data=pr["body"]) - changelog += f"## {fitlered_label.capitalize()}\n" + changelog += f"## {filtered_label.capitalize()}\n" changelog += "".join([f"* {change}\n" for change in change_list]) changelog += "\n" @@ -72,7 +72,7 @@ def get_labels(pr_data: dict) -> list: pr_data (dict): Github PR query result Returns: - list: Liste of unique labels strings found or `None`. + list: List of unique labels strings found or `None`. """ labels = set() @@ -92,7 +92,7 @@ def get_labels(pr_data: dict) -> list: return list(labels) def csv_string_to_list(input: str) -> list: - """Covnert string to list. + """Convert string to list. Args: input (str): Expected csv string. @@ -106,7 +106,7 @@ def csv_string_to_list(input: str) -> list: return [] -def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label_list: list): +def get_version_increment(pr_label_list: list, patch_bump_list: list=[], minor_bump_list: list=[], major_bump_list: list=[]): """Figure out version increment based on PR labels. Args: @@ -119,9 +119,12 @@ def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label """ if not pr_label_list: + logger.warning("PR label list was empty") return "" - # TODO add major bump option + if any(label in pr_label_list for label in major_bump_list): + return "major" + if any(label in pr_label_list for label in minor_bump_list): return "minor" diff --git a/tests/test_github_query.py b/tests/test_github_query.py index d1fe6c6..e5cdefb 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -52,6 +52,10 @@ def pr_api_output_missing_label(): } ] +@pytest.fixture +def major_bump(): + return ["epic"] + @pytest.fixture def minor_bump(): return ["feature", "enhancement"] @@ -68,6 +72,10 @@ def pr_labels_bug(): def pr_labels_enhancement(): return ["bugfix", "documentation", "feature", "enhancement"] +@pytest.fixture +def pr_labels_epic(): + return ["bugfix", "documentation", "feature", "enhancement", "epic"] + @pytest.fixture def pr_labels_wrong_labels(): return ["documentation", "wontfix"] @@ -145,26 +153,56 @@ def test_csv_string_to_list_empty(csv_string_empty): # Version Increment test-cases def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug): - increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_bug) + increment = conversion_logic.get_version_increment( + pr_label_list=pr_labels_bug, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + ) assert increment == "patch" def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhancement): - increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_enhancement) + increment = conversion_logic.get_version_increment( + pr_label_list=pr_labels_enhancement, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + ) assert increment == "minor" +def test_get_version_increment_minor(minor_bump, patch_bump, major_bump, pr_labels_epic): + increment = conversion_logic.get_version_increment( + pr_label_list=pr_labels_epic, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + major_bump_list=major_bump, + ) + + assert increment == "major" + def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wrong_labels): - increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_wrong_labels) + increment = conversion_logic.get_version_increment( + pr_label_list=pr_labels_wrong_labels, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + ) assert increment == "" def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none): - increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_none) + increment = conversion_logic.get_version_increment( + pr_label_list=pr_labels_none, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + ) assert increment == "" def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empty_list): - increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_empty_list) + increment = conversion_logic.get_version_increment( + pr_label_list=pr_labels_empty_list, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + ) assert increment == "" From 5e45bb50182f29d257df1a73a3bf076a7b62bca8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 30 Sep 2024 16:53:19 +0200 Subject: [PATCH 05/66] Add raise in terms of wrong datatype --- github_query.py | 2 +- src/conversion_logic.py | 4 ++++ tests/test_github_query.py | 13 +++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/github_query.py b/github_query.py index 3bfb2bc..4761ec3 100644 --- a/github_query.py +++ b/github_query.py @@ -39,7 +39,7 @@ def pr_labels(latest_release_date, query_tags, repo_name): def version_increment(latest_release_date, query_tags, repo_name): """Output a calculated version increment suggestion. - latest_release_date (str): datatime string\n + latest_release_date (str): datetime string\n query_tags (str): csv string\n repo_name (str): repo name as \n """ diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 81af801..f8ba18f 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -122,6 +122,10 @@ def get_version_increment(pr_label_list: list, patch_bump_list: list=[], minor_b logger.warning("PR label list was empty") return "" + for name, param in locals().items(): + if not isinstance(param, list): + raise ValueError(f"{name} must be a list.") + if any(label in pr_label_list for label in major_bump_list): return "major" diff --git a/tests/test_github_query.py b/tests/test_github_query.py index e5cdefb..57d9766 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -56,6 +56,10 @@ def pr_api_output_missing_label(): def major_bump(): return ["epic"] +@pytest.fixture +def major_bump_no_list(): + return "epic" + @pytest.fixture def minor_bump(): return ["feature", "enhancement"] @@ -206,3 +210,12 @@ def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empt ) assert increment == "" + +def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_list, pr_labels_epic): + with pytest.raises(ValueError, match="must be a list"): + conversion_logic.get_version_increment( + pr_label_list=pr_labels_epic, + patch_bump_list=patch_bump, + minor_bump_list=minor_bump, + major_bump_list=major_bump_no_list, + ) From b9766f7ac7faa8f10bffd0ac1ecbbc3582f4a9d8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 15 Oct 2024 10:02:21 +0200 Subject: [PATCH 06/66] Implement basic changelog filtering --- TODO.md | 2 +- github_query.py | 42 +++++++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/TODO.md b/TODO.md index 3329707..c250e4e 100644 --- a/TODO.md +++ b/TODO.md @@ -13,4 +13,4 @@ ## Structure for implementation * Implement section order in repo variable -* One repo var per section to store PR label names \ No newline at end of file +* One repo var per section to store PR label names diff --git a/github_query.py b/github_query.py index cec0841..5dcfd2f 100644 --- a/github_query.py +++ b/github_query.py @@ -10,6 +10,8 @@ import re import subprocess +from collections import namedtuple + logger = logging.getLogger(__name__) @@ -60,6 +62,19 @@ def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): return changelog_lines +def filter_changelog_per_label(pr_data, changelog_label_list): + + Changelog = namedtuple("Changelog", "labels title number url id") + changes_list = [] + + for pull_request in pr_data: + + label_list = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] + if label_list: + changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"])) + + return changes_list + def changelog_per_label(json_dict): # TODO replace with labels fetched from repo variables changelog_labels = ["bugfix", "enhancement", "feature"] @@ -69,16 +84,12 @@ def changelog_per_label(json_dict): if any(item in changelog_labels for item in labels): pass -def prepare_changelog_markdown(pr_query, minor_bump_list, patch_bump_list): - # ? should version bump labels also be filter for changelog ? - label_list = minor_bump_list + patch_bump_list - changelog = "" - - for pr in pr_query: - # get all label names in a list - pr_label_list = [label["name"] for label in pr["labels"]] - fitlered_label = list(set(label_list).intersection(pr_label_list))[0] +def build_changelog_markdown(filtered_pr_data, changelog_label_list): + changelog = "# Changelog" + for pr_data in filtered_pr_data: + + pr_data.labels in pr_data if fitlered_label: change_list = get_changelog(pr_data=pr["body"]) @@ -160,3 +171,16 @@ def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label return "patch" return "" + +if __name__ == '__main__': + + # TODO remove before merging + command = f"gh pr list --state merged --search 'merged:>=2024-08-01T11:29:22Z' --json body,labels,title,number,url,id --repo ynput/ayon-maya" + pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + pr_data = json.loads(pr_json.stdout) + + changelog_labels = ["type: bug", "type: enhancement", "type: maintenance"] + pr_filtered = filter_changelog_per_label(pr_data=pr_data, changelog_label_list=changelog_labels): + changelog = build_changelog_markdown(filtered_pr_data=pr_filtered, changelog_label_list=changelog_labels) + + print(changelog) From 0ce18b7d9515bcb03e9c82857501cf491bc5f4d7 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Thu, 17 Oct 2024 10:01:08 +0200 Subject: [PATCH 07/66] Implement markdown change output --- github_query.py | 50 +++++++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/github_query.py b/github_query.py index 5dcfd2f..8cc67ba 100644 --- a/github_query.py +++ b/github_query.py @@ -11,6 +11,7 @@ import subprocess from collections import namedtuple +from itertools import groupby logger = logging.getLogger(__name__) @@ -62,40 +63,45 @@ def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): return changelog_lines -def filter_changelog_per_label(pr_data, changelog_label_list): +def filter_changes_per_label(pr_data: dict, changelog_label_list: list) -> namedtuple: Changelog = namedtuple("Changelog", "labels title number url id") changes_list = [] for pull_request in pr_data: + # TODO refactor this to become more readable label_list = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] if label_list: changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"])) return changes_list -def changelog_per_label(json_dict): - # TODO replace with labels fetched from repo variables - changelog_labels = ["bugfix", "enhancement", "feature"] - labels = [] - for item in json_dict: - labels.append(item["labels"]) - if any(item in changelog_labels for item in labels): - pass +def sort_changes(changes_list: namedtuple, changelog_label_list: list) -> namedtuple: -def build_changelog_markdown(filtered_pr_data, changelog_label_list): + # TODO implement this logic in a more clever way + sorted_changes = [] + for order_label in changelog_label_list: + for change in changes_list: + if any(label == order_label for label in change.labels): + sorted_changes.append(change) + + return sorted_changes + +def build_changelog_markdown(changes): changelog = "# Changelog" + previous_labels = [] - for pr_data in filtered_pr_data: + # TODO implement this logic in a more clever way, checkout `from itertools import groupby` + for change in changes: + current_labels = change.labels - pr_data.labels in pr_data - if fitlered_label: - change_list = get_changelog(pr_data=pr["body"]) - - changelog += f"## {fitlered_label.capitalize()}\n" - changelog += "".join([f"* {change}\n" for change in change_list]) - changelog += "\n" + if not any(label in previous_labels for label in current_labels): + changelog += f"\n\n## {change.labels[0]}\n\n" + + changelog += f"* {change.title} - [{change.number}]({change.url})\n" + + previous_labels = current_labels return changelog @@ -180,7 +186,7 @@ def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label pr_data = json.loads(pr_json.stdout) changelog_labels = ["type: bug", "type: enhancement", "type: maintenance"] - pr_filtered = filter_changelog_per_label(pr_data=pr_data, changelog_label_list=changelog_labels): - changelog = build_changelog_markdown(filtered_pr_data=pr_filtered, changelog_label_list=changelog_labels) - - print(changelog) + pr_filtered = filter_changes_per_label(pr_data=pr_data, changelog_label_list=changelog_labels) + sorted_changes = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) + markdown_changelog = build_changelog_markdown(sorted_changes) + print(markdown_changelog) From 5257cf35f5b0cdc2f56f8d19c7ea155ae83cd771 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Fri, 18 Oct 2024 09:41:49 +0200 Subject: [PATCH 08/66] Small refactor Enabled cli output --- github_query.py | 91 ++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 39 deletions(-) diff --git a/github_query.py b/github_query.py index 8cc67ba..c29d12c 100644 --- a/github_query.py +++ b/github_query.py @@ -1,38 +1,41 @@ """ This script is written in a certain - maybe even unconventional way - by intention. -It's supposed to be run from comamndline right away to be used in a github action workflow yaml file. -Additonally it's test suite relies mainly on putest and therefore the functions need to be importable to the pytest script. +It's supposed to be run from command line right away to be used in a github action workflow yaml file. +Additionally it's test suite relies mainly on pytest and therefore the functions need to be importable to the pytest script. """ -import argparse import json import logging import re import subprocess from collections import namedtuple -from itertools import groupby logger = logging.getLogger(__name__) -def parse_args() -> dict: - """Parse command-line arguments and store them in a global variable.""" +Changelog = namedtuple("Changelog", "labels title number url id") - parser = argparse.ArgumentParser(description="A python script to convert GitHub PR information to a more simple format.") - parser.add_argument("repo", type=str, help="Repository name consisting of 'repo-owner/repo-name'") - parser.add_argument("query_parameters", type=str, help="Keys to query for.") - parser.add_argument("date", type=str, default="2024-07-08T09:48:33Z", help="Latest release date.") - parsed_args = parser.parse_args() - repo_name = parsed_args.repo - query_tags = parsed_args.query_parameters.split(',') - latest_release_date = parsed_args.date - command = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" - pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) +# def parse_args() -> dict: +# """Parse command-line arguments and store them in a global variable.""" + +# parser = argparse.ArgumentParser(description="A python script to convert GitHub PR information to a more simple format.") +# parser.add_argument("repo", type=str, help="Repository name consisting of 'repo-owner/repo-name'") +# parser.add_argument("query_parameters", type=str, help="Keys to query for.") +# parser.add_argument("date", type=str, default="2024-07-08T09:48:33Z", help="Latest release date.") +# parsed_args = parser.parse_args() + +# repo_name = parsed_args.repo +# query_tags = parsed_args.query_parameters.split(',') +# latest_release_date = parsed_args.date + +# command = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" +# pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + +# return json.loads(pr_json.stdout) - return json.loads(pr_json.stdout) def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): """Get list of changes from a PRs changelog. @@ -63,24 +66,25 @@ def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): return changelog_lines -def filter_changes_per_label(pr_data: dict, changelog_label_list: list) -> namedtuple: - - Changelog = namedtuple("Changelog", "labels title number url id") - changes_list = [] + +def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]: + + changes_list: list[Changelog] = [] for pull_request in pr_data: # TODO refactor this to become more readable - label_list = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] + label_list: list[str] = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] if label_list: changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"])) return changes_list -def sort_changes(changes_list: namedtuple, changelog_label_list: list) -> namedtuple: + +def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) -> list[Changelog]: # TODO implement this logic in a more clever way - sorted_changes = [] + sorted_changes: list[Changelog] = [] for order_label in changelog_label_list: for change in changes_list: if any(label == order_label for label in change.labels): @@ -88,13 +92,14 @@ def sort_changes(changes_list: namedtuple, changelog_label_list: list) -> namedt return sorted_changes -def build_changelog_markdown(changes): + +def build_changelog_markdown(changes: list[Changelog]) -> str: changelog = "# Changelog" - previous_labels = [] + previous_labels: list[str] = [] # TODO implement this logic in a more clever way, checkout `from itertools import groupby` for change in changes: - current_labels = change.labels + current_labels: list[str] = change.labels if not any(label in previous_labels for label in current_labels): changelog += f"\n\n## {change.labels[0]}\n\n" @@ -106,7 +111,7 @@ def build_changelog_markdown(changes): return changelog -def get_labels(pr_data: dict) -> list: +def get_labels(pr_data: list[dict[str, str]]) -> list[str]: """Filter all unique labels from dictionary. Args: @@ -129,7 +134,8 @@ def get_labels(pr_data: dict) -> list: return list(labels) -def get_repo_var(repo: str, var_name: str) -> list: + +def get_repo_var(repo: str, var_name: str) -> list[str]: """Query labels from repository variables. Args: @@ -148,13 +154,15 @@ def get_repo_var(repo: str, var_name: str) -> list: return csv_string_to_list(labels.stdout) -def csv_string_to_list(input: str) -> list: + +def csv_string_to_list(input: str) -> list[str]: if input: return re.split(r',\s*', input.strip()) return [] -def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label_list: list): + +def get_version_increment(patch_bump_list: list[str], minor_bump_list: list[str], pr_label_list: list[str]): """Figure out version increment based on PR labels. Args: @@ -178,15 +186,20 @@ def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label return "" -if __name__ == '__main__': - # TODO remove before merging - command = f"gh pr list --state merged --search 'merged:>=2024-08-01T11:29:22Z' --json body,labels,title,number,url,id --repo ynput/ayon-maya" +def generate_release_changelog() -> str: + command: str = f"gh pr list --state merged --search 'merged:>=2024-08-01T11:29:22Z' --json body,labels,title,number,url,id --repo ynput/ayon-maya" pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - pr_data = json.loads(pr_json.stdout) + pr_data: str = json.loads(pr_json.stdout) + changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] + + pr_filtered: Changelog = filter_changes_per_label(pr_data=pr_data, changelog_label_list=changelog_labels) + sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) + markdown_changelog: str = build_changelog_markdown(sorted_changes) - changelog_labels = ["type: bug", "type: enhancement", "type: maintenance"] - pr_filtered = filter_changes_per_label(pr_data=pr_data, changelog_label_list=changelog_labels) - sorted_changes = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) - markdown_changelog = build_changelog_markdown(sorted_changes) print(markdown_changelog) + + return markdown_changelog + +if __name__ == "__main__": + generate_release_changelog() From d5cfd4e62952542549d0c9f3d7455738060059f4 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 09:41:16 +0200 Subject: [PATCH 09/66] Refactor cli call to use click --- action.yml | 17 +++++++---------- github_query.py | 16 ++++++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/action.yml b/action.yml index c50d6d4..926617d 100644 --- a/action.yml +++ b/action.yml @@ -71,15 +71,12 @@ runs: increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") echo "increment=$increment" >> $GITHUB_OUTPUT - # disabled until fixed - # - name: Prepare Changelog - # id: write-changelog - # shell: bash - # run: | - # cd $GITHUB_ACTION_PATH - # changelog=$(python -c 'import github_query; gh_query = github_query.parse_args(); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.prepare_changelog_markdown(pr_query=gh_query, minor_bump_list=minor_repo_var, patch_bump_list=patch_repo_var))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - # oneline_changelog=$(echo "$changelog" | base64 | tr -d '/n') - # echo "oneline changelog: $oneline_changelog" - # # echo "changelog=$oneline_changelog" >> $GITHUB_OUTPUT + - name: Prepare Changelog + id: write-changelog + shell: bash + run: | + cd $GITHUB_ACTION_PATH + changelog=$(python github_query.py generate-release-changelog) + echo "changelog=$changelog" >> $GITHUB_OUTPUT ... diff --git a/github_query.py b/github_query.py index c29d12c..3eb87ab 100644 --- a/github_query.py +++ b/github_query.py @@ -4,6 +4,7 @@ Additionally it's test suite relies mainly on pytest and therefore the functions need to be importable to the pytest script. """ +import click import json import logging import re @@ -17,7 +18,6 @@ Changelog = namedtuple("Changelog", "labels title number url id") - # def parse_args() -> dict: # """Parse command-line arguments and store them in a global variable.""" @@ -187,19 +187,23 @@ def get_version_increment(patch_bump_list: list[str], minor_bump_list: list[str] return "" +@click.group() +def cli(): + pass + + +@cli.command() def generate_release_changelog() -> str: command: str = f"gh pr list --state merged --search 'merged:>=2024-08-01T11:29:22Z' --json body,labels,title,number,url,id --repo ynput/ayon-maya" pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - pr_data: str = json.loads(pr_json.stdout) + pr_data: list[dict[str, str]] = json.loads(pr_json.stdout) changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] - pr_filtered: Changelog = filter_changes_per_label(pr_data=pr_data, changelog_label_list=changelog_labels) + pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_data, changelog_label_list=changelog_labels) sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) markdown_changelog: str = build_changelog_markdown(sorted_changes) - print(markdown_changelog) - return markdown_changelog if __name__ == "__main__": - generate_release_changelog() + cli() From 48f05b0e8a5130c729e584047323f74a1e135b4c Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 09:52:41 +0200 Subject: [PATCH 10/66] Update workflow for expected failure --- action.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/action.yml b/action.yml index 926617d..94b56e4 100644 --- a/action.yml +++ b/action.yml @@ -79,4 +79,9 @@ runs: changelog=$(python github_query.py generate-release-changelog) echo "changelog=$changelog" >> $GITHUB_OUTPUT + - name: Show changelog formatted + shell: bash + run: | + echo "${{ steps.write-changelog.outputs.changelog }}" + ... From ef02f45085f656de8f0a44db2d02d2d21de56f25 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 09:55:15 +0200 Subject: [PATCH 11/66] Enable changelog display again --- .github/workflows/action-ci.yml | 2 +- action.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 6c6d643..78a2290 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -55,4 +55,4 @@ jobs: echo "RAW-response: " && echo '${{ steps.test-action.outputs.raw-output }}' echo "Labels: " && echo '${{ steps.test-action.outputs.label-list }}' echo "Bump-increment: " && echo '${{ steps.test-action.outputs.bump-increment }}' - # echo "Changelog: " && echo '${{ steps.test-action.outputs.changelog-markdown }}' + echo "Changelog: " && echo '${{ steps.test-action.outputs.changelog-markdown }}' diff --git a/action.yml b/action.yml index 94b56e4..42234e0 100644 --- a/action.yml +++ b/action.yml @@ -30,9 +30,9 @@ outputs: bump-increment: description: Increment for version bumping - either `patch` or 'minor' value: ${{ steps.bump-increment.outputs.increment }} - # changelog-markdown: - # description: String containing full makrdown syntax for release changelog information - # value: ${{ steps.write-changelog.outputs.changelog }} + changelog-markdown: + description: String containing full markdown syntax for release changelog information + value: ${{ steps.write-changelog.outputs.changelog }} runs: using: composite From 0196c6ea3cd5b2942e34a1da543d4fc15829c2c8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 09:57:49 +0200 Subject: [PATCH 12/66] Update branch pointer --- .github/workflows/action-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 78a2290..953fc6b 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -44,7 +44,7 @@ jobs: steps: - name: Run action id: test-action - uses: ynput/github-query@main + uses: ynput/github-query@generate-changelog with: repo: "ynput/ayon-addon-action-testing" date: "2024-08-20T12:03:23Z" From 86f3f03ccf3da4960e820fde8b8daf7aeffd031a Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:04:34 +0200 Subject: [PATCH 13/66] Replace return with click.echo --- github_query.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/github_query.py b/github_query.py index 3eb87ab..745a0c8 100644 --- a/github_query.py +++ b/github_query.py @@ -18,23 +18,23 @@ Changelog = namedtuple("Changelog", "labels title number url id") -# def parse_args() -> dict: -# """Parse command-line arguments and store them in a global variable.""" +def parse_args() -> dict: + """Parse command-line arguments and store them in a global variable.""" -# parser = argparse.ArgumentParser(description="A python script to convert GitHub PR information to a more simple format.") -# parser.add_argument("repo", type=str, help="Repository name consisting of 'repo-owner/repo-name'") -# parser.add_argument("query_parameters", type=str, help="Keys to query for.") -# parser.add_argument("date", type=str, default="2024-07-08T09:48:33Z", help="Latest release date.") -# parsed_args = parser.parse_args() + parser = argparse.ArgumentParser(description="A python script to convert GitHub PR information to a more simple format.") + parser.add_argument("repo", type=str, help="Repository name consisting of 'repo-owner/repo-name'") + parser.add_argument("query_parameters", type=str, help="Keys to query for.") + parser.add_argument("date", type=str, default="2024-07-08T09:48:33Z", help="Latest release date.") + parsed_args = parser.parse_args() -# repo_name = parsed_args.repo -# query_tags = parsed_args.query_parameters.split(',') -# latest_release_date = parsed_args.date + repo_name = parsed_args.repo + query_tags = parsed_args.query_parameters.split(',') + latest_release_date = parsed_args.date -# command = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" -# pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + command = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" + pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) -# return json.loads(pr_json.stdout) + return json.loads(pr_json.stdout) def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): @@ -203,7 +203,7 @@ def generate_release_changelog() -> str: sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) markdown_changelog: str = build_changelog_markdown(sorted_changes) - return markdown_changelog + click.echo(markdown_changelog) if __name__ == "__main__": cli() From d96fe3bade95f30cf5a03dcb58931fc62d7df572 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:07:25 +0200 Subject: [PATCH 14/66] Disable all non-relevant steps --- action.yml | 74 +++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/action.yml b/action.yml index 42234e0..1ed77d9 100644 --- a/action.yml +++ b/action.yml @@ -21,15 +21,15 @@ inputs: required: true outputs: - raw-output: - description: Full output json dictionary from github api. - value: ${{ steps.raw-output.outputs.raw_output }} - label-list: - description: List of unique labels found in PRs. - value: ${{ steps.get-labels-list.outputs.label_list }} - bump-increment: - description: Increment for version bumping - either `patch` or 'minor' - value: ${{ steps.bump-increment.outputs.increment }} + # raw-output: + # description: Full output json dictionary from github api. + # value: ${{ steps.raw-output.outputs.raw_output }} + # label-list: + # description: List of unique labels found in PRs. + # value: ${{ steps.get-labels-list.outputs.label_list }} + # bump-increment: + # description: Increment for version bumping - either `patch` or 'minor' + # value: ${{ steps.bump-increment.outputs.increment }} changelog-markdown: description: String containing full markdown syntax for release changelog information value: ${{ steps.write-changelog.outputs.changelog }} @@ -38,38 +38,38 @@ runs: using: composite steps: - - name: Get raw GitHub output - id: raw-output - shell: bash - run: | - raw_output=$(gh pr list --state merged --search 'merged:>=${{ inputs.date }}' --json ${{ inputs.query_parameters }} --repo ${{ inputs.repo }}) - if [[ "$raw_output" == '[]' ]]; then - echo "raw_output=''" >> $GITHUB_OUTPUT - exit 0 - fi + # - name: Get raw GitHub output + # id: raw-output + # shell: bash + # run: | + # raw_output=$(gh pr list --state merged --search 'merged:>=${{ inputs.date }}' --json ${{ inputs.query_parameters }} --repo ${{ inputs.repo }}) + # if [[ "$raw_output" == '[]' ]]; then + # echo "raw_output=''" >> $GITHUB_OUTPUT + # exit 0 + # fi - echo "raw_output=$raw_output" >> $GITHUB_OUTPUT + # echo "raw_output=$raw_output" >> $GITHUB_OUTPUT - - name: Get label list - id: get-labels-list - shell: bash - run: | - cd $GITHUB_ACTION_PATH - label_list=$(python -c 'import github_query; print(github_query.get_labels(github_query.parse_args()))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - if [[ "$label_list" == '[]' ]]; then - echo "label_list=''" >> $GITHUB_OUTPUT - exit 0 - fi + # - name: Get label list + # id: get-labels-list + # shell: bash + # run: | + # cd $GITHUB_ACTION_PATH + # label_list=$(python -c 'import github_query; print(github_query.get_labels(github_query.parse_args()))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + # if [[ "$label_list" == '[]' ]]; then + # echo "label_list=''" >> $GITHUB_OUTPUT + # exit 0 + # fi - echo "label_list=$label_list" >> $GITHUB_OUTPUT + # echo "label_list=$label_list" >> $GITHUB_OUTPUT - - name: Get version increment - id: bump-increment - shell: bash - run: | - cd $GITHUB_ACTION_PATH - increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - echo "increment=$increment" >> $GITHUB_OUTPUT + # - name: Get version increment + # id: bump-increment + # shell: bash + # run: | + # cd $GITHUB_ACTION_PATH + # increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + # echo "increment=$increment" >> $GITHUB_OUTPUT - name: Prepare Changelog id: write-changelog From f07524e6622eb8acc9d635171994e6b4ffd89b3b Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:11:42 +0200 Subject: [PATCH 15/66] Implement multiline processing according to docs --- action.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 1ed77d9..cfb9856 100644 --- a/action.yml +++ b/action.yml @@ -77,7 +77,10 @@ runs: run: | cd $GITHUB_ACTION_PATH changelog=$(python github_query.py generate-release-changelog) - echo "changelog=$changelog" >> $GITHUB_OUTPUT + delimiter="$(openssl rand -hex 8)" + echo "changelog<<${delimiter}" >> "${GITHUB_OUTPUT}" + echo $changelog" >> "${GITHUB_OUTPUT}" + echo "${delimiter}" >> "${GITHUB_OUTPUT}" - name: Show changelog formatted shell: bash From 3c66f446408f9f6d3f8e985752d9ae59fe7d99a5 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:19:21 +0200 Subject: [PATCH 16/66] Fix typo --- action.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/action.yml b/action.yml index cfb9856..5056955 100644 --- a/action.yml +++ b/action.yml @@ -77,9 +77,8 @@ runs: run: | cd $GITHUB_ACTION_PATH changelog=$(python github_query.py generate-release-changelog) - delimiter="$(openssl rand -hex 8)" echo "changelog<<${delimiter}" >> "${GITHUB_OUTPUT}" - echo $changelog" >> "${GITHUB_OUTPUT}" + echo $changelog >> "${GITHUB_OUTPUT}" echo "${delimiter}" >> "${GITHUB_OUTPUT}" - name: Show changelog formatted From 66f69ef015f46ba0524a65a540be16d9b1eda9da Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:22:58 +0200 Subject: [PATCH 17/66] Add generic delimiter --- action.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/action.yml b/action.yml index 5056955..f7caad3 100644 --- a/action.yml +++ b/action.yml @@ -77,6 +77,7 @@ runs: run: | cd $GITHUB_ACTION_PATH changelog=$(python github_query.py generate-release-changelog) + delimiter="$(openssl rand -hex 8)" echo "changelog<<${delimiter}" >> "${GITHUB_OUTPUT}" echo $changelog >> "${GITHUB_OUTPUT}" echo "${delimiter}" >> "${GITHUB_OUTPUT}" From 5a2fa9832377b94159761859fda819d5581c375d Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:29:59 +0200 Subject: [PATCH 18/66] Try different method --- action.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/action.yml b/action.yml index f7caad3..d4b854c 100644 --- a/action.yml +++ b/action.yml @@ -78,9 +78,11 @@ runs: cd $GITHUB_ACTION_PATH changelog=$(python github_query.py generate-release-changelog) delimiter="$(openssl rand -hex 8)" - echo "changelog<<${delimiter}" >> "${GITHUB_OUTPUT}" - echo $changelog >> "${GITHUB_OUTPUT}" - echo "${delimiter}" >> "${GITHUB_OUTPUT}" + { + echo "changelog<<${delimiter}" + echo $changelog + echo "${delimiter}" + } >> $GITHUB_OUTPUT - name: Show changelog formatted shell: bash From 1bf417445748bae5a3a15c904daec7914fd18287 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:47:29 +0200 Subject: [PATCH 19/66] Add info comment --- action.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/action.yml b/action.yml index d4b854c..50486b5 100644 --- a/action.yml +++ b/action.yml @@ -71,6 +71,10 @@ runs: # increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") # echo "increment=$increment" >> $GITHUB_OUTPUT + # INFO multiline strings need to be precessed like this according to + # INFO https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings + # INFO and + # INFO https://stackoverflow.com/questions/74137120/how-to-fix-or-avoid-error-unable-to-process-file-command-output-successfully/74232400#74232400 - name: Prepare Changelog id: write-changelog shell: bash From 49ac1c08780ef0fdda734e38642cb02fddca4dc8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:53:39 +0200 Subject: [PATCH 20/66] Add cli formatting --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 50486b5..dcfb0ce 100644 --- a/action.yml +++ b/action.yml @@ -84,7 +84,7 @@ runs: delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" - echo $changelog + printf "%s" "$changelog" echo "${delimiter}" } >> $GITHUB_OUTPUT From 4f5bcbe5416b2ddab032e18cb8cefad373b301b5 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 10:58:14 +0200 Subject: [PATCH 21/66] Debug multiline string display --- action.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index dcfb0ce..2cd106e 100644 --- a/action.yml +++ b/action.yml @@ -84,13 +84,15 @@ runs: delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" - printf "%s" "$changelog" + echo $changelog echo "${delimiter}" } >> $GITHUB_OUTPUT - name: Show changelog formatted shell: bash run: | - echo "${{ steps.write-changelog.outputs.changelog }}" + echo -e "${{ steps.write-changelog.outputs.changelog }}" + echo "" + printf "%s\n" "${{ steps.write-changelog.outputs.changelog }}" ... From a37a78e5296ebbbb7663afc2241bab614d07abc1 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Sat, 19 Oct 2024 11:01:05 +0200 Subject: [PATCH 22/66] Move string formatting to ci workflow --- .github/workflows/action-ci.yml | 8 ++++++++ action.yml | 7 ------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 953fc6b..71eb771 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -56,3 +56,11 @@ jobs: echo "Labels: " && echo '${{ steps.test-action.outputs.label-list }}' echo "Bump-increment: " && echo '${{ steps.test-action.outputs.bump-increment }}' echo "Changelog: " && echo '${{ steps.test-action.outputs.changelog-markdown }}' + + + - name: Show changelog formatted + shell: bash + run: | + echo -e "${{ steps.test-action.outputs.changelog-markdown }}" + echo "" + printf "%s\n" "${{ steps.test-action.outputs.changelog-markdown }}" \ No newline at end of file diff --git a/action.yml b/action.yml index 2cd106e..e4afd4d 100644 --- a/action.yml +++ b/action.yml @@ -88,11 +88,4 @@ runs: echo "${delimiter}" } >> $GITHUB_OUTPUT - - name: Show changelog formatted - shell: bash - run: | - echo -e "${{ steps.write-changelog.outputs.changelog }}" - echo "" - printf "%s\n" "${{ steps.write-changelog.outputs.changelog }}" - ... From f11eb9a5121a14470431fb7c39fc6fdb19d07f34 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 21 Oct 2024 08:52:11 +0200 Subject: [PATCH 23/66] Reenable other inputs and outputs --- .github/workflows/action-ci.yml | 2 +- action.yml | 78 ++++++++++++++++----------------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 71eb771..ef9b4e8 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -63,4 +63,4 @@ jobs: run: | echo -e "${{ steps.test-action.outputs.changelog-markdown }}" echo "" - printf "%s\n" "${{ steps.test-action.outputs.changelog-markdown }}" \ No newline at end of file + printf "%s\n" "${{ steps.test-action.outputs.changelog-markdowncear }}" \ No newline at end of file diff --git a/action.yml b/action.yml index e4afd4d..4efaa88 100644 --- a/action.yml +++ b/action.yml @@ -1,12 +1,12 @@ --- -# TODO need strategy where to store defaults - which an be overriden by repo var +# TODO need strategy where to store defaults - which an be override by repo var name: Github Release Information description: Fetch and convert data from github to use for a release trigger branding: - icon: plus + icon: arrow-left-circle color: green inputs: @@ -21,15 +21,15 @@ inputs: required: true outputs: - # raw-output: - # description: Full output json dictionary from github api. - # value: ${{ steps.raw-output.outputs.raw_output }} - # label-list: - # description: List of unique labels found in PRs. - # value: ${{ steps.get-labels-list.outputs.label_list }} - # bump-increment: - # description: Increment for version bumping - either `patch` or 'minor' - # value: ${{ steps.bump-increment.outputs.increment }} + raw-output: + description: Full output json dictionary from github api. + value: ${{ steps.raw-output.outputs.raw_output }} + label-list: + description: List of unique labels found in PRs. + value: ${{ steps.get-labels-list.outputs.label_list }} + bump-increment: + description: Increment for version bumping - either `patch` or 'minor' + value: ${{ steps.bump-increment.outputs.increment }} changelog-markdown: description: String containing full markdown syntax for release changelog information value: ${{ steps.write-changelog.outputs.changelog }} @@ -38,38 +38,38 @@ runs: using: composite steps: - # - name: Get raw GitHub output - # id: raw-output - # shell: bash - # run: | - # raw_output=$(gh pr list --state merged --search 'merged:>=${{ inputs.date }}' --json ${{ inputs.query_parameters }} --repo ${{ inputs.repo }}) - # if [[ "$raw_output" == '[]' ]]; then - # echo "raw_output=''" >> $GITHUB_OUTPUT - # exit 0 - # fi + - name: Get raw GitHub output + id: raw-output + shell: bash + run: | + raw_output=$(gh pr list --state merged --search 'merged:>=${{ inputs.date }}' --json ${{ inputs.query_parameters }} --repo ${{ inputs.repo }}) + if [[ "$raw_output" == '[]' ]]; then + echo "raw_output=''" >> $GITHUB_OUTPUT + exit 0 + fi - # echo "raw_output=$raw_output" >> $GITHUB_OUTPUT + echo "raw_output=$raw_output" >> $GITHUB_OUTPUT - # - name: Get label list - # id: get-labels-list - # shell: bash - # run: | - # cd $GITHUB_ACTION_PATH - # label_list=$(python -c 'import github_query; print(github_query.get_labels(github_query.parse_args()))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - # if [[ "$label_list" == '[]' ]]; then - # echo "label_list=''" >> $GITHUB_OUTPUT - # exit 0 - # fi + - name: Get label list + id: get-labels-list + shell: bash + run: | + cd $GITHUB_ACTION_PATH + label_list=$(python -c 'import github_query; print(github_query.get_labels(github_query.parse_args()))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + if [[ "$label_list" == '[]' ]]; then + echo "label_list=''" >> $GITHUB_OUTPUT + exit 0 + fi - # echo "label_list=$label_list" >> $GITHUB_OUTPUT + echo "label_list=$label_list" >> $GITHUB_OUTPUT - # - name: Get version increment - # id: bump-increment - # shell: bash - # run: | - # cd $GITHUB_ACTION_PATH - # increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - # echo "increment=$increment" >> $GITHUB_OUTPUT + - name: Get version increment + id: bump-increment + shell: bash + run: | + cd $GITHUB_ACTION_PATH + increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + echo "increment=$increment" >> $GITHUB_OUTPUT # INFO multiline strings need to be precessed like this according to # INFO https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings From b035753047148eee807b901801d5946ced75dbb2 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 21 Oct 2024 08:56:26 +0200 Subject: [PATCH 24/66] Add argparse import back in --- github_query.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/github_query.py b/github_query.py index 745a0c8..b4b04c6 100644 --- a/github_query.py +++ b/github_query.py @@ -4,6 +4,7 @@ Additionally it's test suite relies mainly on pytest and therefore the functions need to be importable to the pytest script. """ +import argparse import click import json import logging @@ -31,7 +32,7 @@ def parse_args() -> dict: query_tags = parsed_args.query_parameters.split(',') latest_release_date = parsed_args.date - command = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" + command: str = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) return json.loads(pr_json.stdout) From 4a73d84982e92e9aec55e1c21c412dd3f1e7c661 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 21 Oct 2024 09:32:07 +0200 Subject: [PATCH 25/66] Update ci workflow --- .github/workflows/action-ci.yml | 2 +- action.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index ef9b4e8..71eb771 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -63,4 +63,4 @@ jobs: run: | echo -e "${{ steps.test-action.outputs.changelog-markdown }}" echo "" - printf "%s\n" "${{ steps.test-action.outputs.changelog-markdowncear }}" \ No newline at end of file + printf "%s\n" "${{ steps.test-action.outputs.changelog-markdown }}" \ No newline at end of file diff --git a/action.yml b/action.yml index 4efaa88..a1ea472 100644 --- a/action.yml +++ b/action.yml @@ -84,7 +84,7 @@ runs: delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" - echo $changelog + echo -e $changelog echo "${delimiter}" } >> $GITHUB_OUTPUT From 24152b063a508a031e2d20b3adf2701bff976851 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 21 Oct 2024 09:40:37 +0200 Subject: [PATCH 26/66] Remove unnecessary debug code --- .github/workflows/action-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 71eb771..e5eccb7 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -61,6 +61,4 @@ jobs: - name: Show changelog formatted shell: bash run: | - echo -e "${{ steps.test-action.outputs.changelog-markdown }}" - echo "" - printf "%s\n" "${{ steps.test-action.outputs.changelog-markdown }}" \ No newline at end of file + echo "${{ steps.test-action.outputs.changelog-markdown }}" From 63d4832f958f268f360c388ef7f82bc12ceb77f2 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 22 Oct 2024 08:48:48 +0200 Subject: [PATCH 27/66] Adjust formatting for GITHUB_OUTPUT --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index a1ea472..a2a8643 100644 --- a/action.yml +++ b/action.yml @@ -84,7 +84,7 @@ runs: delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" - echo -e $changelog + echo "$changelog" echo "${delimiter}" } >> $GITHUB_OUTPUT From 39e0a8df0760a74395367f5ab2c06d54b59bf00d Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 22 Oct 2024 09:39:37 +0200 Subject: [PATCH 28/66] Extend debug output formatting --- .github/workflows/action-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index e5eccb7..7d48f81 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -61,4 +61,5 @@ jobs: - name: Show changelog formatted shell: bash run: | - echo "${{ steps.test-action.outputs.changelog-markdown }}" + changelog="${{ steps.test-action.outputs.changelog-markdown }}" + echo "$changelog" From b4dd09d469b3feb69be991aaf468b5ecbbb7e997 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 22 Oct 2024 09:42:21 +0200 Subject: [PATCH 29/66] Further formatting updates --- .github/workflows/action-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 7d48f81..25fc36e 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -61,5 +61,5 @@ jobs: - name: Show changelog formatted shell: bash run: | - changelog="${{ steps.test-action.outputs.changelog-markdown }}" + changelog=${{ steps.test-action.outputs.changelog-markdown }} echo "$changelog" From 80f13daad7fb96a594631f9a4da84899b12b0d2d Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 22 Oct 2024 09:44:06 +0200 Subject: [PATCH 30/66] Update formatting --- .github/workflows/action-ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 25fc36e..62f6d77 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -61,5 +61,5 @@ jobs: - name: Show changelog formatted shell: bash run: | - changelog=${{ steps.test-action.outputs.changelog-markdown }} - echo "$changelog" + changelog="${{ steps.test-action.outputs.changelog-markdown }}" + printf '%s\n' "$changelog" From f62e60354cca002d20f6d91766ad5248aaf4f67e Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 22 Oct 2024 09:45:23 +0200 Subject: [PATCH 31/66] Update formatting --- .github/workflows/action-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 62f6d77..7ab15b6 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -61,5 +61,4 @@ jobs: - name: Show changelog formatted shell: bash run: | - changelog="${{ steps.test-action.outputs.changelog-markdown }}" - printf '%s\n' "$changelog" + printf '%s\n' "${{ steps.test-action.outputs.changelog-markdown }}" From 0390cfb3721b3c4fadb6b9af5c11b93786704951 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 22 Oct 2024 09:47:04 +0200 Subject: [PATCH 32/66] Update formatting --- .github/workflows/action-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 7ab15b6..7faaddb 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -61,4 +61,4 @@ jobs: - name: Show changelog formatted shell: bash run: | - printf '%s\n' "${{ steps.test-action.outputs.changelog-markdown }}" + printf '${{ steps.test-action.outputs.changelog-markdown }}' From ff788cbd1fef33d131185cd3099cefa39ac8237b Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Thu, 24 Oct 2024 09:23:37 +0200 Subject: [PATCH 33/66] Add first changelog test --- tests/merged_pr_query.json | 131 +++++++++++++++++++++++++++++++++++++ tests/test_github_query.py | 49 +++++++++----- 2 files changed, 164 insertions(+), 16 deletions(-) create mode 100644 tests/merged_pr_query.json diff --git a/tests/merged_pr_query.json b/tests/merged_pr_query.json new file mode 100644 index 0000000..c39c973 --- /dev/null +++ b/tests/merged_pr_query.json @@ -0,0 +1,131 @@ +[ + { + "body": "## Changelog Description\r\nIt seems that Maya UI is not completely visible or shutting down, `view.readColorBuffer` causes RuntimeError: (kFailure): Unexpected Internal Failure aas view is not visible.\r\n\r\n## Additional info\r\nThis applies only to running Maya in automatic tests.\r\n\r\n\r\n## Testing notes:\r\n\r\n1. publish in Maya ordinarily, active view thumbnail should be still captured for workfile instance\r\n", + "id": "PR_kwDOMQ8b8s58xOK1", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABvFhgWw", + "name": "type: maintenance", + "description": "Changes to the code that don't affect product functionality (Technical debt, refactors etc.))", + "color": "BFD4F2" + } + ], + "number": 126, + "title": "Skip extraction of active view for automatic tests", + "url": "https://github.com/ynput/ayon-maya/pull/126" + }, + { + "body": "## Changelog Description\r\n\r\nRemoves deprecated color management settings for Maya.\r\n\r\nThis is a tricky one, because this will be backwards compatible for everyone who had not previously EXPLICITLY enabled `ayon+settings://maya/imageio/workfile/enabled` because it would've been disabled before and in that case they were still using the deprecated settings. Now, the newer values will apply when enabled by default.\r\n\r\nIf the setting was overridden explicitly to disabled it will now log a message that the AYON Maya workfile color management is disabled.\r\n\r\n## Additional info\r\n\r\n\r\nThis was \"deprecated\" since OpenPype 3.15.5.\r\n\r\nAlso removed the legacy OCIO config settings that were for Maya 2020 and older since those are Py2 anyway and are already unsupported.\r\n\r\n## Testing notes:\r\n\r\n1. Test whether the color management settings work and apply as you'd expect\r\n2. Preferably you also test how this influences older projects from before and highlight where the issues may appear.\r\n", + "id": "PR_kwDOMQ8b8s57Ivvp", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABvFMNlw", + "name": "bump minor", + "description": "", + "color": "F1F25D" + } + ], + "number": 103, + "title": "Remove deprecated color management settings ", + "url": "https://github.com/ynput/ayon-maya/pull/103" + }, + { + "body": "## Changelog Description\r\n\r\n\r\nThis fixes a case where looks failed to apply due to `None` values being present in the collected attributes.\r\nThese will now be ignored in collected. There's an edge case where Maya returns `None` for string attributes that have no values set - those are captured now explicitly to just `\"\"` to still collect and apply them later.\r\n\r\nExisting looks will now also apply correctly with `None` value in their look attributes, but the attributes with `None` values will be ignored with a warning.\r\n\r\n## Additional info\r\n\r\n\r\n## Testing notes:\r\n\r\n1. Load a model reference\r\n2. Create a string attribute, e.g. `test`\r\n3. Do not set any value for it.\r\n - Maya will return None for this attribute, e.g. select the object and run:\r\n```python\r\nfrom maya import cmds\r\nprint(cmds.getAttr(\".test\"))\r\n```\r\nIt will print `None`.\r\n4. Publish the look for this mesh\r\n5. The published `.json` file should have attribute value for `test` set to `\"\"`\r\n\r\nTo test the 'backwards compatible fix':\r\n- Publish the same look with `develop` branch. The value will be `null` in the `.json` file.`\r\n- OR, just open the last published `.json` file, and edit the `\"\"` value to `null`\r\n\r\nThen, confirm that applying the look succeeds without errors but with a warning regarding the `None` value when applying with this PR. For example in my test run it logged:\r\n\r\n```\r\n// Warning: ayon_maya.api.lib : Skipping setting |_GRP|cube_GEO.test with value 'None'\r\n```", + "id": "PR_kwDOMQ8b8s56Ps1m", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABqmH60w", + "name": "type: bug", + "description": "Something isn't working", + "color": "FFA696" + }, + { + "id": "LA_kwDOMQ8b8s8AAAABtfdQMg", + "name": "sponsored", + "description": "This is directly sponsored by a client or community member", + "color": "FCD63D" + } + ], + "number": 89, + "title": "AY-6654 Look: Fix None values in collecting and applying attributes", + "url": "https://github.com/ynput/ayon-maya/pull/89" + }, + { + "body": "## Changelog Description\r\n\r\n\r\nFix name in settings to match with name of plug-in to ensure settings are actually applied\r\n\r\n## Additional info\r\n\r\n\r\nOriginally reported by @LiborBatek here: https://github.com/ynput/ayon-maya/pull/68#issuecomment-2288791598\r\n\r\n## Testing notes:\r\n\r\n1. Settings should adjust the extractor's defaults\r\n2. Disabling it in settings should hide the attributes from the publisher UI\r\n", + "id": "PR_kwDOMQ8b8s55oDx8", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABqmH60w", + "name": "type: bug", + "description": "Something isn't working", + "color": "FFA696" + } + ], + "number": 77, + "title": "Fix settings for Maya USD Animation Extractor", + "url": "https://github.com/ynput/ayon-maya/pull/77" + }, + { + "body": "## Changelog Description\r\n\r\n\r\nFix pixel aspect ratio / device aspect ratio getting messed up for Arnold renderer on render settings reset.\r\n\r\nAdditionally:\r\n- This now applies the resolution from the task entity, not the folder entity.\r\n- This now also applies pixel aspect ratio as defined on the entity.\r\n\r\n## Additional info\r\n\r\n\r\nThis fixes a bug when resetting render resolution for Arnold where on reset the pixel/device aspect ratio would be oddly set with a pixel aspect ratio that is not 1.0.\r\n\r\nE.g. left is before, right is after resetting render settings **without this PR**\r\n![image](https://github.com/user-attachments/assets/1b36d70b-2490-47f0-8731-d1ce5b20dfe9)\r\n\r\nAfter this PR the pixel aspect ratio will now adhere to what is specified on the task entity.\r\n_This bug was only occurring if the current renderer render settings were reset for was actively Arnold (mtoa) renderer._\r\n\r\n## Testing notes:\r\n\r\n1. Resetting render settings should work for the different renderers and should set the resolution (and pixel aspect ratio correctly!)\r\n - [x] Arnold (mtoa)\r\n - [x] Redshift (should work if Arnold works because it uses same attributes as Arnold)\r\n - [x] V-Ray (may be good to check because it uses a custom render settings node!)\r\n - [ ] Renderman (should work if Arnold works because it uses same attributes as Arnold)\r\n\r\nNote that this is about **Set Render Settings** or the feature that it automatically does so on creating a render publish instance in the scene (enabled by default).\r\n\r\n![image](https://github.com/user-attachments/assets/ad8b0534-0921-4dc2-add9-eb276326030f)\r\n", + "id": "PR_kwDOMQ8b8s55L5zV", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABqmH60w", + "name": "type: bug", + "description": "Something isn't working", + "color": "FFA696" + }, + { + "id": "LA_kwDOMQ8b8s8AAAABqmH62w", + "name": "type: enhancement", + "description": "Improvement of existing functionality or minor addition", + "color": "b9f29d" + }, + { + "id": "LA_kwDOMQ8b8s8AAAABtfdQMg", + "name": "sponsored", + "description": "This is directly sponsored by a client or community member", + "color": "FCD63D" + } + ], + "number": 75, + "title": "Improve applying render resolution and aspect ratio on render settings reset", + "url": "https://github.com/ynput/ayon-maya/pull/75" + }, + { + "body": "## Changelog Description\r\n\r\n\r\nOn Maya scene exports only include the relevant history for the selected nodes downstream and upstream and not upstream, and also their downstream descendant children.\r\n\r\n## Additional info\r\n\r\n\r\nNote: This may affect maya scene exports, camera rig exports and layout exports. However, I do feel this is a way more sensible default behavior on exports _with_ construction history enabled.\r\n\r\nWith this change, if you have a hierarchy like:\r\n```\r\ngrp/\r\n obj1\r\n obj2\r\n```\r\nAnd `obj1` is inside the instance then after this PR `obj2` is not included.\r\nBefore this PR all other descendents from upstream groups would be included, regardless of whether they were \"inputs\" to the `obj1`.\r\n\r\nAfter this PR, if `obj2` is an input connection to `obj1` (e.g. there are active constraints driving `obj1` or some other connections driving it) then `obj2` **will still be included.**\r\n\r\nAs such, only objects actively contributing to members of the instance will still be included in the output.\r\n\r\n## Testing notes:\r\n\r\n1. Recreate the aforementioned hierarchy from additional info.\r\n2. Publish `obj1` - it should not include `obj2`\r\n3. Now make a connection from `obj2` to `obj1` (e.g. translate connection)\r\n4. Now `obj2` should also be included in `obj2`.\r\n5. Now disconnect the connection, and key `obj1` transforms.\r\n6. The keys should be exported along just fine.", + "id": "PR_kwDOMQ8b8s542vNM", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABqmH60w", + "name": "type: bug", + "description": "Something isn't working", + "color": "FFA696" + } + ], + "number": 71, + "title": "Maya Scene exports do not default to including nodes that not children of members", + "url": "https://github.com/ynput/ayon-maya/pull/71" + }, + { + "body": "## Changelog Description\r\n\r\n\r\nValidate unique names only within the instance not in full scene\r\n\r\n## Additional info\r\n\r\n\r\nThis is allowed:\r\n![image](https://github.com/user-attachments/assets/ce25d2aa-fa3a-4b25-b0ff-b58ebe7b6124)\r\n\r\nThis is not allowed:\r\n![image](https://github.com/user-attachments/assets/67b3099b-18a1-4779-ae1c-422887675ba8)\r\n\r\nThe validation only checks for member transforms that are included in the export instance.\r\n\r\n![image](https://github.com/user-attachments/assets/e6950101-1210-423b-afe8-6797c33ea5bf)\r\n\r\n## Testing notes:\r\n\r\nMake sure to enable the validator: `ayon+settings://maya/publish/ValidateUniqueNames/enabled`\r\n\r\n1. Create a scene with non-unique node names (e.g. see screenshots above).\r\n2. When both included in the instance it should not be allowed, \r\n3. Otherwise when just present elsewhere in the scene unrelated to the export it should be allowed.\r\n", + "id": "PR_kwDOMQ8b8s54uX2I", + "labels": [ + { + "id": "LA_kwDOMQ8b8s8AAAABqmH62w", + "name": "type: enhancement", + "description": "Improvement of existing functionality or minor addition", + "color": "b9f29d" + }, + { + "id": "LA_kwDOMQ8b8s8AAAABtfdQMg", + "name": "sponsored", + "description": "This is directly sponsored by a client or community member", + "color": "FCD63D" + } + ], + "number": 70, + "title": "Validate unique names only within the instance not in full scene", + "url": "https://github.com/ynput/ayon-maya/pull/70" + } +] diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 2948f8d..8aba075 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -1,10 +1,11 @@ +from typing import Any, Literal +import json import pytest -from unittest.mock import patch import github_query @pytest.fixture -def pr_api_output(): +def pr_api_output() -> list[dict[str, Any]]: return [ { "body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement
\r\n[ ] Bugfix
\r\n[ ] Documentation update
\r\n\r\n## Summary\r\n\r\n\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\n\r\n\r\n## Changes\r\n\r\n\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n", @@ -54,55 +55,60 @@ def pr_api_output_missing_label(): ] @pytest.fixture -def minor_bump(): +def merged_pr_samples(): + with open("merged_pr_query.json") as file: + return json.load(file) + +@pytest.fixture +def minor_bump() -> list[str]: return ["feature", "enhancement"] @pytest.fixture -def patch_bump(): +def patch_bump() -> list[str]: return ["bugfix"] @pytest.fixture -def pr_labels_bug(): +def pr_labels_bug() -> list[str]: return ["bugfix"] @pytest.fixture -def pr_labels_enhancement(): +def pr_labels_enhancement() -> list[str]: return ["bugfix", "documentation", "feature", "enhancement"] @pytest.fixture -def pr_labels_wrong_labels(): +def pr_labels_wrong_labels() -> list[str]: return ["documentation", "wontfix"] @pytest.fixture -def pr_labels_empty_list(): +def pr_labels_empty_list() -> list[Any]: return [] @pytest.fixture -def pr_labels_none(): +def pr_labels_none() -> None: return None @pytest.fixture -def csv_string_spaces(): +def csv_string_spaces() -> Literal['bugfix, enhancement, feature']: return "bugfix, enhancement, feature" @pytest.fixture -def csv_string_no_spaces(): +def csv_string_no_spaces() -> Literal['bugfix,enhancement,feature']: return "bugfix,enhancement,feature" @pytest.fixture -def csv_string_no_spaces(): +def csv_string_no_spaces() -> Literal['bugfix,enhancement,feature']: return "bugfix,enhancement,feature" @pytest.fixture -def csv_string_no_comma(): +def csv_string_no_comma() -> Literal['bugfix']: return "bugfix" @pytest.fixture -def csv_string_no_comma(): +def csv_string_no_comma() -> Literal['bugfix']: return "bugfix" @pytest.fixture -def csv_string_empty(): +def csv_string_empty() -> Literal['']: return "" @@ -165,7 +171,18 @@ def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none): assert increment == "" -def test_get_version_increment_ampty_list(minor_bump, patch_bump, pr_labels_empty_list): +def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empty_list): increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_empty_list) assert increment == "" + + +# Changelog test-cases + +def test_changer_pert_label(merged_pr_samples): + changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] + filtered_results = github_query.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels) + + for result in filtered_results: + for label in result.labels: + assert label in changelog_labels \ No newline at end of file From 1c90ee2970727fd2675a20420cf7e6c6d8c37ac7 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Fri, 25 Oct 2024 09:33:26 +0200 Subject: [PATCH 34/66] Integrate changelog creation into action.yml --- action.yml | 8 ++++-- github_query.py | 27 ++++++++++++++------ src/conversion_logic.py | 16 ++++++++++++ src/queries.py | 51 ++++++++++++++++++++++++++++++++++++++ tests/test_github_query.py | 4 +-- 5 files changed, 94 insertions(+), 12 deletions(-) create mode 100644 src/conversion_logic.py create mode 100644 src/queries.py diff --git a/action.yml b/action.yml index a2a8643..9f0aa32 100644 --- a/action.yml +++ b/action.yml @@ -19,6 +19,9 @@ inputs: query_parameters: description: Parameters to query for in pr Information required: true + changelog_labels: + description: CSV string of labels for changelog order + required: false outputs: raw-output: @@ -75,12 +78,13 @@ runs: # INFO https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#multiline-strings # INFO and # INFO https://stackoverflow.com/questions/74137120/how-to-fix-or-avoid-error-unable-to-process-file-command-output-successfully/74232400#74232400 - - name: Prepare Changelog + - name: Prepare Changelog + if: changelog_labels id: write-changelog shell: bash run: | cd $GITHUB_ACTION_PATH - changelog=$(python github_query.py generate-release-changelog) + changelog=$(python github_query.py generate-release-changelog "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}" "{{ inputs.changelog_labels }}")) delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" diff --git a/github_query.py b/github_query.py index b4b04c6..88b9d70 100644 --- a/github_query.py +++ b/github_query.py @@ -13,10 +13,12 @@ from collections import namedtuple +from src import conversion_logic, queries -logger = logging.getLogger(__name__) -Changelog = namedtuple("Changelog", "labels title number url id") +logger: logging.Logger = logging.getLogger(__name__) + +Changelog: type[Changelog] = namedtuple("Changelog", "labels title number url id") def parse_args() -> dict: @@ -194,13 +196,22 @@ def cli(): @cli.command() -def generate_release_changelog() -> str: - command: str = f"gh pr list --state merged --search 'merged:>=2024-08-01T11:29:22Z' --json body,labels,title,number,url,id --repo ynput/ayon-maya" - pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - pr_data: list[dict[str, str]] = json.loads(pr_json.stdout) - changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] +@click.argument('repo_name', type=click.STRING) +@click.argument('query_tags', type=click.STRING) +@click.argument('latest_release_date', type=click.STRING) +@click.argument('changelog_labels', type=click.STRING) +def generate_release_changelog(latest_release_date: str, query_tags: str, repo_name: str, changelog_labels: str) -> None: + """Output a markdown formatted changelog. + + latest_release_date (str): datetime string\n + query_tags (str): csv string\n + repo_name (str): repo name as \n + """ + + pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + changelog_markdown_result: list[str] = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name=changelog_labels)) - pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_data, changelog_label_list=changelog_labels) + pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_markdown_result) sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) markdown_changelog: str = build_changelog_markdown(sorted_changes) diff --git a/src/conversion_logic.py b/src/conversion_logic.py new file mode 100644 index 0000000..6de199a --- /dev/null +++ b/src/conversion_logic.py @@ -0,0 +1,16 @@ +import re + +def csv_string_to_list(input: str) -> list[str]: + """Convert string to list. + + Args: + input (str): Expected csv string. + + Returns: + list: List of strings. + """ + + if input: + return re.split(r',\s*', input.strip()) + + return [] \ No newline at end of file diff --git a/src/queries.py b/src/queries.py new file mode 100644 index 0000000..641a3dc --- /dev/null +++ b/src/queries.py @@ -0,0 +1,51 @@ +import json +import subprocess + + +def query_merged_prs(latest_release_date: str, query_tags: str, repo_name: str) -> list[dict[str, str]]: + """Run gh pull request query. + + Args: + latest_release_date (str): datetime string + query_tags (str): csv string + repo_name (str): repo name as + + Returns: + dict: json-dictionary. + """ + + pr_list: subprocess.CompletedProcess[str] = subprocess.run( + [ + "gh", "pr", "list", + "--state", "merged", + "--search", f'merged:>={latest_release_date}', + "--json", ','.join(query_tags), + "--repo", repo_name + ], + capture_output=True, + text=True, + check=True + ) + + return json.loads(pr_list.stdout) + + +def get_repo_var(repo: str, var_name: str) -> str: + """Query labels from repository variables. + + Args: + repo (str): Repository name `owner/repo-name` + var_name (str): Repo variable name + + Returns: + str: csv-string. + """ + + labels: subprocess.CompletedProcess[str] = subprocess.run( + ["gh", "variable", "get", var_name, "--repo", repo], + capture_output=True, + text=True, + check=True + ) + + return labels.stdout \ No newline at end of file diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 8aba075..4eb3382 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -179,9 +179,9 @@ def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empt # Changelog test-cases -def test_changer_pert_label(merged_pr_samples): +def test_changer_pert_label(merged_pr_samples: dict[str, str]) -> None: changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] - filtered_results = github_query.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels) + filtered_results: list[Changelog] = github_query.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels) for result in filtered_results: for label in result.labels: From 66dfab5cf4b90e495f3309754ea09d6e322ab94c Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 08:57:40 +0100 Subject: [PATCH 35/66] Update variable reference --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 9f0aa32..5d0a768 100644 --- a/action.yml +++ b/action.yml @@ -79,7 +79,7 @@ runs: # INFO and # INFO https://stackoverflow.com/questions/74137120/how-to-fix-or-avoid-error-unable-to-process-file-command-output-successfully/74232400#74232400 - name: Prepare Changelog - if: changelog_labels + if: ${{ !inputs.changelog_labels }} id: write-changelog shell: bash run: | From a970cdcc07454cf285de3c1da4ce4d8d07a570c0 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:08:30 +0100 Subject: [PATCH 36/66] Fix typo in variable reference --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 5d0a768..32552e9 100644 --- a/action.yml +++ b/action.yml @@ -79,7 +79,7 @@ runs: # INFO and # INFO https://stackoverflow.com/questions/74137120/how-to-fix-or-avoid-error-unable-to-process-file-command-output-successfully/74232400#74232400 - name: Prepare Changelog - if: ${{ !inputs.changelog_labels }} + if: ${{ inputs.changelog_labels }} id: write-changelog shell: bash run: | From e7883964c910e6eee34bc321cbce0c44fe6cd709 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:14:34 +0100 Subject: [PATCH 37/66] Update ci-action --- .github/workflows/action-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 7faaddb..04001e1 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -49,6 +49,7 @@ jobs: repo: "ynput/ayon-addon-action-testing" date: "2024-08-20T12:03:23Z" query_parameters: "body,labels,title" + changelog_labels: "feature,enhancement,bugfix,refactor,docs,test,pr" - name: Show results run: | From 9f9efc0251f5a0ac1b4704b10b777406b56bfeab Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:16:35 +0100 Subject: [PATCH 38/66] FIx bracket typo --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 32552e9..8fccf01 100644 --- a/action.yml +++ b/action.yml @@ -84,7 +84,7 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - changelog=$(python github_query.py generate-release-changelog "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}" "{{ inputs.changelog_labels }}")) + changelog=$(python github_query.py generate-release-changelog "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}" "{{ inputs.changelog_labels }}") delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" From e8020ba58a4c9ed5013d46647956e4b264eb1169 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:26:50 +0100 Subject: [PATCH 39/66] Fix query label splitting --- github_query.py | 3 ++- src/queries.py | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/github_query.py b/github_query.py index 88b9d70..2fb7938 100644 --- a/github_query.py +++ b/github_query.py @@ -208,7 +208,8 @@ def generate_release_changelog(latest_release_date: str, query_tags: str, repo_n repo_name (str): repo name as \n """ - pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) + pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) changelog_markdown_result: list[str] = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name=changelog_labels)) pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_markdown_result) diff --git a/src/queries.py b/src/queries.py index 641a3dc..88159ee 100644 --- a/src/queries.py +++ b/src/queries.py @@ -2,7 +2,7 @@ import subprocess -def query_merged_prs(latest_release_date: str, query_tags: str, repo_name: str) -> list[dict[str, str]]: +def query_merged_prs(latest_release_date: str, query_tags: list[str], repo_name: str) -> list[dict[str, str]]: """Run gh pull request query. Args: From e3da661766a7490f046665f47eacb444a78876e9 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:42:24 +0100 Subject: [PATCH 40/66] Add variable $ sign for evaluation --- action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/action.yml b/action.yml index 8fccf01..d82dbbe 100644 --- a/action.yml +++ b/action.yml @@ -84,7 +84,7 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - changelog=$(python github_query.py generate-release-changelog "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}" "{{ inputs.changelog_labels }}") + changelog=$(python github_query.py generate-release-changelog "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}" "${{ inputs.changelog_labels }}") delimiter="$(openssl rand -hex 8)" { echo "changelog<<${delimiter}" From 3dba933e21622955b39a1b748e0f2e6d28633b26 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:44:48 +0100 Subject: [PATCH 41/66] remove variable query --- github_query.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github_query.py b/github_query.py index 2fb7938..bfa2789 100644 --- a/github_query.py +++ b/github_query.py @@ -210,7 +210,7 @@ def generate_release_changelog(latest_release_date: str, query_tags: str, repo_n query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) - changelog_markdown_result: list[str] = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name=changelog_labels)) + changelog_markdown_result: list[str] = conversion_logic.csv_string_to_list(changelog_labels) pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_markdown_result) sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) From 4fc7fd711d7ecd2a4fdeb36c1941c275136b322f Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 09:48:55 +0100 Subject: [PATCH 42/66] Add query labels --- .github/workflows/action-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 04001e1..f2eae42 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -48,7 +48,7 @@ jobs: with: repo: "ynput/ayon-addon-action-testing" date: "2024-08-20T12:03:23Z" - query_parameters: "body,labels,title" + query_parameters: "body,labels,title,number,url,id" changelog_labels: "feature,enhancement,bugfix,refactor,docs,test,pr" - name: Show results From b4f09afc0a53dcef196db59a9d5081b52704dd15 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 28 Oct 2024 10:04:39 +0100 Subject: [PATCH 43/66] Add debug output for changelog issues --- github_query.py | 8 ++++++-- tests/merged_pr_query_testing.json | 32 ++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 tests/merged_pr_query_testing.json diff --git a/github_query.py b/github_query.py index bfa2789..33fb0aa 100644 --- a/github_query.py +++ b/github_query.py @@ -88,6 +88,10 @@ def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) # TODO implement this logic in a more clever way sorted_changes: list[Changelog] = [] + + print(changes_list) + print(changelog_label_list) + for order_label in changelog_label_list: for change in changes_list: if any(label == order_label for label in change.labels): @@ -210,9 +214,9 @@ def generate_release_changelog(latest_release_date: str, query_tags: str, repo_n query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) - changelog_markdown_result: list[str] = conversion_logic.csv_string_to_list(changelog_labels) + changelog_labels_result: list[str] = conversion_logic.csv_string_to_list(changelog_labels) - pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_markdown_result) + pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_labels_result) sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) markdown_changelog: str = build_changelog_markdown(sorted_changes) diff --git a/tests/merged_pr_query_testing.json b/tests/merged_pr_query_testing.json new file mode 100644 index 0000000..000685a --- /dev/null +++ b/tests/merged_pr_query_testing.json @@ -0,0 +1,32 @@ +[ + { + "body": "\n# Memory usage check added\n\n## Summary\n\nGot a check for memory usage implemented\n\n## Root Cause Analysis\n\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)\n\n## Changelog\n\n* Add text file\n* Commit it the memory check\n* Fix no memory usage file\n\n## Testing Strategy\n\nTested all the way.\n\n## Checklist\n\n* [x] The fix has been locally tested\n* [x] New unit tests have been added to prevent future regressions\n* [x] The documentation has been updated if necessary\n", + "id": "PR_kwDONG2H-M6ADxBD", + "labels": [ + { + "id": "LA_kwDONG2H-M8AAAAByPb2-g", + "name": "enhancement", + "description": "New feature or request", + "color": "b9f29d" + } + ], + "number": 2, + "title": "Add mem file", + "url": "https://github.com/ynput/ayon-addon-action-testing/pull/2" + }, + { + "body": "\n# Date file added\n\n## Summary\n\nGot a date file included\n\n## Root Cause Analysis\n\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)\n\n## Changelog\n\n* Add date file\n* Commit it\n* Fix no date file\n\n## Testing Strategy\n\nTested all the way.\n\n## Checklist\n\n* [x] The fix has been locally tested\n* [x] New unit tests have been added to prevent future regressions\n* [x] The documentation has been updated if necessary\n", + "id": "PR_kwDONG2H-M6ADxAA", + "labels": [ + { + "id": "LA_kwDONG2H-M8AAAAByPb6PA", + "name": "bugfix", + "description": "Something got fixed", + "color": "f96713" + } + ], + "number": 1, + "title": "Add date file", + "url": "https://github.com/ynput/ayon-addon-action-testing/pull/1" + } + ] From 1107e74905d5b6c90d6e3c2a4f0f46da3919acbe Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 08:40:58 +0100 Subject: [PATCH 44/66] Update variable reference --- github_query.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/github_query.py b/github_query.py index 33fb0aa..2582e32 100644 --- a/github_query.py +++ b/github_query.py @@ -217,7 +217,7 @@ def generate_release_changelog(latest_release_date: str, query_tags: str, repo_n changelog_labels_result: list[str] = conversion_logic.csv_string_to_list(changelog_labels) pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_labels_result) - sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels) + sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels_result) markdown_changelog: str = build_changelog_markdown(sorted_changes) click.echo(markdown_changelog) From 29104c126d6633c599f9542c954f3707f95aa877 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 08:49:20 +0100 Subject: [PATCH 45/66] Remove obsolete debug output --- github_query.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/github_query.py b/github_query.py index 2582e32..65e768b 100644 --- a/github_query.py +++ b/github_query.py @@ -89,9 +89,6 @@ def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) # TODO implement this logic in a more clever way sorted_changes: list[Changelog] = [] - print(changes_list) - print(changelog_label_list) - for order_label in changelog_label_list: for change in changes_list: if any(label == order_label for label in change.labels): From bba78ae29620080ab5ddf0aa9a0d062bcb830594 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 09:17:32 +0100 Subject: [PATCH 46/66] Add label filtering before output --- github_query.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/github_query.py b/github_query.py index 65e768b..4e57cba 100644 --- a/github_query.py +++ b/github_query.py @@ -106,7 +106,8 @@ def build_changelog_markdown(changes: list[Changelog]) -> str: current_labels: list[str] = change.labels if not any(label in previous_labels for label in current_labels): - changelog += f"\n\n## {change.labels[0]}\n\n" + label: str = change.labels[0].removeprefix("type: ") + changelog += f"\n\n## {label.capitalize()}\n\n" changelog += f"* {change.title} - [{change.number}]({change.url})\n" From 862b5e0065a6abe46ee6239f9637d4ffcff01802 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 09:31:43 +0100 Subject: [PATCH 47/66] Update script docstring --- github_query.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/github_query.py b/github_query.py index 4e57cba..5586f11 100644 --- a/github_query.py +++ b/github_query.py @@ -1,6 +1,5 @@ """ -This script is written in a certain - maybe even unconventional way - by intention. -It's supposed to be run from command line right away to be used in a github action workflow yaml file. +This script is supposed to be run from command line right away to be used in a github action workflow yaml file. Additionally it's test suite relies mainly on pytest and therefore the functions need to be importable to the pytest script. """ From 4479a6211ee2932ab73e4adc5dda3d4c581f3f76 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 09:57:47 +0100 Subject: [PATCH 48/66] Update structure to match refactor branch --- action.yml | 9 +- github_query.py | 212 ++++++------------------------------- src/conversion_logic.py | 147 ++++++++++++++++++++++++- tests/test_github_query.py | 26 ++--- 4 files changed, 197 insertions(+), 197 deletions(-) diff --git a/action.yml b/action.yml index d82dbbe..f640e52 100644 --- a/action.yml +++ b/action.yml @@ -58,12 +58,8 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - label_list=$(python -c 'import github_query; print(github_query.get_labels(github_query.parse_args()))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - if [[ "$label_list" == '[]' ]]; then - echo "label_list=''" >> $GITHUB_OUTPUT - exit 0 - fi - + label_list=$(python github_query.py pr-labels "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + echo "label_list=$label_list" >> $GITHUB_OUTPUT - name: Get version increment @@ -72,6 +68,7 @@ runs: run: | cd $GITHUB_ACTION_PATH increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + echo "increment=$increment" >> $GITHUB_OUTPUT # INFO multiline strings need to be precessed like this according to diff --git a/github_query.py b/github_query.py index 5586f11..01d06ee 100644 --- a/github_query.py +++ b/github_query.py @@ -3,197 +3,55 @@ Additionally it's test suite relies mainly on pytest and therefore the functions need to be importable to the pytest script. """ -import argparse import click -import json -import logging -import re -import subprocess - -from collections import namedtuple - from src import conversion_logic, queries -logger: logging.Logger = logging.getLogger(__name__) - -Changelog: type[Changelog] = namedtuple("Changelog", "labels title number url id") - - -def parse_args() -> dict: - """Parse command-line arguments and store them in a global variable.""" - - parser = argparse.ArgumentParser(description="A python script to convert GitHub PR information to a more simple format.") - parser.add_argument("repo", type=str, help="Repository name consisting of 'repo-owner/repo-name'") - parser.add_argument("query_parameters", type=str, help="Keys to query for.") - parser.add_argument("date", type=str, default="2024-07-08T09:48:33Z", help="Latest release date.") - parsed_args = parser.parse_args() - - repo_name = parsed_args.repo - query_tags = parsed_args.query_parameters.split(',') - latest_release_date = parsed_args.date - - command: str = f"gh pr list --state merged --search 'merged:>={latest_release_date}' --json {','.join(query_tags)} --repo {repo_name}" - pr_json = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) - - return json.loads(pr_json.stdout) - - -def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): - """Get list of changes from a PRs changelog. - - Args: - pr_body (list(str)): List of PR body contents. - changelog_start (str, optional): Indicates markdown changelog section. Defaults to "## Changes". - heading (str, optional): Markdown heading. Defaults to "##". - - Returns: - list(str): List of changes found. - """ - - lines = pr_data.splitlines() - changelog_section = None - changelog_lines = [] - - for line in lines: - if line.startswith(changelog_start): - changelog_section = True - continue - - if changelog_section and line.startswith(heading): - break - - if changelog_section and line.startswith("* "): - changelog_lines.append(line.strip("* ").strip()) - - return changelog_lines - - -def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]: - - changes_list: list[Changelog] = [] - - for pull_request in pr_data: - - # TODO refactor this to become more readable - label_list: list[str] = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] - if label_list: - changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"])) - - return changes_list - - -def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) -> list[Changelog]: - - # TODO implement this logic in a more clever way - sorted_changes: list[Changelog] = [] - - for order_label in changelog_label_list: - for change in changes_list: - if any(label == order_label for label in change.labels): - sorted_changes.append(change) - - return sorted_changes - - -def build_changelog_markdown(changes: list[Changelog]) -> str: - changelog = "# Changelog" - previous_labels: list[str] = [] - - # TODO implement this logic in a more clever way, checkout `from itertools import groupby` - for change in changes: - current_labels: list[str] = change.labels - - if not any(label in previous_labels for label in current_labels): - label: str = change.labels[0].removeprefix("type: ") - changelog += f"\n\n## {label.capitalize()}\n\n" - - changelog += f"* {change.title} - [{change.number}]({change.url})\n" - - previous_labels = current_labels - - return changelog - - -def get_labels(pr_data: list[dict[str, str]]) -> list[str]: - """Filter all unique labels from dictionary. - - Args: - pr_data (dict): Github PR query result - - Returns: - [str]: Liste of unique labels strings found or `None`. - """ - - labels = set() - - for item in pr_data: - if not item.get("labels"): - return [] - for label in item["labels"]: - if not label.get("name"): - return [] - - labels.add(label["name"]) - - return list(labels) - +@click.group() +def cli() -> None: + pass -def get_repo_var(repo: str, var_name: str) -> list[str]: - """Query labels from repository variables. - Args: - repo (str): Repository name `owner/repo-name` - var_name (str): Repo variable name +@cli.command() +@click.argument('repo_name', type=click.STRING) +@click.argument('query_tags', type=click.STRING) +@click.argument('latest_release_date', type=click.STRING) +def pr_labels(latest_release_date, query_tags, repo_name): + """Get a list of all version relevant PR labels. - Returns: - str: Comma separated value string. + latest_release_date (str): datatime string\n + query_tags (str): csv string\n + repo_name (str): repo name as \n """ - labels = subprocess.run( - ["gh", "variable", "get", var_name, "--repo", repo], - capture_output=True, - text=True, - check=True - ) - - return csv_string_to_list(labels.stdout) + pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + pr_labels = conversion_logic.get_labels(pr_data=pr_result) -def csv_string_to_list(input: str) -> list[str]: - if input: - return re.split(r',\s*', input.strip()) + if not pr_labels: + click.echo("") - return [] + click.echo(pr_labels) -def get_version_increment(patch_bump_list: list[str], minor_bump_list: list[str], pr_label_list: list[str]): - """Figure out version increment based on PR labels. - - Args: - patch_bump_list ([str]): Labels for bumping patch version - minor_bump_list ([str]): Labels for bumping minor version - label_list([str]): Labels found in PRs +@cli.command() +@click.argument('repo_name', type=click.STRING) +@click.argument('query_tags', type=click.STRING) +@click.argument('latest_release_date', type=click.STRING) +def version_increment(latest_release_date, query_tags, repo_name): + """Output a calculated version increment suggestion. - Returns: - str: version increment + latest_release_date (str): datetime string\n + query_tags (str): csv string\n + repo_name (str): repo name as \n """ - if not pr_label_list: - return "" - - # TODO add major bump option - if any(label in pr_label_list for label in minor_bump_list): - return "minor" - - if any(label in pr_label_list for label in patch_bump_list): - return "patch" + pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + pr_labels = conversion_logic.get_labels(pr_data=pr_result) + patch_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) + minor_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_repo_var_list, minor_bump_list=minor_repo_var_list, pr_label_list=pr_labels) - return "" - - -@click.group() -def cli(): - pass + click.echo(increment) @cli.command() @@ -213,9 +71,9 @@ def generate_release_changelog(latest_release_date: str, query_tags: str, repo_n pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) changelog_labels_result: list[str] = conversion_logic.csv_string_to_list(changelog_labels) - pr_filtered: list[Changelog] = filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_labels_result) - sorted_changes: list[Changelog] = sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels_result) - markdown_changelog: str = build_changelog_markdown(sorted_changes) + pr_filtered: list[Changelog] = conversion_logic.filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_labels_result) + sorted_changes: list[Changelog] = conversion_logic.sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels_result) + markdown_changelog: str = conversion_logic.build_changelog_markdown(sorted_changes) click.echo(markdown_changelog) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 6de199a..ebb56b3 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -1,5 +1,117 @@ +import logging import re +from collections import namedtuple + + +logger: logging.Logger = logging.getLogger(__name__) +Changelog: type[Changelog] = namedtuple("Changelog", "labels title number url id") + + +def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) -> list[Changelog]: + + # TODO implement this logic in a more clever way + sorted_changes: list[Changelog] = [] + + for order_label in changelog_label_list: + for change in changes_list: + if any(label == order_label for label in change.labels): + sorted_changes.append(change) + + return sorted_changes + + +# INFO currently not in use +def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): + """Get list of changes from a PRs changelog. + + Args: + pr_body (list(str)): List of PR body contents. + changelog_start (str, optional): Indicates markdown changelog section. Defaults to "## Changes". + heading (str, optional): Markdown heading. Defaults to "##". + + Returns: + list(str): List of changes found. + """ + + lines: list[str] = pr_data.splitlines() + changelog_section = None + changelog_lines: list[str] = [] + + for line in lines: + if line.startswith(changelog_start): + changelog_section = True + continue + + if changelog_section and line.startswith(heading): + break + + if changelog_section and line.startswith("* "): + changelog_lines.append(line.strip("* ").strip()) + + return changelog_lines + + +def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]: + + changes_list: list[Changelog] = [] + + for pull_request in pr_data: + + # TODO refactor this to become more readable + label_list: list[str] = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] + if label_list: + changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"])) + + return changes_list + + +def build_changelog_markdown(changes: list[Changelog]) -> str: + changelog = "# Changelog" + previous_labels: list[str] = [] + + # TODO implement this logic in a more clever way, checkout `from itertools import groupby` + for change in changes: + current_labels: list[str] = change.labels + + if not any(label in previous_labels for label in current_labels): + label: str = change.labels[0].removeprefix("type: ") + changelog += f"\n\n## {label.capitalize()}\n\n" + + changelog += f"* {change.title} - [{change.number}]({change.url})\n" + + previous_labels = current_labels + + return changelog + + +def filter_unique_labels(pr_data: dict[dict[str, str]]) -> list[str]: + """Filter all unique labels from dictionary. + + Args: + pr_data (dict): Github PR query result + + Returns: + list: List of unique labels strings found or `None`. + """ + + labels = set() + + for item in pr_data: + if not item.get("labels"): + logger.warning("No PR label data found.") + return [] + for label in item["labels"]: + if not label.get("name"): + logger.warning("No PR label names found.") + return [] + + labels.add(label["name"]) + logger.debug("PR labels found.") + + return list(labels) + + def csv_string_to_list(input: str) -> list[str]: """Convert string to list. @@ -13,4 +125,37 @@ def csv_string_to_list(input: str) -> list[str]: if input: return re.split(r',\s*', input.strip()) - return [] \ No newline at end of file + return [] + + +def get_version_increment(pr_label_list: list, patch_bump_list: list=[], minor_bump_list: list=[], major_bump_list: list=[]): + """Figure out version increment based on PR labels. + + Args: + patch_bump_list ([str]): Labels for bumping patch version + minor_bump_list ([str]): Labels for bumping minor version + label_list ([str]): Labels found in PRs + + Returns: + str: version increment + """ + + if not pr_label_list: + logger.warning("PR label list was empty") + return "" + + for name, param in locals().items(): + if not isinstance(param, list): + raise ValueError(f"{name} must be a list.") + + if any(label in pr_label_list for label in major_bump_list): + return "major" + + if any(label in pr_label_list for label in minor_bump_list): + return "minor" + + if any(label in pr_label_list for label in patch_bump_list): + return "patch" + + logger.warning("No relevant labels found for version increment.") + return "" \ No newline at end of file diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 4eb3382..c1cf136 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -2,7 +2,7 @@ import json import pytest -import github_query +from src import conversion_logic, queries @pytest.fixture def pr_api_output() -> list[dict[str, Any]]: @@ -115,13 +115,13 @@ def csv_string_empty() -> Literal['']: # Get PR Label test-cases def test_get_labels(pr_api_output): - labels = github_query.get_labels(pr_data=pr_api_output) + labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output) assert isinstance(labels, list) assert set(labels) == {"bugfix", "enhancement"} def test_get_labels_missing_input(pr_api_output_missing_label): - labels = github_query.get_labels(pr_data=pr_api_output_missing_label) + labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output_missing_label) assert labels == [] @@ -129,22 +129,22 @@ def test_get_labels_missing_input(pr_api_output_missing_label): # Convert repo label list def test_csv_string_to_list_spaces(csv_string_spaces): - string_list = github_query.csv_string_to_list(csv_string_spaces) + string_list = conversion_logic.csv_string_to_list(csv_string_spaces) assert string_list == ["bugfix", "enhancement", "feature"] def test_csv_string_to_list_no_spaces(csv_string_no_spaces): - string_list = github_query.csv_string_to_list(csv_string_no_spaces) + string_list = conversion_logic.csv_string_to_list(csv_string_no_spaces) assert string_list == ["bugfix", "enhancement", "feature"] def test_csv_string_to_list_no_comma(csv_string_no_comma): - string_list = github_query.csv_string_to_list(csv_string_no_comma) + string_list = conversion_logic.csv_string_to_list(csv_string_no_comma) assert string_list == ["bugfix"] def test_csv_string_to_list_empty(csv_string_empty): - string_list = github_query.csv_string_to_list(csv_string_empty) + string_list = conversion_logic.csv_string_to_list(csv_string_empty) assert string_list == [] @@ -152,27 +152,27 @@ def test_csv_string_to_list_empty(csv_string_empty): # Version Increment test-cases def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_bug) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_bug) assert increment == "patch" def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhancement): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_enhancement) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_enhancement) assert increment == "minor" def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wrong_labels): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_wrong_labels) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_wrong_labels) assert increment == "" def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_none) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_none) assert increment == "" def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empty_list): - increment = github_query.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_empty_list) + increment = conversion_logic.get_version_increment(patch_bump_list=patch_bump, minor_bump_list=minor_bump, pr_label_list=pr_labels_empty_list) assert increment == "" @@ -181,7 +181,7 @@ def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empt def test_changer_pert_label(merged_pr_samples: dict[str, str]) -> None: changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] - filtered_results: list[Changelog] = github_query.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels) + filtered_results: list[Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels) for result in filtered_results: for label in result.labels: From c06e14790230843e545077f050dcef0196f7bc99 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 10:01:03 +0100 Subject: [PATCH 49/66] Fix list conversion --- github_query.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/github_query.py b/github_query.py index 01d06ee..062514d 100644 --- a/github_query.py +++ b/github_query.py @@ -23,8 +23,9 @@ def pr_labels(latest_release_date, query_tags, repo_name): query_tags (str): csv string\n repo_name (str): repo name as \n """ - - pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + + query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) + pr_result = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) pr_labels = conversion_logic.get_labels(pr_data=pr_result) if not pr_labels: From cdf6aed5636985d4eaf2f43f4b6c67f9528f1067 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 29 Oct 2024 10:03:22 +0100 Subject: [PATCH 50/66] Update labels function call --- github_query.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/github_query.py b/github_query.py index 062514d..360eadf 100644 --- a/github_query.py +++ b/github_query.py @@ -26,7 +26,7 @@ def pr_labels(latest_release_date, query_tags, repo_name): query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) pr_result = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) - pr_labels = conversion_logic.get_labels(pr_data=pr_result) + pr_labels = conversion_logic.filter_unique_labels(pr_data=pr_result) if not pr_labels: click.echo("") @@ -47,7 +47,7 @@ def version_increment(latest_release_date, query_tags, repo_name): """ pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) - pr_labels = conversion_logic.get_labels(pr_data=pr_result) + pr_labels = conversion_logic.filter_unique_labels(pr_data=pr_result) patch_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) minor_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) increment = conversion_logic.get_version_increment(patch_bump_list=patch_repo_var_list, minor_bump_list=minor_repo_var_list, pr_label_list=pr_labels) From 19e3f1cc94c6d9640980dc0d2f0c5bce3f7c37e8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Wed, 30 Oct 2024 07:37:37 +0100 Subject: [PATCH 51/66] Update bump-increment step to click version --- action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/action.yml b/action.yml index f640e52..488e0ef 100644 --- a/action.yml +++ b/action.yml @@ -67,8 +67,8 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - increment=$(python -c 'import github_query; pr_labels = github_query.get_labels(github_query.parse_args()); patch_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="PATCH_BUMP_LABEL"); minor_repo_var = github_query.get_repo_var(repo="${{ inputs.repo }}", var_name="MINOR_BUMP_LABEL"); print(github_query.get_version_increment(patch_bump_list=patch_repo_var, minor_bump_list=minor_repo_var, pr_label_list=pr_labels))' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - + increment=$(python github_query.py version-increment "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + echo "increment=$increment" >> $GITHUB_OUTPUT # INFO multiline strings need to be precessed like this according to From 6a1048f5f5760f2d1ffb940b34d9a4ec0ea0c70c Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Wed, 30 Oct 2024 07:43:07 +0100 Subject: [PATCH 52/66] Include csv conversion for version increment calls --- github_query.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/github_query.py b/github_query.py index 360eadf..4570969 100644 --- a/github_query.py +++ b/github_query.py @@ -38,7 +38,7 @@ def pr_labels(latest_release_date, query_tags, repo_name): @click.argument('repo_name', type=click.STRING) @click.argument('query_tags', type=click.STRING) @click.argument('latest_release_date', type=click.STRING) -def version_increment(latest_release_date, query_tags, repo_name): +def version_increment(latest_release_date: str, query_tags: str, repo_name: str): """Output a calculated version increment suggestion. latest_release_date (str): datetime string\n @@ -46,7 +46,8 @@ def version_increment(latest_release_date, query_tags, repo_name): repo_name (str): repo name as \n """ - pr_result = queries.query_merged_prs(latest_release_date, query_tags, repo_name) + query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) + pr_result = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) pr_labels = conversion_logic.filter_unique_labels(pr_data=pr_result) patch_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) minor_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) From 720f0722a0770e72d22eed1f4693a5f47eb8da5f Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Wed, 30 Oct 2024 08:14:18 +0100 Subject: [PATCH 53/66] Remove duplicate test --- tests/test_github_query.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/test_github_query.py b/tests/test_github_query.py index a6b9a69..c7a19a6 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -235,15 +235,6 @@ def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_lis major_bump_list=major_bump_no_list, ) -def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_list, pr_labels_epic): - with pytest.raises(ValueError, match="must be a list"): - conversion_logic.get_version_increment( - pr_label_list=pr_labels_epic, - patch_bump_list=patch_bump, - minor_bump_list=minor_bump, - major_bump_list=major_bump_no_list, - ) - # Changelog test-cases From 2a362ef5cfa93b8ecac7461176194d45d4b235d9 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 4 Nov 2024 14:16:26 +0100 Subject: [PATCH 54/66] Cleanup changelog creation Extend test suite Delete obsolete logic --- src/conversion_logic.py | 80 +++++++++++++++++------------- tests/formatted_changelog.md | 16 ++++++ tests/test_github_query.py | 95 +++++++++++++++++++----------------- 3 files changed, 111 insertions(+), 80 deletions(-) create mode 100644 tests/formatted_changelog.md diff --git a/src/conversion_logic.py b/src/conversion_logic.py index ebb56b3..2521faa 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -1,24 +1,43 @@ import logging import re -from collections import namedtuple - +from typing import NamedTuple logger: logging.Logger = logging.getLogger(__name__) -Changelog: type[Changelog] = namedtuple("Changelog", "labels title number url id") -def sort_changes(changes_list: list[Changelog], changelog_label_list: list[str]) -> list[Changelog]: +class Changelog(NamedTuple): + labels: list[str] + title: str + number: int + url: str + id: int + + +def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]: + """Convert list of PR dictionaries to Changelog list + + Args: + pr_data (list[dict[str, str]]): PR information and metadata + changelog_label_list (list[str]): Changelog labels + + Returns: + list[Changelog]: List of changelog objects + """ - # TODO implement this logic in a more clever way - sorted_changes: list[Changelog] = [] + changes_list: list[Changelog] = [] - for order_label in changelog_label_list: - for change in changes_list: - if any(label == order_label for label in change.labels): - sorted_changes.append(change) + for pull_request in pr_data: + if pull_request.get("labels"): + changes_list.append(Changelog(labels=[label["name"] for label in pull_request["labels"]], + title=pull_request["title"], + number=pull_request["number"], + url=pull_request["url"], + id=pull_request["id"], + ) + ) - return sorted_changes + return changes_list # INFO currently not in use @@ -52,35 +71,26 @@ def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): return changelog_lines -def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]: - - changes_list: list[Changelog] = [] - - for pull_request in pr_data: - - # TODO refactor this to become more readable - label_list: list[str] = [label["name"] for label in pull_request["labels"] if label["name"] in changelog_label_list] - if label_list: - changes_list.append(Changelog(label_list, pull_request["title"], pull_request["number"], pull_request["url"], pull_request["id"])) +def format_changelog_markdown(changes: list[Changelog], changelog_label_list: list[str]) -> str: + """Create markdown formatted changelog. - return changes_list + Args: + changes (list[Changelog]): Changelogs in a list + changelog_label_list (list[str]): Label list to control order and filtering + Returns: + str: Markdown formatted string + """ -def build_changelog_markdown(changes: list[Changelog]) -> str: changelog = "# Changelog" - previous_labels: list[str] = [] - - # TODO implement this logic in a more clever way, checkout `from itertools import groupby` - for change in changes: - current_labels: list[str] = change.labels - - if not any(label in previous_labels for label in current_labels): - label: str = change.labels[0].removeprefix("type: ") - changelog += f"\n\n## {label.capitalize()}\n\n" - changelog += f"* {change.title} - [{change.number}]({change.url})\n" + for label in changelog_label_list: + formatted_label: str = label.removeprefix("type: ").capitalize() + changelog += f"\n\n## {formatted_label}\n\n" - previous_labels = current_labels + for change in changes: + if change.labels[0] == label: + changelog += f"* {change.title} - [{change.number}]({change.url})\n" return changelog @@ -128,7 +138,7 @@ def csv_string_to_list(input: str) -> list[str]: return [] -def get_version_increment(pr_label_list: list, patch_bump_list: list=[], minor_bump_list: list=[], major_bump_list: list=[]): +def get_version_increment(pr_label_list: list[str], patch_bump_list: list[str]=[], minor_bump_list: list[str]=[], major_bump_list: list[str]=[]): """Figure out version increment based on PR labels. Args: diff --git a/tests/formatted_changelog.md b/tests/formatted_changelog.md new file mode 100644 index 0000000..4340d1b --- /dev/null +++ b/tests/formatted_changelog.md @@ -0,0 +1,16 @@ +# Changelog + +## Enhancement + +* Validate unique names only within the instance not in full scene - [70](https://github.com/ynput/ayon-maya/pull/70) + +## Bug + +* AY-6654 Look: Fix None values in collecting and applying attributes - [89](https://github.com/ynput/ayon-maya/pull/89) +* Fix settings for Maya USD Animation Extractor - [77](https://github.com/ynput/ayon-maya/pull/77) +* Improve applying render resolution and aspect ratio on render settings reset - [75](https://github.com/ynput/ayon-maya/pull/75) +* Maya Scene exports do not default to including nodes that not children of members - [71](https://github.com/ynput/ayon-maya/pull/71) + +## Maintenance + +* Skip extraction of active view for automatic tests - [126](https://github.com/ynput/ayon-maya/pull/126) diff --git a/tests/test_github_query.py b/tests/test_github_query.py index c7a19a6..8b4586a 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -1,11 +1,11 @@ -from typing import Any, Literal +from typing import Any, Literal, List import json import pytest from src import conversion_logic @pytest.fixture -def pr_api_output() -> list[dict[str, Any]]: +def pr_api_output() -> List[dict[str, Any]]: return [ { "body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement
\r\n[ ] Bugfix
\r\n[ ] Documentation update
\r\n\r\n## Summary\r\n\r\n\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\n\r\n\r\n## Changes\r\n\r\n\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n", @@ -55,17 +55,22 @@ def pr_api_output_missing_label(): ] @pytest.fixture -def major_bump(): +def major_bump() -> List[str]: return ["epic"] @pytest.fixture -def major_bump_no_list(): +def major_bump_no_list() -> Literal['epic']: return "epic" @pytest.fixture def merged_pr_samples(): with open("merged_pr_query.json") as file: return json.load(file) + +@pytest.fixture +def changelog_markdown() -> str: + with open("formatted_changelog.md") as file: + return file.read() @pytest.fixture def minor_bump() -> list[str]: @@ -84,11 +89,7 @@ def pr_labels_enhancement() -> list[str]: return ["bugfix", "documentation", "feature", "enhancement"] @pytest.fixture -def pr_labels_epic(): - return ["bugfix", "documentation", "feature", "enhancement", "epic"] - -@pytest.fixture -def pr_labels_epic(): +def pr_labels_epic() -> List[str]: return ["bugfix", "documentation", "feature", "enhancement", "epic"] @pytest.fixture @@ -111,14 +112,6 @@ def csv_string_spaces() -> Literal['bugfix, enhancement, feature']: def csv_string_no_spaces() -> Literal['bugfix,enhancement,feature']: return "bugfix,enhancement,feature" -@pytest.fixture -def csv_string_no_spaces() -> Literal['bugfix,enhancement,feature']: - return "bugfix,enhancement,feature" - -@pytest.fixture -def csv_string_no_comma() -> Literal['bugfix']: - return "bugfix" - @pytest.fixture def csv_string_no_comma() -> Literal['bugfix']: return "bugfix" @@ -127,16 +120,24 @@ def csv_string_no_comma() -> Literal['bugfix']: def csv_string_empty() -> Literal['']: return "" +@pytest.fixture +def changelog_label_list() -> list[str]: + return ["type: enhancement", "type: bug", "type: maintenance"] + +@pytest.fixture +def changelog_exclude_label_list() -> List[str]: + return ["sponsored"] + # Get PR Label test-cases -def test_get_labels(pr_api_output): - labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output) +def test_get_labels(pr_api_output: List[dict[str, Any]]) -> None: + labels: List[str] = conversion_logic.filter_unique_labels(pr_data=pr_api_output) assert isinstance(labels, list) assert set(labels) == {"bugfix", "enhancement"} -def test_get_labels_missing_input(pr_api_output_missing_label): +def test_get_labels_missing_input(pr_api_output_missing_label) -> None: labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output_missing_label) assert labels == [] @@ -144,34 +145,34 @@ def test_get_labels_missing_input(pr_api_output_missing_label): # Convert repo label list -def test_csv_string_to_list_spaces(csv_string_spaces): - string_list = conversion_logic.csv_string_to_list(csv_string_spaces) - string_list = conversion_logic.csv_string_to_list(csv_string_spaces) +def test_csv_string_to_list_spaces(csv_string_spaces: Literal['bugfix, enhancement, feature']) -> None: + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_spaces) + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_spaces) assert string_list == ["bugfix", "enhancement", "feature"] -def test_csv_string_to_list_no_spaces(csv_string_no_spaces): - string_list = conversion_logic.csv_string_to_list(csv_string_no_spaces) - string_list = conversion_logic.csv_string_to_list(csv_string_no_spaces) +def test_csv_string_to_list_no_spaces(csv_string_no_spaces: Literal['bugfix,enhancement,feature']) -> None: + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_spaces) + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_spaces) assert string_list == ["bugfix", "enhancement", "feature"] -def test_csv_string_to_list_no_comma(csv_string_no_comma): - string_list = conversion_logic.csv_string_to_list(csv_string_no_comma) - string_list = conversion_logic.csv_string_to_list(csv_string_no_comma) +def test_csv_string_to_list_no_comma(csv_string_no_comma: Literal['bugfix']) -> None: + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_comma) + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_no_comma) assert string_list == ["bugfix"] -def test_csv_string_to_list_empty(csv_string_empty): - string_list = conversion_logic.csv_string_to_list(csv_string_empty) - string_list = conversion_logic.csv_string_to_list(csv_string_empty) +def test_csv_string_to_list_empty(csv_string_empty: Literal['']) -> None: + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_empty) + string_list: List[str] = conversion_logic.csv_string_to_list(csv_string_empty) assert string_list == [] # Version Increment test-cases -def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug): +def test_get_version_increment_patch(minor_bump: List[str], patch_bump: List[str], pr_labels_bug: List[str]) -> None: increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_bug, patch_bump_list=patch_bump, @@ -180,7 +181,7 @@ def test_get_version_increment_patch(minor_bump, patch_bump, pr_labels_bug): assert increment == "patch" -def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhancement): +def test_get_version_increment_minor(minor_bump: List[str], patch_bump: List[str], pr_labels_enhancement: List[str]) -> None: increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_enhancement, patch_bump_list=patch_bump, @@ -189,7 +190,7 @@ def test_get_version_increment_minor(minor_bump, patch_bump, pr_labels_enhanceme assert increment == "minor" -def test_get_version_increment_minor(minor_bump, patch_bump, major_bump, pr_labels_epic): +def test_get_version_increment_minor(minor_bump: List[str], patch_bump: List[str], major_bump: List[str], pr_labels_epic: List[str]) -> None: increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_epic, patch_bump_list=patch_bump, @@ -199,7 +200,7 @@ def test_get_version_increment_minor(minor_bump, patch_bump, major_bump, pr_labe assert increment == "major" -def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wrong_labels): +def test_get_version_increment_wrong_labels(minor_bump: List[str], patch_bump: List[str], pr_labels_wrong_labels: List[str]): increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_wrong_labels, patch_bump_list=patch_bump, @@ -208,7 +209,7 @@ def test_get_version_increment_wrong_labels(minor_bump, patch_bump, pr_labels_wr assert increment == "" -def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none): +def test_get_version_increment_none(minor_bump: List[str], patch_bump: List[str], pr_labels_none: None) -> None: increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_none, patch_bump_list=patch_bump, @@ -217,7 +218,7 @@ def test_get_version_increment_none(minor_bump, patch_bump, pr_labels_none): assert increment == "" -def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empty_list): +def test_get_version_increment_empty_list(minor_bump: List[str], patch_bump: List[str], pr_labels_empty_list: List[Any]) -> None: increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_empty_list, patch_bump_list=patch_bump, @@ -226,7 +227,7 @@ def test_get_version_increment_empty_list(minor_bump, patch_bump, pr_labels_empt assert increment == "" -def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_list, pr_labels_epic): +def test_get_version_increment_no_list(minor_bump: List[str], patch_bump: List[str], major_bump_no_list: Literal['epic'], pr_labels_epic: List[str]) -> None: with pytest.raises(ValueError, match="must be a list"): conversion_logic.get_version_increment( pr_label_list=pr_labels_epic, @@ -238,10 +239,14 @@ def test_get_version_increment_no_list(minor_bump, patch_bump, major_bump_no_lis # Changelog test-cases -def test_changer_pert_label(merged_pr_samples: dict[str, str]) -> None: - changelog_labels: list[str] = ["type: bug", "type: enhancement", "type: maintenance"] - filtered_results: list[Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_labels) +def test_filter_changes_per_label_types(merged_pr_samples: List[dict[str, str]], changelog_label_list: List[str]) -> None: + filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list) + + assert all(isinstance(changelog, conversion_logic.Changelog) for changelog in filtered_pr_list) + + +def test_format_changelog_markdown(merged_pr_samples: List[dict[str, str]], changelog_label_list: List[str], changelog_markdown: str) -> None: + filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list) + changelog_result: str = conversion_logic.format_changelog_markdown(changes=filtered_pr_list, changelog_label_list=changelog_label_list) - for result in filtered_results: - for label in result.labels: - assert label in changelog_labels \ No newline at end of file + assert changelog_result == changelog_result From 2668e98353d0bfe36c58d0f6690a5064791bb055 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 4 Nov 2024 14:16:41 +0100 Subject: [PATCH 55/66] Remove obsolete function --- src/conversion_logic.py | 31 ------------------------------- 1 file changed, 31 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 2521faa..8674af5 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -40,37 +40,6 @@ def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list return changes_list -# INFO currently not in use -def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): - """Get list of changes from a PRs changelog. - - Args: - pr_body (list(str)): List of PR body contents. - changelog_start (str, optional): Indicates markdown changelog section. Defaults to "## Changes". - heading (str, optional): Markdown heading. Defaults to "##". - - Returns: - list(str): List of changes found. - """ - - lines: list[str] = pr_data.splitlines() - changelog_section = None - changelog_lines: list[str] = [] - - for line in lines: - if line.startswith(changelog_start): - changelog_section = True - continue - - if changelog_section and line.startswith(heading): - break - - if changelog_section and line.startswith("* "): - changelog_lines.append(line.strip("* ").strip()) - - return changelog_lines - - def format_changelog_markdown(changes: list[Changelog], changelog_label_list: list[str]) -> str: """Create markdown formatted changelog. From 1e393fa9531d4a94c23dbef13b77eda362fa5fd8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 4 Nov 2024 14:46:19 +0100 Subject: [PATCH 56/66] Update caller functions --- github_query.py | 23 +++++++++++------------ src/conversion_logic.py | 16 ++++++++-------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/github_query.py b/github_query.py index 4570969..1fcd4cb 100644 --- a/github_query.py +++ b/github_query.py @@ -5,6 +5,7 @@ import click from src import conversion_logic, queries +from typing import List @click.group() @@ -16,7 +17,7 @@ def cli() -> None: @click.argument('repo_name', type=click.STRING) @click.argument('query_tags', type=click.STRING) @click.argument('latest_release_date', type=click.STRING) -def pr_labels(latest_release_date, query_tags, repo_name): +def pr_labels(latest_release_date: str, query_tags: str, repo_name: str) -> None: """Get a list of all version relevant PR labels. latest_release_date (str): datatime string\n @@ -24,9 +25,9 @@ def pr_labels(latest_release_date, query_tags, repo_name): repo_name (str): repo name as \n """ - query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) - pr_result = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) - pr_labels = conversion_logic.filter_unique_labels(pr_data=pr_result) + query_tags_list: List[str] = conversion_logic.csv_string_to_list(input=query_tags) + pr_result: List[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) + pr_labels: List[str] = conversion_logic.filter_unique_labels(pr_data=pr_result) if not pr_labels: click.echo("") @@ -47,10 +48,10 @@ def version_increment(latest_release_date: str, query_tags: str, repo_name: str) """ query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) - pr_result = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) - pr_labels = conversion_logic.filter_unique_labels(pr_data=pr_result) - patch_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) - minor_repo_var_list = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) + pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) + pr_labels: conversion_logic.List[str] = conversion_logic.filter_unique_labels(pr_data=pr_result) + patch_repo_var_list: conversion_logic.List[str] = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="PATCH_BUMP_LABEL")) + minor_repo_var_list: conversion_logic.List[str] = conversion_logic.csv_string_to_list(queries.get_repo_var(repo=repo_name, var_name="MINOR_BUMP_LABEL")) increment = conversion_logic.get_version_increment(patch_bump_list=patch_repo_var_list, minor_bump_list=minor_repo_var_list, pr_label_list=pr_labels) click.echo(increment) @@ -72,10 +73,8 @@ def generate_release_changelog(latest_release_date: str, query_tags: str, repo_n query_tags_list: list[str] = conversion_logic.csv_string_to_list(query_tags) pr_result: list[dict[str, str]] = queries.query_merged_prs(latest_release_date, query_tags_list, repo_name) changelog_labels_result: list[str] = conversion_logic.csv_string_to_list(changelog_labels) - - pr_filtered: list[Changelog] = conversion_logic.filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_labels_result) - sorted_changes: list[Changelog] = conversion_logic.sort_changes(changes_list=pr_filtered, changelog_label_list=changelog_labels_result) - markdown_changelog: str = conversion_logic.build_changelog_markdown(sorted_changes) + pr_filtered: list[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=pr_result, changelog_label_list=changelog_labels_result) + markdown_changelog: str = conversion_logic.format_changelog_markdown(changes=pr_filtered, changelog_label_list=changelog_labels_result) click.echo(markdown_changelog) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 8674af5..1ac1dd1 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -1,20 +1,20 @@ import logging import re -from typing import NamedTuple +from typing import NamedTuple, List logger: logging.Logger = logging.getLogger(__name__) class Changelog(NamedTuple): - labels: list[str] + labels: List[str] title: str number: int url: str id: int -def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list: list[str]) -> list[Changelog]: +def filter_changes_per_label(pr_data: List[dict[str, str]], changelog_label_list: List[str]) -> List[Changelog]: """Convert list of PR dictionaries to Changelog list Args: @@ -25,7 +25,7 @@ def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list list[Changelog]: List of changelog objects """ - changes_list: list[Changelog] = [] + changes_list: List[Changelog] = [] for pull_request in pr_data: if pull_request.get("labels"): @@ -40,7 +40,7 @@ def filter_changes_per_label(pr_data: list[dict[str, str]], changelog_label_list return changes_list -def format_changelog_markdown(changes: list[Changelog], changelog_label_list: list[str]) -> str: +def format_changelog_markdown(changes: List[Changelog], changelog_label_list: List[str]) -> str: """Create markdown formatted changelog. Args: @@ -64,7 +64,7 @@ def format_changelog_markdown(changes: list[Changelog], changelog_label_list: li return changelog -def filter_unique_labels(pr_data: dict[dict[str, str]]) -> list[str]: +def filter_unique_labels(pr_data: List[dict[str, str]]) -> List[str]: """Filter all unique labels from dictionary. Args: @@ -91,7 +91,7 @@ def filter_unique_labels(pr_data: dict[dict[str, str]]) -> list[str]: return list(labels) -def csv_string_to_list(input: str) -> list[str]: +def csv_string_to_list(input: str) -> List[str]: """Convert string to list. Args: @@ -107,7 +107,7 @@ def csv_string_to_list(input: str) -> list[str]: return [] -def get_version_increment(pr_label_list: list[str], patch_bump_list: list[str]=[], minor_bump_list: list[str]=[], major_bump_list: list[str]=[]): +def get_version_increment(pr_label_list: List[str], patch_bump_list: List[str]=[], minor_bump_list: List[str]=[], major_bump_list: List[str]=[]): """Figure out version increment based on PR labels. Args: From e73ef7208f923e210fc93270878f257d82dbd0a5 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 4 Nov 2024 14:55:06 +0100 Subject: [PATCH 57/66] Add missing return statement --- github_query.py | 1 + 1 file changed, 1 insertion(+) diff --git a/github_query.py b/github_query.py index 1fcd4cb..3cd1eb6 100644 --- a/github_query.py +++ b/github_query.py @@ -31,6 +31,7 @@ def pr_labels(latest_release_date: str, query_tags: str, repo_name: str) -> None if not pr_labels: click.echo("") + return click.echo(pr_labels) From 165e75423bb2cf6eaf2abd873e49946d16cdc40a Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 4 Nov 2024 15:52:24 +0100 Subject: [PATCH 58/66] Enhance changelog creation Handle missing labels by skipping --- src/conversion_logic.py | 108 ++++++++++++++++++----------------- tests/formatted_changelog.md | 1 + tests/test_github_query.py | 8 ++- 3 files changed, 64 insertions(+), 53 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 1ac1dd1..0923270 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -1,7 +1,7 @@ import logging import re -from typing import NamedTuple, List +from typing import NamedTuple, List, Set logger: logging.Logger = logging.getLogger(__name__) @@ -14,56 +14,6 @@ class Changelog(NamedTuple): id: int -def filter_changes_per_label(pr_data: List[dict[str, str]], changelog_label_list: List[str]) -> List[Changelog]: - """Convert list of PR dictionaries to Changelog list - - Args: - pr_data (list[dict[str, str]]): PR information and metadata - changelog_label_list (list[str]): Changelog labels - - Returns: - list[Changelog]: List of changelog objects - """ - - changes_list: List[Changelog] = [] - - for pull_request in pr_data: - if pull_request.get("labels"): - changes_list.append(Changelog(labels=[label["name"] for label in pull_request["labels"]], - title=pull_request["title"], - number=pull_request["number"], - url=pull_request["url"], - id=pull_request["id"], - ) - ) - - return changes_list - - -def format_changelog_markdown(changes: List[Changelog], changelog_label_list: List[str]) -> str: - """Create markdown formatted changelog. - - Args: - changes (list[Changelog]): Changelogs in a list - changelog_label_list (list[str]): Label list to control order and filtering - - Returns: - str: Markdown formatted string - """ - - changelog = "# Changelog" - - for label in changelog_label_list: - formatted_label: str = label.removeprefix("type: ").capitalize() - changelog += f"\n\n## {formatted_label}\n\n" - - for change in changes: - if change.labels[0] == label: - changelog += f"* {change.title} - [{change.number}]({change.url})\n" - - return changelog - - def filter_unique_labels(pr_data: List[dict[str, str]]) -> List[str]: """Filter all unique labels from dictionary. @@ -137,4 +87,58 @@ def get_version_increment(pr_label_list: List[str], patch_bump_list: List[str]=[ return "patch" logger.warning("No relevant labels found for version increment.") - return "" \ No newline at end of file + return "" + + +def filter_changes_per_label(pr_data: List[dict[str, str]], changelog_label_list: List[str]) -> List[Changelog]: + """Convert list of PR dictionaries to Changelog list + + Args: + pr_data (list[dict[str, str]]): PR information and metadata + changelog_label_list (list[str]): Changelog labels + + Returns: + list[Changelog]: List of changelog objects + """ + + changes_list: List[Changelog] = [] + + for pull_request in pr_data: + if pull_request.get("labels"): + changes_list.append(Changelog(labels=[label["name"] for label in pull_request["labels"]], + title=pull_request["title"], + number=pull_request["number"], + url=pull_request["url"], + id=pull_request["id"], + ) + ) + + return changes_list + + +def format_changelog_markdown(changes: List[Changelog], changelog_label_list: List[str]) -> str: + """Create markdown formatted changelog. + + Args: + changes (list[Changelog]): Changelogs in a list + changelog_label_list (list[str]): Label list to control order and filtering + + Returns: + str: Markdown formatted string + """ + + changelog = "# Changelog\n" + change_label_list: set[str] = {label for change in changes for label in change.labels} + + for label in changelog_label_list: + if label not in change_label_list: + continue + + formatted_label: str = label.removeprefix("type: ").capitalize() + changelog += f"\n## {formatted_label}\n\n" + + for change in changes: + if label in change.labels: + changelog += f"* {change.title} - [{change.number}]({change.url})\n" + + return changelog \ No newline at end of file diff --git a/tests/formatted_changelog.md b/tests/formatted_changelog.md index 4340d1b..ef9b9bb 100644 --- a/tests/formatted_changelog.md +++ b/tests/formatted_changelog.md @@ -2,6 +2,7 @@ ## Enhancement +* Improve applying render resolution and aspect ratio on render settings reset - [75](https://github.com/ynput/ayon-maya/pull/75) * Validate unique names only within the instance not in full scene - [70](https://github.com/ynput/ayon-maya/pull/70) ## Bug diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 8b4586a..ad1f740 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -249,4 +249,10 @@ def test_format_changelog_markdown(merged_pr_samples: List[dict[str, str]], chan filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list) changelog_result: str = conversion_logic.format_changelog_markdown(changes=filtered_pr_list, changelog_label_list=changelog_label_list) - assert changelog_result == changelog_result + assert changelog_result == changelog_markdown + +def test_format_changelog_markdown_no_data(changelog_label_list: List[str]) -> None: + filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=[], changelog_label_list=changelog_label_list) + changelog_result: str = conversion_logic.format_changelog_markdown(changes=filtered_pr_list, changelog_label_list=changelog_label_list) + + assert changelog_result == "# Changelog\n" From 6c9ad3a58c1df4d7c00719fe7faa5b17ba5799b1 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Mon, 4 Nov 2024 16:59:23 +0100 Subject: [PATCH 59/66] Add details formatting to changelog --- src/conversion_logic.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 0923270..73dfb4f 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -135,10 +135,14 @@ def format_changelog_markdown(changes: List[Changelog], changelog_label_list: Li continue formatted_label: str = label.removeprefix("type: ").capitalize() - changelog += f"\n## {formatted_label}\n\n" + changelog += f"\n### **{formatted_label}**\n\n" for change in changes: if label in change.labels: - changelog += f"* {change.title} - [{change.number}]({change.url})\n" + changelog += f"
\n" + changelog += f"{change.title} - [#{change.number}]({change.url})\n\n" + changelog += f"details\n\n\n" + changelog += f"___\n\n" + changelog += f"
" return changelog \ No newline at end of file From 7ede1a98b9dabf72e820cd06d86cfcb44edafea8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 09:33:07 +0100 Subject: [PATCH 60/66] Add details to changelog Update test suite --- src/conversion_logic.py | 41 +++++++++++++++- tests/formatted_changelog.md | 92 ++++++++++++++++++++++++++++++++---- 2 files changed, 121 insertions(+), 12 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 73dfb4f..0575c6d 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -12,6 +12,7 @@ class Changelog(NamedTuple): number: int url: str id: int + body: str def filter_unique_labels(pr_data: List[dict[str, str]]) -> List[str]: @@ -110,12 +111,43 @@ def filter_changes_per_label(pr_data: List[dict[str, str]], changelog_label_list number=pull_request["number"], url=pull_request["url"], id=pull_request["id"], + body=pull_request["body"], ) ) return changes_list +def get_changelog(pr_body: str, changelog_desc: str ="## Changelog Description", heading: str ="##") -> List[str]: + """Get list of changes from a PRs changelog. + + Args: + pr_body list(str): PR body content + changelog_desc (str, optional): Indicates markdown changelog section. Defaults to "## Changes" + heading (str, optional): Markdown heading. Defaults to "##" + + Returns: + list(str): List of changes found. + """ + + lines: list[str] = pr_body.splitlines() + changelog_section = None + description_lines: list[str] = [] + + for line in lines: + if line.startswith(changelog_desc): + changelog_section = True + continue + + if changelog_section and line.startswith(heading): + break + + if changelog_section: + description_lines.append(line.strip()) + + return description_lines + + def format_changelog_markdown(changes: List[Changelog], changelog_label_list: List[str]) -> str: """Create markdown formatted changelog. @@ -139,10 +171,15 @@ def format_changelog_markdown(changes: List[Changelog], changelog_label_list: Li for change in changes: if label in change.labels: + changelog_desc: List[str] = get_changelog(change.body, changelog_desc="## Changelog Description", heading="##") + changelog += f"
\n" changelog += f"{change.title} - [#{change.number}]({change.url})\n\n" - changelog += f"details\n\n\n" + + for desc_line in changelog_desc: + changelog += f"{desc_line}\n" + changelog += f"___\n\n" - changelog += f"
" + changelog += f"\n" return changelog \ No newline at end of file diff --git a/tests/formatted_changelog.md b/tests/formatted_changelog.md index ef9b9bb..f6b1786 100644 --- a/tests/formatted_changelog.md +++ b/tests/formatted_changelog.md @@ -1,17 +1,89 @@ # Changelog -## Enhancement +### **Enhancement** -* Improve applying render resolution and aspect ratio on render settings reset - [75](https://github.com/ynput/ayon-maya/pull/75) -* Validate unique names only within the instance not in full scene - [70](https://github.com/ynput/ayon-maya/pull/70) +
+Improve applying render resolution and aspect ratio on render settings reset - [#75](https://github.com/ynput/ayon-maya/pull/75) -## Bug + -* AY-6654 Look: Fix None values in collecting and applying attributes - [89](https://github.com/ynput/ayon-maya/pull/89) -* Fix settings for Maya USD Animation Extractor - [77](https://github.com/ynput/ayon-maya/pull/77) -* Improve applying render resolution and aspect ratio on render settings reset - [75](https://github.com/ynput/ayon-maya/pull/75) -* Maya Scene exports do not default to including nodes that not children of members - [71](https://github.com/ynput/ayon-maya/pull/71) +Fix pixel aspect ratio / device aspect ratio getting messed up for Arnold renderer on render settings reset. -## Maintenance +Additionally: +- This now applies the resolution from the task entity, not the folder entity. +- This now also applies pixel aspect ratio as defined on the entity. -* Skip extraction of active view for automatic tests - [126](https://github.com/ynput/ayon-maya/pull/126) +___ + +
+
+Validate unique names only within the instance not in full scene - [#70](https://github.com/ynput/ayon-maya/pull/70) + + + +Validate unique names only within the instance not in full scene + +___ + +
+ +### **Bug** + +
+AY-6654 Look: Fix None values in collecting and applying attributes - [#89](https://github.com/ynput/ayon-maya/pull/89) + + + +This fixes a case where looks failed to apply due to `None` values being present in the collected attributes. +These will now be ignored in collected. There's an edge case where Maya returns `None` for string attributes that have no values set - those are captured now explicitly to just `""` to still collect and apply them later. + +Existing looks will now also apply correctly with `None` value in their look attributes, but the attributes with `None` values will be ignored with a warning. + +___ + +
+
+Fix settings for Maya USD Animation Extractor - [#77](https://github.com/ynput/ayon-maya/pull/77) + + + +Fix name in settings to match with name of plug-in to ensure settings are actually applied + +___ + +
+
+Improve applying render resolution and aspect ratio on render settings reset - [#75](https://github.com/ynput/ayon-maya/pull/75) + + + +Fix pixel aspect ratio / device aspect ratio getting messed up for Arnold renderer on render settings reset. + +Additionally: +- This now applies the resolution from the task entity, not the folder entity. +- This now also applies pixel aspect ratio as defined on the entity. + +___ + +
+
+Maya Scene exports do not default to including nodes that not children of members - [#71](https://github.com/ynput/ayon-maya/pull/71) + + + +On Maya scene exports only include the relevant history for the selected nodes downstream and upstream and not upstream, and also their downstream descendant children. + +___ + +
+ +### **Maintenance** + +
+Skip extraction of active view for automatic tests - [#126](https://github.com/ynput/ayon-maya/pull/126) + +It seems that Maya UI is not completely visible or shutting down, `view.readColorBuffer` causes RuntimeError: (kFailure): Unexpected Internal Failure aas view is not visible. + +___ + +
From e53155bba06962eddf41e9b10d07f447c46919db Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 09:41:09 +0100 Subject: [PATCH 61/66] Update function name --- src/conversion_logic.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 0575c6d..5893e72 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -118,7 +118,7 @@ def filter_changes_per_label(pr_data: List[dict[str, str]], changelog_label_list return changes_list -def get_changelog(pr_body: str, changelog_desc: str ="## Changelog Description", heading: str ="##") -> List[str]: +def get_changelog_description(pr_body: str, changelog_desc: str ="## Changelog Description", heading: str ="##") -> List[str]: """Get list of changes from a PRs changelog. Args: @@ -171,11 +171,11 @@ def format_changelog_markdown(changes: List[Changelog], changelog_label_list: Li for change in changes: if label in change.labels: - changelog_desc: List[str] = get_changelog(change.body, changelog_desc="## Changelog Description", heading="##") - changelog += f"
\n" changelog += f"{change.title} - [#{change.number}]({change.url})\n\n" - + + changelog_desc: List[str] = get_changelog_description(change.body, changelog_desc="## Changelog Description", heading="##") + for desc_line in changelog_desc: changelog += f"{desc_line}\n" From 3dde7bb24a9a5a74772ca38b766bc9ed10ad5d08 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 10:09:45 +0100 Subject: [PATCH 62/66] Update url handling in changelog switch to html based syntax --- src/conversion_logic.py | 2 +- tests/formatted_changelog.md | 14 +++++++------- tests/test_github_query.py | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 5893e72..c43851c 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -172,7 +172,7 @@ def format_changelog_markdown(changes: List[Changelog], changelog_label_list: Li for change in changes: if label in change.labels: changelog += f"
\n" - changelog += f"{change.title} - [#{change.number}]({change.url})\n\n" + changelog += f"{change.title} - #{change.number}\n\n" changelog_desc: List[str] = get_changelog_description(change.body, changelog_desc="## Changelog Description", heading="##") diff --git a/tests/formatted_changelog.md b/tests/formatted_changelog.md index f6b1786..15153f8 100644 --- a/tests/formatted_changelog.md +++ b/tests/formatted_changelog.md @@ -3,7 +3,7 @@ ### **Enhancement**
-Improve applying render resolution and aspect ratio on render settings reset - [#75](https://github.com/ynput/ayon-maya/pull/75) +Improve applying render resolution and aspect ratio on render settings reset - #75 @@ -17,7 +17,7 @@ ___
-Validate unique names only within the instance not in full scene - [#70](https://github.com/ynput/ayon-maya/pull/70) +Validate unique names only within the instance not in full scene - #70 @@ -30,7 +30,7 @@ ___ ### **Bug**
-AY-6654 Look: Fix None values in collecting and applying attributes - [#89](https://github.com/ynput/ayon-maya/pull/89) +AY-6654 Look: Fix None values in collecting and applying attributes - #89 @@ -43,7 +43,7 @@ ___
-Fix settings for Maya USD Animation Extractor - [#77](https://github.com/ynput/ayon-maya/pull/77) +Fix settings for Maya USD Animation Extractor - #77 @@ -53,7 +53,7 @@ ___
-Improve applying render resolution and aspect ratio on render settings reset - [#75](https://github.com/ynput/ayon-maya/pull/75) +Improve applying render resolution and aspect ratio on render settings reset - #75 @@ -67,7 +67,7 @@ ___
-Maya Scene exports do not default to including nodes that not children of members - [#71](https://github.com/ynput/ayon-maya/pull/71) +Maya Scene exports do not default to including nodes that not children of members - #71 @@ -80,7 +80,7 @@ ___ ### **Maintenance**
-Skip extraction of active view for automatic tests - [#126](https://github.com/ynput/ayon-maya/pull/126) +Skip extraction of active view for automatic tests - #126 It seems that Maya UI is not completely visible or shutting down, `view.readColorBuffer` causes RuntimeError: (kFailure): Unexpected Internal Failure aas view is not visible. diff --git a/tests/test_github_query.py b/tests/test_github_query.py index ad1f740..51cbed6 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -249,6 +249,8 @@ def test_format_changelog_markdown(merged_pr_samples: List[dict[str, str]], chan filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list) changelog_result: str = conversion_logic.format_changelog_markdown(changes=filtered_pr_list, changelog_label_list=changelog_label_list) + # print(changelog_result) + assert changelog_result == changelog_markdown def test_format_changelog_markdown_no_data(changelog_label_list: List[str]) -> None: From 031eb3e0d5a3ed36dc9a009a0caecb228744898b Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 11:35:45 +0100 Subject: [PATCH 63/66] Add unit-test for changelog description formatting --- src/conversion_logic.py | 8 +++++++- tests/changelog.md | 15 +++++++++++++++ tests/formatted_changelog.md | 6 ------ tests/test_github_query.py | 16 ++++++++++++++-- 4 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 tests/changelog.md diff --git a/src/conversion_logic.py b/src/conversion_logic.py index c43851c..011b758 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -145,6 +145,10 @@ def get_changelog_description(pr_body: str, changelog_desc: str ="## Changelog D if changelog_section: description_lines.append(line.strip()) + for index in [0, -1]: + if not description_lines[index]: + description_lines.pop(index) + return description_lines @@ -177,9 +181,11 @@ def format_changelog_markdown(changes: List[Changelog], changelog_label_list: Li changelog_desc: List[str] = get_changelog_description(change.body, changelog_desc="## Changelog Description", heading="##") for desc_line in changelog_desc: + if desc_line.startswith(" Fix pixel aspect ratio / device aspect ratio getting messed up for Arnold renderer on render settings reset. @@ -19,7 +18,6 @@ ___
Validate unique names only within the instance not in full scene - #70 - Validate unique names only within the instance not in full scene @@ -32,7 +30,6 @@ ___
AY-6654 Look: Fix None values in collecting and applying attributes - #89 - This fixes a case where looks failed to apply due to `None` values being present in the collected attributes. These will now be ignored in collected. There's an edge case where Maya returns `None` for string attributes that have no values set - those are captured now explicitly to just `""` to still collect and apply them later. @@ -45,7 +42,6 @@ ___
Fix settings for Maya USD Animation Extractor - #77 - Fix name in settings to match with name of plug-in to ensure settings are actually applied @@ -55,7 +51,6 @@ ___
Improve applying render resolution and aspect ratio on render settings reset - #75 - Fix pixel aspect ratio / device aspect ratio getting messed up for Arnold renderer on render settings reset. @@ -69,7 +64,6 @@ ___
Maya Scene exports do not default to including nodes that not children of members - #71 - On Maya scene exports only include the relevant history for the selected nodes downstream and upstream and not upstream, and also their downstream descendant children. diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 51cbed6..9bd971b 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -71,6 +71,15 @@ def merged_pr_samples(): def changelog_markdown() -> str: with open("formatted_changelog.md") as file: return file.read() + +@pytest.fixture +def changelog_body() -> str: + with open("changelog.md") as file: + return file.read() + +@pytest.fixture +def changelog_description() -> List[str]: + return ['Some more information', '', '- Prototype loading of USD references into a Maya USD proxy while keeping it managed by the pipeline', '- Prototype loading of Maya references into a Maya USD proxy while keeping it managed by the pipeline'] @pytest.fixture def minor_bump() -> list[str]: @@ -244,13 +253,16 @@ def test_filter_changes_per_label_types(merged_pr_samples: List[dict[str, str]], assert all(isinstance(changelog, conversion_logic.Changelog) for changelog in filtered_pr_list) +def test_get_changelog_description(changelog_body: str, changelog_description: str) -> None: + filtered_changelog: List[str] = conversion_logic.get_changelog_description(changelog_body) + + assert filtered_changelog == changelog_description def test_format_changelog_markdown(merged_pr_samples: List[dict[str, str]], changelog_label_list: List[str], changelog_markdown: str) -> None: filtered_pr_list: List[conversion_logic.Changelog] = conversion_logic.filter_changes_per_label(pr_data=merged_pr_samples, changelog_label_list=changelog_label_list) changelog_result: str = conversion_logic.format_changelog_markdown(changes=filtered_pr_list, changelog_label_list=changelog_label_list) - # print(changelog_result) - + print(changelog_result) assert changelog_result == changelog_markdown def test_format_changelog_markdown_no_data(changelog_label_list: List[str]) -> None: From 1154f265ceec08d8f67cf3d24902fc3144736683 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 14:11:08 +0100 Subject: [PATCH 64/66] Move json fixtures to files --- src/conversion_logic.py | 4 +- tests/pr_api_output.json | 26 ++++++++++++ tests/pr_api_output_missing_label.json | 18 +++++++++ tests/test_github_query.py | 56 ++++---------------------- 4 files changed, 54 insertions(+), 50 deletions(-) create mode 100644 tests/pr_api_output.json create mode 100644 tests/pr_api_output_missing_label.json diff --git a/src/conversion_logic.py b/src/conversion_logic.py index 011b758..13ddaa6 100644 --- a/src/conversion_logic.py +++ b/src/conversion_logic.py @@ -1,7 +1,7 @@ import logging import re -from typing import NamedTuple, List, Set +from typing import NamedTuple, List logger: logging.Logger = logging.getLogger(__name__) @@ -58,7 +58,7 @@ def csv_string_to_list(input: str) -> List[str]: return [] -def get_version_increment(pr_label_list: List[str], patch_bump_list: List[str]=[], minor_bump_list: List[str]=[], major_bump_list: List[str]=[]): +def get_version_increment(pr_label_list: List[str] | None, patch_bump_list: List[str]=[], minor_bump_list: List[str]=[], major_bump_list: List[str] | str=[]): """Figure out version increment based on PR labels. Args: diff --git a/tests/pr_api_output.json b/tests/pr_api_output.json new file mode 100644 index 0000000..8f9d049 --- /dev/null +++ b/tests/pr_api_output.json @@ -0,0 +1,26 @@ +[ + { + "body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement
\r\n[ ] Bugfix
\r\n[ ] Documentation update
\r\n\r\n## Summary\r\n\r\n\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\n\r\n\r\n## Changes\r\n\r\n\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n", + "labels": [ + { + "id": "LA_kwDOMje8_88AAAABtOJ1Ig", + "name": "enhancement", + "description": "New feature or request", + "color": "b9f29d" + } + ], + "title": "Add more data" + }, + { + "body": "# Date file added\r\n\r\n## Summary\r\n\r\nSome awesome summary going on right here.\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\nDate file so absolutely needed.\r\n\r\n## Changes\r\n\r\n\r\n* Run a command\r\n* Pipe its output to a text file\r\n* Commit dem stuff\r\n\r\n## Testing Strategy\r\n\r\nnahhhhh\r\n\r\n## Checklist\r\n\r\n* [x] The fix has been locally tested\r\n* [x] New unit tests have been added to prevent future regressions\r\n* [x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\nNop", + "labels": [ + { + "id": "LA_kwDOMje8_88AAAABtOJ1Gw", + "name": "bugfix", + "description": "Something got fixed", + "color": "ff9195" + } + ], + "title": "Add date file" + } +] \ No newline at end of file diff --git a/tests/pr_api_output_missing_label.json b/tests/pr_api_output_missing_label.json new file mode 100644 index 0000000..2a97d4a --- /dev/null +++ b/tests/pr_api_output_missing_label.json @@ -0,0 +1,18 @@ +[ + { + "body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement
\r\n[ ] Bugfix
\r\n[ ] Documentation update
\r\n\r\n## Summary\r\n\r\n\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\n\r\n\r\n## Changes\r\n\r\n\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n", + "title": "Add more data" + }, + { + "body": "# Date file added\r\n\r\n## Summary\r\n\r\nSome awesome summary going on right here.\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\nDate file so absolutely needed.\r\n\r\n## Changes\r\n\r\n\r\n* Run a command\r\n* Pipe its output to a text file\r\n* Commit dem stuff\r\n\r\n## Testing Strategy\r\n\r\nnahhhhh\r\n\r\n## Checklist\r\n\r\n* [x] The fix has been locally tested\r\n* [x] New unit tests have been added to prevent future regressions\r\n* [x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\nNop", + "labels": [ + { + "id": "LA_kwDOMje8_88AAAABtOJ1Gw", + "name": "bug", + "description": "Something isn't working", + "color": "ff9195" + } + ], + "title": "Add date file" + } +] \ No newline at end of file diff --git a/tests/test_github_query.py b/tests/test_github_query.py index 9bd971b..1922ef0 100644 --- a/tests/test_github_query.py +++ b/tests/test_github_query.py @@ -6,53 +6,13 @@ @pytest.fixture def pr_api_output() -> List[dict[str, Any]]: - return [ - { - "body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement
\r\n[ ] Bugfix
\r\n[ ] Documentation update
\r\n\r\n## Summary\r\n\r\n\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\n\r\n\r\n## Changes\r\n\r\n\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n", - "labels": [ - { - "id": "LA_kwDOMje8_88AAAABtOJ1Ig", - "name": "enhancement", - "description": "New feature or request", - "color": "b9f29d" - } - ], - "title": "Add more data" - }, - { - "body": "# Date file added\r\n\r\n## Summary\r\n\r\nSome awesome summary going on right here.\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\nDate file so absolutely needed.\r\n\r\n## Changes\r\n\r\n\r\n* Run a command\r\n* Pipe its output to a text file\r\n* Commit dem stuff\r\n\r\n## Testing Strategy\r\n\r\nnahhhhh\r\n\r\n## Checklist\r\n\r\n* [x] The fix has been locally tested\r\n* [x] New unit tests have been added to prevent future regressions\r\n* [x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\nNop", - "labels": [ - { - "id": "LA_kwDOMje8_88AAAABtOJ1Gw", - "name": "bugfix", - "description": "Something got fixed", - "color": "ff9195" - } - ], - "title": "Add date file" - } - ] + with open("pr_api_output.json") as file: + return json.load(file) @pytest.fixture -def pr_api_output_missing_label(): - return [ - { - "body": "# Bug Fix PR Template\r\n\r\n[ x] Feature/Enhancement
\r\n[ ] Bugfix
\r\n[ ] Documentation update
\r\n\r\n## Summary\r\n\r\n\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\n\r\n\r\n## Changes\r\n\r\n\r\n* Add more test\r\n* Was very important\r\n* Needed to add this here\r\n\r\n## Testing Strategy\r\n\r\n\r\n\r\n## Checklist\r\n\r\n* [ x] The fix has been locally tested\r\n* [ x] New unit tests have been added to prevent future regressions\r\n* [ x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\n", - "title": "Add more data" - }, - { - "body": "# Date file added\r\n\r\n## Summary\r\n\r\nSome awesome summary going on right here.\r\n\r\n## Root Cause Analysis\r\n\r\n[Issue Link](https://github.com/ynput/ci-testing/blob/develop/.github/ISSUE_TEMPLATE/bug_report.yml)
\r\nDate file so absolutely needed.\r\n\r\n## Changes\r\n\r\n\r\n* Run a command\r\n* Pipe its output to a text file\r\n* Commit dem stuff\r\n\r\n## Testing Strategy\r\n\r\nnahhhhh\r\n\r\n## Checklist\r\n\r\n* [x] The fix has been locally tested\r\n* [x] New unit tests have been added to prevent future regressions\r\n* [x] The documentation has been updated if necessary\r\n\r\n## Additional Notes\r\n\r\nNop", - "labels": [ - { - "id": "LA_kwDOMje8_88AAAABtOJ1Gw", - "name": "bug", - "description": "Something isn't working", - "color": "ff9195" - } - ], - "title": "Add date file" - } - ] +def pr_api_output_missing_label() -> List[dict[str, Any]]: + with open("pr_api_output_missing_label.json") as file: + return json.load(file) @pytest.fixture def major_bump() -> List[str]: @@ -146,8 +106,8 @@ def test_get_labels(pr_api_output: List[dict[str, Any]]) -> None: assert isinstance(labels, list) assert set(labels) == {"bugfix", "enhancement"} -def test_get_labels_missing_input(pr_api_output_missing_label) -> None: - labels = conversion_logic.filter_unique_labels(pr_data=pr_api_output_missing_label) +def test_get_labels_missing_input(pr_api_output_missing_label: List[dict[str, Any]]) -> None: + labels: List[str] = conversion_logic.filter_unique_labels(pr_data=pr_api_output_missing_label) assert labels == [] @@ -199,7 +159,7 @@ def test_get_version_increment_minor(minor_bump: List[str], patch_bump: List[str assert increment == "minor" -def test_get_version_increment_minor(minor_bump: List[str], patch_bump: List[str], major_bump: List[str], pr_labels_epic: List[str]) -> None: +def test_get_version_increment_major(minor_bump: List[str], patch_bump: List[str], major_bump: List[str], pr_labels_epic: List[str]) -> None: increment = conversion_logic.get_version_increment( pr_label_list=pr_labels_epic, patch_bump_list=patch_bump, From 21855360c368e2e9632652eb34aa3142e80b63f9 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 14:57:48 +0100 Subject: [PATCH 65/66] Add documentation to readme --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++++--- TODO.md | 16 ---------------- 2 files changed, 45 insertions(+), 19 deletions(-) delete mode 100644 TODO.md diff --git a/README.md b/README.md index bfb0956..87b08d4 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,47 @@ -# CI-Status +# Github-Query + [![CI-Status](https://github.com/ynput/github-query/actions/workflows/action-ci.yml/badge.svg)](https://github.com/ynput/github-query/actions/workflows/action-ci.yml) -# Github-Data -Fetch and convert certain information retrieved from github +**This is a customized query action for Ayon-related repo-workflows.** + +## Purpose + +This action mainly queries pull request related information. +It got a bunch of conversion going on to prepare the data for further usage. This includes + +* Filtering PR labels +* Suggest version increment based on found labels +* Preparing data structure for release information +* Prepare a markdown formatted changelog based on PR information + +## Usage + +For details see [action.yml](https://github.com/ynput/github-query/blob/main/action.yml) file + +```yaml +- name: Query PR data + uses: ynput/github-query@main + with: + # Repository name with owner. For example, actions/checkout + repo: "" + # Date-Time-Stamp as a starting point for the query, will only process merged PRs newer then that date + # format: "2024-08-20T12:03:23Z" + date: "" + # JSON keys to query for in a gh query command + # gh pr list --state merged --search f'merged:>=' --json "body,labels,title,id,number,url" --repo + query_parameters: "" + # Define change log content and order by this comma separated value string + # example: "enhancement,bugfix,docs" + changelog_labels: "" +``` + +## Outputs + +* raw-output - Full output json dictionary from github api +* label-list - List of unique labels found in PRs +* bump-increment - Increment for version bumping - either 'patch', 'minor' or 'major' +* changelog-markdown - String containing markdown formatted release changelog + +## Testing + +Unit-test are included in `tests/` and will run on every pr targeting main and very push to main. diff --git a/TODO.md b/TODO.md deleted file mode 100644 index c250e4e..0000000 --- a/TODO.md +++ /dev/null @@ -1,16 +0,0 @@ -# Implement changelog creation - -## Changelog sections - -* New Features -* Enhancements -* Bug Fixes -* Refactored code -* Documentation -* Testing -* Merged Pull requests - -## Structure for implementation - -* Implement section order in repo variable -* One repo var per section to store PR label names From 7ddf77bfb1bdb9f7c727010231b457f2c81600c8 Mon Sep 17 00:00:00 2001 From: PhilNewm Date: Tue, 5 Nov 2024 15:07:38 +0100 Subject: [PATCH 66/66] Add testing information to readme Add Developer information --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 87b08d4..5030348 100644 --- a/README.md +++ b/README.md @@ -45,3 +45,9 @@ For details see [action.yml](https://github.com/ynput/github-query/blob/main/act ## Testing Unit-test are included in `tests/` and will run on every pr targeting main and very push to main. +These tests can be run local by changing into the `tests/` directory and running `pytest` + +## Developer-Hints + +The python file `github_query.py` calls all the main logic and provides it's function to `action.yml` through click-parameters. +This makes the python function calls convenient to use from terminal while keeping them easy to test.