From dcf03f41fb924a9c779b1901b5e7a53d8199546a Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 11:38:33 +0545 Subject: [PATCH 1/7] fix: pr workflow --- .github/workflows/pr.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index f0696f23e..b0da1b962 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -11,6 +11,7 @@ on: permissions: contents: read pull-requests: write + issues: write packages: write jobs: From a16714c7c8ee7564e16516cc564cc940bac737cc Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 11:46:53 +0545 Subject: [PATCH 2/7] fix: pr workflow, add github token --- .github/workflows/pr.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index b0da1b962..2719da201 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -13,6 +13,7 @@ permissions: pull-requests: write issues: write packages: write + actions: read jobs: static-checks: @@ -135,6 +136,7 @@ jobs: UNIT_TEST_RESULT: ${{ steps.unit_tests.outcome }} DOCKLE_RESULT: ${{ steps.dockle.outcome }} with: + github-token: ${{ secrets.GITHUB_TOKEN }} script: | const fs = require('fs'); From ad630e946e2bfd6f418604e92415fce04cd077e6 Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 11:58:06 +0545 Subject: [PATCH 3/7] fix pr workflow --- .github/workflows/pr.yaml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 2719da201..267f0c185 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -129,12 +129,7 @@ jobs: - name: Create PR comment if: always() - uses: actions/github-script@v6 - env: - HADOLINT_RESULT: ${{ steps.hadolint.outcome }} - CODE_LINT_RESULT: ${{ steps.code_lint.outcome }} - UNIT_TEST_RESULT: ${{ steps.unit_tests.outcome }} - DOCKLE_RESULT: ${{ steps.dockle.outcome }} + uses: actions/github-script@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -145,30 +140,35 @@ jobs: const unitTestResult = fs.existsSync('${{ matrix.workdir }}/unit_test_output.txt') ? fs.readFileSync('${{ matrix.workdir }}/unit_test_output.txt', 'utf8') : 'No output'; const dockleScanResult = fs.existsSync('${{ matrix.workdir }}/dockle_scan_output.json') ? fs.readFileSync('${{ matrix.workdir }}/dockle_scan_output.json', 'utf8') : 'No output'; + const hadolintOutcome = '${{ steps.hadolint.outcome }}'; + const codeLintOutcome = '${{ steps.code_lint.outcome }}'; + const unitTestOutcome = '${{ steps.unit_tests.outcome }}'; + const dockleResult = '${{ steps.dockle.outcome }}'; + let commentBody = ''; - if (process.env.HADOLINT_RESULT !== 'success') { + if (hadolintOutcome !== 'success') { commentBody = ` :x: Dockerfile Lint (Hadolint) failed \`\`\`json ${hadolintResult} \`\`\` `; - } else if (process.env.CODE_LINT_RESULT !== 'success') { + } else if (codeLintOutcome !== 'success') { commentBody = ` :x: Code Lint failed \`\`\` ${codeLintResult} \`\`\` `; - } else if (process.env.UNIT_TEST_RESULT !== 'success') { + } else if (unitTestOutcome !== 'success') { commentBody = ` :x: Unit Tests failed \`\`\` ${unitTestResult} \`\`\` `; - } else if (process.env.DOCKLE_RESULT !== 'success') { + } else if (dockleResult !== 'success') { commentBody = ` :x: Docker Image Scan (Dockle) failed \`\`\`json From 5f698d7e530e6df0ff36d2db695749670c43af5f Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 12:16:05 +0545 Subject: [PATCH 4/7] remove pr comment with summary --- .github/workflows/pr.yaml | 163 ++++++++++++++++++++++++-------------- 1 file changed, 102 insertions(+), 61 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 267f0c185..711b854a6 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -127,64 +127,105 @@ jobs: echo "outcome=success" >> $GITHUB_OUTPUT - - name: Create PR comment - if: always() - uses: actions/github-script@v7 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const fs = require('fs'); - - const hadolintResult = fs.existsSync('${{ matrix.workdir }}/hadolint_output.json') ? fs.readFileSync('${{ matrix.workdir }}/hadolint_output.json', 'utf8') : 'No output'; - const codeLintResult = fs.existsSync('${{ matrix.workdir }}/code_lint_output.txt') ? fs.readFileSync('${{ matrix.workdir }}/code_lint_output.txt', 'utf8') : 'No output'; - const unitTestResult = fs.existsSync('${{ matrix.workdir }}/unit_test_output.txt') ? fs.readFileSync('${{ matrix.workdir }}/unit_test_output.txt', 'utf8') : 'No output'; - const dockleScanResult = fs.existsSync('${{ matrix.workdir }}/dockle_scan_output.json') ? fs.readFileSync('${{ matrix.workdir }}/dockle_scan_output.json', 'utf8') : 'No output'; - - const hadolintOutcome = '${{ steps.hadolint.outcome }}'; - const codeLintOutcome = '${{ steps.code_lint.outcome }}'; - const unitTestOutcome = '${{ steps.unit_tests.outcome }}'; - const dockleResult = '${{ steps.dockle.outcome }}'; - - let commentBody = ''; - - if (hadolintOutcome !== 'success') { - commentBody = ` - :x: Dockerfile Lint (Hadolint) failed - \`\`\`json - ${hadolintResult} - \`\`\` - `; - } else if (codeLintOutcome !== 'success') { - commentBody = ` - :x: Code Lint failed - \`\`\` - ${codeLintResult} - \`\`\` - `; - } else if (unitTestOutcome !== 'success') { - commentBody = ` - :x: Unit Tests failed - \`\`\` - ${unitTestResult} - \`\`\` - `; - } else if (dockleResult !== 'success') { - commentBody = ` - :x: Docker Image Scan (Dockle) failed - \`\`\`json - ${dockleScanResult} - \`\`\` - `; - } else { - commentBody = ':white_check_mark: All checks succeeded'; - } - - const { owner, repo } = context.repo; - const issue_number = context.issue.number; - - await github.rest.issues.createComment({ - owner, - repo, - issue_number, - body: commentBody - }); + - name: Write test summary + if: ${{ always() }} + run: | + python3 - <<'PY' + import os + import sys + import json + from pathlib import Path + + summary_path = os.environ.get("GITHUB_STEP_SUMMARY") + if not summary_path: + sys.exit(0) + + workdir = "${{ matrix.workdir }}" + name = "${{ matrix.name }}" + + def md_escape(value): + return str(value).replace("|", "\\|").replace("\n", "
") + + lines = [f"## {name} - Check Results", ""] + + # Hadolint Results + hadolint_file = Path(f"{workdir}/hadolint_output.json") + lines.extend([ + "### Dockerfile Lint (Hadolint)", + f"**Status:** ${{ steps.hadolint.outcome }}", + "" + ]) + if hadolint_file.exists(): + with open(hadolint_file) as f: + content = f.read() + lines.extend(["```json", content, "```", ""]) + + # Code Lint Results + code_lint_file = Path(f"{workdir}/code_lint_output.txt") + lines.extend([ + "### Code Lint", + f"**Status:** ${{ steps.code_lint.outcome }}", + "" + ]) + if code_lint_file.exists(): + with open(code_lint_file) as f: + content = f.read() + lines.extend(["```", content, "```", ""]) + + # Unit Tests Results + unit_test_file = Path(f"{workdir}/unit_test_output.txt") + lines.extend([ + "### Unit Tests", + f"**Status:** ${{ steps.unit_tests.outcome }}", + "" + ]) + if unit_test_file.exists(): + with open(unit_test_file) as f: + content = f.read() + lines.extend(["```", content, "```", ""]) + + # Dockle Scan Results + dockle_file = Path(f"{workdir}/dockle_scan_output.json") + lines.extend([ + "### Docker Image Scan (Dockle)", + f"**Status:** ${{ steps.dockle.outcome }}", + "" + ]) + if dockle_file.exists(): + with open(dockle_file) as f: + dockle_data = json.load(f) + + summary = dockle_data.get("summary", {}) + lines.extend([ + "| Metric | Count |", + "| --- | ---: |", + f"| Fatal | {summary.get('fatal', 0)} |", + f"| Warn | {summary.get('warn', 0)} |", + f"| Info | {summary.get('info', 0)} |", + "", + "```json", + ]) + + with open(dockle_file) as f: + lines.append(f.read()) + + lines.extend(["```", ""]) + + # Metadata + lines.extend([ + "### Metadata", + "", + "| Key | Value |", + "| --- | --- |", + f"| Workdir | `{md_escape(workdir)}` |", + f"| Event | {md_escape(os.environ.get('GITHUB_EVENT_NAME', 'unknown'))} |", + f"| Ref | {md_escape(os.environ.get('GITHUB_REF_NAME', 'unknown'))} |", + f"| SHA | `{md_escape(os.environ.get('GITHUB_SHA', 'unknown')[:7])}` |", + f"| Actor | {md_escape(os.environ.get('GITHUB_ACTOR', 'unknown'))} |", + "", + ]) + + with open(summary_path, "a", encoding="utf-8") as summary: + summary.write("\n".join(lines)) + summary.write("\n") + PY From 4bb7574a2f511cea9f07e45d94405fe4baabb897 Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 12:43:25 +0545 Subject: [PATCH 5/7] format fix --- .github/workflows/pr.yaml | 58 +++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 711b854a6..de619d66b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -157,8 +157,22 @@ jobs: ]) if hadolint_file.exists(): with open(hadolint_file) as f: - content = f.read() - lines.extend(["```json", content, "```", ""]) + hadolint_data = json.load(f) + + if hadolint_data: + lines.extend([ + "| Code | Line | Level | Message |", + "| --- | ---: | --- | --- |", + ]) + for issue in hadolint_data: + code = md_escape(issue.get("code", "")) + line = issue.get("line", "") + level = md_escape(issue.get("level", "")) + message = md_escape(issue.get("message", "")) + lines.append(f"| {code} | {line} | {level} | {message} |") + lines.append("") + else: + lines.extend(["✅ No issues found", ""]) # Code Lint Results code_lint_file = Path(f"{workdir}/code_lint_output.txt") @@ -169,8 +183,11 @@ jobs: ]) if code_lint_file.exists(): with open(code_lint_file) as f: - content = f.read() - lines.extend(["```", content, "```", ""]) + content = f.read().strip() + if content and content != "lint skipped": + lines.extend(["```", content, "```", ""]) + else: + lines.extend(["✅ Lint skipped or passed", ""]) # Unit Tests Results unit_test_file = Path(f"{workdir}/unit_test_output.txt") @@ -181,8 +198,11 @@ jobs: ]) if unit_test_file.exists(): with open(unit_test_file) as f: - content = f.read() - lines.extend(["```", content, "```", ""]) + content = f.read().strip() + if content and content != "unit tests skipped": + lines.extend(["```", content, "```", ""]) + else: + lines.extend(["✅ Unit tests skipped or passed", ""]) # Dockle Scan Results dockle_file = Path(f"{workdir}/dockle_scan_output.json") @@ -197,19 +217,35 @@ jobs: summary = dockle_data.get("summary", {}) lines.extend([ + "#### Summary", + "", "| Metric | Count |", "| --- | ---: |", f"| Fatal | {summary.get('fatal', 0)} |", f"| Warn | {summary.get('warn', 0)} |", f"| Info | {summary.get('info', 0)} |", + f"| Passed | {summary.get('pass', 0)} |", "", - "```json", ]) - with open(dockle_file) as f: - lines.append(f.read()) - - lines.extend(["```", ""]) + details = dockle_data.get("details", []) + if details: + lines.extend([ + "#### Details", + "", + "| Code | Title | Level | Alert |", + "| --- | --- | --- | --- |", + ]) + for detail in details: + code = md_escape(detail.get("code", "")) + title = md_escape(detail.get("title", "")) + level = md_escape(detail.get("level", "")) + alerts = detail.get("alerts", []) + alert_text = md_escape(", ".join(alerts[:3])) # Limit to 3 alerts per row + if len(alerts) > 3: + alert_text += f", +{len(alerts)-3} more" + lines.append(f"| {code} | {title} | {level} | {alert_text} |") + lines.append("") # Metadata lines.extend([ From 79d5768dced67c966b1984ed26c2a83265bda6c1 Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 13:09:17 +0545 Subject: [PATCH 6/7] add icons --- .github/workflows/pr.yaml | 44 +++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index de619d66b..37f73625b 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -10,10 +10,6 @@ on: permissions: contents: read - pull-requests: write - issues: write - packages: write - actions: read jobs: static-checks: @@ -146,6 +142,17 @@ jobs: def md_escape(value): return str(value).replace("|", "\\|").replace("\n", "
") + def get_level_icon(level): + level = str(level).upper() + if level == "ERROR": + return "❌" + elif level == "WARN": + return "⚠️" + elif level == "INFO": + return "ℹ️" + else: + return "•" + lines = [f"## {name} - Check Results", ""] # Hadolint Results @@ -167,9 +174,10 @@ jobs: for issue in hadolint_data: code = md_escape(issue.get("code", "")) line = issue.get("line", "") - level = md_escape(issue.get("level", "")) + level = issue.get("level", "") + icon = get_level_icon(level) message = md_escape(issue.get("message", "")) - lines.append(f"| {code} | {line} | {level} | {message} |") + lines.append(f"| {code} | {line} | {icon} {level} | {message} |") lines.append("") else: lines.extend(["✅ No issues found", ""]) @@ -207,7 +215,7 @@ jobs: # Dockle Scan Results dockle_file = Path(f"{workdir}/dockle_scan_output.json") lines.extend([ - "### Docker Image Scan (Dockle)", + "### Docker Image Scan (Dockle)", f"**Status:** ${{ steps.dockle.outcome }}", "" ]) @@ -216,15 +224,24 @@ jobs: dockle_data = json.load(f) summary = dockle_data.get("summary", {}) + fatal = summary.get('fatal', 0) + warn = summary.get('warn', 0) + info = summary.get('info', 0) + passed = summary.get('pass', 0) + + fatal_icon = "❌" if fatal > 0 else "✅" + warn_icon = "⚠️" if warn > 0 else "✅" + info_icon = "ℹ️" if info > 0 else "✅" + lines.extend([ "#### Summary", "", "| Metric | Count |", "| --- | ---: |", - f"| Fatal | {summary.get('fatal', 0)} |", - f"| Warn | {summary.get('warn', 0)} |", - f"| Info | {summary.get('info', 0)} |", - f"| Passed | {summary.get('pass', 0)} |", + f"| {fatal_icon} Fatal | {fatal} |", + f"| {warn_icon} Warn | {warn} |", + f"| {info_icon} Info | {info} |", + f"| ✅ Passed | {passed} |", "", ]) @@ -239,12 +256,13 @@ jobs: for detail in details: code = md_escape(detail.get("code", "")) title = md_escape(detail.get("title", "")) - level = md_escape(detail.get("level", "")) + level = detail.get("level", "") + icon = get_level_icon(level) alerts = detail.get("alerts", []) alert_text = md_escape(", ".join(alerts[:3])) # Limit to 3 alerts per row if len(alerts) > 3: alert_text += f", +{len(alerts)-3} more" - lines.append(f"| {code} | {title} | {level} | {alert_text} |") + lines.append(f"| {code} | {title} | {icon} {level} | {alert_text} |") lines.append("") # Metadata From 89685f56d0e0127f904b87093cc42ad9548881df Mon Sep 17 00:00:00 2001 From: Kushal Acharya Date: Thu, 9 Jul 2026 13:14:28 +0545 Subject: [PATCH 7/7] add icons --- .github/workflows/pr.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index 37f73625b..fc873058a 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -229,7 +229,7 @@ jobs: info = summary.get('info', 0) passed = summary.get('pass', 0) - fatal_icon = "❌" if fatal > 0 else "✅" + fatal_icon = "❌" if fatal >= 0 else "✅" warn_icon = "⚠️" if warn > 0 else "✅" info_icon = "ℹ️" if info > 0 else "✅"