* feat(datasource): add GraalVM version datasource with support for JDK and JRE releases
* feat(datasource): add GraalVM version datasource with support for JDK and JRE releases
* feat(datasource): add GraalVM version datasource with support for JDK and JRE releases
* feat(datasource): add GraalVM version datasource with support for JDK and JRE releases
* feat(datasource): add GraalVM version datasource with support for JDK and JRE releases
* add coverage
* fix
* fix
* fix
* code cov
* code cov
* code cov
* refactor(datasource): integrate GraalVM into java-version datasource
Merges graalvm-version datasource into java-version as a unified multi-vendor
Java distribution datasource. Implements vendor-based modular architecture with
routing layer for Adoptium (Eclipse Temurin) and Oracle GraalVM.
Architecture:
- Vendor-specific handlers (adoptium.ts, graalvm.ts) with routing in index.ts
- Vendor-aware system detection with different arch/os mappings per vendor
- Custom registry support for GraalVM's mise-java API
- Adoptium remains the default registry for backwards compatibility
Package names:
- New explicit: adoptium-jdk, adoptium-jre, oracle-graalvm-jdk, oracle-graalvm-jre
- Legacy (map to Adoptium): java, java-jdk, java-jre
Changes:
- Created adoptium.ts and graalvm.ts vendor handlers
- Enhanced common.ts with vendor detection and vendor-specific system mappings
- Updated index.ts with routing layer and custom registry support
- Merged test suites with comprehensive coverage for both vendors
- Updated mise manager integration to use JavaVersionDatasource
- Removed graalvm-version datasource directory
All 65 datasource tests and 93 mise manager tests passing.
* fix
* test(datasource): add coverage for non-HttpError paths in java-version
* fix(datasource): remove dead code and add coverage for java-version
Remove unreachable HttpError handling from _getReleases catch block
since both getAdoptiumReleases and getGraalvmReleases handle HttpError
internally. Add test for the graalvmRegistryUrl fallback when
registryUrl is undefined.
* fix(datasource): address review comments for GraalVM datasource
- Remove unused 'datasource-graalvm-version' cache namespace
- Convert MiseJavaRelease interface to Zod schema and derive type from it
- Use http.getJson() with the Zod schema in getGraalvmReleases instead
of getJsonUnchecked, letting the schema handle invalid/empty responses
- Update getGraalvmReleases test mock to use getJson
* docs: remove unused datasource-graalvm-version from cacheTtlOverride docs
* fix(datasource): preserve Adoptium config typing
* fix(datasource): harden GraalVM release parsing
* fix(datasource): address GraalVM review feedback
* test: cover GraalVM mise package mapping
* test(datasource): cover default GraalVM registry fallback
* test(datasource): cover legacy registry resolution
* test(datasource): type legacy datasource mocks
* fix(datasource): harden GraalVM defaults and responses
* refactor(datasource): use function-only registry accessors
* test(datasource): cover registry accessor functions
* test: restore coverage exclusions
* chore: retrigger CI checks
As noted in #46343, upstream mise renamed a large number of `pipx`
registry entries to use the `pypi` backend instead, e.g. `ansible`
went from `pipx:ansible` to `pypi:ansible`.
As we didn't previously recognise `pypi` as a backend, we'd silently
stop updating those dependencies when we updated the mise registry
in #46343.
As the `pypi` uses the same tool syntax as `pipx`, we can share the
existing implementation.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
Migrate pub, gleam, helmfile, pixi, mise, poetry, pep621/pdm and
pep621/uv onto `updateLockFile()`, so each manager keeps only its
command and `ExecOptions` construction.
Behaviour changes:
- Artifact error text now comes from `artifactErrorMessageFromExecError`,
i.e. a non-blank `err.stderr`, else a non-blank `err.stdout`, else
`err.message`. Previously pixi used `${err}` ("Error: " prefix), mise
joined stdout, stderr and message, and poetry rendered
"<stdout>\n<stderr>" (literally "undefined\nundefined" when the error
carried neither).
- helmfile, pixi, poetry, pdm and uv now return null instead of an
addition when the lock file is missing or empty after the run, which
is what gleam and mise already did.
- Unchanged/missing lock file debug messages are now uniformly
"<lockFileName> is unchanged" / "No <lockFileName> found". pub gains
such a message, mise loses "Returning updated mise lock file" and
poetry loses "Returning updated <lockFileName>".
* 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.
* feat(manager/mise): support gitlab backend
Maps the mise `gitlab` backend (e.g. `gitlab:gitlab-org/cli`) to the gitlab-releases datasource, mirroring the github backend including version_prefix support.
* refactor(manager/mise): use optional instead of Nullish for tool options
TOML has no null type, so MiseToolOptions values are only ever a string or absent. .optional() models that exactly; Nullish only adds value for sources that can emit explicit null.
* fix(manager/mise): use RegExp.escape in gitlab backend
Main switched `createGithubToolConfig` from the `escapeRegExp` util to
`RegExp.escape` and dropped the import, which left the newly added
`createGitlabToolConfig` referencing an undefined symbol after the merge.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Michael Kriese <michael.kriese@mend.io>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
* feat(data): automatic update of static data
* test(manager/mise): drop stale cargo-backend registry test
The mise registry now lists a github mirror for magika alongside its
cargo backend, so a bare `magika` entry resolves via the
github-prioritised branch (already covered by the
'prioritising the github backend over others' test) instead of cargo.
No tool in the current registry data reaches the cargo case through
the unprefixed lookup path anymore, and the cargo backend itself
stays covered by the explicit `cargo:` prefix test.
---------
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: secustor <sebastian@poxhofer.at>
* 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>
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.
* 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()`.
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
* 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>
The `rust` tool was resolved via the `github-tags` datasource on
`rust-lang/rust` with the default (semver) versioning. That meant the
release channel values rustup actually accepts were not understood.
Switch all three managers to the `rust-version` datasource, which
declares `rust-release-channel` as its `defaultVersioning`, matching the
`rust-toolchain` manager and `lib/util/exec/containerbase.ts`.
`packageName` becomes `rust` rather than the `rust-lang/rust` owner/repo
slug, which is meaningless for this datasource. It is set rather than
omitted because mise would otherwise fall back to the backend-prefixed
depName, yielding `core:rust` / `asdf:rust` as the package name.
No explicit `versioning` is set: the datasource default already applies,
and the convention in these files is to set `versioning` only to
override a datasource default.
Behaviour change: `nightly-<date>` pins were previously skipped as
`invalid-value` and now update. `stable`, `beta` and `nightly` are now
recognised as ranges rather than flagged invalid, but still only resolve
to a concrete version under `rangeStrategy: pin`.
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>
* feat(manager/mise): set depType for tools and task tools
Allow packageRules to match mise deps via matchDepTypes:
- tools for top-level [tools]
- task-tools for tasks.*.tools
* test(manager/mise): override RUST_197 depType in task extract cases
* Make the task tool dynamic
* Restore formatting
* Restore another formatting
* feat(manager/mise): run mise lock in safe mode without allowedUnsafeExecutions
When `constraints.mise` pins a version that supports mise safe mode
(`MISE_SAFE=1`), run `mise lock` with safe mode enabled instead of
requiring `mise` in `allowedUnsafeExecutions`. Safe mode is a hard
boundary against project config executing code (templates exec/read_file,
_.source, hooks, tasks, asdf scripts, plugin installs are all refused),
so it — not the allowlist — protects the host.
The existing allowlisted path is unchanged: allowlisted repos run
`mise lock` exactly as before, without forcing safe mode, so configs
that legitimately execute code during locking keep working.
Safe mode also removes the need to pre-install node/npm/golang/ruby as
resolver tools, since npm version listing uses mise's built-in registry
HTTP client and go runs with GOTOOLCHAIN=local.
Refs: jdx/mise#11146 (safe mode), jdx/mise#11145 (lock --bump)
* fix: address oxlint and pin safe-mode min version to 2026.7.12
- logger.warn requires a static message with interpolated values in the
metadata object (oxlint rule); move the version into metadata
- set MISE_SAFE_MODE_MIN_VERSION to 2026.7.12, the expected first release
containing safe mode (merged after v2026.7.11)
* feat(manager/mise): use mise lock --bump for lock file maintenance
lockFileMaintenance means "update to the latest versions", but plain
`mise lock` only refreshes metadata for already-locked versions. Use
`mise lock --bump` so fuzzy selectors (e.g. node = "22") advance to the
latest matching version. `--bump` requires the same minimum mise version
as safe mode, so it is gated on the mise constraint and falls back to a
plain refresh otherwise.
Generalizes the version-gate helper (miseConstraintGuarantees) shared by
safe mode and --bump.
* refactor(manager/mise): detect mise version at runtime instead of via constraints
Determine safe-mode / --bump support by running `mise version` (which
does not load or execute project config) rather than requiring a pinned
`constraints.mise`. This works off whatever mise is actually installed,
so no extra configuration is needed.
The probe is skipped on the allowlisted, non-maintenance path, where the
version cannot change the outcome — keeping that hot path unchanged.
* feat(manager/mise): skip mise trust in safe mode
Safe mode now makes an untrusted config fully inert and no longer
requires trust to load it (jdx/mise#11151), so on the safe-mode path
`mise trust` is unnecessary and is skipped — `mise lock` runs with
`MISE_SAFE=1` alone. The allowlisted path is unchanged and still runs
`mise trust`.
* feat(manager/mise): confirm safe mode min version against v2026.7.12 release
MISE_SAFE=1 safe mode and `mise lock --bump` first shipped in mise
v2026.7.12 (released 2026-07-23), confirming the assumed
MISE_SAFE_MODE_MIN_VERSION. Resolve the pending-release TODO and align
the test version fixture with the real release date.
Validated end-to-end against the real v2026.7.12 binary: `mise version`
output matches the parser, `MISE_SAFE=1 mise lock` refreshes an untrusted
config without trust, `mise lock --bump` advances fuzzy selectors, and
project [env] is ignored under safe mode.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* test(manager/mise): cover mise version probe failure path
Add a test for the detectMiseVersion catch branch (exec throwing), so the
non-allowlisted path falls back to conservative behavior. Restores 100%
patch coverage for the mise manager.
* Update lib/modules/manager/mise/readme.md
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* Update lib/modules/manager/mise/readme.md
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* docs(mise): fix safe mode section link
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* 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>
* 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>
* 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>
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>
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>
* fix(manager/mise): install resolver tools during mise lock
When binarySource=install, Containerbase only installs tools listed in
toolConstraints. mise lock can invoke npm, go, and gem CLIs while
resolving versions for those backends, but Renovate previously only
installed mise itself.
* fix(manager/mise): use go constraint for golang resolver
* test(manager/mise): remove redundant resolver constraint test
* test(manager/mise): cover resolver tool dynamic installs
* test(manager/mise): cover unconstrained resolver lock updates
* Update lib/modules/manager/mise/artifacts.ts
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
* style(manager/mise): fix prettier whitespace in JSDoc comment
* test(manager/mise): clarify what happens with no `constraints`
* chore(manager/mise): update JsDoc
---------
Co-authored-by: Jamie Tanna <github@jamietanna.co.uk>
Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
mise tool versions are plain version strings (e.g. `"aqua:pnpm/pnpm" = "11.6.0"`)
with no syntax to attach a commit digest, so a digest can never be written to a
mise config file. Backends such as aqua and core resolve to the github-tags
datasource, which exposes `getDigest`, so a global `pinDigests: true` makes
Renovate emit `pinDigest` updates for mise tools. These updates produce no file
change and then fail post-update verification with "Digest is not updated" ->
"Error updating branch: update failure" on every run.
Disable digest pinning at the manager level, matching terraform, gomod, and the
other managers whose dependencies have no place to store a digest.
* chore: migrate from zod/v3 to zod/v4
This commit contains the logic changes
* chore: migrate imports from zod/v3 to zod/v4
This contains import updates and adds explicit record keys as zod/v4 requires these now
* ci: enforce usage of zod/v4
* 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>
As a way of indicating how fresh our list of supported tools in the
registry is, we can make sure we populate the version into a note above
the table.
We can extract a type to make it easier to reference the parsed JSON
file.
This requires a small tweak to handle `content`'s table insertion.
* refactor(docs): don't use an `end` for autogenerated docs
As part of #42910, we wanted to avoid needing a "begin" and "end" to
each of our autogenerated docs replacements.
While looking into it, we're not actually using the "end" for anything,
so we can instead refactor this to be a single-line replacement.
To simplify the code and docs, we can remove this. At the point we need
this again, we can re-add the functionality.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* fixup! Merge remote-tracking branch 'origin/HEAD' into chore/no-replaceStop
---------
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* feat(mise): automagically support all tools through Mise Registry
As noted in #42250, we should try and auto-support tools from Mise where
possible.
Similar to other areas of the codebase, we should use the "static data"
pattern, and periodically sync the `mise registry --json` output with
`lib/data/mise-registry.json`, and then auto-detect the tools that we
support through the known backends the tools support.
This takes lower precedence than existing in-code tool definitions, so
we can still provide an "override" if we can support lookups or version
extraction more appropriately.
Because we now have many more tools we (mostly) support out-of-the-box,
we need to provide an improved documentation page, and:
- only link to tools we have an explicit tools URL for
- note where a backend may not be supported
To automate the updating of this data, we:
- make sure we have `mise` in GitHub Actions, before we run
- don't pin the `mise` version to make sure that we're always seeing the
latest supported tools
- make sure the commits generated are now `feat(...)`, as they introduce
functionality changes (in the case new tool(s) are supported)
This improves support from ~170 tool short names to just over 1000.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* refactor: use Typescript
As we can now, we should.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* refactor(tools/static-data): use Zod schemas for parsing
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* refactor(mise): use Zod for types
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* chore(mise): prefer the GitHub backend over other sources
As we generally prefer it as a project, we should automagically use that
when looking at a mise registry entry.
With help from GPT-4.1 to write the `sortBackend` function.
Co-authored-by: gpt-4.1 <jamie.tanna+github-copilot@mend.io>
* test: ignore else coverage
* docs(mise): preference of `github` backend
* docs(mise): auto-link autogenerated tools
* perf(mise): sort registry only once
* refactor(mise): transform when parsing
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* refactor: use `execa`
* perf(mise): read the Mise registry once
* perf(mise): pre-transform
---------
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
Co-authored-by: gpt-4.1 <jamie.tanna+github-copilot@mend.io>
Co-authored-by: Sebastian Poxhofer <secustor@users.noreply.github.com>
* fix: preserve vendor prefixes in mise manager version updates
* test: cover kafka fallback path for 100% coverage
* test(mise): add failing tests for short java version versioning
Bare major versions like java = "21" or temurin-21 should use
semver-partial versioning to prevent invalid update proposals.
Full versions like "21.0.2" should keep the default versioning.
* fix(mise): use semver-partial versioning for short java versions
Short java versions (bare major like "21" or major.minor like "21.0")
now use semver-partial versioning, which treats them as ranges and
preserves precision in updates (e.g. "21" → "22" on major bump).
This replaces the replaceString/autoReplaceStringTemplate approach
with a versioning-based fix as suggested in discussion #41159.
Full versions (e.g. "21.0.2") keep the default semver-coerced
versioning unchanged.
* test(mise): remove unrelated kafka test
* refactor(mise): inline regex in shortJavaVersioning
* refactor(mise): return empty object instead of undefined
* refactor: use it.each to reduce duplication
* refactor: hardcode semver-partial in it.each test
* feat(mise): add support for github backend
* test(mise): remove redundant github backend test
* refactor(mise): flatten nested conditionals in github backend
* refactor(mise): only set extractVersion for custom version_prefix
* refactor(mise): use escapeRegExp and simplify extractVersion spread