Support Maven mirrors in generated settings.xml (#1289)

* Support Maven mirrors in generated settings.xml

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 59df028a-0d1b-49cb-8126-ab26408663e4

* Reject Maven mirrors missing selectors after URL authorities

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 59df028a-0d1b-49cb-8126-ab26408663e4

* Use self-repository syntax in Maven mirrors E2E

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 59df028a-0d1b-49cb-8126-ab26408663e4

* Document mvn-mirrors URL scheme and colon encoding requirements

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 59df028a-0d1b-49cb-8126-ab26408663e4

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 59df028a-0d1b-49cb-8126-ab26408663e4
This commit is contained in:
Bruno Borges
2026-11-04 17:10:04 -05:00
committed by GitHub
co-authored by Copilot App
parent 644a850ee5
commit 77dd5b2ce2
10 changed files with 476 additions and 9 deletions
+71
View File
@@ -28,6 +28,7 @@
- [Testing against different platforms](#Testing-against-different-platforms)
- [Publishing using Apache Maven](#Publishing-using-Apache-Maven)
- [Publishing to multiple Maven servers](#publishing-to-multiple-maven-servers)
- [Redirecting Maven repositories with mirrors](#redirecting-maven-repositories-with-mirrors)
- [Apache Maven with a settings path](#apache-maven-with-a-settings-path)
- [Maven transfer progress (download logs)](#Maven-transfer-progress-download-logs)
- [Java problem matcher (compiler annotations)](#java-problem-matcher-compiler-annotations)
@@ -1105,6 +1106,76 @@ default; `mvn-repositories-prioritize-central: false` places it after them.
All repository generation respects `settings-path` and `overwrite-settings`;
an existing settings file is left untouched when `overwrite-settings: false`.
### Redirecting Maven repositories with mirrors
Use `mvn-mirrors` to redirect matching dependency and plugin repositories,
including Maven Central and repositories declared in project or parent POMs.
Unlike repository profiles, mirrors replace the destination Maven contacts.
The Central controls described above do not redirect arbitrary POM repositories.
Each nonblank line has the format `mirror-id:mirror-url:mirror-of`. IDs must be
unique within this input. `mirror-url` must be an absolute URL that includes a
scheme, such as `https://`. URL schemes, ports, IPv6 addresses, and colons in
`mirrorOf` selectors are preserved. An explicit `mirror-of` field is required
after the complete URL, including any port. Percent-encode colons in the URL
path, query, or fragment as `%3A`. Otherwise, text after the last unencoded
colon may be read as the `mirror-of` value. For example:
```yaml
steps:
- uses: actions/checkout@v7
- uses: actions/setup-java@v6
with:
distribution: 'temurin'
java-version: '21'
mvn-server-credentials: |
private:PRIVATE_REPOSITORY_USERNAME:PRIVATE_REPOSITORY_TOKEN
mvn-mirrors: |
private:https://maven.example.com/releases:*
- run: mvn --batch-mode verify
env:
PRIVATE_REPOSITORY_USERNAME: ${{ secrets.PRIVATE_REPOSITORY_USERNAME }}
PRIVATE_REPOSITORY_TOKEN: ${{ secrets.PRIVATE_REPOSITORY_TOKEN }}
```
This adds the following directly under `<settings>`, not inside a profile:
```xml
<mirrors>
<mirror>
<id>private</id>
<url>https://maven.example.com/releases</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
```
For authentication, the mirror ID must match a server ID configured through
`mvn-server-credentials` or the single-server inputs. Public mirrors do not need
matching credentials. Credentials remain environment-variable references in the
generated settings; do not put credential values in `mvn-mirrors`.
Mirrors can be used alone, as above, or alongside `mvn-repositories` and
`mvn-plugin-repositories`. They do not change those inputs or the Central
controls. Omitting `mvn-mirrors`, or supplying only blank lines, adds no
`<mirrors>` section or repository profile.
Maven interprets `mirrorOf`: `*` matches every repository, `central` matches
only that repository ID, `external:*` matches external repositories, and
`external:http:*` matches external HTTP repositories. Comma-separated patterns
such as `external:*,!internal` exclude specific IDs. Selector text and mirror
order are retained; Maven applies its own matching and precedence rules.
For example, a public mirror needs no additional repository or credential input:
```yaml
mvn-mirrors: |
public:https://mirror.example.com:8443/maven:external:*,!internal
```
Mirror generation respects `settings-path` and `overwrite-settings`. An existing
settings file is left untouched when `overwrite-settings: false`; this input
does not merge mirrors into that file.
### GPG
The example above uses the [Maven GPG Plugin](https://maven.apache.org/plugins/maven-gpg-plugin/)'s Bouncy Castle signer (`-Dgpg.signer=bc`, available since `maven-gpg-plugin` 3.2.0). It is a pure-Java signer that reads the key directly from the `MAVEN_GPG_KEY` environment variable, so it does **not** require the `gpg` executable, importing the key into a GPG keychain, or the `--pinentry-mode loopback` workaround in your `pom.xml`. The key must be an ASCII-armored secret key (transferable secret key format).