Commit Graph

2394 Commits

Author SHA1 Message Date
Jamie Tanna a5eb22bb2f fix(manager/maven-wrapper): correctly set Java version when handling a group
Similar to a fix already made for gradle-wrapper, this fixes an issue
with grouped dependencies leading to a wrong Java version, as
`config.currentValue` may be the version of an unrelated dependency in
the group rather than the version of maven itself.

We can instead look up the `maven` dependency's own `currentValue` in
`updatedDeps`.

This does change behaviour when only `maven-wrapper` (and not `maven`
itself) is being updated: previously `config.currentValue` happened to
hold the wrapper's own version in that single-upgrade case, which
mostly tracks the same major version as the actual Maven release.
Now, with no `maven` entry in `updatedDeps` to look up, this falls
back to the default Java constraint. This is deemed acceptable, as it
matches the same trade-off the gradle-wrapper fix already made.

Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-23 17:00:39 +01:00
Gregor Zeitlinger 0d9888a4f2 feat(datasource): add GraalVM version datasource (#40497)
* 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
2026-09-23 08:40:24 +00:00
Michael Munch 2e23302665 feat(manager/helmv3): support token-only registry logins (#46373)
🐛 fix(helmv3): support token-only registry logins
2026-09-22 21:48:36 +00:00
Kim Gustyr eee64df614 fix(workers/repository/extract): pass vulnerability alert state to managers (#46385)
* fix(extract): pass vulnerability alert state to managers

Managers cannot tell whether vulnerability remediation is active, so they
cannot decide to extract dependencies which are only useful to a security
update, e.g. transitive dependencies in a lock file.

Add `hasVulnerabilityAlertsRules` to `ExtractConfig`, derived from any
vulnerability source: `osvVulnerabilityAlerts`, or platform alerts, which
are turned into `isVulnerabilityAlert` package rules during init.

The flag is part of the extraction fingerprint, so cached extract results
are invalidated when it changes.

* refactor: drop redundant JSDoc on hasVulnerabilityAlertsRules

* docs(manager): document hasVulnerabilityAlertsRules on ExtractConfig

* fix(extract): omit hasVulnerabilityAlertsRules from fingerprint when false

Keeps the extract config hash unchanged for repositories which have no
vulnerability alerts, so they do not re-extract once on upgrade.
2026-09-22 17:43:43 +00:00
Jamie Tanna fd5e9f403b feat(manager/mise): support pypi backend (#46359)
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>
2026-09-22 12:06:07 +00:00
Sebastian Poxhofer 2169a5786f fix(manager): share one local Helm chart path check (#46181)
helmfile, flux, fleet and terraform each decided differently whether a Helm chart reference points at a local path. fleet and terraform used terraform's checkIfStringIsPath, whose regex was unanchored with unescaped dots, so it matched any string containing a slash followed by a non-slash character.

Add isLocalChartPath to helmv3/utils.ts with helmfile's prefix check and use it in all four managers. This drops the fleet to terraform dependency and removes checkIfStringIsPath, which had no other users.
2026-09-22 11:59:41 +00:00
Sebastian Poxhofer c8ce514ff3 refactor(manager/helmv3): share OCI registry login helper with helmfile (#46180)
Extract a shared generateRegistryLoginCmd(name, registry) helper in
helmv3/common.ts that strips the oci:// prefix, derives the host and
looks up the matching host rule before delegating to generateLoginCmd.

helmv3/artifacts.ts and helmfile/artifacts.ts now both call this
helper instead of each building a RepositoryRule inline, removing the
stale oci:// TODO. helmfile/utils.ts loses its duplicate
generateRegistryLoginCmd, and its unrelated isOCIRegistry(repository)
(checking the oci flag) is renamed to isOciRepositoryFlagSet so it no
longer collides in name with helmv3/oci.ts's prefix-based
isOCIRegistry(string), which helmfile/extract.ts also imports.

Addresses audit finding M8. Generated `helm registry login` commands
are unchanged, proved by the existing artifacts specs passing with
their original expectations untouched.
2026-09-22 11:59:41 +00:00
Sebastian Poxhofer 35f44f3137 fix(manager/helmv3): share generateHelmEnvs with kustomize (#46179)
refactor(manager/helmv3): share generateHelmEnvs with kustomize

Move kustomize's generateHelmEnvs into helmv3/common.ts and delete the
kustomize copy. The merged function always sets the three HELM_*
path variables and sets HELM_EXPERIMENTAL_OCI unless a helm
constraint is present and proves helm >= 3.8 (which ignores the
variable).

Behaviour change: kustomize now sets HELM_EXPERIMENTAL_OCI when the
helm constraint is unknown (previously it only set it for a known
constraint below 3.8). helmv3 and helmfile now omit the variable
once a resolved helm constraint proves helm >= 3.8.
2026-09-22 11:59:40 +00:00
Sebastian Poxhofer 0583e54718 refactor(constants): add a platform family capability table (#46191)
* refactor(constants): add a platform family capability table

Every consumer of `detectPlatform` carried its own mapping from the
detected platform to a tags datasource or a web UI path, and the seven
`*_API_USING_HOST_TYPES` arrays were checked one by one to produce that
platform in the first place.

Introduce `PLATFORM_FAMILIES`, one record keyed by family holding the
host types, the hostnames which identify the family outright, the tags
datasource, the API base URL derivation and the web UI path to a
directory at the default branch. A family is a group of platforms, so
the ids are checked against `PlatformId`: a family which is not a
platform is a compile error. Not every platform is a family, because
codecommit, gerrit, local and scm-manager are never recognized from a
URL.

`detectPlatform` loops the table for both its hostname and its hostType
matching, and the consumers look their answers up:

- `github-actions` and `pre-commit` read `tagsDatasource` instead of
  importing the tags datasource classes.
- The PR body reads `webDirPath` instead of special-casing Bitbucket and
  Bitbucket Server.

`apiBaseUrl` has no consumer yet; the changelog sources pick it up in
the next commit.

`lib/util/http/auth.ts` and `lib/util/http/host-rules.ts` still read six
of the old arrays by name, so those stay as aliases of the table and are
migrated in a follow-up. `AZURE_API_USING_HOST_TYPES` had no other
consumer and is dropped.

Behaviour changes: none. `detectPlatform` now tests every known hostname
before its name heuristics instead of interleaving the two, which is
equivalent because the hostname lists are pairwise disjoint and no known
hostname contains the name of another family.

* Apply suggestion from @secustor
2026-09-21 15:27:50 +00:00
Charles LESECQ 75647e2bd0 fix(manager/quadlet): make Image optional for volume (#44959) 2026-09-21 08:56:36 +00:00
Alex Sweet 87111d8141 fix(manager/gomod): match gofmt-style unindented closing paren in block end regex (#45781)
* fix(manager/gomod): match gofmt-style unindented closing paren in block end regex

gofmt places the closing ) of require/replace/exclude blocks at column 0,
but endBlockRegex required at least one leading whitespace character. This
caused inExcludeBlock to never reset after an exclude (...) block formatted
by gofmt, silently discarding every subsequent line in the file, including
all later require/replace blocks.

* fix(manager/gomod): correct test expectation for valid version

v0.17.3 is a valid version so no skipReason is set; the test incorrectly
asserted skipReason: 'invalid-version', copied from other fixtures using
the deliberately invalid v1.2 placeholder.
2026-09-21 08:54:34 +00:00
Sebastian Poxhofer e069399843 feat(manager/mise): support arrays of inline tables as tool versions (#46330) 2026-09-21 07:12:40 +00:00
renovate[bot] 84b8df81b6 docs: update references to python to be8ccd0 (main) (#46349)
docs: update references to python to be8ccd0

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-09-21 00:24:13 +00:00
Jamie Tanna 0253f4b23e fix(manager/dockerfile): don't attempt to update apk/apt for unknown image families (#46325)
If we don't discover the image family for a given image, instead of
suggesting a package update that may not exist - as we may look up a
`defaultRegistryUrls` entry that doesn't match the distro we're using -
we should not suggest any update.

In these cases, we can specify the `skipReason: unknown-registry`.

In #45706, we'll try and auto-detect this where possible.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-18 15:59:58 +00:00
fxwx23 8a378fc5b4 fix(manager/swift): don't rewrite Package.resolved pins in unrelated packages (#44317)
For exact (single-version) specs, only update a pin whose current version
matches the version being upgraded from. This prevents the repo-wide
Package.resolved sweep from rewriting a same-named transitive pin in an
unrelated package to a version that package's constraints don't allow.

Co-authored-by: Jamie Tanna <jamie.tanna@mend.io>
2026-09-18 11:02:17 +00:00
Sebastian Poxhofer 606b0b360a fix(manager): stop logging credential-bearing env and commands (#46129)
Two trace statements emitted registry credentials and relied on the secret
sanitizer alone to mask them:

- `pip-compile` logged the whole `extraEnv` object, which holds the
  `KEYRING_SERVICE_PASSWORD_n` values built from host rules.
- `helmv3` logged the generated `helm registry login` command, which
  carries `--password <password>`.

The sanitizer only registers secrets longer than three characters and
only those that went through `hostRules.add()`, so both lines could leak
a short or an externally sourced password.

`pip-compile` now logs the credential variable names alongside the command
and `helmv3` logs the target host only. Specs assert that neither logger
call receives the credential values.
2026-09-18 10:53:13 +00:00
Sebastian Poxhofer f0dd862bd5 fix(python): share PyPI index credential resolution (#46127)
* refactor(python): share PyPI index credential resolution

pipenv, poetry, uv, pip-compile and the pypi datasource each resolved
index credentials differently, so a host rule that worked for one Python
manager did not necessarily work for the next. Add
`findPypiIndexCredentials()` in `lib/modules/datasource/pypi/host-rules.ts`,
which strips the URL's own `user:password@` part, runs a `pypi`-scoped
`hostRules.find()`, and only falls back to Google Artifact Registry when
the matched rule has no username and no password. The repeated
`.pkg.dev` test moves into a single `isGoogleArtifactRegistry()`
predicate next to `getGoogleAuthHostRule()`.

Behaviour changes:

- pipenv now supports Google Artifact Registry; previously it only ever
  consulted host rules.
  Spec: manager/pipenv/artifacts > "passes Google Artifact Registry
  credential environment vars"
- pip-compile now supports Google Artifact Registry.
  Spec: manager/pip-compile/common > getRegistryCredVarsFromPackageFiles()
  > "supports Google Artifact Registry"
- pip-compile now matches `hostType: pypi` rules; its find call was
  unscoped, so such rules were skipped.
  Spec: manager/pip-compile/common > getRegistryCredVarsFromPackageFiles()
  > "ignores a rule scoped to another hostType"
- pip-compile now matches a `matchHost` that contains a path; it reduced
  every registry URL to its origin first, and `matchesHost()` compares
  with `href.startsWith()`, so a path-scoped rule could never match.
  Spec: manager/pip-compile/common > getRegistryCredVarsFromPackageFiles()
  > "matches a rule scoped to a path"
- poetry and uv now strip `${USER}:${PASS}@` style placeholders from the
  index URL before matching, so a `matchHost` can match those URLs too.
  Spec: datasource/pypi/host-rules > "strips credentials from the URL
  before matching"
- poetry now falls back to Google Artifact Registry when the matched rule
  carries no username or password; any non-empty rule used to suppress
  the fallback. Its dead unscoped `find({ url })` fallback is gone: a
  `pypi`-scoped find already matches every rule an unscoped one would.
  Spec: manager/poetry/artifacts > "falls back to Google auth when the
  matching rule has no credentials"
- the pypi datasource now prefers host rule credentials over the Google
  token for `*.pkg.dev`; it took the Google token unconditionally, and
  the resulting `authorization` header made `applyHostRule()` skip the
  configured credentials.
  Spec: datasource/pypi/index > getReleases > "prefers host rule
  credentials over Google Auth"

`getRegistryCredEnvVars()` also no longer logs the whole matched host
rule as the log merge object.

* test(pipenv): inline the Google Artifact Registry Pipfile

The fixture was used by a single spec case; inline it as requested in the
review of #46127.

* test(datasource/pypi): cover partial Google Artifact Registry credentials

A host rule that carries only a username or only a password still produces a
Basic header, but nothing exercised those two `?? ''` fallbacks, so the merge
queue failed the global branch threshold.
2026-09-18 10:53:11 +00:00
Sebastian Poxhofer 4220c0fe36 feat(manager): share the .npmrc host-rule wrapper between bun, deno and npm (#46131)
* refactor(manager): share the .npmrc host-rule wrapper between bun, deno and npm

Adds `withNpmrcHostRules()` to the npm manager utils: it injects the host-rule lines into a directory's `.npmrc`, runs the callback, and restores the original `.npmrc` from a `finally` block. bun, deno, the corepack `updateArtifacts()` and the three lock file loops in `post-update/index.ts` now share it instead of repeating getNpmrcContent / updateNpmrcContent / resetNpmrcContent.

Adds `readUpdatedBinaryLockFile()` to the shared manager utils for the `Buffer.compare` plus file-addition block that bun and deno both carried.

Behaviour changes:

- bun and deno now restore `.npmrc` when `exec()` throws. The reset previously ran only after a successful install, so a failed lock file update left the injected registry credentials in the working tree. Covered by "restores .npmrc when the install fails" in `bun/artifacts.spec.ts` and `deno/artifacts.spec.ts`.
- The npm, yarn and pnpm loops in `post-update/index.ts` now restore `.npmrc` when the loop body throws an `ExternalHostError`, for the same reason.
- deno reads `config.isLockFileMaintenance` instead of deriving the flag from `config.updateType === 'lockFileMaintenance'`. Grouped branches overwrite `updateType` while `isLockFileMaintenance` is set explicitly, so the flag is the reliable source. The deno specs were updated to set it.

* refactor(manager): let updateLockFile() compare binary lock files

A Buffer as the existing content makes the skeleton read, compare and
return the new lock file as bytes, so bun and deno use it instead of a
separate readUpdatedBinaryLockFile() helper.

* refactor(manager/devbox): update the lock file through updateLockFile()

devbox kept the same Buffer compare as bun and deno; the trace log before
returning the lock file goes away with it.

* fix(manager/devbox): type the command list explicitly

The list is now only read inside the run() closure, where TypeScript
cannot resolve an evolving array type, so tsc reported an implicit any.
2026-09-18 09:30:27 +00:00
Jamie Tanna 6add79a9a5 feat(manager/dockerfile): extract apt install packages from RUN instructions (#46247)
* feat(manager/dockerfile): extract `apt install` packages from `RUN` instructions

Similar to the support we've recently added for extracting `apk`
packages in `Dockerfile`s, we can also extract `apt install` and
`apt-get install`s.

We can build on top of our shared extraction layer, and:

- preserving an `:arch` qualifier when replacing the version
- skipping versions/constraints we can't update

Co-Authored-By: Claude Opus 5 <jamie.tanna+claude-code@mend.io>

* docs(manager/dockerfile): clarify where to find skipped logs

---------

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-18 08:25:59 +00:00
Jamie Tanna 56983c3fdb refactor(manager/dockerfile): share the RUN command parsing (#46299)
As part of future changes, we want to extract system package managers'
packages in `Dockerfile`s more generally.

Instead of an `apk`-specific file, we can introduce a shared file for
extracting commands from `RUN`s.

From here, it can then be used by `apk` and follow-up tools by providing
the `names` to look for.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-18 08:25:59 +00:00
Jamie Tanna 426bf15b26 feat(manager/dockerfile): update APK packages pinned with a fuzzy constraint (#45693)
In the Wolfi undistribution, which Chainguard Images are built upon,
it is common to use a fuzzy constraint rather than exact versions[0]:

    RUN apk update && apk add --no-cache libcurl-openssl4=~8.12.1
          curl=~8.12.1 make

which we previously skipped as `unsupported-version` when we started
extracting `apk add` packages.

As the `apk` version resolves these, we should extract the constraint as
the `currentValue`, and let the lookup evaluate it.

A constraint of `~8.12.1` matches every `8.12.1-rN` version, so we don't
need to update these constraints.

However, when the `newVersion` is i.e. `8.13.0-r0`, the constraint is
rewritten to `curl=~8.13.0`.

If using an exact pin, the version is upgraded with the same precision
i.e. `curl=8.12.1` -> `curl=8.13.0`.

We still skip constraints we can't handle with i.e. `contains-variable`
or `unsupported-version`.

[0]: https://github.com/elastic/crawler/blob/bc15328fb808affd00dff0cd92527bbe402f5ded/Dockerfile.wolfi#L7

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-18 07:06:55 +00:00
Tyler Gillson 2e1a079c7f feat(manager/helm-values): support version in sibling tag/version key (#46267)
Some charts define the image reference and its version as sibling keys
of the same object, with the parent key unrelated to the image name:

    cli:
      image: ghcr.io/fluxcd/flux-cli
      tag: v2.7.2

The walker previously extracted the `image` string via
matchesHelmValuesInlineImage but, without an embedded version, produced
a version-less dependency that could never be updated; the sibling
`tag`/`version` key was invisible because
matchesHelmValuesDockerHeuristic requires the keys to live inside an
object whose parent key ends in `image`.

When an inline reference carries no version and no digest, adopt a
sibling `tag` (preferred) or `version` string as the version, reusing
the same update mechanics as the repository/tag object form
(replaceString = version, docker versioning, `{{newValue}}` template).
Inline references with an embedded version or digest keep current
behavior, and repository/tag objects never reach the inline branch.

Discussion #46265 documents the layout with a real-world example.

Signed-off-by: Tyler Gillson <tyler.gillson@gmail.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-17 13:48:24 +00:00
Jamie Tanna 9b87f8de2f feat(manager/dockerfile): extract apk add packages from RUN instructions (#45691)
* feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions

As noted in #43711, users pin APK packages in their Dockerfiles and want
Renovate to update them, which so far has needed a custom manager[0].

Now that we have the `apk` datasource, we can extract these ourselves,
and parse the `RUN` instruction more effectively than a regex can.

We can do this by:

- extracting `apk add` dependencies when processing a `Dockerfile`
- ignoring common flags to `apk` before we extract the dependency names,
  which wasn't straightforward with a Custom Manager
- ignoring i.e. `--virtual .build-deps`
- handle example cases from [0] and other usages i.e. with a comment in
  between lines
- ensure that `final` doesn't run against the final `apk` install
- removing the docs for how to do this with a Custom Manager, as that
  complexity is no longer needed
- skipping `unspecified-version` and `contains-variable`

We inform the user that they will need to override the `registryUrls`,
as we already have a default on the `apk` datasource and can't override
it in a straightforward means.

[0]: https://www.jvt.me/posts/2025/03/24/renovate-regex-dockerfile-apk/

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

* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions

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

* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions

Co-Authored-By: Claude Opus 5 <jamie.tanna+claude-code@mend.io>

* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions

Find the command by name wherever it sits in the tokens, rather than
skipping an allowlist of shell keywords and variable assignments, so that
a wrapper program like `sudo`, `chroot /mnt` or `timeout 30` is handled
too.

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

* fixup! feat(manager/dockerfile): extract `apk add` packages from `RUN` instructions

---------

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-17 08:00:50 +00:00
Jamie Tanna a14607f7e4 test(manager/renovate-config): guard supportedPresetSources against drift (#46256)
In #46201, we found that although `forgejo>` support was added to
Shareable Config Presets, the `renovate-config` manager didn't actually
implement the lookup, meaning we didn't previously propose updates we
should have.

We can validate this is done by making sure that the `{platform}-tags`
datasource is used to look up a preset.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 15:31:57 +00:00
Skyler Mäntysaari 1f3b3a9d56 feat(manager/terragrunt): detect forgejo-tags datasource for git-tag sources (#46202)
feat(terragrunt): detect forgejo-tags datasource for git-tag sources

detectGitTagDatasource() in the terragrunt manager only handled
gitlab, bitbucket and gitea platforms, so Forgejo-hosted modules
(e.g. codeberg.org) fell through to the generic git-tags datasource
and lost release timestamps, sourceUrl and changelog data. Add a
'forgejo' case mapping to ForgejoTagsDatasource, mirroring the
existing pattern in the github-actions manager's detectDatasource().

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 13:15:37 +00:00
Sebastian Poxhofer 9fc451c44d refactor(manager): share the lock file updateArtifacts skeleton (#46093)
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>".
2026-09-16 13:13:42 +00:00
Sebastian Poxhofer bf5ff94d28 refactor(manager): build artifact results with the shared helpers (#46092)
Migrate apm, bun, cargo, cocoapods, composer, conan, copier, deno,
devbox, gomod, helmv3, jsonnet-bundler, kustomize, mix, nuget and vendir
onto `fileAddition()`, `artifactError()` and `artifactErrorResult()`.
copier's private `artifactError()` is replaced by the shared one.

Behaviour change: artifact error text now comes from
`artifactErrorMessageFromExecError` everywhere, i.e. a non-blank
`err.stderr`, else a non-blank `err.stdout`, else `err.message`.
Previously apm used `${err}` ("Error: " prefix), cocoapods used a
nullish coalesce that kept an empty stderr, nuget preferred stdout over
stderr, and jsonnet-bundler emitted an undefined stderr with no
fallback. The rest used `err.message` only and are unchanged for errors
without output.
2026-09-16 13:13:41 +00:00
Sebastian Poxhofer 296d92caaf refactor(manager): add shared artifact result and lock file helpers (#46091)
Add `fileAddition()`, `artifactError()`, `artifactErrorResult()` and an
`updateLockFile()` skeleton to `lib/modules/manager/util.ts`. The
skeleton rewrites the package file, optionally drops the lock file for
lock file maintenance, runs the manager's own command and returns the
lock file when its content changed.

No manager uses them yet; the adoptions follow in separate changes.
2026-09-16 13:13:41 +00:00
Sebastian Poxhofer 9defb36404 refactor(manager): share repo status to file change conversion (#46090)
Add `collectFileChanges()` next to the other repository helpers, plus a
thin `fileChangesToArtifactResults()` in `lib/modules/manager/util.ts`,
and migrate the managers which re-implemented the same status loops:
apm, cocoapods, composer, copier, gomod, helmv3, jsonnet-bundler,
kustomize and vendir.

Each site keeps its own status bucket selection and path filter, so the
emitted artifacts are unchanged. Two dead pieces of logic are dropped:
vendir's `vendorDir || isFileInVendorDir` condition, which was always
true, and kustomize's optional chaining on a non-nullable status, which
only ever mattered for an unset test mock (now set explicitly).
2026-09-16 13:13:40 +00:00
Jamie Tanna 9303449af1 fix(manager/github-actions): treat setup-beam's versions as ranges
While looking at the fix for `actions/setup-java`, we noticed that
`erlef/setup-beam` may also be affected, as it notes:

> values like `22.x`, or even `>22`, are also accepted, and we attempt
> to resolve them according to semantic versioning rules

As these fall back to `semver-coerced`, Renovate then raises a PR
rewriting the range into a full version, which isn't the intent.

We can use `npm` versioning for the Elixir, Gleam and rebar3
dependencies.

This deliberately leaves `otp-version` alone: Erlang/OTP releases
4-component versions (e.g. `26.2.5.3`) which aren't valid semver, so
`npm` versioning would discard those releases entirely. Resolving that
needs a versioning which handles both the 4-component versions and the
ranges, which is left as a follow-up.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 71f67417b7 fix(manager/github-actions): don't pin partial golangci-lint versions
While looking at the fix for `actions/setup-java`, we noticed that
`golangci/golangci-lint-action` may also be affected, as it notes for
its default `binary` install mode:

> the value can be v2.3, v2.3.4, or `latest` to use the latest version.

As the value falls back to `semver-coerced`, `v2.3` is treated as a
pinned version, so Renovate then raises a PR to bump to a full version,
which isn't the intent.

Unlike the other Actions looked at here, the partial versions are
`v`-prefixed, so we need to widen the partial-version check to allow
that. `semver-partial` versioning preserves the prefix, so `v2.5` is
bumped to `v2.6` rather than to a full `v2.6.0`.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna db9e8bc1a0 fix(manager/github-actions): don't pin partial install-crystal versions
While looking at the fix for `actions/setup-java`, we noticed that
`crystal-lang/install-crystal` may also be affected, as it notes for
both its `crystal` and `shards` inputs:

> Install a particular release of Crystal (if the full version is
> specified), or the latest patch version of a release series.

As these fall back to `semver-coerced`, a partial version such as `1.21`
is treated as a pinned version, so Renovate then raises a PR to bump to
a full version, which isn't the intent.

We can reuse the same `semver-partial` handling to keep the value's
precision.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 5a34d96074 fix(manager/github-actions): don't pin partial swift-versions
While looking at the fix for `actions/setup-java`, we noticed that
`swift-actions/setup-swift` may also be affected, as it notes:

> YAML interprets eg. 5.0 as a float, this action will then interpret
> that as 5 which will result in eg. Swift 5.5 being resolved.

As the value falls back to `semver-coerced`, a partial `swift-version`
is treated as a pinned version, so Renovate then raises a PR to bump to
a full version, which isn't the intent.

Unlike the other Actions looked at here, no ranges are documented, so
`semver-partial` versioning is enough to keep a partial version's
precision.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna e650960c18 fix(manager/github-actions): treat GitVersion's versionSpec as a range
While looking at the fix for `actions/setup-java`, we noticed that
`GitTools/actions/gitversion/setup` may also be affected, as it
documents `versionSpec` as:

> Required version in the form of 6.8.x or exact version like 6.0.0.

with its own examples using the `6.8.x` form throughout.

As the value falls back to `semver-coerced`, Renovate then raises a PR
rewriting `6.8.x` into a full version, which isn't the intent.

We can use `npm` versioning here too.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 88303b26b0 fix(manager/github-actions): treat flutter-version as a range
While looking at the fix for `actions/setup-java`, we noticed that
`subosito/flutter-action` may also be affected. It doesn't describe
`flutter-version` in prose, but its examples use x-ranges to pick the
latest release of a line:

> flutter-version: 1.22.x
> flutter-version: 3.x

As these fall back to `semver-coerced`, Renovate then raises a PR
rewriting `3.24.x` into a full version, which isn't the intent.

We can use `npm` versioning here too.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 231c3e617f fix(manager/github-actions): treat cmake-version as a range
While looking at the fix for `actions/setup-java`, we noticed that
`jwlawson/actions-setup-cmake` may also be affected, as it notes:

> This can be a fully specified verison `3.3.0`, partly specified `3.2`,
> a wildcard version `3.2.x`.

As the value falls back to `semver-coerced`, Renovate then raises a PR
rewriting `3.2.x` into a full version, which isn't the intent.

We can use `npm` versioning here too, which understands both the partly
specified and the wildcard forms.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 219c8f718e fix(manager/github-actions): treat Terraform/OpenTofu versions as constraints
While looking at the fix for `actions/setup-java`, we noticed that
`hashicorp/setup-terraform` and `opentofu/setup-opentofu` may also be
affected, as both note:

> Instead of a full version string, you can also specify a constraint
> string (see Semver Ranges for available range specifications).

As these fall back to `semver-coerced`, which coerces `~1.1.0` to
`1.1.0`, Renovate then raises a PR rewriting the constraint into a full
version, which isn't the intent.

We can use `npm` versioning, which handles the constraint strings the
Actions document, and leaves `latest` alone as a value we have no
version to bump it to.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 08d11825c8 fix(manager/github-actions): treat setup-julia's version as a range
While looking at the fix for `actions/setup-java`, we noticed that
`julia-actions/setup-julia` may also be affected, as it notes:

> Internally the action uses node's semver package to resolve version
> ranges.

Its documented values therefore include `1.0`, which "matches the
highest available version starting with that prefix", as well as
`^1.3.0-rc1` and `~1.3.0-rc1`.

As these fall back to `semver-coerced`, Renovate then raises a PR to
bump `1.10` to the full-precision tag `v1.11.7`, which isn't the intent.

We can instead use `npm` versioning, as we already do for
`goreleaser/goreleaser-action` and `j178/prek-action`.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna fe649335ce fix(manager/github-actions): treat dotnet-version as a range
While looking at the fix for `actions/setup-java`, we noticed that
`actions/setup-dotnet` may also be affected, as it notes:

> - **A.B** or **A.B.x** installs the latest patch version of .NET SDK
>   on the channel
> - **A** or **A.x** installs the latest minor version of the specified
>   major tag

alongside `A.B.Cxx` for "the latest version of the specific SDK release"
and `latest` for "the highest active .NET SDK version".

As these fall back to `semver-coerced`, which happily coerces `8.0.x` to
`8.0.0`, Renovate then raises a PR to bump to a full version such as
`9.0.100`, which isn't the intent.

Rather than the `semver-partial` versioning used for the other Actions,
here we can use `npm` versioning, which understands the x-range form
too, and safely rejects `8.0.4xx`/`latest` as values we have no version
to bump them to.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 71aa945494 fix(manager/github-actions): don't pin partial setup-dart SDK versions
While looking at the fix for `actions/setup-java`, we noticed that
`dart-lang/setup-dart` may also be affected, as it notes:

> An SDK release version - e.g. `2.19` or `3.1`. This will install the
> latest patch release for that specific release version.

As the `sdk` value falls back to `semver-coerced`, `3.5` is treated as a
pinned version, so Renovate then raises a PR to bump to a full version
such as `3.9.5`, which isn't the intent.

We can reuse the same `semver-partial` handling to keep the value's
precision.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna e0a77f8121 fix(manager/github-actions): don't pin partial ruby-versions
While looking at the fix for `actions/setup-java`, we noticed that the
`ruby/setup-ruby` may also be affected, as it notes:

> short version like '2.6', automatically using the latest release
> matching that version

As Ruby versioning treats `3.4` as a pinned version rather than a range,
we'd propose a patch upgrade rewriting it to `3.4.7`, losing the rolling
behaviour the workflow asked for.

We can reuse the `semver-partial` handling as a `partialValSchema`
helper, so short versions keep their precision and only exact versions
are looked up as pinned.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Jamie Tanna 967f480f6d fix(manager/github-actions): don't pin partial java-versions
As noted in #46249, `actions/setup-java` documents `java-version` as:

> Java version to install. Supports whole versions, semver ranges,
> early-access versions, and latest.

When the Java version is parsed using the versioning in
`workarounds:javaLTSVersions`, this leads to `11` looking older than
`11.0.32+101`, so Renovate then raises a PR to bump to a full version,
which isn't the intent.

Similar to the fix for mise in
5f5e58b822, we can use `semver-partial`
versioning for whole versions, so `11` stays `11` and only a new major
bumps it to `25`, and exempt `github-actions` from the preset rule that
would otherwise force the Java regex versioning back on.

The remaining documented forms (`21.x`, `>=21`, `21-ea`, `latest`) have
no version we could bump them to, so we skip them as
`unsupported-version` rather than mangling them.

`graalvm/setup-graalvm` reads the same datasource from its own
`java-version` input, so it gets the same treatment.

Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 14:14:43 +01:00
Sergei Zharinov 48006f8856 fix(datasource/typst): set cacheable explicitly (#46126) 2026-09-16 12:13:48 +00:00
Skyler Mäntysaari 2d4a77d932 feat(manager/renovate-config): support forgejo> preset references (#46201)
Add 'forgejo' to supportedPresetSources mapping to the forgejo-tags
datasource, so pinned forgejo> preset references (e.g.
"forgejo>org/repo#1.2.3") can be extracted and updated, matching the
existing support for gitea> presets.

Closes discussion #40153.

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 12:07:10 +00:00
Jamie Tanna 2b84f8c13d refactor(manager/github-actions): restructure directory for known-actions (#46248)
As noted in #46242, the `known-actions.ts` file was getting a bit big.

Where we have dynamic extractions, using `transform`, we split these
into a `<datasource>-dynamic.ts` file.

Where we have multiple packages extracted from the same Action, we use
`multiple.ts`.

Per suggestion from Sebastian, we can break this down by the datasource
used by the Action's inputs.

We can also try to enforce the structure of the directories by adding a
test in each file.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 11:40:35 +00:00
Jamie Tanna 6763ca2704 refactor(manager/github-actions): don't advertise an incorrect datasource for graalvm (#46250)
As the graalvm Action doesn't actually use the `datasource`, given it is
dynamic based on the dependencies extracted, we should note this more
clearly with a sentinel string.

We could alternatively make `datasource` optional, but given this is the
only case right now, this is simpler.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 11:40:34 +00:00
Jamie Tanna 809e56572c test(versioning/conda): clarify latest is a valid version (#46246)
As a follow-up to 4b5a64e6e1, we should
make sure that we document the fact that `latest` is a valid version to
Conda.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 10:57:16 +00:00
Jamie Tanna 4b5a64e6e1 fix(manager/github-actions): don't try and upgrade non-versions of Gradle (#46242)
As noted in #46241.

Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
2026-09-16 07:06:14 +00:00
Michael Kriese 1ea8602aaa test(manager): reach 100% branch coverage by closing the else-if chains (#46222)
* test(manager): cover twelve else-if branches

The trailing `else if` of a chain leaves v8 counting an implicit else
that no coverage-ignore hint can suppress. Fourteen of those were marked
as structurally unreachable, but only two of them actually are -- each of
these twelve has an input that takes it:

- `bazel`: an archive url whose file name is only a suffix, which strips
  to an empty value, so neither value nor digest is set
- `cargo`: a `[package]` section with no `version` at all
- `composer`: an inline `package` repository, which the discriminated
  union does carry, contrary to the comment that claimed otherwise
- `deps-edn`: an `:mvn/repos` entry whose spec is a plain string
- `gomod`: an update where only the `go` directive changed, leaving no
  additional dependencies to count
- `helmfile`: a release with an empty chart name, which is neither a
  local path nor an oci ref and yields an empty repo name
- `nuget`: a lock file that is gone after the restore
- `swift`: a comma where `from` expects a colon, and where `from:`
  expects a version -- both are labels the state machine searches for and
  then ignores
- `terraform`: a module source too short to be a registry module
- `tflint-plugin`: a quoted attribute that is neither version nor source
- `travis`: a matrix `node_js` that is a number

The stale comments go with them. Three more in `swift` were already
wrong before this change: the branches they described were covered.

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* refactor(manager): collapse two exhaustive else-if chains

`glasskube` and `gradle` were the only two of the fourteen trailing
`else if` branches that really are unreachable, and both are provable
from a type rather than from a reading of the surrounding code:

- `glasskube` parses resources with a schema that admits exactly
  `Package`, `ClusterPackage` and `PackageRepository`, and filters
  anything else out
- `gradle`'s `ContentDescriptorSpec.mode` is `'include' | 'exclude'`

Turning the final `else if` into a plain `else` drops the phantom branch
v8 was counting. With these, the manager tree reaches 100% branch
coverage. The glasskube check is inverted so that the single-literal
discriminant narrows for the compiler.

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(manager/travis): inline the numeric node_js fixture

The three-line fixture went into `__fixtures__` only because every other
fixture in this spec is loaded through `Fixtures.get`. A reader of the
test should be able to see the input without opening a second file, so
write it inline with `codeBlock`.

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>

---------

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-16 06:43:03 +00:00
Michael Kriese 312c380926 test(manager): cover the pre-commit warning switch and drop unreachable fallbacks (#46221)
* fix(util/http): make the legacy `headers` getter configurable

Every other property defined on `HttpError.prototype` in this file is
`configurable`, but `headers` was not. That makes the module fail with
`TypeError: Cannot redefine property: headers` whenever a test resets the
module registry and re-imports anything that pulls in `got.ts`.

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* test(manager/pre-commit): cover the suppress-warning env var

`defaultConfig.prBodyNotes` drops the unsupported-manager warning when
`RENOVATE_X_SUPPRESS_PRE_COMMIT_WARNING` is set. Since the value is
computed at module load, the new spec resets the module registry and
re-imports the manager with the variable stubbed.

The `istanbul ignore next` on that arm is dropped because the branch is
now exercised.

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>

* refactor(manager): remove unreachable fallbacks

Drop three defensive fallbacks that can never be taken:

- `docker-compose`: `config.services ?? config` always yields an object,
  so the `|| {}` guard behind it is dead
- `git-submodules`: `git.raw()` resolves to a string, so the `?? ''`
  never applies
- `maven`: the only site that builds a `MavenProp` always passes a
  `packageFile` string, so narrow the type and drop the `?? undefined`

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>

---------

Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
2026-09-16 06:43:02 +00:00