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>
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>
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>
* 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>
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>
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>
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>".
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.
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.
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).
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
* 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>
* 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>
* test(manager): close helmfile, hermit, leiningen and mix gaps
Adds a leiningen vector whose version references a variable that was
never defined, which yields no dep.
Marks six guards. The mix host rules were already filtered on a match
host and on the same regex, hermit tracks its packages as symlinks, and
the remaining three need a repository the helm login helper cannot
handle, an umbrella parent lock file that reads cleanly, or a dep name
carrying no organization.
The helmfile repository chain stays counted: `repoName` is only left
null when an oci dep was set, so its implicit else cannot run, and a
coverage-ignore hint does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): mark the nuget, ocb and pep621 guards
Twelve guards, none of which a test reaches. A global.json without an
sdk version is rejected a few lines earlier, and the nuget registry loop
always finds at least one url. The rest need inputs no fixture provides:
a blank ContainerBaseImage, a package reference pinned to a non-semver
value, a registry url with no protocol version, a host rule carrying
only a username or only a password, and a pixi manifest declaring its
requirement only under workspace.
The nuget lock file chain stays counted, since a coverage-ignore hint
does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): mark the python and vendir guards
Ten guards across pip-compile, pipenv, pixi, poetry and vendir. A
compile command always records its arguments, every lock file of a
package file is already in the sorted list, a python dep always carries
a current value, a successful parse always yields a value, and the
vendir vendor dir is always set. The rest need credentials no fixture
supplies, a requirement naming an undeclared index, or a source url
outside artifact registry.
The travis node_js chain stays counted, since a coverage-ignore hint
does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): close the deps-edn, docker-compose and pep723 gaps
Three of the remaining manager branches turn out to be reachable after
all.
The deps-edn extractor skipped an `aliases` value that is not a map; the
existing test only covered an alias *entry* that is not a map, so the
outer guard was never taken. A modern docker-compose file with an `x-`
extension that carries no image never reached the schema's extension
filter either, because the only such fixture omitted `services` and so
parsed as a v1 file. A PEP 723 script block without `requires-python`
was likewise untested.
Co-Authored-By: Claude Opus 5 (1M context) <michael.kriese+claude-code@mend.io>
* test(manager/nuget): cover a global.json with no sdk version
The `v8 ignore else` on the sdk-version check claimed the guard above it
rejects any global.json without one. That guard is
`!manifest['msbuild-sdks'] && !manifest.sdk?.version`, so it rejects only
when both are missing — a file carrying just `msbuild-sdks` passes it and
takes the else.
Replace the ignore with a test for that shape, plus one for an empty
`{}` document, which the guard does reject.
Co-Authored-By: Claude Opus 5 (1M context) <michael.kriese+claude-code@mend.io>
---------
Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): close ansible-galaxy, bun and droneci gaps
Adds three extractions: a bun workspace glob that matches no file, a
workspace package file that cannot be read, and a drone image
continuation that is never terminated.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager/gradle): mark the gradle parser and extract guards
Nineteen guards across the gradle family, none of which a test reaches
without a build script contrived to defeat the parser. Most are variable
lookups and string interpolations that resolved to nothing; the rest
cover a catalog fallback already marked unreachable, a registry that is
already known, and a dep that did not default to the maven datasource a
line earlier.
The include/exclude mode chain stays counted, since a coverage-ignore
hint does not attach to an `else if`.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): close kustomize, jenkins and homebrew gaps
All five by test, no ignores. A kustomization declaring a local
component, a nameless image and a nameless helm chart yields none of
them, a jenkins plugin entry without an artifactId is skipped, and a
github archive url that is not a tar.gz keeps its suffix in the version
rather than having it trimmed.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager/maven): mark the maven extract and update guards
Fifteen guards across the maven family. Most check a field the extractor
always populates - a dep name, registry urls, a current value. The rest
cover a settings.xml carrying no registries, an array that is never
falsy, a regex whose groups are present because the line already
matched, and three update paths that a buildpack or snapshot bump always
satisfies.
One is left counted: the `propSource` fallback carries an
`istanbul ignore next` that covers the line but not the expression's
branch, and widening it would mean rewriting an existing hint.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager/droneci): write the fixture with codeBlock
The unterminated image fixture was assembled by joining an array of
strings, which hid the shape of the file behind quoting and escapes. It
is now a codeBlock literal laid out as the yaml it represents, with a
parent key so the indentation the extractor matches on survives the
dedent.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* test(manager): indent the kustomize and jenkins fixtures properly
The kustomize fixture sat flush with the statement and listed its
components, images and helm charts at the same indentation as their
keys. It is now indented one level inside the literal, with the list
items nested under the keys as yaml is normally written.
The jenkins fixture was an inline string with escaped newlines; it is
now a codeBlock literal laid out the same way.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
---------
Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
version has a default (latest), so real workflows commonly omit it
from with: entirely rather than passing an empty string.
Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
graalvm/graalvm-ce-builds still alternates between jdk- and graal-
prefixed tags for current-era releases, so extractVersion matches both
rather than jdk- alone.
Co-Authored-By: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>