diff --git a/.github/workflows/action-ci.yml b/.github/workflows/action-ci.yml index 982e29d..2fe282c 100644 --- a/.github/workflows/action-ci.yml +++ b/.github/workflows/action-ci.yml @@ -1,29 +1,48 @@ name: Test custom action on: + push: + branches: + - main + pull_request: + branches: + - main workflow_dispatch: env: GH_TOKEN: ${{ secrets.CI_TOKEN }} jobs: - test-action: + run-unit-tests: runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + ref: ${{ vars.MAIN_BRANCH }} + fetch-depth: 0 + + - name: Run Pytest + # TODO try this one: https://github.com/pavelzw/pytest-action + run: | + pip install pytest pytest-cov + pytest + + run-action: + runs-on: ubuntu-latest + needs: + - run-unit-tests + steps: - name: Run action id: test-action - uses: ynput/github-data@main + uses: ynput/github-data@unit-test with: repo: "ynput/ayon-addon-action-testing" - date: "2024-20-08T09:48:33Z" + date: "2024-08-20T12:03:23Z" query_parameters: "body,labels,title" - - name: Test empty pr output - if: ${{ steps.test-action.outputs.raw-output }} - run: | - echo "::error:: Found value: ${{ steps.test-action.outputs.raw-output }}, expected empty value" - exit 1 - - - name: Test empty pr output - if: ${{ steps.test-action.outputs.label-list }} + - name: Show results run: | - echo "::error:: Found value: ${{ steps.test-action.outputs.label-list }}, expected empty value" - exit 1 + 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.label-list }}' + # echo "Changelog: " && echo '${{ steps.test-action.outputs.changelog-markdown }}' \ No newline at end of file diff --git a/action.yml b/action.yml index 8d5d2f0..977dde9 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,6 @@ --- -# TODO need strategy where to store defaults - which an be overriden by repo vars +# TODO need strategy where to store defaults - which an be overriden by repo var name: Github Release Information description: Fetch and convert data from github to use for a release trigger @@ -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 makrdown syntax for release changelog information + # value: ${{ steps.write-changelog.outputs.changelog }} runs: using: composite @@ -55,7 +55,7 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - label_list=$(python -c 'import fetch_github_data; print(fetch_github_data.get_labels())' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + 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 @@ -63,12 +63,12 @@ runs: echo "label_list=$label_list" >> $GITHUB_OUTPUT - - name: Get bump increment + - name: Get version increment id: bump-increment shell: bash run: | cd $GITHUB_ACTION_PATH - increment=$(python -c 'import fetch_github_data; print(fetch_github_data.get_version_increment())' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") + 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 @@ -76,9 +76,9 @@ runs: shell: bash run: | cd $GITHUB_ACTION_PATH - changelog=$(python -c 'import fetch_github_data; print(fetch_github_data.prepare_changelog_markdown())' "${{ inputs.repo }}" "${{ inputs.query_parameters }}" "${{ inputs.date }}") - oneline_changelog=$(echo "$changelog" | base64) + 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 + # echo "changelog=$oneline_changelog" >> $GITHUB_OUTPUT ... diff --git a/fetch_github_data.py b/github_query.py similarity index 59% rename from fetch_github_data.py rename to github_query.py index 8abcb70..e33dd2f 100644 --- a/fetch_github_data.py +++ b/github_query.py @@ -6,41 +6,28 @@ import argparse import json +import logging import subprocess -parsed_args = None - -def parse_arguments(): - """Parse command-line arguments and store them in a global variable.""" - global parsed_args - if parsed_args is None: - 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() +logger = logging.getLogger(__name__) -def get_inputs(): - """Get the parsed command-line arguments. +def parse_args() -> dict: + """Parse command-line arguments and store them in a global variable.""" - Returns: - tuple(str): Parameters as string tuple. - """ + 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() - if parsed_args is None: - parse_arguments() - repo_name = parsed_args.repo query_tags = parsed_args.query_parameters.split(',') latest_release_date = parsed_args.date - return repo_name, query_tags, latest_release_date - -def get_raw_output(repo_name, query_tags, latest_release_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) def get_changelog(pr_data, changelog_start="## Changelog", heading="##"): @@ -81,15 +68,9 @@ def changelog_per_label(json_dict): if any(item in changelog_labels for item in labels): pass -def prepare_changelog_markdown(): - repo_name, query_tags, latest_release_date = get_inputs() - pr_query = get_raw_output(repo_name=repo_name, query_tags=query_tags, latest_release_date=latest_release_date) - - minor_bump_label_list = get_repo_label(repo=repo_name, label_name="MINOR_BUMP_LABEL") - patch_bump_label_list = get_repo_label(repo=repo_name, label_name="PATCH_BUMP_LABEL") - +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_label_list + patch_bump_label_list + label_list = minor_bump_list + patch_bump_list changelog = "" for pr in pr_query: @@ -107,20 +88,41 @@ def prepare_changelog_markdown(): return changelog -def get_labels(): - github_data = get_raw_output(*get_inputs()) +def get_labels(pr_data: dict) -> list: + """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 github_data: + 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 json.dumps(list(labels)) + return list(labels) + +def get_repo_var(repo, var_name): + """Query labels from repository variables. + + Args: + repo (str): Repository name `owner/repo-name` + var_name (str): Repo variable name -def get_repo_label(repo, label_name): - + Returns: + [str]: list of found strings in variable + """ label= subprocess.run( - ["gh", "variable", "get", label_name, "--repo", repo], + ["gh", "variable", "get", var_name, "--repo", repo], capture_output=True, text=True, check=True @@ -128,18 +130,20 @@ def get_repo_label(repo, label_name): return label.stdout.strip().split(", " or ",") -def get_version_increment(): +def get_version_increment(patch_bump_list: list, minor_bump_list: list, pr_label_list: list): + """Figure out version increment based on PR labels. - repo_name, _, _ = get_inputs() + 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 - minor_bump_label_list = get_repo_label(repo=repo_name, label_name="MINOR_BUMP_LABEL") - patch_bump_label_list = get_repo_label(repo=repo_name, label_name="PATCH_BUMP_LABEL") + Returns: + str: version increment + """ - for label in json.loads(get_labels()): - if label.lower() in minor_bump_label_list: + for label in pr_label_list: + if label.lower() in minor_bump_list: return "minor" - if label.lower() in patch_bump_label_list: + if label.lower() in patch_bump_list: return "patch" - -if __name__ == "__main__": - parse_arguments() \ No newline at end of file diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_fetch_github_data.py b/tests/test_fetch_github_data.py deleted file mode 100644 index f461963..0000000 --- a/tests/test_fetch_github_data.py +++ /dev/null @@ -1,64 +0,0 @@ - -import argparse -import json -from unittest import mock -import os -import sys - -from unittest.mock import patch - -# Add the parent directory of 'tests' to the system path -sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) -import fetch_github_data - -# Mock data to return for your tests -mock_repo_name = 'ynput/ayon-addon-action-testing' -mock_query_parameters = 'title,body,labels' -mock_date = '2024-07-08T09:48:33Z' -mock_labels_output = ['bug', 'enhancement'] - -# Mocking the subprocess to prevent actual GitHub CLI calls -def mock_get_raw_output(repo_name, query_tags, latest_release_date): - 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": "bug", - "description": "Something isn't working", - "color": "ff9195" - } - ], - "title": "Add date file" - } - ] - -@patch('argparse.ArgumentParser.parse_args') -@patch('fetch_github_data.get_raw_output', side_effect=mock_get_raw_output) -def test_get_labels(mock_parse_args, mock_get_raw_output): - # Configure the mock to return desired arguments - mock_parse_args.return_value = argparse.Namespace( - repo=mock_repo_name, - query_parameters=mock_query_parameters, - date=mock_date - ) - - fetch_github_data.parse_arguments() - - labels = fetch_github_data.get_labels() - - assert set(json.loads(labels)) == set(mock_labels_output) - diff --git a/tests/test_github_query.py b/tests/test_github_query.py new file mode 100644 index 0000000..cdd224d --- /dev/null +++ b/tests/test_github_query.py @@ -0,0 +1,106 @@ +import pytest +from unittest.mock import patch + +import github_query + +@pytest.fixture +def pr_api_output(): + 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": "bug", + "description": "Something isn't working", + "color": "ff9195" + } + ], + "title": "Add date 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" + } + ] + +@pytest.fixture +def minor_bump(): + return ["feature", "enhancement"] + +@pytest.fixture +def patch_bump(): + return ["bugfix"] + +@pytest.fixture +def pr_labels_bug(): + return ["bugfix"] + +@pytest.fixture +def pr_labels_enhancement(): + return ["enhancement"] + +@pytest.fixture +def pr_labels_none(): + return [] + + +# Get PR Label test-cases + +def test_get_labels(pr_api_output): + labels = github_query.get_labels(pr_data=pr_api_output) + + assert isinstance(labels, list) + assert set(labels) == {"bug", "enhancement"} + +def test_get_labels_missign_input(pr_api_output_missing_label): + labels = github_query.get_labels(pr_data=pr_api_output_missing_label) + + assert labels == None + + +# 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) + + 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) + + assert increment == "minor" + +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) + + assert increment == None