From 1e35386f9b0e49345e563980b2d783949960aa5d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 19:18:02 +0000 Subject: [PATCH 1/7] Initial plan From 978990a4341e5948d27a4c56d30b4fa7dfaab27e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 19:20:41 +0000 Subject: [PATCH 2/7] Add shellcheck GitHub Action workflow Co-authored-by: danieljurek <2158838+danieljurek@users.noreply.github.com> --- .github/workflows/shellcheck.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/shellcheck.yml diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml new file mode 100644 index 00000000000..4bc64c2e0a0 --- /dev/null +++ b/.github/workflows/shellcheck.yml @@ -0,0 +1,22 @@ +name: shellcheck + +on: + pull_request: + paths: + - "**.sh" + branches: [main] + +permissions: + contents: read + pull-requests: read + +jobs: + shellcheck: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@master + with: + severity: style + scandir: '.' From 299d686362704f82ba05f84dd81d1d8399ae0738 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 19:21:48 +0000 Subject: [PATCH 3/7] Update shellcheck workflow to use reviewdog for annotations Co-authored-by: danieljurek <2158838+danieljurek@users.noreply.github.com> --- .github/workflows/shellcheck.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 4bc64c2e0a0..35596f18e81 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -4,11 +4,18 @@ on: pull_request: paths: - "**.sh" + - ".github/workflows/shellcheck.yml" branches: [main] +# If two events are triggered within a short time in the same PR, cancel the run of the oldest event +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + permissions: contents: read pull-requests: read + checks: write jobs: shellcheck: @@ -16,7 +23,10 @@ jobs: steps: - uses: actions/checkout@v4 - name: Run ShellCheck - uses: ludeeus/action-shellcheck@master + uses: reviewdog/action-shellcheck@v1 with: - severity: style - scandir: '.' + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + path: "." + pattern: "*.sh" + level: info From 5525c1344d068ac7dfc7eb75938baf473298ca7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:45:15 +0000 Subject: [PATCH 4/7] Replace third-party action with native shellcheck and problem matcher Co-authored-by: danieljurek <2158838+danieljurek@users.noreply.github.com> --- .github/agents/github-workflows.agent.md | 137 +++++++++++++++++++++++ .github/shellcheck-matcher.json | 18 +++ .github/workflows/shellcheck.yml | 16 ++- 3 files changed, 162 insertions(+), 9 deletions(-) create mode 100644 .github/agents/github-workflows.agent.md create mode 100644 .github/shellcheck-matcher.json diff --git a/.github/agents/github-workflows.agent.md b/.github/agents/github-workflows.agent.md new file mode 100644 index 00000000000..582caddeddc --- /dev/null +++ b/.github/agents/github-workflows.agent.md @@ -0,0 +1,137 @@ +--- +name: GitHub Workflows Instructions +description: Guidelines for creating and maintaining GitHub Actions workflows +infer: true +--- + +# GitHub Workflows Instructions + +Guidelines for creating and maintaining GitHub Actions workflows in `.github/workflows/*.yml`. + +## General Principles + +### Third-Party Actions Policy + +**Do not use third-party actions** except for the following approved actions: +- `actions/*` (official GitHub actions like `actions/checkout`, `actions/setup-go`, `actions/setup-node`) +- Well-established, organization-specific actions that are widely used (e.g., `golangci/golangci-lint-action`) + +For linting and checking tools that don't have approved third-party actions: +1. Install and run the tool directly using shell commands +2. Use GitHub Actions problem matchers to create annotations + +### Problem Matchers for Annotations + +To surface errors and warnings as GitHub Actions annotations without third-party actions: + +1. **Create a problem matcher JSON file** in `.github/` directory (e.g., `.github/shellcheck-matcher.json`): + ```json + { + "problemMatcher": [ + { + "owner": "tool-name", + "pattern": [ + { + "regexp": "^([^:]+):(\\d+):(\\d+):\\s+(warning|error|note):\\s+(.*)$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5 + } + ] + } + ] + } + ``` + +2. **Register the matcher** before running the tool: + ```yaml + - name: Register problem matcher + run: echo "::add-matcher::.github/tool-matcher.json" + ``` + +3. **Run the tool** with output format matching the regex: + ```yaml + - name: Run tool + run: tool --format gcc files + ``` + +4. **Unregister the matcher** (optional, but recommended): + ```yaml + - name: Unregister problem matcher + if: always() + run: echo "::remove-matcher owner=tool-name::" + ``` + +### ShellCheck Example + +For shellcheck specifically: +- ShellCheck is pre-installed on `ubuntu-latest` runners +- Use `shellcheck -f gcc` format for gcc-style output +- Problem matcher regex should match: `file:line:column: severity: message [CODE]` + +Example workflow: +```yaml +steps: + - uses: actions/checkout@v4 + - name: Register ShellCheck problem matcher + run: echo "::add-matcher::.github/shellcheck-matcher.json" + - name: Run ShellCheck + run: find . -name "*.sh" -type f -exec shellcheck -f gcc {} \; + - name: Unregister ShellCheck problem matcher + if: always() + run: echo "::remove-matcher owner=shellcheck-gcc::" +``` + +## Workflow Structure + +### Standard Patterns + +All workflows should follow these patterns from existing workflows: + +1. **Trigger only on relevant changes**: + ```yaml + on: + pull_request: + paths: + - "path/to/relevant/files/**" + - ".github/workflows/this-workflow.yml" + branches: [main] + ``` + +2. **Include concurrency control** to cancel old runs: + ```yaml + concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + ``` + +3. **Minimal permissions** (principle of least privilege): + ```yaml + permissions: + contents: read + ``` + +4. **Use specific versions** for setup actions: + ```yaml + - uses: actions/setup-go@v6 + with: + go-version: "^1.25" + ``` + +## Pre-installed Tools + +The following tools are pre-installed on `ubuntu-latest` runners and don't need installation: +- shellcheck +- git +- curl +- jq +- Many others - check GitHub's runner images documentation + +## Testing Workflows + +Before committing a new workflow: +1. Validate YAML syntax: `python3 -c "import yaml; yaml.safe_load(open('.github/workflows/new-workflow.yml'))"` +2. Test any shell commands locally +3. Verify problem matcher regex against actual tool output diff --git a/.github/shellcheck-matcher.json b/.github/shellcheck-matcher.json new file mode 100644 index 00000000000..7d0416426bb --- /dev/null +++ b/.github/shellcheck-matcher.json @@ -0,0 +1,18 @@ +{ + "problemMatcher": [ + { + "owner": "shellcheck-gcc", + "pattern": [ + { + "regexp": "^([^:]+):(\\d+):(\\d+):\\s+(warning|error|note|style):\\s+(.*?)(?:\\s\\[([^\\]]+)\\])?$", + "file": 1, + "line": 2, + "column": 3, + "severity": 4, + "message": 5, + "code": 6 + } + ] + } + ] +} diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 35596f18e81..83bf585209b 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -14,19 +14,17 @@ concurrency: permissions: contents: read - pull-requests: read - checks: write jobs: shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + - name: Register ShellCheck problem matcher + run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck - uses: reviewdog/action-shellcheck@v1 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - reporter: github-check - path: "." - pattern: "*.sh" - level: info + run: | + find . -name "*.sh" -type f -exec shellcheck -f gcc {} \; + - name: Unregister ShellCheck problem matcher + if: always() + run: echo "::remove-matcher owner=shellcheck-gcc::" From cbcd389aa09e66ccfaa8beffcf42a4b36f220310 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:47:05 +0000 Subject: [PATCH 5/7] Improve shellcheck performance with batched file processing Co-authored-by: danieljurek <2158838+danieljurek@users.noreply.github.com> --- .github/agents/github-workflows.agent.md | 8 ++++++-- .github/workflows/shellcheck.yml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/agents/github-workflows.agent.md b/.github/agents/github-workflows.agent.md index 582caddeddc..39443f6726d 100644 --- a/.github/agents/github-workflows.agent.md +++ b/.github/agents/github-workflows.agent.md @@ -32,7 +32,7 @@ To surface errors and warnings as GitHub Actions annotations without third-party "owner": "tool-name", "pattern": [ { - "regexp": "^([^:]+):(\\d+):(\\d+):\\s+(warning|error|note):\\s+(.*)$", + "regexp": "^([^:]+):(\\d+):(\\d+):\\s+(warning|error|note|style):\\s+(.*)$", "file": 1, "line": 2, "column": 3, @@ -44,6 +44,8 @@ To surface errors and warnings as GitHub Actions annotations without third-party ] } ``` + + Note: Adjust the severity levels in the regex to match your tool's output format. 2. **Register the matcher** before running the tool: ```yaml @@ -78,12 +80,14 @@ steps: - name: Register ShellCheck problem matcher run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck - run: find . -name "*.sh" -type f -exec shellcheck -f gcc {} \; + run: find . -name "*.sh" -type f -exec shellcheck -f gcc {} + - name: Unregister ShellCheck problem matcher if: always() run: echo "::remove-matcher owner=shellcheck-gcc::" ``` +Note: Using `{} +` instead of `{} \;` batches all files into a single shellcheck invocation, improving performance and allowing shellcheck to follow sourced dependencies. + ## Workflow Structure ### Standard Patterns diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 83bf585209b..ddcb9d88149 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -24,7 +24,7 @@ jobs: run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck run: | - find . -name "*.sh" -type f -exec shellcheck -f gcc {} \; + find . -name "*.sh" -type f -exec shellcheck -f gcc {} + - name: Unregister ShellCheck problem matcher if: always() run: echo "::remove-matcher owner=shellcheck-gcc::" From 3f722c9c8fa71632cfef8beac6afc846485fd8d3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 29 Jan 2026 23:49:39 +0000 Subject: [PATCH 6/7] Add exclusions for hidden dirs and include matcher in trigger paths Co-authored-by: danieljurek <2158838+danieljurek@users.noreply.github.com> --- .github/agents/github-workflows.agent.md | 11 +++++++++-- .github/workflows/shellcheck.yml | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/.github/agents/github-workflows.agent.md b/.github/agents/github-workflows.agent.md index 39443f6726d..b4b9f267539 100644 --- a/.github/agents/github-workflows.agent.md +++ b/.github/agents/github-workflows.agent.md @@ -80,13 +80,20 @@ steps: - name: Register ShellCheck problem matcher run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck - run: find . -name "*.sh" -type f -exec shellcheck -f gcc {} + + run: | + find . -name "*.sh" -type f \ + -not -path "*/.*" \ + -not -path "*/node_modules/*" \ + -not -path "*/vendor/*" \ + -exec shellcheck -f gcc {} + - name: Unregister ShellCheck problem matcher if: always() run: echo "::remove-matcher owner=shellcheck-gcc::" ``` -Note: Using `{} +` instead of `{} \;` batches all files into a single shellcheck invocation, improving performance and allowing shellcheck to follow sourced dependencies. +Note: +- Using `{} +` instead of `{} \;` batches all files into a single shellcheck invocation, improving performance and allowing shellcheck to follow sourced dependencies. +- Excludes hidden directories (e.g., `.git/`), `node_modules/`, and `vendor/` to avoid checking unintended scripts. ## Workflow Structure diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index ddcb9d88149..21baa325a13 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -5,6 +5,7 @@ on: paths: - "**.sh" - ".github/workflows/shellcheck.yml" + - ".github/shellcheck-matcher.json" branches: [main] # If two events are triggered within a short time in the same PR, cancel the run of the oldest event @@ -24,7 +25,11 @@ jobs: run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck run: | - find . -name "*.sh" -type f -exec shellcheck -f gcc {} + + find . -name "*.sh" -type f \ + -not -path "*/.*" \ + -not -path "*/node_modules/*" \ + -not -path "*/vendor/*" \ + -exec shellcheck -f gcc {} + - name: Unregister ShellCheck problem matcher if: always() run: echo "::remove-matcher owner=shellcheck-gcc::" From f9376b2ab8b2144dd22b9f9a0740dabf0aa61d31 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 30 Jan 2026 16:59:04 +0000 Subject: [PATCH 7/7] Check only changed shell scripts instead of all files Co-authored-by: danieljurek <2158838+danieljurek@users.noreply.github.com> --- .github/agents/github-workflows.agent.md | 35 ++++++++++++++++++------ .github/workflows/shellcheck.yml | 27 ++++++++++++++---- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/.github/agents/github-workflows.agent.md b/.github/agents/github-workflows.agent.md index b4b9f267539..1467f82961c 100644 --- a/.github/agents/github-workflows.agent.md +++ b/.github/agents/github-workflows.agent.md @@ -72,28 +72,45 @@ For shellcheck specifically: - ShellCheck is pre-installed on `ubuntu-latest` runners - Use `shellcheck -f gcc` format for gcc-style output - Problem matcher regex should match: `file:line:column: severity: message [CODE]` +- **Check only changed files** in PRs to avoid blocking unrelated changes -Example workflow: +Example workflow (checking only changed files in PR): ```yaml steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 # Required for git diff + - name: Get changed shell scripts + id: changed-files + run: | + git fetch origin ${{ github.base_ref }} + CHANGED_SH_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }}...HEAD | grep '\.sh$' || true) + if [ -z "$CHANGED_SH_FILES" ]; then + echo "No shell scripts changed" + echo "files=" >> $GITHUB_OUTPUT + else + echo "Changed shell scripts:" + echo "$CHANGED_SH_FILES" + echo "files<> $GITHUB_OUTPUT + echo "$CHANGED_SH_FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + fi - name: Register ShellCheck problem matcher + if: steps.changed-files.outputs.files != '' run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck + if: steps.changed-files.outputs.files != '' run: | - find . -name "*.sh" -type f \ - -not -path "*/.*" \ - -not -path "*/node_modules/*" \ - -not -path "*/vendor/*" \ - -exec shellcheck -f gcc {} + + echo "${{ steps.changed-files.outputs.files }}" | xargs shellcheck -f gcc - name: Unregister ShellCheck problem matcher - if: always() + if: always() && steps.changed-files.outputs.files != '' run: echo "::remove-matcher owner=shellcheck-gcc::" ``` Note: -- Using `{} +` instead of `{} \;` batches all files into a single shellcheck invocation, improving performance and allowing shellcheck to follow sourced dependencies. -- Excludes hidden directories (e.g., `.git/`), `node_modules/`, and `vendor/` to avoid checking unintended scripts. +- Using `fetch-depth: 0` ensures full git history is available for diff comparison +- `--diff-filter=ACMRT` includes only added, copied, modified, renamed, or type-changed files +- Checking only changed files prevents blocking PRs due to pre-existing issues in unrelated scripts ## Workflow Structure diff --git a/.github/workflows/shellcheck.yml b/.github/workflows/shellcheck.yml index 21baa325a13..d194029c6bd 100644 --- a/.github/workflows/shellcheck.yml +++ b/.github/workflows/shellcheck.yml @@ -21,15 +21,30 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Get changed shell scripts + id: changed-files + run: | + git fetch origin ${{ github.base_ref }} + CHANGED_SH_FILES=$(git diff --name-only --diff-filter=ACMRT origin/${{ github.base_ref }}...HEAD | grep '\.sh$' || true) + if [ -z "$CHANGED_SH_FILES" ]; then + echo "No shell scripts changed" + echo "files=" >> $GITHUB_OUTPUT + else + echo "Changed shell scripts:" + echo "$CHANGED_SH_FILES" + echo "files<> $GITHUB_OUTPUT + echo "$CHANGED_SH_FILES" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + fi - name: Register ShellCheck problem matcher + if: steps.changed-files.outputs.files != '' run: echo "::add-matcher::.github/shellcheck-matcher.json" - name: Run ShellCheck + if: steps.changed-files.outputs.files != '' run: | - find . -name "*.sh" -type f \ - -not -path "*/.*" \ - -not -path "*/node_modules/*" \ - -not -path "*/vendor/*" \ - -exec shellcheck -f gcc {} + + echo "${{ steps.changed-files.outputs.files }}" | xargs shellcheck -f gcc - name: Unregister ShellCheck problem matcher - if: always() + if: always() && steps.changed-files.outputs.files != '' run: echo "::remove-matcher owner=shellcheck-gcc::"