* 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()`.
* 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>
* feat(deps): update ghcr.io/renovatebot/base-image docker tag to v13.84.0
| datasource | package | from | to |
| ---------- | ------------------------------ | ------- | ------- |
| docker | ghcr.io/renovatebot/base-image | 13.83.0 | 13.84.0 |
* feat(util/exec): add support for `gh` tool
As a prerequisite for #44753 and #45190, we need to support the `gh`
CLI.
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
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>
As noted in #43489, it's not currently possible to install the nightly
variant of Rust.
Although Containerbase does have support for `install-tool rust nightly`
it never gets that far, as the version lookup occurs through the
`docker` datasource.
We can instead make sure we move to the `rust-version` datasource and
its associated `rust-release-channel` versioning.
The result from the `rust-release-channel` returns a version like
`nightly-2026-06-19`, which needs extra handling in Containerbase.
We can also update **??** what supported Rust versions we'd accept.
* feat(mise): add lock file support
- Add lockfile.ts with getLockFileName() for deriving lock file paths
- Add artifacts.ts with updateArtifacts() and updateLockedDependency()
- Add MiseLockFile Zod schema for parsing lock files
- Update extract.ts to be async and extract lockedVersion from lock files
- Export supportsLockFileMaintenance, lockFileNames, updateArtifacts, updateLockedDependency
* refactor(mise): remove redundant comments
Remove comments that simply restate what the code already clearly
communicates. Keep valuable comments that explain non-obvious behavior
(e.g., why temporary errors are rethrown) and move helpful examples
into JSDoc comments.
* fix(mise): improve lock file version lookup and add tests
- Fix lock file key lookup for non-registry tools (aqua:, ubi:, etc.)
Registry tools use short names (node), non-registry use full names
(aqua:cli/cli). New getLockedVersion() tries both patterns.
- Add injection prevention test for shell quoting
- Add update-failed test for error handling
- Add comprehensive tests for getLockedVersion()
- Add null check for depName in updateLockedDependency
- Add JSDoc to updateArtifacts and extractPackageFile
- Add lock file support documentation to README
- Remove code duplication by consolidating into lockfile.ts
* fix(mise): pass --local flag and MISE_ENV for env/local config files
When updating mise.local.toml, `mise lock` updates mise.lock, not
mise.local.lock. Add --local flag to target the correct lock file.
For env-specific configs (mise.test.toml), set MISE_ENV=test so mise
reads and locks the correct configuration.
Extracted getConfigType() from getLockFileName() to share the parsing
logic between lock file name derivation and command flag generation.
Builds on #42099 by altendky.
* test(mise): cover tool absent from lock file
* refactor(mise): remove dead branches in extractPackageFile
tools is required by MiseFile schema so if(tools) is always true.
depName is always set by createDependency so if(dep.depName) is always true.
Add test for tool absent from lock file to cover the lockedVersion
assignment branch.
* fix(mise): address review feedback on lock file support
* fix(mise): remove unsupported tool constraint
* fix(mise): add containerbase tool definition
* fix(mise): add typed exec constraint support
* fix(config): restore requireConfig typing
* test(mise): await registry extraction cases
* Update lib/modules/manager/mise/artifacts.ts
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* fix: revert unrelated types cleanup
* fix: drop missing VersioningName import
* fix(mise): use npm versioning string after import removal
* test(mise): set binarySource=global in artifacts spec
GlobalConfig.get now returns defaults; without explicit binarySource the
test fell into containerbase dynamic install and tried to resolve the
mise version via the github-releases datasource, causing missing HTTP
mock errors. Force binarySource=global so the spec only exercises the
mocked exec path.
---------
Co-authored-by: Kyle Altendorf <sda@fstab.net>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
* feat(manager/renovate-config): extract `constraints`
As noted in #41571, it would be useful to detect and suggest updates
when specifying `constraints` in Renovate config, where it's a known
tool we provide versioning information for.
We can extend our existing `renovate-config` manager to add support for
`constraints` that are known Containerbase tools.
We can support top-level `constraints` as well as `constraints` inside
`packageRules`.
* refactor(renovate-config): remove nesting
* fix(validation): validate `constraints`
To provide better coverage for our users of what is a valid option for a
`constraints` value, we can validate the overall format of the
`constraints` block, as well as the given names of constraints.
Where we have a Tool defined, we can use the default versioning for that
Tool to validate the constraint's value.
For now, both the validation of the `constraints`' value, and the
validation of `constraints`' names will be a warning, but in the future
may be made an error.
* chore(validation): remove check for `compatibility`
As this was renamed in #7308. It's been long enough since then that we
can remove this check.
* chore(validation): add logger in `else` case
For coverage fix, and also to provide insight when this does happen
* fixup! chore(validation): add logger in `else` case
* fixup! chore(validation): add logger in `else` case
* key
* coverage
* Remove duplicate function
As it's been pulled in via another PR.
* fixup! docs(constraints): document the possible `constraints` and `installTools` (#42837)
As it can't be `undefined`.
* test: coverage
And more whitespace to make it clearer they're two separate `if` blocks.
* typo
* typo
---------
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
* docs(constraints): list the possible `constraints` and `installTools`
Now we have a stronger type for what a valid tool constraint is, and
what additional constraints are, we should be very explicit with what
each option is, and specify them in the `constraints` as well as our
`installTools` docs.
* test: add coverage
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>
* chore(types): add a strong type for `ToolName`s
Until #41849, we can use our local definitions of the tool names that
Containerbase supports by extracting out a `ToolName` type.
* fixup! chore(types): add a strong type for `ToolName`s
Co-authored-by: Claude Opus 4.6 <jamie.tanna+claude-code@mend.io>
Co-authored-by: gpt-4.1 <jamie.tanna+github-copilot@mend.io>
* fixup! fixup! chore(types): add a strong type for `ToolName`s
* no-never
* simplify
* coverage
* sq
* warn
* sq
* fixup! sq
* sq
* fixup! sq
---------
Co-authored-by: Claude Opus 4.6 <jamie.tanna+claude-code@mend.io>
Co-authored-by: gpt-4.1 <jamie.tanna+github-copilot@mend.io>
* feat(exec): register bazelisk as containerbase tool
* test(bazel-module): add failing tests for updateArtifacts
* feat(bazel-module): implement updateArtifacts for lockfile support
* feat(bazel-module): export updateArtifacts from manager index
* fix(bazel-module): address code review feedback
- Use logger.warn instead of debug for artifact errors
- Add utf8 encoding to readLocalFile calls
- Use getSiblingFileName for lockfile path derivation
- Add empty updatedDeps guard
- Strengthen test assertions
* docs(bazel-module): document lockfile support
* Update lib/modules/manager/bazel-module/index.ts
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* Apply suggestions from code review
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* fix(bazel-module): address review feedback
- Remove unnecessary afterEach in tests
- Use partial<StatusResult> for all StatusResult mocks
- Add lockfile maintenance support
- Export supportsLockFileMaintenance flag
* fix(bazel-module): handle untracked lock files and clarify docs
Check status.not_added alongside status.modified for lock file changes,
matching the pattern used by other managers (composer, gomod, etc.).
Clarify that Bazelisk (not Renovate) reads .bazelversion. Add test for
lockfile maintenance with no changes.
* feat(bazelisk): implement updateArtifacts for MODULE.bazel.lock
When the Bazel version in .bazelversion changes, run `bazel mod deps` to
regenerate MODULE.bazel.lock and return the updated lockfile as an artifact.
* feat(bazelisk): add lockfile maintenance support
* docs(bazelisk): add lockfile support section linking to bazel-module docs
* refactor(bazel-module): extract shared lockfile update helper
* refactor(bazel-module): delegate lockfile update to shared helper
Replace inline lockfile update logic in artifacts.ts with a call to the
shared updateBazelLockfile() helper, and update tests to mock the helper.
* refactor(bazelisk): delegate lockfile update to shared helper
Replace inline lockfile update logic in bazelisk/artifacts.ts with a
call to the shared updateBazelLockfile() helper from bazel-module/lockfile.ts.
* fix(bazelisk): use index.md for cross-manager docs link
The docs pipeline renames readme.md to index.md, so cross-manager
links must reference index.md to pass the docs link checker.
* feat(bazel-module,bazelisk): support bazelisk version constraint
Pass config.constraints.bazelisk through to toolConstraints so users
can pin the bazelisk version if the newest release is broken.
* fix(bazel-module): rename lockFile to fileName in ArtifactError
Upstream renamed lockFile to fileName in ArtifactError type (#41631).
---------
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
After recent changes to remove `shell: true`, it's clear from #40231
that this breaks Containerbase's installing of tools, as we use the
`hash` shell built-in.
As we no longer need the `hash` call, we can remove it.