diff --git a/.codacy.yml b/.codacy.yml new file mode 100644 index 0000000..07d8b4f --- /dev/null +++ b/.codacy.yml @@ -0,0 +1,14 @@ +--- +# Codacy analyses this repository through its GitHub App; no workflow invokes +# it. Unlike SonarQube Cloud, additions here are honoured on the pull request +# that makes them — only removals wait for the default branch. +# +# Note that once this file exists, the "Ignored files" settings in the Codacy UI +# no longer apply: everything must be ignored from here. +exclude_paths: + # Generated by `bun run build:skill` from `scripts/*.ts` and committed, because + # the `npx skills` install channel copies only the skill directory and runs no + # dependency install. They are the same program as their sources, so analysing + # them reports every finding twice and counts the whole bundle as duplication. + # `eslint.config.js` and `.sonarcloud.properties` exclude the same directory. + - 'skills/*/scripts/**' diff --git a/.please/docs/knowledge/gotchas.md b/.please/docs/knowledge/gotchas.md index ca0501d..9641573 100644 --- a/.please/docs/knowledge/gotchas.md +++ b/.please/docs/knowledge/gotchas.md @@ -18,6 +18,20 @@ - **lint-staged + `--max-warnings 0` + ignored files**: when a staged path falls under eslint's ignore-list, eslint emits a "File ignored because of a matching ignore pattern" *warning* that trips `--max-warnings 0` and fails the pre-commit hook. Add `--no-warn-ignored` to the lint-staged eslint command to suppress. +## Static analysis (SonarQube Cloud, Codacy) + +Neither service is invoked by a workflow — both analyse every push through their GitHub App. That changes where their configuration lives and when it takes effect. + +- **SonarQube Cloud is in Automatic Analysis mode, which reads `.sonarcloud.properties` and ignores `sonar-project.properties`.** The docs are explicit that the two files are different and that a `sonar-project.properties` in an imported project is ignored. Three further constraints: only the copy on the **default branch** applies (a change does not affect the PR that makes it), **wildcards are not allowed** in the values, and where the file and the SonarQube Cloud UI disagree the **file wins** — so an entry that matches nothing cannot be corrected from the UI while it is still there. + +- **Codacy reads `.codacy.yml` (or `.codacy.yaml`), and the first line must be `---`.** Additions are honoured on the PR that makes them; only removals wait for the default branch. Once the file exists, the UI's "Ignored files" settings stop applying. Validate before pushing: `docker run --rm -v "$(pwd)":/src codacy/codacy-analysis-cli validate-configuration --directory /src`. + +- **Codacy's ESLint runs its own rule set, not this repo's, unless the Code patterns UI toggle says otherwise.** That is why `bun run lint` is clean while Codacy reports dozens of `Found from package "node:fs" with non literal argument` — the rule is `detect-non-literal-fs-filename` from `eslint-plugin-security`, which is not in this repo's dependency tree at all. On a module whose job is building and reading cache paths it fires on nearly every line. Codacy detects `eslint.config.js` for ESLint v9, but using it requires activating the per-tool "Configuration file" toggle on the repository's Code patterns page — a UI action, not a repo change. + +- **The committed skill bundles must be excluded from both.** `skills/*/scripts/*.mjs` is generated from `scripts/*.ts` and committed for the `npx skills` channel, so analysing it scores the same program twice: full-file duplication against its source, plus the `var` declarations Bun emits, which cannot be edited away because `build:skill:check` byte-compares the bundle. `eslint.config.js` already ignored it; `.sonarcloud.properties` and `.codacy.yml` now do too. + +- **Neither check blocks a merge.** The `main` ruleset carries no `required_status_checks` rule — only `deletion`, `non_fast_forward`, and a `pull_request` rule with `required_approving_review_count: 0`, `allowed_merge_methods: ["squash"]`, and `required_review_thread_resolution: true`. A PR showing `mergeStateStatus: BLOCKED` on green CI is almost always an **unresolved review thread**, not a failing analyser. Auto-merge cannot be armed at all: the repository has `allow_auto_merge: false`. + ## Repo / process - **Husky 9 pre-commit hook**: just `bunx lint-staged` on a single line. No shebang, no `set -e` — the `_/h` wrapper handles shell setup. Adding the legacy boilerplate is harmless but stale. diff --git a/.sonarcloud.properties b/.sonarcloud.properties new file mode 100644 index 0000000..dca9717 --- /dev/null +++ b/.sonarcloud.properties @@ -0,0 +1,23 @@ +# SonarQube Cloud runs here in Automatic Analysis mode — no workflow invokes a +# scanner, the GitHub App analyses every push on its own. That mode reads this +# file and ignores `sonar-project.properties`, and it accepts no wildcards in +# these values, so paths are written as plain directory prefixes. +# +# Two consequences worth knowing before editing: +# - Only the copy on the default branch takes effect. A change here does not +# alter the analysis of the pull request that makes it; it applies once +# merged. +# - Where this file and the SonarQube Cloud UI disagree, this file wins. An +# entry that matches nothing therefore cannot be corrected from the UI while +# it is still here. + +# Generated by `bun run build:skill` from `scripts/*.ts`, committed because the +# `npx skills` install channel copies only the skill directory and runs no +# dependency install. Analysing them scores the same program twice: every line +# of `scripts/docs.ts` reappears in the bundle, which read as 7.7% duplication +# on new code, and the `var` declarations Bun emits cost a reliability rating +# that no edit can recover — `bun run build:skill:check` byte-compares the +# bundle against a fresh build, so hand-editing it fails CI. +# `eslint.config.js` ignores the same directory, for the same reason. +sonar.exclusions=skills/spring-docs/scripts/ +sonar.cpd.exclusions=skills/spring-docs/scripts/