Commit Graph

115 Commits

Author SHA1 Message Date
Sebastian Poxhofer 05e1271376 test: use expect().resolves instead of awaiting inside expect (#45672)
Enables the vitest/prefer-expect-resolves oxlint rule and applies its
autofix across the spec suite.
2026-09-04 10:40:46 +00:00
Sebastian Poxhofer 300e3a616c test: shrink oversized fixtures to representative examples (#45666)
* test: reduce oversized expectation literals to representative examples

* test: shrink oversized fixtures instead of trimming assertions

Cut the real-world fixtures down to a representative set of entries that still covers every parser shape, and assert the complete output again with a single toEqual.
2026-09-04 10:40:45 +00:00
Sebastian Poxhofer 5a9c0852bf test(bundler): replace file snapshots with explicit assertions (#45657)
* test(bundler): replace file snapshots with explicit assertions

* test(bundler): replace inline snapshots with explicit assertions

* test(bundler): drop assertions implied by full equality

* test(bundler): address review feedback
2026-09-04 06:36:40 +00:00
Sebastian Poxhofer 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>
2026-09-03 09:54:40 +00:00
Sebastian Poxhofer 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>
2026-09-03 07:42:45 +00:00
Jamie Tanna b62fe59594 fix: remove references to "bot" (#39305)
We dropped the "bot" from our terminology long ago, but it looks like
we've got some outdated docs + code that reference it.

We should remove this to keep things consistent.

A `fix`, as we're changing the commit author's name, and log lines.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-09-02 08:56:20 +00:00
Sebastian Poxhofer 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()`.
2026-08-28 09:27:58 +00:00
Sebastian Poxhofer 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.
2026-08-28 09:26:20 +00:00
Jamie Tanna 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>
2026-08-26 13:02:26 +00:00
Jamie Tanna aa5d1e59a0 test(manager/bundler): add missing branch coverage in extract() (#45457)
The `else if (gitRefsMatch.repoName)` branch was unreachable, so we can
simplify this check.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-08-25 20:07:09 +00:00
Jamie Tanna 5b1749983c feat: always set CI=true for subprocesses
As noted in #43761, we had recently set `CI=true` for the Renovate and
Containerbase orgs on Mend-hosted apps due to a pnpm v11 requirement:

    ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY  Aborted removal of
      modules directory due to no TTY

    If you are running pnpm in CI, set the CI environment variable to
      "true", or set "confirmModulesPurge" to "false".

Similarly in #43606, it was noted that we should do this for `mise lock`
to mark the workspace as "trusted".

Although we went with a different situation, there will be cases where
this is useful for tools being executed, for instance when we invoke `yarn`.

We also make sure to keep our documentation up-to-date as we add to the
specific overrides.

With help from Claude Sonnet and Opus to:

- perform some of the mechanical updates as part of this change
- ensure that the Docker sidecar always has `hardcodedProcessEnv` passed
  into it
- catch a needed change to `exposeAllEnv` handling

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-08-24 17:21:24 +01:00
Sebastian Poxhofer 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>
2026-08-14 14:30:46 +00:00
Jamie Tanna b017c7548a fix(exec/docker): single-quote the sidecar bash command
When executing commands for `binarySource=docker`, we have two areas
that a command could have shell expansion/injection:

- on the host (when constructing the `bash -l -c`)
- in the container (when running a manager-specific command)

When constructing the host's command, we previously would escape the
`"`, which allows Bash syntax for `${VAR}` and `$(...)` syntax inside
it.

While managers use `quote()` to make the inputs safer, the use of `"`
around that would not provide any protection, and lead to cases where
the `quote()` could be expanded on the host, before `docker run`
executes.

After recent changes to each manager - and removal of `shell: true` -
this doesn't seem to be exploitable, but this hardens it further.

Additionally, we never escaped `\`, so a value containing `\"` produces
a command that `shlex.split` rejects, and the update fails rather than
running.

Instead, we can quote the whole `-c` argument with `quote()`, which
round-trips through both `shlex.split` - the default, no-shell path - and
a real shell.

This removes the `lgtm [js/incomplete-sanitization]` suppression as
we're now correctly sanitising this.

Note this doesn't remove the need for the managers to quote their own
values, as the second area above is still a real shell.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-08-07 14:25:42 +01:00
Jamie Tanna 5ffc308673 docs(manager): indicate where lockFileMaintenance runs external commands (#44914)
As found with recent changes to the Terraform manager, although we
generally have `lockFileMaintenance` being executed by an external
package manager being invoked by `exec(...)`, there are a few package
managers that do not do so.

To make it very clear how this happens, we can add a new field to the
Manager API, which will provide a means to document this.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-07-28 11:44:22 +00:00
Jamie Tanna 0e6429b13e refactor(types): document localDir isn't a globalOnly option (#44635)
* refactor(types): document `localDir` isn't a `globalOnly` option

To make sure that it's clear when reviewing `GlobalConfig`, as well as
working with our types, we can move the `localDir` definition into a
separate type.

* fixup! refactor(types): document `localDir` isn't a `globalOnly` option

* fixup! refactor(types): document `localDir` isn't a `globalOnly` option

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

* fixup! refactor(types): document `localDir` isn't a `globalOnly` option

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

* fixup! refactor(types): document `localDir` isn't a `globalOnly` option

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>

---------

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-07-20 08:07:17 +00:00
Sebastian Poxhofer 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>
2026-07-19 10:36:12 +00:00
Sebastian Poxhofer 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>
2026-07-17 10:47:30 +00:00
Sebastian Poxhofer e9c9c92e10 test(oxlint): enable vitest/consistent-test-it (#44554)
refactor(oxlint): enable vitest/consistent-test-it

Enforce `it` over `test` in spec files via
vitest/consistent-test-it (fn: "it"), matching repo convention.
Renamed all 52 pre-existing `test(`/`test.each` usages across
13 spec files to `it(`/`it.each` using oxlint --fix.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:28:52 +00:00
Sebastian Poxhofer 9717259ffc refactor(oxlint): enable no-else-return and unicorn/no-lonely-if (#44553)
Enable no-else-return (with allowElseIf: false) and unicorn/no-lonely-if
as errors in .oxlintrc.json and fix all 131 pre-existing violations
(91 no-else-return, 40 unicorn/no-lonely-if) across 98 files.

The no-else-return violations were fixed with the oxlint autofix
(iterated to a fixpoint, plus two else-if chains that required
--fix-dangerously) followed by Prettier formatting. One comment dropped
by the autofix in lib/modules/manager/pub/artifacts.ts was restored
manually. The unicorn/no-lonely-if violations were merged by hand,
preserving comments and coverage-ignore hints.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 12:11:21 +00:00
Sebastian Poxhofer 73b90e958b refactor: remove string concetation for production code (#43442)
refactor: prefer templates rather than `+`
2026-05-19 13:31:27 +00:00
Jamie Tanna 68cb7c71d5 test: ensure we set binarySource=global (#43382)
* test: ensure we set `binarySource=global`

As part of future changes, we'll correctly return the default value from
`GlobalConfig.get`, instead of `undefined` if no default is provided in
the `get` call.

As `binarySource=install` is the default, this then leads to these tests
failing, as they're intended to run with `binarySource=global`.

Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>

* fixup! test: ensure we set `binarySource=global`

* fixup! fixup! test: ensure we set `binarySource=global`

---------

Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
2026-05-15 15:40:22 +00:00
Jamie Tanna 2d1e57532f refactor(types): rename lockFile to fileName in ArtifactError (#41631)
As `fileName` makes more sense (as it's not always a lock file we're
updating).

Also, if you set `fileName`, it would never actually output the
filename.

This renames the usages of `lockFile` to `fileName`.

Co-authored-by: Claude Sonnet 4.5 <jamie.tanna+github-copilot@mend.io>
2026-03-10 09:57:31 +00:00
RahulGautamSingh d024075d00 refactor: add lock file names to manager api (#41133)
* feat(nuget): add supportsLockFileMaintenance flag

The NuGet manager supports lock file maintenance via `packages.lock.json`
but was missing the `supportsLockFileMaintenance` export.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat(manager): add lockFileNames metadata to all lock file managers

Add `lockFileNames` field to `ManagerApi` interface and export it from
all 24 managers that support lock file maintenance. This metadata will
be used to auto-generate the lock file support table in docs.

Also adds a validation test ensuring managers with
`supportsLockFileMaintenance` always provide `lockFileNames`.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 22:56:16 +00:00
Sergei Zharinov 9d857c1f68 refactor(lint): Organize imports with biome (#40966) 2026-02-06 13:40:01 +00:00
Michael Kriese cd0426babd feat(sidecar): use renovatebot/base-image instead of containerbase/sidecar (#40772)
* feat(sidecar): use `renovatebot/base-image` instead of `containerbase/sidecar`

* refactor: simplify sidecar handling

* test: fixup

* docs: fixup
2026-01-29 10:05:24 +00:00
Sergei Zharinov 930cf6633c refactor: Rewrite imports with .ts extensions (#40700)
fix: Additional vi.mock path corrections and prettier formatting
2026-01-26 22:48:17 +00:00
Jamie Tanna 39bfc0975e refactor(util/exec): remove deprecated encoding property (#40199)
This has been deprecated since 2022-07, and is unused as we only ever
use UTF-8.

In `tools/utils/exec.ts` we make sure to specify it explicitly, so we
don't get a Buffer returned.
2025-12-30 09:55:31 +00:00
RahulGautamSingh 76f911041a refactor: use named exports (#39196)
* use named exports

* fix test

* add missing imnport

* fix prettier
2025-11-10 12:00:35 +00:00
Sergei Zharinov 4a87850bbf fix(bundler): Strip platform suffixes from locked versions (#38170) 2025-09-23 07:03:40 +00:00
Sergei Zharinov 7c79c11285 fix: Always use default import from upath and semver-stable (#37325) 2025-08-05 11:01:45 +00:00
RahulGautamSingh bc7d0595d0 feat(config): managerFilePatterns (#34615)
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
Co-authored-by: Rhys Arkins <rhys@arkins.net>
2025-05-04 08:30:24 +00:00
RahulGautamSingh 80b7cdf1e0 refactor(util): move user env to util folder (#35103) 2025-04-02 10:27:27 +00:00
Sebastian Poxhofer c43be225f9 refactor: use isHttpUrl where possible (#34982) 2025-03-25 05:51:22 +00:00
Michael Kriese 19c115c813 test: cleanup (#34785) 2025-03-13 17:52:09 +00:00
Michael Kriese 4f60a8b7fe test: mock git globally (#34783) 2025-03-13 15:48:02 +00:00
Michael Kriese b9484f10ba fix: optimize type checks (#34654) 2025-03-06 11:46:35 +00:00
Michael Kriese 1644d9cb18 test: migrate more to vitest (#34500) 2025-02-26 15:45:17 +00:00
Trim21 6e5731b554 test: migrate from jest to vitest (#34499) 2025-02-26 14:18:38 +00:00
Michael Kriese 997c23502e test: migrate to vitest (#34475)
Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com>
2025-02-26 09:35:54 +00:00
renovate[bot] 55845508b6 chore(deps): update eslint monorepo to v9 (major) (#33573)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
2025-02-20 11:31:13 +00:00
RahulGautamSingh bc20797d06 fix(manager/bundler): drop strict flag (#33713) 2025-01-21 06:34:06 +00:00
lbarros-asml 0fae10626b fix(bundler): authentication using only env vars (#33339)
Co-authored-by: Leandro <grandinetti@gmail.com>
Co-authored-by: Rhys Arkins <rhys@arkins.net>
2025-01-08 10:03:03 +00:00
Julien Tanay f40c0351ad fix(bundler): fix inline source variable parsing (#32946) 2024-12-07 09:20:09 +00:00
Julien Tanay fd3184487a fix(bundler): gracefully ignore internal packages (#32923) 2024-12-05 16:05:47 +00:00
Julien Tanay 2f49607fec refactor(bundler): refactor extraction regexes (#32870) 2024-12-05 08:32:39 +00:00
Julien Tanay b9b38b3faf feat(bundler): add git refs support (#32362)
Co-authored-by: Rhys Arkins <rhys@arkins.net>
2024-12-03 10:32:06 +00:00
Risu 397ab49ef3 docs(managers): add missing url and displayName (#32621)
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
2024-12-01 08:47:27 +00:00
Julien Tanay 8e5262538c feat(bundler): add inline source support (#32600) 2024-11-20 05:38:50 +00:00
Julien Tanay a1c5150977 feat(bundler): add source variables support (#32337) 2024-11-15 10:40:22 +00:00
John Andrews 6560bedab8 fix(manager/bundler): Escape special characters in bundler usernames (#32229)
Co-authored-by: Rhys Arkins <rhys@arkins.net>
2024-10-31 13:25:21 +00:00