From b8fb75e6cdcb9759d308abb5b8d54b2c35c87e35 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 18:22:49 +0930 Subject: [PATCH 01/10] feat(parser): add table for each tool used for annotations ref: #3 #1 --- includes/usr/bin/annotations.py | 41 ++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index bafc31a..4afbf3e 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -231,23 +231,52 @@ for tool, tool_results in results.items(): api_body['comments'] += [ pylint_matcher( entry ) ] -review_body = '## :no_entry_sign: Annotations found\n\n' \ - f'@{os.getenv("GITHUB_ACTOR")}, found some issues.\n\n' \ - '| Type | Count | \n|:---|:---:| \n' + if tool not in type_count: + + type_count[tool] = 1 + + else: + + type_count[tool] += 1 + + +review_body = { + 'header': str( + '## :no_entry_sign: Annotations found \n' \ + f'@{os.getenv("GITHUB_ACTOR")}, \n\n' + 'I found some issues that need addressing. \n\n' + ) +} for msg_type, cnt in type_count.items(): - review_body += f'| {msg_type} | {cnt} | \n' + if msg_type not in review_body: + + review_body[msg_type] = str('| Type | Count | \n|:---|:---:| \n') + + review_body[msg_type] += f'| {msg_type} | {cnt} | \n' -api_body['body'] = review_body + '\n' +api_body['body'] = review_body['header'] + +for msg_type, value in review_body.items(): + + if msg_type != 'header': + + api_body['body'] += str( + f'### {msg_type} issues found ' + '\n' + f'{value}\n' + '\n' + ) + data = { "pull_request": pull_request, "api_body": api_body } -print(json.dumps(data)) +print(json.dumps(data, indent=4)) # URL = os.getenv("GITHUB_API_URL") + '/repos/' + os.getenv("GITHUB_REPOSITORY") + '/pulls/' + os.getenv("GITHUB_REF_NAME") + '/reviews?token=' + str(os.getenv("AGITHUB_TOKEN")) From ea2f7e76cbd990bf319addd6612b47c3f4a855dd Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 19:59:25 +0930 Subject: [PATCH 02/10] feat(parser): admonition layout set to be same as pylint for default matcherr ref: #3 #1 --- includes/usr/bin/annotations.py | 41 ++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index 4afbf3e..790055b 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -8,42 +8,51 @@ import os -def default_matcher( entry ) -> dict: +def default_matcher( entry, tool_name = '' ) -> dict: + if tool_name == 'default': + tool_name = '' + else: + + tool_name = tool_name + ' ' filename = str(entry['file']) msg_type = str(entry['type']).upper() - if msg_type in type_count: + # if msg_type in type_count: - type_count[msg_type] += 1 + # type_count[msg_type] += 1 - else: + # else: - type_count[msg_type] = 1 + # type_count[msg_type] = 1 if filename.startswith('./'): filename = str(entry['file'])[2:] - body = f"> [!NOTE]\n>\n> **{msg_type} in file: {filename}** " \ - f"_Line: {str(entry['line'])} Column: {str(entry['column'])}_" \ - f"\n>\n> _{str(entry['text'])}_\n>" - + admonition_level = 'NOTE' if msg_type in [ 'ERROR' ]: + admonition_level = 'IMPORTANT' - body = f"> [!IMPORTANT]\n>\n> **{msg_type} in file: {filename}** " \ - f"_Line: {str(entry['line'])} Column: {str(entry['column'])}_" \ - f"\n>\n> _{str(entry['text'])}_\n>" - elif msg_type in [ 'WARNING' ]: - body = f"> [!WARNING]\n>\n> **{msg_type} in file: {filename}** " \ - f"_Line: {str(entry['line'])} Column: {str(entry['column'])}_" \ - f"\n>\n> _{str(entry['text'])}_\n>" + admonition_level = 'WARNING' + + + body =str ( + f"> [!{admonition_level}]" + "\n>" + f"\n> **{tool_name}Severity:** _{str(msg_type).lower()}_ " + f"\n> **file**: _{filename}_ " + f"**Line**: _{str(entry['line'])}_ **Column**: _{str(entry['column'])}_" + "\n>" + f"\n> {str(entry['text'])}" + "\n>" + ) return { "body": body, From f53cd102411eec9bc7a55ff9d0f16c82a03dd474 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 19:59:58 +0930 Subject: [PATCH 03/10] refactor(parser): clean up pylint admonition vars ref: #3 #1 --- includes/usr/bin/annotations.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index 790055b..2d94ecc 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -74,20 +74,20 @@ def pylint_matcher( entry ) -> dict: comment_line = int(entry.get('line', int(1))) severity = str(entry['severity']).lower() - default_admonition_level = 'NOTE' + admonition_level = 'NOTE' if severity in [ 'major' ]: - default_admonition_level = 'IMPORTANT' + admonition_level = 'IMPORTANT' if severity in [ 'minor' ]: - default_admonition_level = 'WARNING' + admonition_level = 'WARNING' body = str( - f"> [!{default_admonition_level}] " + f"> [!{admonition_level}] " f"\n> " - f"\n>**Severity**: {severity} " + f"\n>**PyLint Severity**: {severity} " f"\n>**file**: _{entry['path']}_ " f"**Line**: _{entry.get('line', 0)}_ " f"\n>" From b18043c2f0f231dea1ec93a22e505d7f6ca8b353 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 20:00:29 +0930 Subject: [PATCH 04/10] feat(parser): enable setting mather name for defaul regex ref: #3 #1 --- includes/usr/bin/annotations.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index 2d94ecc..6af5aa0 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -181,12 +181,16 @@ for line in sys.stdin: if match_matcher_type: regex_type = match_matcher_type['type'] - pattern = re.compile( regex[regex_type] ) + + + if regex_type in regex: + + pattern = re.compile( regex[regex_type] ) match = pattern.finditer(line) - problem_matcher = matcher.search(line,) + problem_matcher = matcher.search(line) if problem_matcher: @@ -231,14 +235,13 @@ for tool, tool_results in results.items(): for entry in tool_results: - if tool == 'default': - - api_body['comments'] += [ default_matcher( entry ) ] - - elif tool == 'pylint-json': + if tool == 'pylint-json': api_body['comments'] += [ pylint_matcher( entry ) ] + else: + + api_body['comments'] += [ default_matcher( entry, tool_name = tool ) ] if tool not in type_count: From 598cd7db5cc053459624fecd8adfbc0d6f0b1958 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 20:52:35 +0930 Subject: [PATCH 05/10] refactor(parser): store matcher name seperatly ref: #3 #1 --- includes/usr/bin/annotations.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index 6af5aa0..3d35f00 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -173,7 +173,7 @@ matcher_type = re.compile(r'NFC_PROBLEM_MATCHER_TYPE=(?P[a-z_-]+)') regex_type = 'default' pattern = re.compile( regex[regex_type] ) - +matcher_name = 'Default Matcher' for line in sys.stdin: @@ -181,12 +181,15 @@ for line in sys.stdin: if match_matcher_type: regex_type = match_matcher_type['type'] - + matcher_name = match_matcher_type['type'] if regex_type in regex: pattern = re.compile( regex[regex_type] ) + else: + + pattern = re.compile( regex['default'] ) match = pattern.finditer(line) @@ -201,13 +204,13 @@ for line in sys.stdin: if match: - if regex_type not in results: - results[regex_type] = [] + if matcher_name not in results: + results[matcher_name] = [] for obj in match: - results[regex_type].append(obj.groupdict()) + results[matcher_name].append(obj.groupdict()) From 55b7dc396f544809e2b3362b5ca4d611b33ca3b6 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 20:53:04 +0930 Subject: [PATCH 06/10] fix(parser): allow upper case leters in matchers name ref: #3 #1 --- includes/usr/bin/annotations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index 3d35f00..bca8bba 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -169,7 +169,7 @@ NFC_PROBLEM_MATCHER = False pull_request: int = None matcher = re.compile(r'NFC_PROBLEM_MATCHER=(?P\d+)') -matcher_type = re.compile(r'NFC_PROBLEM_MATCHER_TYPE=(?P[a-z_-]+)') +matcher_type = re.compile(r'NFC_PROBLEM_MATCHER_TYPE=(?P[a-zA-Z_-]+)') regex_type = 'default' pattern = re.compile( regex[regex_type] ) From 9516803f78a44f5fec9c967402aecf854b301d63 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 20:53:43 +0930 Subject: [PATCH 07/10] chore(parser): code cleanup ref: #3 #1 --- includes/usr/bin/annotations.py | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/includes/usr/bin/annotations.py b/includes/usr/bin/annotations.py index bca8bba..733983b 100755 --- a/includes/usr/bin/annotations.py +++ b/includes/usr/bin/annotations.py @@ -13,32 +13,21 @@ def default_matcher( entry, tool_name = '' ) -> dict: if tool_name == 'default': tool_name = '' else: - tool_name = tool_name + ' ' filename = str(entry['file']) - msg_type = str(entry['type']).upper() - - # if msg_type in type_count: - - # type_count[msg_type] += 1 - - # else: - - # type_count[msg_type] = 1 - if filename.startswith('./'): filename = str(entry['file'])[2:] admonition_level = 'NOTE' - if msg_type in [ 'ERROR' ]: + if str(entry['type']).upper() in [ 'ERROR' ]: admonition_level = 'IMPORTANT' - elif msg_type in [ 'WARNING' ]: + elif str(entry['type']).upper() in [ 'WARNING' ]: admonition_level = 'WARNING' @@ -46,7 +35,7 @@ def default_matcher( entry, tool_name = '' ) -> dict: body =str ( f"> [!{admonition_level}]" "\n>" - f"\n> **{tool_name}Severity:** _{str(msg_type).lower()}_ " + f"\n> **{tool_name}Severity:** _{str(entry['type']).lower()}_ " f"\n> **file**: _{filename}_ " f"**Line**: _{str(entry['line'])}_ **Column**: _{str(entry['column'])}_" "\n>" @@ -263,6 +252,7 @@ review_body = { ) } + for msg_type, cnt in type_count.items(): if msg_type not in review_body: @@ -274,6 +264,7 @@ for msg_type, cnt in type_count.items(): api_body['body'] = review_body['header'] + for msg_type, value in review_body.items(): if msg_type != 'header': From 27fcf1fde4adbd86c74dc939b511e85bbcf89e93 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 20:54:30 +0930 Subject: [PATCH 08/10] chore(rulebook): add user and repo to log out ref: #3 #1 --- extensions/eda/rulebooks/webhook.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/extensions/eda/rulebooks/webhook.yml b/extensions/eda/rulebooks/webhook.yml index 1a6a4ce..88b718c 100644 --- a/extensions/eda/rulebooks/webhook.yml +++ b/extensions/eda/rulebooks/webhook.yml @@ -20,7 +20,10 @@ actions: - debug: - msg: "Received workflow_job event with action of {{ event.payload.action }}" + msg: |- + Received workflow_job event from {{ event.payload.sender.username + ' ' -}} + for repository {{ event.payload.repository.full_name + ' ' -}} + with action of {{ event.payload.action }} - name: Process Completed workflow_job From 9f3b07c9f898db3634c95745deef5b68aa4baa5a Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 23:25:47 +0930 Subject: [PATCH 09/10] refactor(rulebook): rulebook should share playbook name ref: #3 #1 --- extensions/eda/rulebooks/{webhook.yml => problem_matcher.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename extensions/eda/rulebooks/{webhook.yml => problem_matcher.yml} (100%) diff --git a/extensions/eda/rulebooks/webhook.yml b/extensions/eda/rulebooks/problem_matcher.yml similarity index 100% rename from extensions/eda/rulebooks/webhook.yml rename to extensions/eda/rulebooks/problem_matcher.yml From b928a044f75c110a40d138b495f31408e5f86622 Mon Sep 17 00:00:00 2001 From: Jon Date: Tue, 1 Jul 2025 23:27:05 +0930 Subject: [PATCH 10/10] refactor(docker): use arg to set rulebook name ref: #3 #1 --- dockerfile | 15 +++++++++------ includes/entrypoint.sh | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 includes/entrypoint.sh diff --git a/dockerfile b/dockerfile index 7f96b03..156f57b 100644 --- a/dockerfile +++ b/dockerfile @@ -1,3 +1,4 @@ +ARG GIT_EVENT_RULEBOOK_NAME='problem_matcher' FROM python:3.11-alpine3.22 AS Build @@ -49,9 +50,13 @@ RUN cd /tmp/python_modules; \ + FROM python:3.11-alpine3.22 +ARG GIT_EVENT_RULEBOOK_NAME + + RUN apk --no-cache update; \ apk --no-cache add \ openjdk21-jdk @@ -63,6 +68,8 @@ ENV ANSIBLE_INVENTORY hosts.yaml ENV JAVA_HOME /usr/lib/jvm/java-21-openjdk +ENV GIT_EVENT_RULEBOOK_NAME ${GIT_EVENT_RULEBOOK_NAME} + COPY includes/ / @@ -80,6 +87,7 @@ RUN pip install --no-cache-dir /tmp/python_builds/*; \ rm -rf /home/eda/.ansible/collections/ansible_collections/nofusscomputing/git_events/includes; \ mv /usr/bin/annotations.py /usr/bin/annotations; \ chmod +x /usr/bin/annotations; \ + chmod +x /entrypoint.sh; \ chown eda:eda -R /home/eda; @@ -89,9 +97,4 @@ WORKDIR /home/eda USER eda -CMD [ \ - "ansible-rulebook", \ - "-r", "nofusscomputing.git_events.webhook", \ - "--env-vars", "PROBLEM_MATCHER_PORT,PROBLEM_MATCHER_TOKEN", \ - "-v" \ -] +ENTRYPOINT [ "/entrypoint.sh" ] diff --git a/includes/entrypoint.sh b/includes/entrypoint.sh new file mode 100644 index 0000000..38517b6 --- /dev/null +++ b/includes/entrypoint.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +set -e + +if [ $# -eq 0 ]; then + + cd ${HOME}; + + ansible-rulebook \ + -r nofusscomputing.git_events.${GIT_EVENT_RULEBOOK_NAME} \ + --env-vars PROBLEM_MATCHER_PORT,PROBLEM_MATCHER_TOKEN \ + -v; + +else + + exec "$@" + +fi