* fix(prune): refresh PR state before autoclosing
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* refactor(platform): align getPr refresh param with bitbucket-server
Signed-off-by: Adam Setch <adam.setch@outlook.com>
---------
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* fix(github): rendered md alerts
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* fix(github): rendered md alerts
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* fix(github): rendered md alerts
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* refactor(pr): use `codeBlock` and address review feedback
- Use `codeBlock` template helper for Caution/Important PR body notes
- Drop the all-platform truncation notice text change (moved to separate PR)
- Remove GitHub truncation-notice test depending on the extracted change
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* remove extra space
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* fix(github): tolerate blockquote blank line whitespace in alert conversion
The emoji callout to GitHub alert syntax conversion relied on the blank
blockquote line being exactly '> ' (trailing space). Linters/CI strip
trailing whitespace from the emitted notes, so also accept '>' without
a trailing space.
* fix(dashboard): render abandoned-dependencies note as a GitHub alert
The '[!NOTE]' callout inside the abandoned-dependencies <details> block
never rendered: GitHub alerts only render at the top level of a body, not
inside collapsible sections, and the description text sat outside the
blockquote (no '> ' prefix), leaving the alert empty.
Move the note outside (above) the <details> block and keep the
description inside the blockquote with '> ' prefixes.
* Revert "fix(dashboard): render abandoned-dependencies note as a GitHub alert"
This reverts commit 55a5d9490e.
* incorporate feedback
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* update test case per feedback
Signed-off-by: Adam Setch <adam.setch@outlook.com>
---------
Signed-off-by: Adam Setch <adam.setch@outlook.com>
* refactor(util): one "read repo file at ref" helper per host
The "fetch a single file from a repository at a ref" logic was implemented
separately in the platform, preset and changelog layers for every host, and
`lib/config/presets` reached into `lib/modules/platform` to reuse the Gitea
client and its contents helper.
Add per-host util modules that own the URL shape, the response schema and the
decoding, taking the caller's own `Http` instance so the host type stays with
the calling layer:
- `lib/util/gitea/contents.ts` (shared by Gitea and Forgejo): the `RepoContents`
and `ContentsListResponse` schemas, `getRepoFile()` and `listRepoDir()`
- `lib/util/github/contents.ts`, `lib/util/gitlab/files.ts`,
`lib/util/bitbucket/files.ts`: `getRepoFile()`
Callers rewired: `getRawFile` for github/gitlab/bitbucket and the shared
Gitea/Forgejo platform, `fetchJSONFile` for the github/gitlab presets and the
shared Gitea/Forgejo preset source, and `getReleaseNotesMd` for the bitbucket
changelog source and the shared Gitea/Forgejo changelog source.
`getRepoContents` is gone from `gitea-helper.ts`, the contents schemas move out
of `platform/gitea/schema.ts`, and the Gitea and Forgejo preset sources build
their own `Http` instance instead of importing the platform's.
Behaviour changes:
- GitLab presets no longer look up the project's default branch before
fetching; they request `?ref=HEAD` like the platform already does, and they
use the JSON contents endpoint instead of `/raw`. This removes one HTTP
request per preset lookup.
- A GitHub contents response without a `content` field now surfaces as
`PRESET_DEP_NOT_FOUND` instead of an uncaught `TypeError`, because the
base64 decode moved inside the try block.
- GitLab `getRawFile` escapes the file name with `encodeURIComponent` instead
of only escaping `/`.
- Gitea/Forgejo contents URLs escape each path segment on its own, so a nested
path keeps its slashes: the platform `getRawFile` and the preset source now
request `contents/path/custom.json` where they used to request
`contents/path%2Fcustom.json`. Both spellings work; the unescaped one is the
documented form and the one the changelog source already used.
- The Gitea/Forgejo changelog source now escapes the segments of the source
directory and of the changelog file path, as the platform and preset callers
already did.
- The `Preset URL` trace log in the GitHub and GitLab presets is gone; the URL
is built inside the util helper.
Not covered here: Bitbucket Server (platform reads `browse`, changelog reads
`raw` - genuinely different endpoints) and the GitHub/GitLab changelog sources,
which use the git tree/blob APIs rather than a path lookup.
* refactor(platform): keep the repo-file helpers in the platform folders
The helpers landed under `lib/util/<host>/`, which added a second home for
host API code next to the platform modules that already own it. Move them
into the platform folder of their host instead, so there is one place per
host rather than two:
- `lib/util/github/contents.ts` -> `lib/modules/platform/github/contents.ts`
- `lib/util/gitlab/files.ts` -> `lib/modules/platform/gitlab/files.ts`
- `lib/util/bitbucket/files.ts` -> `lib/modules/platform/bitbucket/files.ts`
- `lib/util/gitea/contents.ts` -> `lib/modules/platform/gitea/contents.ts`
The preset and changelog layers import them from there, which is the
direction they already had: the preset sources read `gitea-helper.ts` and the
changelog sources read `platform/*/schema.ts`.
`RepoContents` and `ContentsListResponse` go back to `platform/gitea/schema.ts`
with their tests, because `renovate/zod-schema-location` keeps zod schemas
under `lib/modules/**` in a `schema.ts`. That is also where the changelog
sources read them from today.
The functions keep taking the caller's `Http` instance, so the host type and
its host rules still belong to the calling layer; only the file location
changes.
* refactor(presets): keep using the platform's Gitea and Forgejo clients
The preset sources were switched to `new GiteaHttp()` / `new ForgejoHttp()` to
keep `lib/config/presets` from importing `lib/modules/platform`. That boundary
is gone now that the contents helpers live in the platform folder, and the
second instance never bought anything: `giteaHttp` and `forgejoHttp` are
themselves plain `new GiteaHttp()` / `new ForgejoHttp()`, an `HttpBase` holds
only its host type and its merged default options, and `baseUrl` is module
state shared by every instance of the class rather than per-instance.
Both files are back to what they were, so the preset sources no longer appear
in this change at all.
* refactor(platform): resolve repo-file URLs against the client base url
`getRepoFile()` and `listRepoDir()` took an `apiBaseUrl` positional argument
that meant three different things depending on the caller: an empty string or
a slash for "use the client's own base", a path prefix for Gitea, and a full
API base URL for the preset and changelog layers.
`Http` already owns this: `resolveUrl()` reads `options.baseUrl ?? this.baseUrl`.
The helpers now build a URL relative to the API root and take no base of their
own, so callers reading the host their client is configured for pass nothing,
and callers reading a foreign host pass `baseUrl` in the options they already
pass.
The GitHub, GitLab and Bitbucket platform clients are based at the API root,
so those three call sites lose their placeholder argument outright. The Gitea
client is based at the web root and the rest of that folder prefixes every URL
with `API_PATH`, so the Gitea callers pass that same constant instead of the
duplicate `API_BASE_PATH` this stack had added next to it.
* test(platform): cover the client base url fallback for repo files
The GitHub and GitLab `getRepoFile()` specs always passed a `baseUrl` option,
so the fallback to the client's own base url - the path the platform callers
take now that they pass no base at all - was never exercised. Both specs get a
case that sets a self-hosted base url on the client and reads a file without
passing one, which also pins that a configured endpoint reaches the request.
The Bitbucket and Gitea specs already covered it.
* refactor(platform): name the repo-file helper files.ts on every platform
The helper was named after each vendor's own word for the endpoint:
GitHub and Gitea call it "contents", GitLab calls it "files" and
Bitbucket calls it "src", so the same helper sat under two different
names and neither matched Bitbucket.
Use files.ts everywhere, so a reader looking for "read a file from a
repo" finds the same filename in every platform folder. The vendor's
noun still appears where it belongs: in the request paths, the doc links
and the Gitea schema names.
fix(github): attempt direct merge before falling back to the merge queue
PR automerge against a merge-queue-protected base branch could no longer
merge directly when the authenticated actor is allowed to bypass the
queue: mergePr() enqueues the PR unconditionally once the base branch has
a merge queue, and the enqueuePullRequest mutation evaluates queue-entry
requirements (e.g. required code-owner review) without honoring ruleset
bypass, leaving bypass-enabled installs unable to merge at all.
Attempt the direct REST merge first and enqueue only when that merge is
refused, mirroring the try-first design #45724 shipped for branch
automerge. Repositories without a bypass actor pay one refused REST merge
call per automerge attempt before the queue fallback, and up to four when
an unrecognized refusal message triggers method guessing.
Docs: describe the direct-merge-first behavior in the GitHub merge queue
section of the automerge documentation.
* test: close remaining line coverage gaps
A full coverage run reported three uncovered lines:
- `rez` versioning: `rez2pep440()` was never called with a plain version,
because `getNewValue()` short-circuits via `matchVersionPrecision()`
whenever the new version is valid for npm. A four-component rez version
is not, so it reaches the pep440 path.
- `nuget` v3: only the inner nuspec 404 was covered, never a 404 escaping
from the `.nupkg` download into the outer catch.
- `github` platform: the statement after `await` in the GitHub App branch
is a v8/source-map false negative - it runs, but is counted zero. The
branch used to carry the `v8 ignore` comment, which moved away with the
`ghHostname` block in #44587.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* build: ratchet coverage thresholds
A full run now reports 100% statements (49776/49776), 100% lines
(49256/49256), 100% functions and 98.72% branches (25756/26089), so the
thresholds move up accordingly. Branches keep the same rounding-down
margin as before.
Co-Authored-By: Claude Opus 5 <michael.kriese+claude-code@mend.io>
---------
Co-authored-by: Claude Opus 5 <michael.kriese+claude-code@mend.io>
* feat(github): add experimental support for using merge queues without auto merge
* test(github): use vi.stubEnv for merge queue env flag
* fix(github): do not re-enqueue PRs already waiting in the merge queue
* refactor(github): reuse merge queue detection from #45252 for isBranchMergeQueueEnabled
* refactor(github): read the base branch from the PR instead of extending MergePRConfig
* feat(github): enable merge queue support without the RENOVATE_X_GITHUB_MERGE_QUEUE flag
* Apply suggestion from @secustor
* refactor(github): model GitHub hosts explicitly
* refactor(github): move `isGithubEnterpriseServer()` to utils
* test(github): cover version-gated features with unknown GHES version
We dropped the "bot" from our terminology long ago, but it looks like
we've got some outdated docs + code that reference it.
We should remove this to keep things consistent.
A `fix`, as we're changing the commit author's name, and log lines.
Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* fix(github): treat graphql_rate_limit as rate limiting
GitHub answers a spent app-installation budget with a GraphQL error carrying
code graphql_rate_limit, which neither call site recognised: the repository
query reported platform-unknown-error, and app authentication reported
Init: Authentication failure. Both readings send the user looking for a
problem that is not there, and neither is retried the way rate limiting is.
The two shapes are now recognised in one place and both call sites use it.
* fix(github): propagate GraphQL rate limits
* fix(github): preserve GraphQL response contract
---------
Co-authored-by: Sergei Zharinov <zharinov@users.noreply.github.com>
* 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()`.
* test: replace manual process.env mutation with vi.stubEnv
Enable Vitest's `unstubEnvs` so env stubs are reverted automatically
before every test, and convert the manual `process.env.X = ...` /
`delete process.env.X` pairs in specs to `vi.stubEnv()`.
This removes the hand-written `afterEach` cleanup blocks and the
`const OLD_ENV = process.env` / `process.env = { ...OLD_ENV }`
save-restore dance, which silently leaked state between tests when a
test set a variable without a matching delete.
Left as-is (incompatible with `unstubEnvs`, which unstubs before each
test, not after):
- module top-level env writes (cocoapods, gomod, post-update, pip-compile
and bundler artifacts specs)
- `beforeAll` env writes -- the two in `util/http` moved to `beforeEach`
* test: stop asserting on ambient environment variables
Three specs asserted on values that the surrounding environment can
override, so they only passed on a machine that happened not to set them:
- `util/exec/env`: `getChildProcessEnv()` forwards every entry of
`basicEnvVars`, but the spec only seeded a subset. Any other forwarded
variable that was set ambiently (e.g. a lowercase `http_proxy`) leaked
into the `toEqual` assertion. Clear all of them first.
- `util/git/index`: `process.env.GIT_SSH_COMMAND` deliberately overrides
the default that the two env-inheritance tests assert on. Clear it.
- `logger/pretty-stdout`: the colorized level strings are built at import
time, so the `beforeEach` setting `FORCE_COLOR` could never affect them
-- it was dead code, and the test silently assumed a terminal without
colour support. Derive the expectation the same way the module does.
* test(datasource/nuget): use a throwaway cache dir for nupkg downloads
The `determine source URL from nupkg` tests do not mock the filesystem,
so they really wrote downloaded packages into a fixed `/tmp/cache` path.
That fails wherever the system tmpdir is not writable, and two checkouts
running the suite at once would share the same directory.
Use `tmp.dir({ unsafeCleanup: true })` and clean it up afterwards, which
is the pattern the other specs that touch disk already use.
* feat(lint): add renovate/prefer-stub-env rule
Enforces in specs what the migration to `vi.stubEnv` established:
- assigning to or deleting `process.env.X` inside `beforeEach`, `afterEach`,
`it` or `test` is reported, with a fixer that rewrites it to `vi.stubEnv()`
- module scope, `describe` bodies and `beforeAll` / `afterAll` are left alone:
`unstubEnvs` reverts stubs *before* each test, so a stub created there is
gone by the time the first test runs, and those must keep assigning directly
- replacing the `process.env` object is reported everywhere and never fixed.
`vi.stubEnv()` captures the original object when the worker starts, so after
a reassignment its deletes silently target the old object
The rule found 28 further violations in specs the earlier sweep missed, since
that one was anchored on `delete process.env`. Twelve were auto-fixed; the
rest replaced `process.env` wholesale and are now `clearEnv()` from test/util.
`util/exec/index.spec.ts` opts out with a comment: it asserts on the whole
child env, and `vi.stubEnv()` cannot express that because it maps `PROD`,
`DEV` and `SSR` onto '' instead of deleting them.
* fix(github): recognize another "needs approving review" message
"response": {
"message": "Repository rule violations found\n\nNew changes require approval from someone other than the last pusher.\n\n",
"documentation_url": "https://docs.github.com/rest/pulls/pulls#merge-a-pull-request",
"status": "405"
}
* Add tests
* Include message in test 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>
* fix(platform/github): skip PR update when PR is in merge queue
Updating a PR that is queued for merging can remove it from the merge
queue. Check the PR's merge queue status via GraphQL before updating
and skip the update if it is queued. The check is skipped on GHES
<3.12.0 and fails open on errors.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(platform/github): dequeue PR from merge queue instead of skipping update
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* docs(platform/github): note re-queue behavior after dequeue
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(platform/github): dequeue merge queue PR in commitAndPush
Dequeue on push instead of on PR metadata update, since pushing to the
branch is what invalidates the queued merge result.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(platform/github): extract dequeuePr to pr.ts
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(platform/github): abort branch update when PR is in merge queue
Instead of dequeueing the PR, throw PR_ALREADY_IN_MERGE_QUEUE from
commitAndPush and handle it gracefully in processBranch.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(platform/github): check merge queue enablement per base branch
Cache merge queue enablement per base branch like branchForceRebase and
skip the per-PR merge queue check when the base branch has no merge
queue. Errors are treated as enabled.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(platform/github): fetch default branch merge queue status in initRepo
Include mergeQueue in repoInfoQuery so no extra query is needed for the
default branch, stripping it on GHES <3.12.0 like other unsupported
fields.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(github): include commitTrailers in platform-native commits
The GitHub platform-native commit path (platformCommit) recreates the
commit via the REST API using only message, so trailers from
commitTrailers / :gitSignOff were dropped even though prepareCommit
wrote them into the local commit.
* test: use codeBlock for multi-line commit trailer expectations
* Remove unnecessary comment
* refactor(gerrit): format commit message with shared helper
Use formatCommitMessage for Gerrit reserved trailers so the final
message is built the same way as the git and GitHub platform-native
paths, then clear trailers so prepareCommit does not append them twice.
* Revert "refactor(gerrit): format commit message with shared helper"
This reverts commit d230fa3802.
* refactor(git): fold commit trailers into the message before scm
Remove CommitFilesConfig.trailers so platforms only ever see a fully
formatted message. Workers call formatCommitMessage once; prepareCommit
and GitHub platform-native commits pass message through as-is. Gerrit
parses the existing trailer block to merge Renovate-Branch/Change-Id.
* refactor(git): drop formatCommitMessage helper
Trailers are already folded into message at the worker boundary, so the
shared formatter only re-joined strings. Inline that at the few call sites
and keep splitCommitMessage for Gerrit's reserved-trailer merge.
* revert: keep the minimal commitTrailers platform-native fix
Drop the later refactors (fold trailers into message, Gerrit changes,
splitCommitMessage). Keep formatCommitMessage shared by prepareCommit
and GitHub platform-native commits only; Gerrit is unchanged.
* feat(lint): add renovate/zod-schema-location and renovate/prefer-json-pipe rules
Backlog item #23: reviewers repeatedly ask for consistent Zod schema
structure. Two new oxlint JS-plugin rules, both at "warn":
- renovate/zod-schema-location flags `export const X = <zod schema>` at
module scope in lib/modules/**/ files that aren't schema.ts (or a
colocated schema/ directory), reusing the leftmost-identifier schema
detection from zod-schema-naming.js / prefer-nullish-util.js. Only
exported top-level schemas are flagged — non-exported ones are treated
as intentionally local/trivial (e.g. tightly coupled to file-local
helpers), which keeps the rule's signal high.
- renovate/prefer-json-pipe flags `Schema.parse(JSON.parse(x))` /
`Schema.safeParse(JSON.parse(x))` and suggests `Json.pipe(Schema)` from
lib/util/schema-utils instead.
A third mined slice (require a matching `z.infer` type export for every
exported schema) was evaluated and skipped: ~275+ exported schema-like
consts in schema.ts files vs. 231 existing z.infer exports repo-wide is
too high a mismatch to flag mechanically without heavy per-site
judgment, so it would be mostly false positives.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: fix a clean subset of renovate/zod-schema-location and renovate/prefer-json-pipe violations
renovate/prefer-json-pipe: fixed all 5 safe `.parse(JSON.parse(...))`
call sites (bazel datasource, generate-mise-registry script, a hook
spec) by switching to `Json.pipe(Schema).parse(...)`. Left the 2
`.safeParse(JSON.parse(...))` sites (pretooluse-check.ts,
github-query-items.ts) unfixed: JSON.parse throwing before safeParse is
reached today crashes the script, whereas Json.pipe folds the bad-JSON
case into a graceful `{ success: false }`, which is an observable
behavior change, not just a mechanical rewrite.
renovate/zod-schema-location: fixed the one clean, self-contained
violation (platform/github's GithubIssue schema, moved into the
already-existing platform/github/schema.ts) as a representative
example. Left the other 20: they require moving exported schemas out of
files where they're built from local helper functions/config tables
(manager/github-actions/community.ts) or restructuring an entire
directory into a new schema.ts with import-graph updates across many
files (manager/bazel/rules/*.ts, manager/bazel-module/parser/*.ts) —
real refactors needing per-site judgment, not mechanical fixes.
Both rules stay at "warn": renovate/prefer-json-pipe has 2 remaining
violations that shouldn't be auto-fixed, and renovate/zod-schema-location
has 20.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: resolve remaining prefer-json-pipe and zod-schema-location findings
- github-actions: move the derived `CommunityActions` union into the
existing colocated `schema.ts`; the action config table and the
`actionSchema` builder stay in `community.ts` and are now exported.
- tools/docs: fold `JSON.parse` + `safeParse`/rethrow of the `gh` CLI
output into `Json.pipe(...)`. Invalid JSON now surfaces as a ZodError
instead of a SyntaxError; the only consumer catches generically, so
behavior is preserved.
- tools/agents/hooks: keep `JSON.parse` + `safeParse` with a reasoned
disable comment — hook scripts must stay dependency-light, and the
`Json` helper lives in lib/util/schema-utils, which drags in the full
lib import graph (logger, yaml, toml).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* feat(lint): enforce zod-schema-location and prefer-json-pipe as errors
Narrow `renovate/zod-schema-location` to files whose directory already
contains a colocated `schema.ts`. The mined reviewer feedback ("move
this to schema.ts") presumes the module follows that convention and the
schema leaked into a logic file. Modules that deliberately export
schemas from differently-named schema-only files — bazel `rules/*.ts`
Target schemas, bazel-module `parser/fragments.ts` — are a different,
accepted layout, not "schema mixed into logic", and are no longer
flagged.
With that narrowing and the preceding migrations, both rules are clean
repo-wide, so promote them from "warn" to "error".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor: drop GithubIssue re-export from issue.ts
Consumers now import the schema directly from schema.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(lint): register zod-schema-location rule
The rule registration was lost while merging main, so oxlint failed to
parse .oxlintrc.json with "Rule 'zod-schema-location' not found in plugin
'renovate'". Re-add the import and rules entry, and restore alphabetical
ordering for prefer-json-pipe.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(lint): allow sync fs in zod-schema-location rule
ESLint rules execute synchronously, so the sibling `schema.ts` lookup
cannot use async fs. Silence `no-sync` with a justification.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): add renovate/v8-ignore-reason rule
Flag coverage-ignore comments ("v8 ignore") that carry no justification.
Accepted forms: "-- reason" / "--- reason" (recommended) and the legacy
colon form "v8 ignore <kind>[ <count>]: reason", which is already
widespread in the codebase (29 sites). Bare "v8 ignore stop" markers are
exempt because the justification lives on the paired "start" marker. The
"v8 ignore next <N>" count form remains allowed; this rule only requires
a justification.
Registered as "warn" instead of "error": the repo currently has 119
reason-less v8 ignore comments, too many to fix mechanically in one PR,
so existing sites are left untouched and can be fixed incrementally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): promote renovate/v8-ignore-reason to error
Record the empirical verdict on the contested "v8 ignore next <N>" count
semantics in the rule doc: verified against vitest 4 with
ast-v8-to-istanbul that the count is not honored - the ignore hint always
exempts exactly the next AST node regardless of N. Counts are therefore
inert and stay allowed; the rule keeps requiring only a justification.
Promoting to error so all remaining reason-less coverage-ignore comments
must be fixed; the burndown follows in subsequent commits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 1)
Give every reason-less "v8 ignore" comment outside the large platform
index files a site-specific justification explaining why the exempted
branch is untestable or defensive, as now required by the
renovate/v8-ignore-reason rule.
Also guard against a nullish comment.loc in the rule itself; the
merged-in stricter tools typechecking flagged the unguarded access.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 2)
Cover the five large platform index files (github, bitbucket,
bitbucket-server, codecommit, gitlab) with site-specific reasons on
every "v8 ignore" comment, completing the renovate/v8-ignore-reason
burndown. Two meaningless ignore hints inside commented-out CodeCommit
mergePr code are dropped instead of annotated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* Apply suggestions from code review
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* Update lib/util/regex.ts
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
* test: add linter for `as LongCommitSha` in test files
Adds a custom oxlint rule `renovate/prefer-fake-sha-in-specs` that flags
`as LongCommitSha` casts in spec files and suggests the deterministic
`fakeSha()` helper from `test/util` instead. Enabled at error level for
`**/*.spec.ts` and `test/**`; all 131 pre-existing casts across 22 spec
files replaced.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Update lib/modules/platform/bitbucket-server/index.spec.ts
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* refactor(oxlint): enable func-style
Enable the built-in func-style rule as ["warn", "declaration"] so that
named functions are written as function declarations instead of arrow or
function expressions assigned to variables, matching the convention in
docs/development/best-practices.md (Functions section). Inline arrow
callbacks are unaffected; prefer-arrow-callback continues to cover the
callback direction.
Severity is "warn" instead of "error" as a fallback: a repo-wide run
found 196 pre-existing violations (70 in spec files, 126 in production
code), exceeding the 80-violation fix threshold for this change, so no
violations were fixed here. Follow-up work can convert the offenders
(largest clusters: lib/modules/versioning/ruby, lib/util/cache/package,
lib/modules/versioning/maven, lib/modules/versioning/gradle) and then
raise the rule to "error". Note oxlint 1.72 also supports an
allowTypeAnnotation option if typed consts should remain arrows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): enforce func-style at error
* refactor(func-style): convert const-arrow functions to declarations in with-cache spec and ruby versioning
* refactor(func-style): convert const-arrow functions to declarations in maven/gradle modules
* refactor(func-style): convert const-arrow functions to declarations in remaining versioning modules
* refactor(func-style): convert const-arrow functions to declarations in platform modules
Discriminated-union closures (ensureCommentRemoval byTopic/byContent
helpers in github, gitlab, bitbucket, bitbucket-server) needed the
narrowed field passed explicitly as a parameter, since function
declarations are hoisted and lose the outer if-narrowing that inline
arrow-function closures previously relied on.
* refactor(func-style): convert const-arrow functions to declarations across util/manager/datasource modules
One case (logger/renovate-logger.ts logOnceFn) is kept as an arrow
function with a documented oxlint-disable: it is stored on
this.logger.once[level] and relies on lexically-bound this, which a
hoisted function declaration would not preserve.
* refactor(func-style): convert remaining const-arrow test helpers to declarations
get-updated.spec.ts: hoisted expectPipCompilePackageAndLockFile to
module scope (it only closes over the module-level pipCompile mock)
and added a documented oxlint-disable for vitest/expect-expect on its
caller test, since oxlint's expect-expect check does not trace
assertions through an externally-defined helper function.
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): add renovate/no-host-rules-mock rule
Flags vi.mock()/vi.doMock() calls whose module specifier contains
"host-rules" in spec files. Tests should configure real rules via
hostRules.add() instead of mocking the host-rules module.
Enabled at "warn" severity instead of "error": the repo currently has
35 pre-existing violations across 34 spec files, which exceeds the
agreed fix threshold of 12 files. No violation fixes are included;
migrating each spec to real hostRules.add()/clear() setup is a
semantic test rewrite that should be done incrementally, after which
the rule can be promoted to "error".
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): enforce renovate/no-host-rules-mock at error
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(datasource): use real host-rules instead of mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(manager): use real host-rules instead of mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(platform): use real host-rules instead of mocking
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* test(util,workers): use real host-rules instead of mocking
Also narrow renovate/no-host-rules-mock to the host-rules module itself so that mocking e.g. host-rules-from-env is not flagged.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): mention '~test/host-rules.ts' util in no-host-rules-mock message
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(config): make platformCommit global-only
* fix(git): reapply committer check for isBranchModified
Reapply #42975 (reverted in #43171): treat a different committer
(rebase/amend/Gerrit UI) as a branch modification.
* fix(git): ignore platformCommit committer from init-time list
Register noreply@${host} at GitHub initPlatform when platform commits
are active. isBranchModified only consumes the list — correct for
github.com, ghe.com, and self-hosted GHES.
Share isPlatformCommitEnabled() with GithubScm so commit path and
ignore-list registration use the same rule.
* refactor: stop threading platformCommit through commits
Decision is resolved once in GitHub initPlatform
(isPlatformCommitEnabled). Workers no longer pass the raw option on
CommitFilesConfig — it was unused after that change.
* refactor: simplify platformCommit / ignore-author wiring
Drop cached platformCommitEnabled flag — isPlatformCommitEnabled() is
a pure read of GlobalConfig + isGHApp. Trim redundant tests and
trace noise.
* Simplify env var setting
* revert: keep platformCommit packageRules-capable
Do not make platformCommit global-only. Restore CommitFilesConfig
threading and GithubScm reading commitConfig.platformCommit so rules
can still set platformCommit per package (see #44585 discussion).
* fix(github): always ignore platformCommit noreply committer
Do not gate noreply@host on isPlatformCommitEnabled (that needed
global platformCommit). Always register host noreply at init so
packageRules can still flip platformCommit per commit while
isBranchModified stays correct.
Remove isPlatformCommitEnabled; GithubScm again uses
commitConfig.platformCommit.
* Simplify some stuff
* Add one assertion
* Change some comments
Enable the unicorn/prefer-at rule as error in .oxlintrc.json and fix all
43 pre-existing violations (arr[arr.length - 1] -> arr.at(-1)) via oxlint
autofix. Where .at() widened the type to T | undefined, non-null
assertions were added at sites where surrounding logic guarantees the
element exists (length guards, split results), preserving the original
runtime behavior and typing.
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/prefer-zod-nullish rule
Add a custom oxlint rule that flags zod chains calling .optional() and
.nullable() adjacently (in either order) and suggests .nullish(), which
is equivalent (both accept undefined | null in zod v4).
Fix all 26 pre-existing violations across 6 schema files.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): prefer schema-utils Nullish over zod .nullish()
Rename prefer-zod-nullish to prefer-nullish-util and extend it to flag
.nullish() itself, including the standalone forms z.nullish(x) and
z.optional(z.nullable(x)). Migrate all call sites to Nullish() and
DeepNullish() from schema-utils, which normalize null to undefined in
parsed output. Schemas with more than one nullish position are wrapped
in DeepNullish(); nullish object properties with nullish members use
Nullish(DeepNullish(...)) to keep the optional property type marker.
Spec files are exempt (result.spec.ts intentionally tests
null-preserving parses). Spec assertions expecting null in parsed
output were updated to undefined. Note: docker manifests with an
explicit "mediaType": null are now accepted and treated like an absent
mediaType instead of failing the discriminated union.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
As a follow-up to e1e5c398e0, we can make
sure that we remove references to hardcoded docs site URLs, by wiring in
the `GlobalConfig.get(...)` call.
To do this, we need to make sure that `productLinks` exists to be called
by `GlobalConfig.get`.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* chore: ensure we use `productLinks` for docs site links where possible
Where possible, we should be making sure that we're using the
`productLinks`' configuration for the documentation site, especially
where self-hosted users may create a mirror of their docs[0].
To make sure we catch this in the future, we can introduce a custom
linting rule with Oxlint to enforce this.
Where we (currently) can't wire in the config, we can disable it against
that line.
[0]: https://www.jvt.me/posts/2024/11/19/renovate-private-docs/
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* fixup! chore: ensure we use `productLinks` for docs site links where possible
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* fixup! chore: ensure we use `productLinks` for docs site links where possible
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
---------
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* feat(git): validate length commit shas
* test: adapt test mocks
* chore: update import paths
* feat(git): make the validation more strict and support repositories using sha256
* test: add fakeSha function for deterministic git commit shas in tests
* fix(github): use base_tree in pushFiles to avoid org ruleset file-path restrictions (#42554)
pushFiles sent the entire repo tree to POST /git/trees without base_tree.
GitHub validates all file paths against org rulesets, rejecting the tree
when it contains protected files (e.g. semgrep.yaml) — even if Renovate
only changed unrelated paths.
Use base_tree (parent commit's tree) with only the changed files from
git diff-tree, so unchanged protected files are inherited without
validation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(git): add coverage for getCommitTreeSha and diffCommitTree
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(test): assert specific files instead of hardcoding diff count
The test fixture creates 2 known files between develop and
defaultBranch (master_file, file_to_delete), but CI produces 3
changed files — likely a .gitattributes from the CI environment.
Assert on the known files rather than the total count.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(git): handle renames, copies, and submodules in diffCommitTree
- Regex now matches multi-char status codes (R100, C100) and
tab-separated source/target paths for renames and copies.
- Renames emit a deletion for the source path + addition for target.
- Derive tree item type from mode: 160000→commit, 040000→tree,
otherwise blob.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(git): address review comments in diffCommitTree
Keep git utility types centralized and make diff status handling easier to follow.
Made-with: Cursor
* test(git): cover rename handling in diffCommitTree
Verify that renamed files are emitted as a deletion for the old path and an addition for the new path, matching the tree delta expected by GitHub.
Made-with: Cursor
* fix(git): validate parsed tree SHA
Fail fast when commit output cannot be parsed into a tree SHA so pushFiles does not propagate an invalid base_tree, and cover the failure path in tests.
Made-with: Cursor
* fix(git): enable rename detection and cover remaining diffCommitTree branches
Add -M to diff-tree so Git emits R status for renames, exercising the
existing case 'R' handler. Add focused tests for rename parsing,
submodule mode (160000), and tree mode (040000).
Made-with: Cursor
* fix(git): clarify copy vs rename comment in diffCommitTree
R uses both tab-separated paths (delete old + add new), while C falls
through to default where only the target path matters.
Made-with: Cursor
* refactor(git): remove dead listCommitTree and TreeItem
Nothing imports listCommitTree after the switch to diffCommitTree with
base_tree. Remove the function, its regex, its test, and the TreeItem
interface.
Made-with: Cursor
* refactor(git): tighten DiffTreeItem.type to GitObjectType union
Define GitObjectType = 'blob' | 'tree' | 'commit' and use it in
DiffTreeItem and treeTypeFromMode instead of plain string.
Made-with: Cursor
* fix(git): remove unreachable nullish coalescing in getCommitTreeSha
split()[0] on a non-empty string is always defined, so the ?? ''
fallback was unreachable and caused an uncovered branch in Codecov.
Made-with: Cursor
* fix(git): add v8 ignore for partial branch on throw template literal
v8 reports template literal interpolations inside throw as partial
branch coverage even when the line is tested. Use the established
v8 ignore pattern to suppress the false positive.
Made-with: Cursor
* fix(github): guard pushFiles against empty diff from diffCommitTree
GitHub's POST /git/trees rejects an empty tree array with 422
"Invalid tree info". While prepareCommit already prevents no-op
commits from reaching pushFiles, add a defensive early return so
the failure mode is a clear log message instead of a swallowed 422.
Made-with: Cursor
* docs(github): document hybrid git/REST commit strategy in pushFiles
Restore architectural knowledge from PRs #13824 and #14271 that was
lost when the old "for reasons unknown" comments were replaced. The
push-then-recreate pattern exists because custom refs avoid CI triggers,
REST-created commits get GitHub signing, and GraphQL lacks force-push
and file mode support.
Made-with: Cursor
* fix(git): wrap bare regex literals in regEx() in tests
Use the project's regEx() helper instead of bare /pattern/ in
toMatch and stringMatching calls, consistent with repo conventions.
Made-with: Cursor
* fix(git): revert regEx() in expect.stringMatching (only accepts bare RegExp)
expect.stringMatching() is a Vitest/Jest API that requires a native
RegExp, not the wrapped object from Renovate's regEx() helper.
Made-with: Cursor
* fix(git): drop line count from v8 ignore next
Vitest uses ast-v8-to-istanbul which is AST-aware: it ignores the
entire next AST node (here the whole throw statement), making the
line count unnecessary.
Made-with: Cursor
* refactor(git): replace magic mode strings with GitTreeMode enum
Introduce a documented GitTreeMode enum in types.ts and use it in
treeTypeFromMode, replacing raw '160000'/'040000' literals with named
members linked to the git data model documentation.
Made-with: Cursor
* fix(git): use const object instead of enum for GitTreeMode
Node's TypeScript strip-only mode does not support enum syntax.
Use `as const` object pattern consistent with the rest of the codebase.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(config): add github to gitUrl supportedPlatforms
Declare GitHub as a supported platform for the gitUrl option so users
can configure ssh/endpoint URL resolution on github.com and GHES.
Wiring in the github platform module follows in subsequent commits.
Refs: renovatebot/renovate#43086
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(platform/github): fetch sshUrl from repoInfoQuery
Add sshUrl to the GraphQL repository query and to the GhRepo type so
the platform can resolve SSH-based git remotes. Typed as nullable
to match the gitlab pattern and to allow a missing-field error path.
Refs: renovatebot/renovate#43086
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(platform/github): add getRepoUrl helper
Introduce a getRepoUrl helper that returns the repository git URL based
on the gitUrl option:
- 'ssh' uses the sshUrl from the GraphQL repo response; throws
CONFIG_GIT_URL_UNAVAILABLE if not available
- 'default' and 'endpoint' build an https URL from the configured
endpoint with credentials embedded (current behavior)
The helper is unused in this commit; initRepo wiring follows.
Refs: renovatebot/renovate#43086
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* feat(platform/github): support gitUrl in initRepo
Destructure gitUrl from RepoParams and replace the inline URL
construction with getRepoUrl calls. The working URL uses the fork's
ssh_url when running in fork mode, otherwise the GraphQL repo.sshUrl.
The upstream URL (used when forkCreation and a parentRepo is set)
uses repo.sshUrl, which is the parent's URL because the GraphQL
query runs before the fork swap.
GhRestRepo gains an ssh_url field so findFork/createFork responses
can carry the fork's SSH URL forward.
Refs: renovatebot/renovate#43086
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* test(platform/github): cover gitUrl branches
Add unit tests for getRepoUrl in utils.spec.ts and three integration
tests in index.spec.ts that exercise initRepo with gitUrl=ssh:
- ssh URL is forwarded to git.initRepo
- missing sshUrl with gitUrl=ssh throws CONFIG_GIT_URL_UNAVAILABLE
- fork mode uses the fork's ssh_url for url and the parent's sshUrl
for upstreamUrl
initRepoMock and forkInitRepoMock now include sshUrl in the GraphQL
response so existing tests continue to populate the field that the
new code path reads.
Refs: renovatebot/renovate#43086
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* docs: note github-specific gitUrl behavior
Document that 'default' and 'endpoint' produce the same URL on GitHub,
that 'ssh' uses the repository's sshUrl, and that fork mode propagates
SSH selection to both the working URL and the upstream URL.
Refs: renovatebot/renovate#43086
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* refactor(platform/github): pass parsed URL to getRepoUrl
Accept a pre-parsed URL in getRepoUrl instead of re-parsing the
endpoint string inside the helper. The endpoint is validated during
initPlatform so the helper no longer needs its own null check. The
caller now parses once and passes the URL to both initRepo call
sites; the helper clones it before mutating.
Also assert config.repository as non-null at the initRepo call site,
fixing the TS2345 error reported by the lint-other job.
* Update docs/usage/self-hosted-configuration.md
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* 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
* ci: add local mkdocs-admonitions plugin for prettier to allow admonition preservation
* docs: remove uses of `prettier-ignore` for admonitions
* test: rather use await expect
* chore: use named group exclusively
* docs: ensure 2 spaces used for generated admonitions
As a follow-up to 4b0146ab7b and
1844916259b6dc17f532e491eb93f6116327c324., this correctly renders
admonitions with 2 spaces (1 indent).
* fixup! docs: use 2-space indentation for Markdown (#43537)
Plus using 3-space for mixed-style `<ul>` and `<ol>`s.
* fixup! docs: use 2-space indentation for Markdown (#43537)
As otherwise it breaks the rendering of the table.
* fix(config/global): return default values for `GlobalConfig.get`
As noted in #39949, it can be awkward working with in `GlobalConfig.get`, where
we would previously need to specify the default value when calling `.get`,
which could lead to drift with the defaults for a given config option.
To reduce this risk, we can rely on a given `default` for a configuration
option, providing that as a default.
Because this now definitely returns a value that matches the config option, it
now allows us to remove `!` assertions.
* fixup! fix(config/global): return default values for `GlobalConfig.get`
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
* fixup! fix(config/global): return default values for `GlobalConfig.get`
* test(presets): remove impossible test
As it's now not possible to set a value as `undefined` (as
`GlobalConfig` will then use the default), this test no longer validates
anything.
* test(workers/repository): add mock
Now `platform` defaults to `github`, we need to mock out the call to
fetch config.
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* test: coverage
* test: coverage
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
* test(noNewURL): add new rule enforcing parseUrl() from 'lib/util/url.ts'
* replace newURL with parseUrl
* remove non-null assertions marks if appropiate
* test: add additional tests
* test: add additional tests and ignore where it makes sense
* implement suggestions
* test: further improve coverage
* apply suggestion
* fix(github): set commit message explicitly for platform automerge
When GitHub's "Use PR title and body as commit message" setting is
enabled, the verbose Renovate PR description gets used as the squash
commit body. Pass `commitHeadline` and `commitBody` to the
`enablePullRequestAutoMerge` GraphQL mutation so the actual commit
message is used instead.
* add REBASE test
* pr feedback