From 7e73644c8831ebe25b3f21ead59005d6e914d9a7 Mon Sep 17 00:00:00 2001 From: Jon Ryser <241263+jonryser@users.noreply.github.com> Date: Tue, 17 Mar 2026 18:24:34 -0700 Subject: [PATCH] fix: shellcheck errors in start.sh; add code-quality CI workflow --- .github/workflows/CODE_QUALITY.md | 51 +++++++++++++++++++++ .github/workflows/code-quality.yml | 71 ++++++++++++++++++++++++++++++ .tool-versions | 1 + README.md | 4 ++ documentation/CICD.md | 3 ++ documentation/LINTING.md | 29 +++++++++++- start.sh | 6 +-- 7 files changed, 161 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/CODE_QUALITY.md create mode 100644 .github/workflows/code-quality.yml create mode 100644 documentation/CICD.md diff --git a/.github/workflows/CODE_QUALITY.md b/.github/workflows/CODE_QUALITY.md new file mode 100644 index 0000000..f4bee41 --- /dev/null +++ b/.github/workflows/CODE_QUALITY.md @@ -0,0 +1,51 @@ +# Code Quality Workflow + +## What it does + +Lints Markdown files and shell scripts on every pull request to `main`. Also runnable manually via `workflow_dispatch`. + +## When it runs + +- Pull requests to `main` (opened, reopened, or synchronized) when any of the following paths change: + - `**/*.md` + - `**/.markdownlint*` + - `*.sh` + - `.github/workflows/code-quality.yml` +- Manual trigger via the GitHub Actions UI + +## Markdown linting + +**Tool:** [`DavidAnson/markdownlint-cli2-action`](https://github.com/DavidAnson/markdownlint-cli2-action) + +**Config file:** `.markdownlint-cli2.jsonc` (max line length 240, allowed inline HTML, excludes `CLAUDE.md` and `.github/copilot-instructions.md`) + +**Run locally:** + +```sh +markdownlint-cli2 '**/*.md' +``` + +## Shell script linting + +**Tool:** [`reviewdog/action-shellcheck`](https://github.com/reviewdog/action-shellcheck) — posts inline PR review comments via `github-pr-review` reporter. + +**Run locally:** + +```sh +shellcheck start.sh stop.sh reset_env_variables.sh +``` + +**`.shellcheckrc` suppressions** (project-wide): + +| Rule | Reason | +| --- | --- | +| `SC1091` | Not following sourced files (`reset_env_variables.sh`) | +| `SC2153` | False positives on variable name misspelling | +| `SC2317` | False positive on unreachable commands in trap/signal handlers | + +## Adding new checks + +1. Add a "Get changed files" step using `tj-actions/changed-files@v47` scoped to the relevant paths. +2. Add a "Should lint X" step that writes the `any_changed` output to `$GITHUB_OUTPUT`. +3. Add the lint step gated on `if: steps.should_lint_x.outputs.run == 'true'`. +4. Update the paths filter under `on.pull_request.paths` to include the new file patterns. diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml new file mode 100644 index 0000000..9ec1799 --- /dev/null +++ b/.github/workflows/code-quality.yml @@ -0,0 +1,71 @@ +name: Code Quality +on: + pull_request: + branches: [main] + types: [opened, reopened, synchronize] + paths: + - '**/*.md' + - '**/.markdownlint*' + - '*.sh' + - '.github/workflows/code-quality.yml' + workflow_dispatch: +jobs: + quality: + name: Lint and test + timeout-minutes: 15 + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + fetch-depth: 0 + submodules: false + + - name: Get changed markdown files + id: changed_md + uses: tj-actions/changed-files@v47 + with: + files: | + **/*.md + + - name: Get changed shell scripts + id: changed_sh + uses: tj-actions/changed-files@v47 + with: + files: | + *.sh + + - name: Should lint docs + id: should_lint_docs + shell: bash + run: | + run=${{ steps.changed_md.outputs.any_changed }} + echo "run=${run}" >> $GITHUB_OUTPUT + + - name: Should lint shell + id: should_lint_shell + shell: bash + run: | + run=${{ steps.changed_sh.outputs.any_changed }} + echo "run=${run}" >> $GITHUB_OUTPUT + + - name: Lint markdown + if: steps.should_lint_docs.outputs.run == 'true' + uses: DavidAnson/markdownlint-cli2-action@v22 + with: + globs: '**/*.md' + + - name: Lint shell scripts + if: steps.should_lint_shell.outputs.run == 'true' + uses: reviewdog/action-shellcheck@v1 + with: + reporter: github-pr-review + fail_on_error: true + path: '.' + pattern: '*.sh' + exclude: './.git/*' + + - name: Default Job Success + if: steps.should_lint_docs.outputs.run != 'true' && steps.should_lint_shell.outputs.run != 'true' + shell: bash + run: exit 0 diff --git a/.tool-versions b/.tool-versions index b807ae5..37a7e51 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1,2 @@ markdownlint-cli2 0.21.0 +shellcheck 0.11.0 diff --git a/README.md b/README.md index cb82444..2ef81b0 100644 --- a/README.md +++ b/README.md @@ -118,3 +118,7 @@ Example usage: ### Linting See [LINTING.md](./documentation/LINTING.md) + +## Other Documentation + +See [documentation](./documentation/) diff --git a/documentation/CICD.md b/documentation/CICD.md new file mode 100644 index 0000000..e757b5b --- /dev/null +++ b/documentation/CICD.md @@ -0,0 +1,3 @@ +# Ci/Cd + +See [CODE_QUALITY.md](../.github/workflows/CODE_QUALITY.md) diff --git a/documentation/LINTING.md b/documentation/LINTING.md index e729630..a169d54 100644 --- a/documentation/LINTING.md +++ b/documentation/LINTING.md @@ -6,18 +6,45 @@ - Markdownlint must be installed as an extension (extension id: `DavidAnson.vscode-markdownlint`) for local markdown linting to work within VS Code or Cursor on save. - Or run in directly using [markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2). - - `markdownlint-cli2` is included in the asdf tool versions file. + - `markdownlint-cli2` is included in the asdf [`.tool-versions`](../.tool-versions) file. See . ```sh markdownlint-cli2 '**/*.md' ``` +- [ShellCheck](https://github.com/koalaman/shellcheck) `timonwong.shellcheck` + + - ShellCheck must be installed as an extension (extension id: `timonwong.shellcheck`) for local shell script linting to work within VS Code or Cursor on save. + - Or run it directly using the [ShellCheck CLI](https://github.com/koalaman/shellcheck#installing). + - `shellcheck` is included in the asdf [`.tool-versions`](../.tool-versions) file. + + ```sh + shellcheck *.sh + ``` + ## Configuration +### Markdown + MarkdownLint uses [`.markdownlint-cli2.jsonc`](../..markdownlint-cli2.jsonc) to configure the markdown linting rules and to ignore linting for specific files and paths. See +### Shell + +ShellCheck uses [`.shellcheckrc`](../.shellcheckrc) to configure linting rules. +The following rules are disabled project-wide: + +| Rule | Reason | +| --- | --- | +| `SC1091` | Suppresses "not following" warnings for sourced files (e.g. `reset_env_variables.sh`) | +| `SC2153` | Suppresses false-positive variable name misspelling warnings | +| `SC2317` | Suppresses unreachable-command false positives in trap/signal handlers | + +`external-sources=true` is also set to allow ShellCheck to follow sourced files when they are available. + +See + ## Continuous Integration Linting is automatically run in CI/CD via the [Code Quality workflow](../.github/workflows/code-quality.yml) on pull requests to `main`. diff --git a/start.sh b/start.sh index ee09974..8b02b3d 100755 --- a/start.sh +++ b/start.sh @@ -91,7 +91,7 @@ function start() { # Cursor invisible tput civis while sleep 0.1; do - i=$(((i + $charwidth) % ${#char})) + i=$(((i + charwidth) % ${#char})) printf "%s" "${char:$i:$charwidth}" echo -en "\033[1D" done @@ -120,7 +120,7 @@ function start() { function check_status() { local max_num_tries=35 local status_code - status_code=$(curl --write-out %{http_code} --silent --output /dev/null localhost:"${pga_port}") + status_code=$(curl --write-out '%{http_code}' --silent --output /dev/null localhost:"${pga_port}") if [[ ${iterator} -lt ${max_num_tries} && ${status_code} -eq 200 || ${status_code} -eq 302 ]] then # Stop the progress indicator. @@ -140,7 +140,7 @@ function start() { tput cnorm >&2 echo -e "${yellow}Did not work. Perhaps the server is taking a long time to start?${nc}" else - echo -en "${chars:$iterator:1}" "\r" + echo -en "${char:$iterator:1}" "\r" sleep 1 ((iterator++)) check_status