mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-27 07:50:47 +00:00
fix/maven-wrapper-java-version
43 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
295cd65124 |
chore(lint): require cacheable on withCache() calls (#45958)
As found while fixing the `go` datasource in #45949, calls to `withCache()` lean on the default of `cacheable: true`, which can lead to private packages being incorrectly cached. This could lead to cross-pollination of access to private package metadata, so we should be clear where we're not explicitly deciding whether to cache or not, which we can do so with a new linting rule. We'll make new findings an error, and existing issues appear a sa warning. As we improve coverage, we'll then remove this rule and make it so `cacheable` is a required flag in `CachedOptions`. Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io> |
||
|
|
4b4d14ec00 |
feat(manager): pass extracted constraints to updateArtifacts (#45826)
* feat(manager): pass extracted constraints to updateArtifacts `extractedConstraints` were collected during extraction but only ever read by `fetch.ts` for the lookup. At artifact time every manager had to derive the same tool constraints a second time, and when the updated package file no longer carried the constraint there was nothing to fall back to. `generateBranchConfig()` now merges the `extractedConstraints` of all upgrades of a branch onto the branch config, which reaches `updateArtifacts()` through `patchConfigForArtifactsUpdate()`. `UpdateArtifactsConfig` declares the field and documents what it contains. The new `resolveToolConstraint()` helper implements the ladder once: user `constraints` > an optional artifact-time derivation > the extracted value. The derivation is ranked above the extracted value on purpose: it reads the package files as the branch changed them, so poetry (python is an updatable dependency there), composer, pipenv (`pipenv` can be a dev package) and pep621 (`requires-python` is an updatable dependency) would otherwise regress to a stale constraint. pipenv, pep621 uv/pdm, poetry and composer are migrated to the helper and keep their derivation. Behaviour change: these managers now use the extract-time constraint as a last resort instead of running unconstrained, for example on lock file maintenance where pipenv deletes `Pipfile.lock` before deriving. `execute-post-upgrade-commands.ts` is unaffected: it reads `upgrade.constraints` per upgrade, and the extracted values are kept in a separate field rather than folded into `constraints`, so post-upgrade task tool constraints still come from user config only. Not migrated, because their constraints are never extracted, so the fallback would be dead code: bundler (`ruby`/`bundler`), pixi (`pixi`), pep621 uv (`required-version`) and npm's node ladder, whose last step already reads `package.json` engines. * refactor(manager): resolve tool constraints through resolveToolConstraint() Every manager now obtains the constraint of a tool it runs through `resolveToolConstraint()` instead of reading `config.constraints` itself, so the precedence "user config, then a value derived from the updated files, then the constraints collected during extraction" applies everywhere. The helper treats an empty string as not set at every step and accepts the `PostUpdateConfig` shape, whose `constraints` may be `null`. Behaviour changes that go beyond the new fallback to extracted constraints: - `mix` applies its hardcoded erlang default only after the extracted constraint, so an erlang version collected at extraction can win over it. - `kustomize` decides `HELM_EXPERIMENTAL_OCI` from the fully resolved helm constraint; `generateHelmEnvs()` takes that value instead of the config. - `npm` (yarn): an upgrade of yarn without a new value now consults the user constraint before deriving one from package.json or the lock file. - The "Using <tool> constraint from config" debug lines in bundler, composer, copier and pip-compile are gone, as the helper is the only reader of the config now. Helpers that read the config synchronously became async: bundler `getBundlerConstraint()`, copier `getPythonVersionConstraint()` and `getCopierVersionConstraint()`, pip-compile `get*VersionConstraint()` and `getToolVersionConstraint()`, gomod `deriveGoToolchainConstraints()` and `getUpdateImportPathCmds()`, mise `getMiseLockToolConstraints()`. composer `getPhpConstraint()` is removed. Each converted manager has a test showing the extracted constraint reaching the executed tool, and, where a derive callback exists, that the derived value still wins over it. * refactor(linters): add prefer-resolve-tool-constraint rule Reports member reads and destructuring of `constraints` and `extractedConstraints` from a manager config in `lib/modules/manager/**`, so that tool constraints are resolved through `resolveToolConstraint()` in `lib/modules/manager/util.ts` only. Writes and the same properties on package files, which extraction has to populate, are not reported. The helper itself and spec files are exempt in `.oxlintrc.json`. * refactor(manager): inline thin resolveToolConstraint wrappers Drop copier/utils.ts and the pip-compile getPipToolsVersionConstraint / getUvVersionConstraint helpers, which only forwarded to resolveToolConstraint(). Callers now call it directly. * docs(development): note lock file maintenance in tool constraints section * refactor(manager): address review on tool constraint resolution composer only runs extractConstraints() when a user constraint is missing, via Lazy. UpdateArtifactsConfig no longer re-declares constraints and extractedConstraints, which ToolConstraintsConfig already provides. |
||
|
|
134dc6cd38 |
chore(lint): add oxlint rule to block dev-dependency imports in production code (#45851)
As we've recently had a couple of cases where a `devDependency` has been
used in a production file, and CI hasn't caught it, we end up seeing
i.e.
ERROR: unhandledRejection
"err": {
"code": "ERR_MODULE_NOT_FOUND",
"message": "Cannot find package 'common-tags' imported from
/usr/local/renovate/dist/workers/repository/update/pr/index.js"
}
(see
|
||
|
|
b2d3b64c48 |
refactor(lint): enforce err key for errors in logger metadata (#45759)
* refactor(lint): enforce err key for errors in logger metadata * refactor(lint): flag error message and stack strings in logger-err-key |
||
|
|
3412de84ce |
refactor(linters): enable oxlint rule prefer-named-capture-group (#44714)
* refactor(lint): enable oxlint prefer-named-capture-group at error Numbered capture groups (m[1], $1) break silently when a regex is edited and group order shifts. Named groups (?<name>...) make intent explicit and accesses (m.groups.name) resilient to reordering. This enables the built-in eslint rule prefer-named-capture-group, surfacing 321 pre-existing unnamed-group violations across ~121 files to be burned down incrementally in follow-up commits. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(versioning): name capture groups for prefer-named-capture-group Burns down all prefer-named-capture-group violations in lib/modules/versioning/. Unused capture groups (only reachable via .test() or whole-match) become non-capturing (?:...); groups whose value is read become named (?<name>...), with accesses rewritten to match.groups!.<name> (or destructured from .groups!) instead of positional match[n]/$n so a future edit that reorders groups cannot silently break the reader. Two cases needed extra care to preserve behavior: - semver/common.ts and poetry/patterns.ts split() on a regex whose capture group is relied upon by String.prototype.split to keep the separator in the output array; the group is kept capturing and named, not converted to non-capturing. - hashicorp/convertor.ts's semverRegex is only ever embedded via .source into a named `(?<version>...)` group elsewhere and never matched directly, so its internal groups are safe to make non-capturing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(datasource): name capture groups for prefer-named-capture-group Burns down all prefer-named-capture-group violations under lib/modules/datasource/. Same treatment as the versioning module: unused groups become non-capturing, used groups get names, and positional match[n] reads move to match.groups!.<name>. docker/ecr.ts and pypi/common.ts keep their positional destructuring (`const [, region] = ...`, `!!m &&`) working unchanged since a named capture group is still addressable by its numeric index in JavaScript — only pypi/common.ts's access was rewritten to m.groups!.owner for clarity since it read a single group directly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(platform): name capture groups for prefer-named-capture-group Burns down all prefer-named-capture-group violations under lib/modules/platform/. Uses the repo's established idiom of `match.groups?.<name>` after an optional-chained exec()/match() (see bitbucket/index.ts hostnameWithoutApiPrefix, gerrit/utils.ts extractSourceBranch) and `$<name>` in String.replace replacement strings. Unused groups (markdown/HTML massaging regexes matched only to be stripped) become non-capturing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(manager): name capture groups in ansible-galaxy for prefer-named-capture-group Burns down prefer-named-capture-group violations in lib/modules/manager/ansible-galaxy/. newBlockRegEx and blockLineRegEx dropped their unused outer wrapping group (only the inner key/value groups were ever read) and named the key/value groups; nameMatchRegex's remaining unused groups (protocol/user-info/port alternatives) become non-capturing since only source/hostname/depName/version are read via .groups. Accesses in collections.ts and roles.ts move from lineMatch[2]/lineMatch[3] to lineMatch.groups!.key/value. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(manager): name capture groups for prefer-named-capture-group (batch 1) Burns down prefer-named-capture-group violations across the first alphabetical slice of lib/modules/manager/ (ansible through mix). Used groups get names with accesses rewritten to match.groups!.<name> (or $<name> in replacement strings); groups whose value is never read become non-capturing (?:...). Two String.split() call sites (git-submodules/extract.ts, meteor/extract.ts) keep the established "named group still readable positionally from the split() result array" idiom instead of restructuring the destructuring. bazel/rules/go.ts and buildpacks/extract.ts dockerRef verified byte-for-byte equivalent before/after via a quick node script since several nested groups collapsed to non-capturing at once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(manager): name capture groups for prefer-named-capture-group (batch 2) Burns down prefer-named-capture-group violations across the remaining alphabetical slice of lib/modules/manager/ (npm through terragrunt). Same treatment as batch 1: used groups get names with accesses moved to match.groups!.<name> or $<name> replacement strings; unused groups (wrapping alternations, quantifier repetition groups only consumed via .test(), or values never read from a match) become non-capturing. terraform/extractors/others/modules.ts and terragrunt/modules.ts share near-identical URL-parsing regexes (github/bitbucket/git/azure-devops ref matchers) — the same set of always-unused `depth=`/`&depth=` query-string groups is converted to non-capturing in both files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(config): name capture groups for prefer-named-capture-group Burns down prefer-named-capture-group violations in lib/config/. Used groups get names with replacement strings switched from $1/$2 to $<name>; the unused separator group in schedule-migration.ts's afterBeforeRegex becomes non-capturing. presets/parse.ts keeps assigning through the already-declared `repo` variable rather than array-destructuring the exec() result, matching this file's existing style for the other named-group regexes just above it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(util): name capture groups for prefer-named-capture-group Burns down prefer-named-capture-group violations across lib/util/ and lib/logger/. Same treatment as previous batches: named groups for values that are read (via $<name> replacement strings, .groups!.<name>, or destructured from .groups), non-capturing groups where nothing reads the captured value (e.g. semantic.ts's angular-commit .test()-only regex). www-authenticate.ts's tokenizer entries each get their own named group but keep accessing the match generically via match[1], since a positionally-indexed named group is still readable by index. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(workers): name capture groups for prefer-named-capture-group Burns down prefer-named-capture-group violations in lib/workers/. Used groups get names with $<name> replacement strings; unused wrapper/alternation groups (e.g. semantic-commit-message.ts's optional scope/issue wrappers, release-notes.ts's date-heading and horizontal-rule matchers that are only probed with .search()/replaced wholesale) become non-capturing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * refactor(test,tools): name capture groups for prefer-named-capture-group Finishes the prefer-named-capture-group burndown: test/, tools/, and vitest.config.mts. Groups whose value is read get names ($<name> replacement strings or .groups.<name> access); groups only used via .test()/.search() or that feed a .match(/…/g) call (whose return value is the array of whole matches, not captured groups) become non-capturing. This is the last remaining slice of pre-existing violations, so the rule (already enabled at error repo-wide) now passes with zero findings across the whole codebase. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk * fix prettier failure * refactor(lint): use a named capture group in `v8-ignore-no-count` New rule from main trips the newly enabled `prefer-named-capture-group` oxlint rule. --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
6e03e8326f |
refactor(linters): add rule to enforce inline single use fixtures (#45230)
* feat(lint): add renovate/prefer-is-helpers and renovate/prefer-is-object rules Flag ad-hoc type checks that have @sindresorhus/is equivalents: - .filter(Boolean) -> .filter(isTruthy) - typeof x === 'string' -> isString(x) - x === null || x === undefined -> isNullOrUndefined(x) (and negation) The typeof x === 'object' shape lives in a separate suggestion-only rule (renovate/prefer-is-object, kept at warn) because isObject()/isPlainObject() are not drop-in equivalents: null, arrays and functions behave differently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: fix renovate/prefer-is-helpers violations Replace ad-hoc type checks with @sindresorhus/is helpers across lib/: - 13x .filter(Boolean) -> .filter(isTruthy) - 36x typeof x ==/!== 'string' -> isString(x) / !isString(x) - 6x x === null || x === undefined -> isNullOrUndefined(x) (and negation) Promote renovate/prefer-is-helpers to error now that the codebase is clean. renovate/prefer-is-object stays at warn: its 15 remaining sites guard parsed YAML/JSON or unknown values where isObject()/isPlainObject() are not provably equivalent (null/array/function semantics). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: enforce renovate/prefer-is-object at error level Resolve the 15 remaining warnings and raise the rule from warn to error: - Migrate 10 sites to isObject() where the guarded value provably cannot be a function (parsed YAML/JSON, typed exec command arguments, or test-controlled fixtures): helm-values, woodpecker, bun, pre-commit managers, exec utils, file package cache, and the github http spec. In the bun manager this also fixes a latent crash where a null `workspaces` value would throw on the `in` operator. - Keep 5 sites as reasoned oxlint-disable comments where excluding functions is load-bearing: the byte-exact fingerprint canonicalizer (2), the circularity walker, the zod result guard, and the generic hasKey helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): add renovate/inline-single-use-fixtures rule In spec files, a module-scope const fixture that is referenced from exactly one it()/test() block should be inlined into that test so the test is self-contained. The rule is a warn-level nudge (naming for clarity is a valid exception) with no autofix (moving code is risky). Uses oxlint jsPlugins scope analysis (getDeclaredVariables) for exact, shadowing-safe reference counting and bails out conservatively: only top-level non-exported single-declarator consts with multiline, non-function initializers whose every reference sits inside the callback function of one and the same test call are flagged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: inline single-use spec fixtures into their tests Fix 26 renovate/inline-single-use-fixtures warnings in specs where the move is mechanical and value-preserving: codeBlock fixtures were re-indented uniformly (codeBlock strips the common indentation, so the produced string is unchanged) and Fixtures.get() calls resolve relative to the spec file, so relocating them inside the test body has no effect. The remaining 59 warnings are left for per-site judgment, as the rule is a warn-level nudge by design. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: inline remaining relocation-safe single-use spec fixtures Move the 24 remaining single-use module-scope fixtures whose initializer is a codeBlock tagged template or a Fixtures accessor call into the one it() block that uses them. Both shapes are value-preserving to relocate: codeBlock strips the common leading indentation, so the uniformly re-indented templates produce identical strings, and Fixtures.get() resolves relative to the spec file, not the call site's position in it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): enforce inline-single-use-fixtures as error Narrow the rule to the initializer shapes where moving the declaration into the test body is provably value-preserving and unambiguously an improvement: codeBlock/stripIndent tagged templates (indentation- normalizing, so re-indenting is safe) and Fixtures accessor calls (resolve relative to the spec file). Plain object/array literals, untagged template literals (whose leading-newline formatting would need ugly re-indentation) and arbitrary call expressions remain per-site judgment calls and are no longer flagged. With the rule reduced to true defects and all remaining violations inlined, bump it from warn to error in the spec override block. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: inline contents of fixtures relocated into single-use tests The previous commits moved single-use module-scope Fixtures.get() consts into their one it() block, which only relocated the file indirection. Replace those relocated Fixtures.get() calls with the fixture file's actual content — codeBlock tagged templates for text fixtures — so the tests are self-contained, and delete the fixture files that no longer have any references. Relocated fixtures too large to inline comfortably (terraform-provider releases, sbt private-variable file, nuget v2 pkg list, bundled package-lock) keep their Fixtures.get() calls. Value preservation was verified by unchanged vitest results for every touched spec; all consumers parse the content, so codeBlock's trailing newline normalization is behavior-neutral. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: inline remaining large single-use fixtures Inline the four Fixtures.get() sites that were previously exempted for size, so every single-use fixture is now inlined regardless of size: - nuget v2_withoutProjectUrl.xml -> codeBlock (served via http mock) - terraform-provider releaseBackendIndexGoogleBeta.json -> plain object literal passed to the nock reply - npm locked-dependency bundled.package-lock.json -> codeBlock JSON string (consumed as raw lockFileContent) - sbt private-variable-dependency-file.scala -> codeBlock All consumers parse the content, so codeBlock's trailing-newline normalization is behavior-neutral; vitest results are unchanged for every touched spec, including the two pre-existing nuget failures. The nuget, terraform-provider and sbt fixture files have no remaining references and are deleted. bundled.package-lock.json is kept because package-lock/get-locked.spec.ts still reads it via Fixtures.getJson(). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: keep large bundled package-lock fixture in a file The bundled package-lock.json inlined into the "fails remediation if bundled" test is ~150 KB (~4,400 lines); inlining it as a codeBlock hurts readability more than it helps. Read it via Fixtures.get inside the test block instead — the inline-single-use-fixtures rule permits a Fixtures.get() call in test scope, and the fixture file is still present. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c32e2391a0 |
refactor(linters): add prefer-coerce-object rule (#45493)
Refs #45216 The object counterpart to `prefer-coerce-array`: `x ?? {}` becomes `coerceObject(x)`. The rule flags a `??` whose default is a bare `{}` literal, so a populated default or an asserted `({} as Foo)` still passes; a `x ?? y ?? {}` chain maps onto `coerceObject(x, y)`. Every hit across `lib/` converted cleanly, so no disable comments were needed. |
||
|
|
97327c3d28 |
refactor(linters): add prefer-coerce-array rule (#45492)
* refactor(linters): add prefer-coerce-array rule Refs #45217 `x ?? []` and `coerceArray(x)` say the same thing, but only the second one is searchable and consistent. The rule flags a `??` whose default is a bare `[]` literal; a non-empty default or an asserted `([] as Foo[])` still passes. Applying it across `lib/` surfaced three spots the helper cannot cover, which keep `?? []` with a disable comment or a narrower fix: - `package-files.ts` destructures a tuple, which `coerceArray()` widens - `generate.spec.ts` defaults `matchAll()`, an iterator rather than an array - `mise/upgradeable-tooling.ts` declares a `Record` return, so its `?? []` fallback was wrong to begin with and becomes `coerceObject()` * refactor(platform/github): hoist the GHE version header lookup `Object.entries(...).find()` returns a tuple, and defaulting it with `?? []` only to destructure the second element reads as an array default when it is not one. Name the found entry instead, which drops the `?? []` rather than routing a tuple through `coerceArray()`. |
||
|
|
fbedd41e82 |
test: replace env operation with vi.stubEnv() (#45490)
* test: replace manual process.env mutation with vi.stubEnv
Enable Vitest's `unstubEnvs` so env stubs are reverted automatically
before every test, and convert the manual `process.env.X = ...` /
`delete process.env.X` pairs in specs to `vi.stubEnv()`.
This removes the hand-written `afterEach` cleanup blocks and the
`const OLD_ENV = process.env` / `process.env = { ...OLD_ENV }`
save-restore dance, which silently leaked state between tests when a
test set a variable without a matching delete.
Left as-is (incompatible with `unstubEnvs`, which unstubs before each
test, not after):
- module top-level env writes (cocoapods, gomod, post-update, pip-compile
and bundler artifacts specs)
- `beforeAll` env writes -- the two in `util/http` moved to `beforeEach`
* test: stop asserting on ambient environment variables
Three specs asserted on values that the surrounding environment can
override, so they only passed on a machine that happened not to set them:
- `util/exec/env`: `getChildProcessEnv()` forwards every entry of
`basicEnvVars`, but the spec only seeded a subset. Any other forwarded
variable that was set ambiently (e.g. a lowercase `http_proxy`) leaked
into the `toEqual` assertion. Clear all of them first.
- `util/git/index`: `process.env.GIT_SSH_COMMAND` deliberately overrides
the default that the two env-inheritance tests assert on. Clear it.
- `logger/pretty-stdout`: the colorized level strings are built at import
time, so the `beforeEach` setting `FORCE_COLOR` could never affect them
-- it was dead code, and the test silently assumed a terminal without
colour support. Derive the expectation the same way the module does.
* test(datasource/nuget): use a throwaway cache dir for nupkg downloads
The `determine source URL from nupkg` tests do not mock the filesystem,
so they really wrote downloaded packages into a fixed `/tmp/cache` path.
That fails wherever the system tmpdir is not writable, and two checkouts
running the suite at once would share the same directory.
Use `tmp.dir({ unsafeCleanup: true })` and clean it up afterwards, which
is the pattern the other specs that touch disk already use.
* feat(lint): add renovate/prefer-stub-env rule
Enforces in specs what the migration to `vi.stubEnv` established:
- assigning to or deleting `process.env.X` inside `beforeEach`, `afterEach`,
`it` or `test` is reported, with a fixer that rewrites it to `vi.stubEnv()`
- module scope, `describe` bodies and `beforeAll` / `afterAll` are left alone:
`unstubEnvs` reverts stubs *before* each test, so a stub created there is
gone by the time the first test runs, and those must keep assigning directly
- replacing the `process.env` object is reported everywhere and never fixed.
`vi.stubEnv()` captures the original object when the worker starts, so after
a reassignment its deletes silently target the old object
The rule found 28 further violations in specs the earlier sweep missed, since
that one was anchored on `delete process.env`. Twelve were auto-fixed; the
rest replaced `process.env` wholesale and are now `clearEnv()` from test/util.
`util/exec/index.spec.ts` opts out with a comment: it asserts on the whole
child env, and `vi.stubEnv()` cannot express that because it maps `PROD`,
`DEV` and `SSR` onto '' instead of deleting them.
|
||
|
|
e0cec3dc95 |
refactor(lint): add types-location rule and enable it for lib/modules (#45497)
feat(lint): add `types-location` rule and enable it for `lib/modules`
Reviewers consistently ask for exported types to be moved into a
colocated `types.ts`. Add a `renovate/types-location` oxlint rule that
reports `export interface` / `export type` declarations outside such a
file, and turn it on across `lib/modules`.
Re-exports (`export type { X }`, `export type *`), file-local types, and
values (enums, classes, functions) are left alone. `schema.ts` files and
`schema/` directories are excluded via config, matching how
`zod-schema-location` is configured — inferred types belong next to the
schema they are derived from.
Relocating the 87 existing violations means:
- new `types.ts` files for the modules that had none
- `terragrunt/common.ts` folded into its `types.ts`, as it held nothing
else
- `RangeBound` in `versioning/gradle/compare.ts` un-exported, since only
a file-local interface referenced it
- `bazel-module/parser/fragments.ts` split from its inferred types, which
now live in `parser/types.ts` and infer through a namespace import so
each schema keeps its merged name
|
||
|
|
021612414c |
fix(lint): use parseInt over Number (#45472)
* fix(lint): use `parseInt` over `Number` As a code review comment that comes up every so often, we can add a linting rule to enforce this check. This also fixes any existing usages. As this could be breaking, we can release it as a `fix`. Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io> * fixup! fix(lint): use `parseInt` over `Number` * fixup! fix(lint): use `parseInt` over `Number` --------- Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io> |
||
|
|
a9c8f7431f |
fix(lint): extend prefer-is-helpers to catch more cases (#45474)
This now covers everything that isn't `isObject` or `typeof x === 'number'`. Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io> |
||
|
|
a473e73b3e |
fix(linters): forbid inert counts in v8 coverage-ignore comments (#45287)
Adds a custom oxlint rule renovate/v8-ignore-no-count that flags the count form '/* v8 ignore next <N> */'. The count is not honored by vitest's ast-v8-to-istanbul hint parser, which captures only the keyword (if/else/next/file); 'next' always exempts exactly the next AST node. Trailing counts therefore suggest a line range that is never applied and mislead readers. The rule is autofixable (drops the count, preserving actual behavior) and has been applied to all existing occurrences. |
||
|
|
e44c9a2070 |
ci(oxlint): move custom oxlint rules to typescript and alternative API (#45337)
* ci: move custom oxlint rules to typescript and alternative API * ci: add to test sharding |
||
|
|
a1971afa78 |
fix(linters): add linting rule to enforce usage of our regEx utility (#44690)
* ci(linter): add renovate/require-regex-util rule Adds a custom oxlint rule that flags raw RegExp usage in lib/ production code: any `new RegExp(...)` call and any regex literal that is not the direct first argument of `regEx(...)`. The regEx() helper from lib/util/regex.ts uses the RE2 engine for ReDoS-safe matching and caches compiled patterns. lib/util/regex.ts itself is exempt. The rule is disabled for **/*.spec.ts, test/**, and tools/** via config overrides, because vitest APIs such as expect.stringMatching need bare RegExp instances (a past commit reverted regEx() there). Severity is set to "warn" instead of "error": the repo currently has 197 pre-existing violations (above the agreed mechanical-fix threshold of 80), and a number of them are deliberately RE2-incompatible patterns (lookahead/lookbehind/named backreferences, see TODO #12872/#12875 markers in e.g. lib/modules/versioning/rez/ pattern.ts and lib/modules/manager/dockerfile/extract.ts) that need per-site judgment before they can be wrapped in regEx() or suppressed with a justified disable comment. No violation fixes are included in this commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(linter): enforce renovate/require-regex-util at error Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: use regEx() for regex literals and RegExp construction in lib Burn down all renovate/require-regex-util violations (197): - wrap RE2-compatible regex literals and RegExp constructions in regEx() - rewrite lookaround patterns where behavior is provably preserved: goproxy separator split, sbt-package link extraction, leiningen comment stripping and keyword search, npm GitHub owner validation (unit-count bound replaced by an explicit length check) - keep native RegExp with disable comments where RE2 cannot be used: moo / good-enough-parser lexer patterns (moo rejects RE2 instances), MigrationsService propertyName (matched via isRegExp, which RE2 instances fail), rez named backreferences and lookaheads, GitHub markdown link negative lookbehind, emoji astral-plane matching - drop stale TODO #12875 comments for patterns current re2 handles Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: reduce require-regex-util disable comments Rewrite the github massage-markdown-links URL regex to capture an optional `api.` prefix in a named group (skipped in code) instead of relying on a negative lookbehind, so both the base and global variants can use regEx()/RE2 and their two disable comments are removed. Add spec cases for api-prefixed URLs that match the URL shape. Consolidate the four related line disables in rez/pattern.ts (bound and range patterns emulating Python conditional patterns via named backreferences and lookaheads, which RE2 cannot express) into a single block disable/enable pair, matching the treatment of the lexer files. Disable comment count drops from 13 to 8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(datasource/sbt-package): use named capture group in link regex Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(manager/cake): restore original multiLineComment regex spelling The [^] -> [\\s\\S] rewrite was only needed for an RE2 wrap that was later reverted; keep the diff minimal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(datasource/go): skip empty GOPROXY segments The switch from a lookahead split to a capture-group split (needed because RE2 has no lookahead support) changed how empty GOPROXY segments parse: `a|,b` yielded `{ url: ',', fallback: '|' }` before and `{ url: '', fallback: ',' }` after. The comma fallback only continues on 404/410, so a failing proxy ahead of an empty segment silently stopped the lookup instead of falling through to the remaining proxies. Empty segments carry no url to query, so drop them. * refactor(datasource/go): use isTruthy for empty segment filter * fix(datasource/go): filter empty segments before mapping Filtering after the map broke the contextual typing from the GoproxyItem[] annotation, widening fallback to string. * refactor(platform/github): use regEx() for merge queue query stripping --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
c2785bc5a4 |
refactor(oxlint): scope custom JS rules via config overrides (#45266)
Move the file-path filtering of the custom lint rules out of the rule implementations and into .oxlintrc.json overrides. Previously every JS plugin rule was enabled globally and returned early for non-matching files, which still paid the oxlint->Node plugin bridge cost for every linted file. With config scoping the rules are not invoked at all outside their target paths. |
||
|
|
16ef1715e9 |
refactor(linters): add rules for @sindresorhus/is helpers (#45229)
* feat(lint): add renovate/prefer-is-helpers and renovate/prefer-is-object rules Flag ad-hoc type checks that have @sindresorhus/is equivalents: - .filter(Boolean) -> .filter(isTruthy) - typeof x === 'string' -> isString(x) - x === null || x === undefined -> isNullOrUndefined(x) (and negation) The typeof x === 'object' shape lives in a separate suggestion-only rule (renovate/prefer-is-object, kept at warn) because isObject()/isPlainObject() are not drop-in equivalents: null, arrays and functions behave differently. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: fix renovate/prefer-is-helpers violations Replace ad-hoc type checks with @sindresorhus/is helpers across lib/: - 13x .filter(Boolean) -> .filter(isTruthy) - 36x typeof x ==/!== 'string' -> isString(x) / !isString(x) - 6x x === null || x === undefined -> isNullOrUndefined(x) (and negation) Promote renovate/prefer-is-helpers to error now that the codebase is clean. renovate/prefer-is-object stays at warn: its 15 remaining sites guard parsed YAML/JSON or unknown values where isObject()/isPlainObject() are not provably equivalent (null/array/function semantics). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: enforce renovate/prefer-is-object at error level Resolve the 15 remaining warnings and raise the rule from warn to error: - Migrate 10 sites to isObject() where the guarded value provably cannot be a function (parsed YAML/JSON, typed exec command arguments, or test-controlled fixtures): helm-values, woodpecker, bun, pre-commit managers, exec utils, file package cache, and the github http spec. In the bun manager this also fixes a latent crash where a null `workspaces` value would throw on the `in` operator. - Keep 5 sites as reasoned oxlint-disable comments where excluding functions is load-bearing: the byte-exact fingerprint canonicalizer (2), the circularity walker, the zod result guard, and the generic hasKey helper. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e01b50c6ab |
refactor(linter): oxlint prefer partial typed casts for consts (#45239)
* refactor: flag all typed object literal casts in prefer-partial-in-specs * refactor: type maven spec httpError helper against got response shape |
||
|
|
e510b9a64d |
chore: add no-unquoted-exec-interpolation linting rule
To avoid the risk of shell injection being introduced into future `exec` calls, we can add a linter to scan for common variable inputs that may be malicious. The fields to look for come from the generated `templatableFields`, so we track the config options a repository can influence rather than restating them, with credentials and manager-specific fields - which no shared list covers - carried alongside. Booleans and numbers are dropped, as they can't carry shell metacharacters. A value is treated as escaped only when it actually is: `quote()`, `shlex.quote()`, shlex's `join()`, or `.map(quote).join()`. A bare `.join()` isn't, as `Array.prototype.join` escapes nothing, and we look through calls like `String(depName)` so wrapping a value doesn't hide it. Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io> |
||
|
|
52ff375f0a |
chore: add linter rule for shell: true usage (#45110)
As we shouldn't really be using it, we should flag up usages more clearly. In cases where we do need to specify this - when `allowShellExecutorForPostUpgradeCommands` is set - then we can disable the rule. Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io> |
||
|
|
23dd5682be |
test(config/validation): ensure that errors and warnings are always checked and that we don't length check (#45065)
* test(config): ensure that `errors` and `warnings` are always checked
As a follow-up to
|
||
|
|
ae40fbb1a9 |
chore: add a linting rule to enforce resolveSameOriginUrl
To catch this sort of issue in the future. Co-authored-by: Claude Opus 4.8 <jamie.tanna+claude-code@mend.io> |
||
|
|
716baf630b |
fix(linters): add rules for filesystem helpers and Date (#44685)
* feat(lint): add renovate/prefer-fs-util and renovate/prefer-luxon rules Two shared-util substitution rules, both at warn level: - renovate/prefer-fs-util flags value imports of fs, node:fs, fs/promises, node:fs/promises, fs-extra and fs-extra/esm in lib/ source files outside lib/util/fs/, pointing to the scoped helpers from lib/util/fs. Spec files and type-only imports are exempt. A config-only change via no-restricted-imports was considered but rejected: that rule is at error severity globally and per-path warn severity is not expressible, so the 13 existing call sites would break the baseline. - renovate/prefer-luxon flags new Date(...) and Date.now() in lib/ source files, pointing to Luxon per best-practices. Date/time utility modules (lib/util/date, lib/util/pretty-time, lib/util/timestamp) and spec files (vi.setSystemTime etc.) are exempt. Baseline: 13 prefer-fs-util and 45 prefer-luxon warnings, zero errors. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: use Luxon instead of new Date() at remaining call sites Fixes all renovate/prefer-luxon violations for `new Date(...)`: - `new Date().toISOString()` -> `DateTime.utc().toISO()` (byte-identical output) in the http cache provider, schedule logging and PR cache. - `new Date()` -> `DateTime.now().toJSDate()` for the git commit-date fallback and the rubygems `syncedAt` markers (same `Date` values). - rust-release-channel now computes the Rust 1.0 release date and nightly version dates via `DateTime.utc(...)`; previously `new Date(y, m, d)` used the local timezone while the epoch used UTC, so the comparison was timezone-dependent at the boundary date. Tests run with TZ=UTC, where behavior is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: use lib/util/fs helpers in repository worker Fixes renovate/prefer-fs-util violations outside bootstrap code: - `fs.ensureDir()` -> `ensureDir()` from lib/util/fs (same fs-extra call underneath; it no-ops on an empty dir name, so the repository worker spec now simulates the init failure via a rejected `initRepo` instead of relying on `fs.ensureDir('')` throwing). - `fs.remove(privateCacheDir())` -> `cachePathExists()` + `rmCache()`, keeping the remove-if-present semantics while asserting cacheDir containment. Two call sites keep raw imports with reasoned disable comments: - lib/util/modules.ts synchronously enumerates Renovate's own installed module directories at import time. - lib/util/cache/package/impl/sqlite.ts receives cacheDir as an explicit argument during global initialization, before GlobalConfig (which the scoped cache helpers resolve against) contains cacheDir. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): promote prefer-fs-util and prefer-luxon to error Both rules are narrowed to what is actually accepted practice before being promoted: prefer-luxon no longer flags `Date.now()`: it returns UTC-based epoch milliseconds used for elapsed-time measurement and TTL arithmetic, which is timezone-independent by construction. The mined reviewer feedback behind this rule ("use Luxon for date arithmetic outside util") targets timezone-dependent date construction/formatting, which cannot occur with a raw millis number; the rule keeps flagging `new Date(...)`. prefer-fs-util exempts code that legitimately needs raw fs access because the scoped lib/util/fs helpers resolve against GlobalConfig localDir/cacheDir, which does not exist yet or does not apply there: - lib/logger/: log-file streams at user-configured system paths during bootstrap; lib/util/fs also depends on the logger (import cycle). - lib/workers/global/: creates baseDir/cacheDir themselves and reads/writes user-supplied paths before GlobalConfig is seeded. - lib/config-validator.ts: standalone CLI without GlobalConfig. - lib/util/git/: owns the localDir lifecycle (clone, emptyDir, symlinks) and private-key files with sync cleanup on process exit. Also fixes a pre-existing tsc error in prefer-fs-util.js: `importKind` is a TypeScript-ESTree extension missing from eslint's base AST types. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(fs): make rmCache ignore missing paths All rmCache callers use it for cleanup, where a missing path is a no-op, so bake force: true in instead of guarding call sites with an existence check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(linters): exempt lib/instrumentation from prefer-fs-util `lib/instrumentation/file-exporter.ts` landed on main while this branch was open and imports `node:fs/promises` directly. The exporter writes to a user-configured system path (`RENOVATE_TRACING_FILE_EXPORTER_PATH`) outside `localDir`/`cacheDir`, so the scoped helpers do not apply. `lib/instrumentation` is also deliberately kept out of the module graph of instrumented libraries (see the `⚠️` note in `lib/renovate.ts`), so it must not pull in `lib/util/fs` and its config/logger dependencies. Exempt the directory, as is already done for `lib/logger`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * docs: shorten doc --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
ac0407bdee |
refactor(linters): add linters for Json.pipe and schema location (#44684)
* feat(lint): add renovate/zod-schema-location and renovate/prefer-json-pipe rules Backlog item #23: reviewers repeatedly ask for consistent Zod schema structure. Two new oxlint JS-plugin rules, both at "warn": - renovate/zod-schema-location flags `export const X = <zod schema>` at module scope in lib/modules/**/ files that aren't schema.ts (or a colocated schema/ directory), reusing the leftmost-identifier schema detection from zod-schema-naming.js / prefer-nullish-util.js. Only exported top-level schemas are flagged — non-exported ones are treated as intentionally local/trivial (e.g. tightly coupled to file-local helpers), which keeps the rule's signal high. - renovate/prefer-json-pipe flags `Schema.parse(JSON.parse(x))` / `Schema.safeParse(JSON.parse(x))` and suggests `Json.pipe(Schema)` from lib/util/schema-utils instead. A third mined slice (require a matching `z.infer` type export for every exported schema) was evaluated and skipped: ~275+ exported schema-like consts in schema.ts files vs. 231 existing z.infer exports repo-wide is too high a mismatch to flag mechanically without heavy per-site judgment, so it would be mostly false positives. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: fix a clean subset of renovate/zod-schema-location and renovate/prefer-json-pipe violations renovate/prefer-json-pipe: fixed all 5 safe `.parse(JSON.parse(...))` call sites (bazel datasource, generate-mise-registry script, a hook spec) by switching to `Json.pipe(Schema).parse(...)`. Left the 2 `.safeParse(JSON.parse(...))` sites (pretooluse-check.ts, github-query-items.ts) unfixed: JSON.parse throwing before safeParse is reached today crashes the script, whereas Json.pipe folds the bad-JSON case into a graceful `{ success: false }`, which is an observable behavior change, not just a mechanical rewrite. renovate/zod-schema-location: fixed the one clean, self-contained violation (platform/github's GithubIssue schema, moved into the already-existing platform/github/schema.ts) as a representative example. Left the other 20: they require moving exported schemas out of files where they're built from local helper functions/config tables (manager/github-actions/community.ts) or restructuring an entire directory into a new schema.ts with import-graph updates across many files (manager/bazel/rules/*.ts, manager/bazel-module/parser/*.ts) — real refactors needing per-site judgment, not mechanical fixes. Both rules stay at "warn": renovate/prefer-json-pipe has 2 remaining violations that shouldn't be auto-fixed, and renovate/zod-schema-location has 20. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: resolve remaining prefer-json-pipe and zod-schema-location findings - github-actions: move the derived `CommunityActions` union into the existing colocated `schema.ts`; the action config table and the `actionSchema` builder stay in `community.ts` and are now exported. - tools/docs: fold `JSON.parse` + `safeParse`/rethrow of the `gh` CLI output into `Json.pipe(...)`. Invalid JSON now surfaces as a ZodError instead of a SyntaxError; the only consumer catches generically, so behavior is preserved. - tools/agents/hooks: keep `JSON.parse` + `safeParse` with a reasoned disable comment — hook scripts must stay dependency-light, and the `Json` helper lives in lib/util/schema-utils, which drags in the full lib import graph (logger, yaml, toml). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(lint): enforce zod-schema-location and prefer-json-pipe as errors Narrow `renovate/zod-schema-location` to files whose directory already contains a colocated `schema.ts`. The mined reviewer feedback ("move this to schema.ts") presumes the module follows that convention and the schema leaked into a logic file. Modules that deliberately export schemas from differently-named schema-only files — bazel `rules/*.ts` Target schemas, bazel-module `parser/fragments.ts` — are a different, accepted layout, not "schema mixed into logic", and are no longer flagged. With that narrowing and the preceding migrations, both rules are clean repo-wide, so promote them from "warn" to "error". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor: drop GithubIssue re-export from issue.ts Consumers now import the schema directly from schema.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(lint): register zod-schema-location rule The rule registration was lost while merging main, so oxlint failed to parse .oxlintrc.json with "Rule 'zod-schema-location' not found in plugin 'renovate'". Re-add the import and rules entry, and restore alphabetical ordering for prefer-json-pipe. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(lint): allow sync fs in zod-schema-location rule ESLint rules execute synchronously, so the sibling `schema.ts` lookup cannot use async fs. Silence `no-sync` with a justification. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
91e068f1fd |
test(linters): add linting rule to enforce v8 ignore reason declaration (#44726)
* ci(linter): add renovate/v8-ignore-reason rule
Flag coverage-ignore comments ("v8 ignore") that carry no justification.
Accepted forms: "-- reason" / "--- reason" (recommended) and the legacy
colon form "v8 ignore <kind>[ <count>]: reason", which is already
widespread in the codebase (29 sites). Bare "v8 ignore stop" markers are
exempt because the justification lives on the paired "start" marker. The
"v8 ignore next <N>" count form remains allowed; this rule only requires
a justification.
Registered as "warn" instead of "error": the repo currently has 119
reason-less v8 ignore comments, too many to fix mechanically in one PR,
so existing sites are left untouched and can be fixed incrementally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): promote renovate/v8-ignore-reason to error
Record the empirical verdict on the contested "v8 ignore next <N>" count
semantics in the rule doc: verified against vitest 4 with
ast-v8-to-istanbul that the count is not honored - the ignore hint always
exempts exactly the next AST node regardless of N. Counts are therefore
inert and stay allowed; the rule keeps requiring only a justification.
Promoting to error so all remaining reason-less coverage-ignore comments
must be fixed; the burndown follows in subsequent commits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 1)
Give every reason-less "v8 ignore" comment outside the large platform
index files a site-specific justification explaining why the exempted
branch is untestable or defensive, as now required by the
renovate/v8-ignore-reason rule.
Also guard against a nullish comment.loc in the rule itself; the
merged-in stricter tools typechecking flagged the unguarded access.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 2)
Cover the five large platform index files (github, bitbucket,
bitbucket-server, codecommit, gitlab) with site-specific reasons on
every "v8 ignore" comment, completing the renovate/v8-ignore-reason
burndown. Two meaningless ignore hints inside commented-out CodeCommit
mergePr code are dropped instead of annotated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* Apply suggestions from code review
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* Update lib/util/regex.ts
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
|
||
|
|
1e03699cd6 |
test: add linter for as LongCommitSha in test files (#44681)
* test: add linter for `as LongCommitSha` in test files Adds a custom oxlint rule `renovate/prefer-fake-sha-in-specs` that flags `as LongCommitSha` casts in spec files and suggests the deterministic `fakeSha()` helper from `test/util` instead. Enabled at error level for `**/*.spec.ts` and `test/**`; all 131 pre-existing casts across 22 spec files replaced. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Update lib/modules/platform/bitbucket-server/index.spec.ts --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
5ad36a2387 |
test(linters): add linting rule to enforce usage of host rules test util (#44692)
* ci(linter): add renovate/no-host-rules-mock rule Flags vi.mock()/vi.doMock() calls whose module specifier contains "host-rules" in spec files. Tests should configure real rules via hostRules.add() instead of mocking the host-rules module. Enabled at "warn" severity instead of "error": the repo currently has 35 pre-existing violations across 34 spec files, which exceeds the agreed fix threshold of 12 files. No violation fixes are included; migrating each spec to real hostRules.add()/clear() setup is a semantic test rewrite that should be done incrementally, after which the rule can be promoted to "error". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(linter): enforce renovate/no-host-rules-mock at error Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(datasource): use real host-rules instead of mocking Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(manager): use real host-rules instead of mocking Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(platform): use real host-rules instead of mocking Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(util,workers): use real host-rules instead of mocking Also narrow renovate/no-host-rules-mock to the host-rules module itself so that mocking e.g. host-rules-from-env is not flagged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(linter): mention '~test/host-rules.ts' util in no-host-rules-mock message Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4add67e86e |
test: add linter for as any in test files (#44658)
* ci(linter): add prefer-partial-in-specs oxlint rule
Flags object literals cast to `any` (`{...} as any`) in spec/test files and steers toward `partial<T>()` from `test/util`. Enabled at error in the spec-files override so CI blocks new occurrences.
Closes #44646
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: drop unnecessary object-literal `as any` casts
The casts masked values already assignable to the expected type (migration configs accepted as Record<string, unknown>, all-optional param types, etc.); removing them restores real type checking.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: replace object-literal `as any` casts with partial<T>()
Uses partial<T>() from test/util so incomplete mock/config objects keep proper typing. Azure API mocks switch to mockResolvedValue(partial<T>()) and their inner method mocks to mockResolvedValue(), matching the sibling-file idiom.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test: suppress prefer-partial-in-specs for intentionally-invalid inputs
Some tests deliberately pass malformed or legacy data to exercise validation/error paths, where no real type fits; keep the cast with a reasoned oxlint-disable-next-line.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
c41b46bac3 |
feat(logging): do not use dynamic fields in log messages with severity WARN or higher (#44560)
* ci(linter): add renovate/logger-static-message rule Adds a custom oxlint rule that enforces a static msg component for logger.warn/error/fatal calls (including logger.once variants) so the messages can be grouped in metrics and error catching services, per docs/development/best-practices.md. It also flags metadata properties named 'error' that hold error-ish values, because the bunyan serializer only handles the 'err' key. The rule is enabled as an error for lib/ production code and disabled for spec files. All 33 pre-existing violations are fixed by moving interpolated values into the metadata object, making messages static, and renaming 'error' metadata keys to 'err'. Affected log-message assertions in co-located specs are updated accordingly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci: ignore validator output * fixup new merged in log messages --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
00043d193e |
test(linters): add codeblock linter rule for spec fixtures (#44551)
* ci(linter): add renovate/codeblock-in-spec-fixtures rule Add a custom oxlint rule that requires the codeBlock (or stripIndent) template helper from common-tags for multi-line string fixtures in spec files (enabled for **/*.spec.ts and test/** only). The rule only flags shapes whose value can round-trip through the common-tags helpers unchanged, since both codeBlock and stripIndent trim the end result and strip the shortest line indentation: - only literals spanning multiple source lines are flagged (escaped \n one-liners are left alone: tagging them is not value-preserving in general and gains nothing) - values with leading/trailing whitespace (e.g. fixtures ending in a newline) are not flagged - tagged templates, describe/it titles, and inline snapshot arguments are skipped All 55 pre-existing violations (22 files) were fixed with a one-off codemod that re-emits each fixture indented to the statement depth and verifies value preservation by evaluating codeBlock on the rewritten template (substitutions kept as opaque placeholders). One site (pip_requirements/artifacts.spec.ts) mixes line continuations with escaped newlines and was tagged verbatim instead of re-indented. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(linter): address review findings Make getSimpleRequirementsFile in pip-compile/extract.spec.ts value-preserving again: tagging the whole template with codeBlock trimmed the trailing blank line when deps is empty (the headerOnly.txt case), silently changing the fixture from ending in '#\n\n' to '#'. Tag only the static header and append the deps section via a single-line template, which reproduces the original string exactly for both empty and non-empty deps (verified by executing old vs new in node). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
7436b80cda |
test(linter): add renovate/no-redundant-mock-reset rule (#44557)
ci(linter): add renovate/no-redundant-mock-reset rule Vitest sets mockReset: true globally in vitest.config.mts, which resets all mocks before each test. This makes vi.resetAllMocks() / vi.clearAllMocks() and per-mock .mockReset() / .mockClear() calls inside beforeEach/afterEach hooks redundant. Add a custom oxlint rule (enabled for **/*.spec.ts and test/**) flagging such calls, and remove the 40 redundant calls it found. restoreAllMocks/mockRestore are not flagged because restoreMocks is not enabled globally. Two sites keep an inline disable with a reason: nested beforeEach hooks in filter-checks.spec.ts and onboarding/pr/index.spec.ts intentionally call mockReset() to discard once-values queued by an outer beforeEach. Requested by maintainer review feedback (review comment 3052324877). Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
4176a3bc3a |
test(linter): add renovate/no-stateful-global-regex rule (#44566)
ci(linter): add renovate/no-stateful-global-regex rule
Flag module-scope const/let bindings initialized with a g- or y-flagged
regex (regex literal, regEx('...', 'g'), or regEx(/.../g)) that are
later used with .test() or .exec() in the same file. Such regexes are
stateful (lastIndex) and shared across calls, causing intermittent
match failures. Uses via matchAll()/replace()/split() are not flagged.
Fix the four pre-existing violations:
- gitea/forgejo utils: drop the pointless g flag from
reconfigurePrRegex, which made .test() alternate results.
- mix extract: convert module-scope exec() loops on g-flagged regexes
to matchAll().
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|
||
|
|
a31f9cf0f9 |
refactor(schemas): prefer Nullish schema utils instead of z.nullish() (#44565)
* ci(linter): add renovate/prefer-zod-nullish rule Add a custom oxlint rule that flags zod chains calling .optional() and .nullable() adjacently (in either order) and suggests .nullish(), which is equivalent (both accept undefined | null in zod v4). Fix all 26 pre-existing violations across 6 schema files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * ci(linter): prefer schema-utils Nullish over zod .nullish() Rename prefer-zod-nullish to prefer-nullish-util and extend it to flag .nullish() itself, including the standalone forms z.nullish(x) and z.optional(z.nullable(x)). Migrate all call sites to Nullish() and DeepNullish() from schema-utils, which normalize null to undefined in parsed output. Schemas with more than one nullish position are wrapped in DeepNullish(); nullish object properties with nullish members use Nullish(DeepNullish(...)) to keep the optional property type marker. Spec files are exempt (result.spec.ts intentionally tests null-preserving parses). Spec assertions expecting null in parsed output were updated to undefined. Note: docker manifests with an explicit "mediaType": null are now accepted and treated like an absent mediaType instead of failing the discriminated union. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e1e5c398e0 |
chore: ensure we use productLinks for docs site links where possible (#44066)
* chore: ensure we use `productLinks` for docs site links where possible Where possible, we should be making sure that we're using the `productLinks`' configuration for the documentation site, especially where self-hosted users may create a mirror of their docs[0]. To make sure we catch this in the future, we can introduce a custom linting rule with Oxlint to enforce this. Where we (currently) can't wire in the config, we can disable it against that line. [0]: https://www.jvt.me/posts/2024/11/19/renovate-private-docs/ Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io> * fixup! chore: ensure we use `productLinks` for docs site links where possible Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io> * fixup! chore: ensure we use `productLinks` for docs site links where possible Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io> --------- Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io> |
||
|
|
a2b1a4c585 |
ci(linter): detect schema suffixes even when using schema-utils (#43768)
* test(zod-schema): detect zod schemas helpers based on location in `schema-utils` * fix the findings |
||
|
|
914c64afbd |
test(linter): zod schema and infered type naming rule (#43736)
* ci: add linting rule for schema and infered types * refactor: remove usages of Schema and differently named types |
||
|
|
73b90e958b |
refactor: remove string concetation for production code (#43442)
refactor: prefer templates rather than `+` |
||
|
|
03baf6ee4a |
test(noNewURL): add new rule enforcing parseUrl() from 'lib/util/url.ts' (#43247)
* test(noNewURL): add new rule enforcing parseUrl() from 'lib/util/url.ts' * replace newURL with parseUrl * remove non-null assertions marks if appropiate * test: add additional tests * test: add additional tests and ignore where it makes sense * implement suggestions * test: further improve coverage * apply suggestion |
||
|
|
7df11ed734 |
chore(lint): add enforce-ts-extension oxlint rule (#42389)
* refactor(lint): extract custom oxlint rules into separate files Split `tools/lint/rules.js` into one file per rule under `tools/lint/rules/`. Also simplify `test-root-describe` with early-exit guard clauses. * feat(lint): add `enforce-ts-extension` oxlint rule Add a custom JS-based oxlint rule that enforces `.ts` extensions on local imports. The rule catches two problems: - `.js` extension used instead of `.ts` (auto-fixable) - missing file extension entirely (report only) Checked locations: - static import/export declarations - dynamic `import()` expressions - vitest module APIs: `vi.mock`, `vi.doMock`, `vi.unmock`, `vi.doUnmock`, `vi.importActual`, `vi.importMock` Both relative paths (`./`, `../`) and path aliases (`~test/`) are treated as local. Package imports are ignored. Also fixes 26 pre-existing violations across 18 spec files. * Update tools/lint/rules/enforce-ts-extension.js Co-authored-by: Anne Stellingwerf <1637358+astellingwerf@users.noreply.github.com> --------- Co-authored-by: Anne Stellingwerf <1637358+astellingwerf@users.noreply.github.com> |
||
|
|
a67a96eab5 |
refactor(lint): Switch to Oxlint (#42384)
* refactor(lint): Switch to Oxlint * Update .oxlintrc.json * Fix CI --------- Co-authored-by: Jamie Tanna <jamie.tanna@mend.io> |
||
|
|
1a05f1a39c |
refactor(lint): extract custom oxlint rules into separate files (#42388)
Split `tools/lint/rules.js` into one file per rule under `tools/lint/rules/`. Also simplify `test-root-describe` with early-exit guard clauses. |
||
|
|
3201eeedef |
refactor(lint): Switch custom rules from eslint to oxlint (#42212)
refactor: Switch custom rules from eslint to oxlint |
||
|
|
ee2c737d41 |
refactor: Drop more eslint plugins (#41740)
* refactor: replace @containerbase/eslint-plugin and eslint-plugin-import-x with local rules and biome The two containerbase ESLint rules (test-root-describe, no-tools-import) are now implemented locally in tools/lint/rules.js, removing the external dependency. All eslint-plugin-import-x rules are dropped: default, named, namespace, and no-cycle are already covered by oxlint; no-unresolved is covered by TypeScript; no-extraneous-dependencies is replaced by biome's noUndeclaredDependencies. * fix: exclude eslint.config.mjs from type-checking eslint-plugin-promise has no type declarations. Previously this was masked by @types/eslint pulled in transitively via eslint-plugin-import-x. The config file is not application code and gains nothing from type-checking. * refactor: drop eslint-plugin-promise, move covered rules to oxlint The promise rules target .then()/.catch() patterns which are rare in an async/await codebase. The 4 rules oxlint supports (catch-or-return, no-callback-in-promise, no-new-statics, valid-params) are moved there. * fix: prettier formatting after removing eslint-disable comment |