From d16ec887e1619ffa681c11eac1783b14e9161369 Mon Sep 17 00:00:00 2001 From: Bugale Date: Thu, 22 Jan 2026 12:10:16 +0200 Subject: [PATCH] feat: support ghalint --- .github/workflows/check-code.yml | 1 + README.md | 2 ++ __tests__/bugalint.test.ts | 1 + __tests__/ghalint.input.txt | 3 +++ __tests__/ghalint.output.json | 43 ++++++++++++++++++++++++++++++++ dist/index.js | 3 ++- src/bugalint.ts | 4 ++- 7 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 __tests__/ghalint.input.txt create mode 100644 __tests__/ghalint.output.json diff --git a/.github/workflows/check-code.yml b/.github/workflows/check-code.yml index 635f765..b1e7ae2 100644 --- a/.github/workflows/check-code.yml +++ b/.github/workflows/check-code.yml @@ -78,6 +78,7 @@ jobs: - {linter: 'pylint', format: 'pylint', regex: '', levelMap: '', analysisPath: '.'} - {linter: 'mdl', format: 'mdl', regex: '', levelMap: '', analysisPath: '.'} - {linter: 'yamllint', format: 'yamllint', regex: '', levelMap: '', analysisPath: '.'} + - {linter: 'ghalint', format: 'ghalint', regex: '', levelMap: '', analysisPath: '.'} - {linter: 'sarif', format: 'sarif', regex: '', levelMap: '', analysisPath: '.'} - {linter: 'flake8subpath', format: 'flake8', regex: '', levelMap: '', analysisPath: 'A\B'} - linter: 'custom' diff --git a/README.md b/README.md index f030332..b60bdfc 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ This action supports a bunch of linter output formats, for which no `inputRegex` - `yamllint`: The format of [yamllint](https://yamllint.readthedocs.io/en/stable/) linter's parsable output (requires using `-f parsable` in yamllint's command line). +- `ghalint`: The format of [ghallint](https://github.com/suzuki-shunsuke/ghalint/cmd/ghalint/) linter's parsable output. + - `SARIF`: A [standard format for static analysis](https://sarifweb.azurewebsites.net/). This is useful if you already have a SARIF file and want to create a summary for it, or create comments on the PR. diff --git a/__tests__/bugalint.test.ts b/__tests__/bugalint.test.ts index fa4ac86..8114a80 100644 --- a/__tests__/bugalint.test.ts +++ b/__tests__/bugalint.test.ts @@ -9,6 +9,7 @@ describe('fullConversion', () => { ['flake8', getKnownParser('flake8'), '.'], ['mdl', getKnownParser('mdl'), '.'], ['yamllint', getKnownParser('yamllint'), '.'], + ['ghalint', getKnownParser('ghalint'), '.'], ['sarif', getKnownParser('sarif'), '.'], ['flake8subpath', getKnownParser('flake8'), 'A\\B'], [ diff --git a/__tests__/ghalint.input.txt b/__tests__/ghalint.input.txt new file mode 100644 index 0000000..2a7ec9f --- /dev/null +++ b/__tests__/ghalint.input.txt @@ -0,0 +1,3 @@ +Jan 22 09:42:27.969 ERR the job violates policies program=ghalint version="" workflow_file_path=.github/workflows/cancel-stale-merge-queue-workflows.yml policy_name=job_timeout_minutes_is_required reference=https://github.com/suzuki-shunsuke/ghalint/blob/main/docs/policies/012.md job_name=cancel-workflows error="job's timeout-minutes is required" +Jan 22 09:42:27.969 ERR the job violates policies program=ghalint version="" workflow_file_path=.github/workflows/cancel-stale-merge-queue-workflows.yml reference=https://github.com/suzuki-shunsuke/ghalint/blob/main/docs/policies/012.md job_name=cancel-workflows error="job's timeout-minutes is required" policy_name=job_timeout_minutes_is_required +Jan 22 09:42:27.969 ERR the job violates policies program=ghalint version="" reference=https://github.com/suzuki-shunsuke/ghalint/blob/main/docs/policies/012.md job_name=cancel-workflows error="job's timeout-minutes is required" policy_name=job_timeout_minutes_is_required workflow_file_path=.github/workflows/cancel-stale-merge-queue-workflows.yml diff --git a/__tests__/ghalint.output.json b/__tests__/ghalint.output.json new file mode 100644 index 0000000..451a875 --- /dev/null +++ b/__tests__/ghalint.output.json @@ -0,0 +1,43 @@ +{ + "version": "2.1.0", + "$schema": "http://json.schemastore.org/sarif-2.1.0-rtm.6", + "runs": [ + { + "tool": { + "driver": { + "name": "test", + "rules": [] + } + }, + "results": [ + { + "locations": [ + { + "physicalLocation": { "artifactLocation": { "uri": ".github/workflows/cancel-stale-merge-queue-workflows.yml" } } + } + ], + "message": { "text": "job's timeout-minutes is required" }, + "ruleId": "job_timeout_minutes_is_required" + }, + { + "locations": [ + { + "physicalLocation": { "artifactLocation": { "uri": ".github/workflows/cancel-stale-merge-queue-workflows.yml" } } + } + ], + "message": { "text": "job's timeout-minutes is required" }, + "ruleId": "job_timeout_minutes_is_required" + }, + { + "locations": [ + { + "physicalLocation": { "artifactLocation": { "uri": ".github/workflows/cancel-stale-merge-queue-workflows.yml" } } + } + ], + "message": { "text": "job's timeout-minutes is required" }, + "ruleId": "job_timeout_minutes_is_required" + } + ] + } + ] +} diff --git a/dist/index.js b/dist/index.js index 427fa7c..ac67720 100644 --- a/dist/index.js +++ b/dist/index.js @@ -30007,7 +30007,8 @@ const knownParsers = { mypy: (input) => parseRegex(input, /^(?[^:\n]+):(?:(?\d+):)?(?:(?\d+):)?(?:(?\d+):)?(?:(?\d+):)? (?[^:\s]+): (?.+?)\s*(?:\[(?\S+)\])?$/gm), flake8: (input) => parseRegex(input, /^(?[^:\n]+):(?\d+):(?\d+): (?\w\d+) (?[^\n]+)$/gm), mdl: (input) => parseRegex(input, /^(?[^:\n]+)(?::(?\d+))?(?::(?\d+))? (?[^/\n]+)\/(?[^\s]+) (?[^\n]+)$/gm), - yamllint: (input) => parseRegex(input, /^(?[^:\n]+):(?\d+):(?\d+): \[(?[^\n\]]+)\] (?[^\n]+) \((?[^\n)]+)\)$/gm) + yamllint: (input) => parseRegex(input, /^(?[^:\n]+):(?\d+):(?\d+): \[(?[^\n\]]+)\] (?[^\n]+) \((?[^\n)]+)\)$/gm), + ghalint: (input) => parseRegex(input, /^(?=.*\berror="(?[^\n=]*)")(?=.*\bpolicy_name=(?[^\s=\n]*))(?=.*\bworkflow_file_path=(?[^\s=\n]*))[^\n]*$/gm) }; function normalizePath(givenPath, analysisPath) { const fileUrlPrefix = 'file:///'; diff --git a/src/bugalint.ts b/src/bugalint.ts index 99cce89..2a871a8 100644 --- a/src/bugalint.ts +++ b/src/bugalint.ts @@ -91,7 +91,9 @@ const knownParsers: Record = { ), flake8: (input: string) => parseRegex(input, /^(?[^:\n]+):(?\d+):(?\d+): (?\w\d+) (?[^\n]+)$/gm), mdl: (input: string) => parseRegex(input, /^(?[^:\n]+)(?::(?\d+))?(?::(?\d+))? (?[^/\n]+)\/(?[^\s]+) (?[^\n]+)$/gm), - yamllint: (input: string) => parseRegex(input, /^(?[^:\n]+):(?\d+):(?\d+): \[(?[^\n\]]+)\] (?[^\n]+) \((?[^\n)]+)\)$/gm) + yamllint: (input: string) => parseRegex(input, /^(?[^:\n]+):(?\d+):(?\d+): \[(?[^\n\]]+)\] (?[^\n]+) \((?[^\n)]+)\)$/gm), + ghalint: (input: string) => + parseRegex(input, /^(?=.*\berror="(?[^\n=]*)")(?=.*\bpolicy_name=(?[^\s=\n]*))(?=.*\bworkflow_file_path=(?[^\s=\n]*))[^\n]*$/gm) } function normalizePath(givenPath: string, analysisPath: string): string {