mirror of
https://github.com/actions/setup-java.git
synced 2026-10-16 16:31:34 +00:00
Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a18b789e03 | ||
|
|
db92f3d58c | ||
|
|
df4305dee7 | ||
|
|
b843ebf9b9 |
@@ -175,6 +175,94 @@ jobs:
|
||||
throw "settings.xml file is not found in expected location"
|
||||
}
|
||||
|
||||
test-maven-mirrors:
|
||||
name: Maven mirrors (${{ matrix.mirror-of }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
mirror-of: ['*', 'external:*']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Configure Maven mirrors without repository inputs
|
||||
uses: $/
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '21'
|
||||
settings-path: ${{ runner.temp }}/maven-mirror-test
|
||||
mvn-server-credentials: |
|
||||
private:PRIVATE_USERNAME:PRIVATE_TOKEN
|
||||
mvn-mirrors: |
|
||||
private:https://mirror.example.invalid/maven:${{ matrix.mirror-of }}
|
||||
- name: Validate generated settings and Maven mirror selection
|
||||
env:
|
||||
MIRROR_OF: ${{ matrix.mirror-of }}
|
||||
PRIVATE_USERNAME: mirror-test-user
|
||||
PRIVATE_TOKEN: mirror-test-token
|
||||
run: |
|
||||
$directory = Join-Path $env:RUNNER_TEMP "maven-mirror-test"
|
||||
$settingsPath = Join-Path $directory "settings.xml"
|
||||
[xml]$settings = Get-Content -Path $settingsPath -Raw
|
||||
$mirrors = @($settings.settings.mirrors.mirror)
|
||||
if ($mirrors.Count -ne 1 -or $mirrors[0].id -ne "private" -or $mirrors[0].url -ne "https://mirror.example.invalid/maven" -or $mirrors[0].mirrorOf -ne $env:MIRROR_OF) {
|
||||
throw "Incorrect generated mirror"
|
||||
}
|
||||
if ($settings.settings.profiles -or $settings.settings.activeProfiles) {
|
||||
throw "Mirror-only settings must not add repository profiles"
|
||||
}
|
||||
$server = $settings.settings.servers.server
|
||||
if ($server.id -ne "private" -or $server.username -ne '${env.PRIVATE_USERNAME}' -or $server.password -ne '${env.PRIVATE_TOKEN}') {
|
||||
throw "Mirror credentials were not preserved"
|
||||
}
|
||||
|
||||
$pomPath = Join-Path $directory "pom.xml"
|
||||
@'
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>setup-java.test</groupId>
|
||||
<artifactId>mirror-settings</artifactId>
|
||||
<version>1.0</version>
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>pom-dependencies</id>
|
||||
<url>https://dependencies.example.invalid/maven</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>pom-plugins</id>
|
||||
<url>https://plugins.example.invalid/maven</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
||||
'@ | Set-Content -Path $pomPath
|
||||
|
||||
# validate requires no plugins or dependencies, so mirror selection can
|
||||
# be inspected offline without contacting the deliberately invalid URLs.
|
||||
$output = & mvn --batch-mode --no-transfer-progress --offline --debug `
|
||||
--settings $settingsPath --file $pomPath `
|
||||
"-Dmaven.repo.local=$directory/repository" validate 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
throw "Could not inspect Maven mirror selection: $output"
|
||||
}
|
||||
$log = $output -join "`n"
|
||||
foreach ($id in @("central", "pom-dependencies")) {
|
||||
$expected = "Using mirror private (https://mirror.example.invalid/maven) for $id ("
|
||||
if (-not $log.Contains($expected)) {
|
||||
throw "Maven did not select the mirror for ${id}: $log"
|
||||
}
|
||||
}
|
||||
foreach ($type in @("dependencies", "plugins")) {
|
||||
$pattern = 'Repositories \(' + $type + '\)\s*: \[private \(https://mirror\.example\.invalid/maven, [^\]]+\)\]'
|
||||
if ($log -notmatch $pattern) {
|
||||
throw "Maven did not redirect all $type repositories: $log"
|
||||
}
|
||||
}
|
||||
|
||||
test-maven-repositories:
|
||||
name: Maven ${{ matrix.repositories }} repositories
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
@@ -171,6 +171,7 @@ steps:
|
||||
| `mvn-server-repository-origins` | Multiline Maven credential origins in the format `server-id:repository-origin`. Each origin must belong to a configured server ID. Requires Maven 3.10+. | |
|
||||
| `mvn-repositories` | Multiline Maven dependency repositories in the format `repository-id:repository-url:snapshots-enabled`. | |
|
||||
| `mvn-plugin-repositories` | Multiline Maven plugin repositories in the format `repository-id:repository-url:snapshots-enabled`. Can be used independently of `mvn-repositories`. | |
|
||||
| `mvn-mirrors` | Multiline Maven mirrors in the format `mirror-id:mirror-url:mirror-of`. Redirect matching dependency and plugin repositories; use a matching server ID for authentication. | |
|
||||
| `mvn-repositories-include-central` | Include Maven Central for dependency and plugin repositories in the generated profile. When `false`, Central is disabled for both types unless that type explicitly declares `central`. Has no effect when neither repository list is configured. | `true` |
|
||||
| `mvn-repositories-prioritize-central` | Place Maven Central before custom dependency and plugin repositories. Has no effect when Central is excluded or neither repository list is configured. | `true` |
|
||||
| `settings-path` | Directory where `settings.xml` is written. | `~/.m2` |
|
||||
@@ -490,6 +491,11 @@ match `mvn-server-credentials` IDs when authentication is required.
|
||||
See [Resolving Maven dependencies from custom repositories](docs/advanced-usage.md#resolving-maven-dependencies-from-custom-repositories)
|
||||
and [Resolving Maven plugins from custom repositories](docs/advanced-usage.md#resolving-maven-plugins-from-custom-repositories).
|
||||
|
||||
To redirect repositories, including Central and repositories declared in project
|
||||
or parent POMs, use [`mvn-mirrors`](docs/advanced-usage.md#redirecting-maven-repositories-with-mirrors).
|
||||
It works independently of the repository inputs; a `mirrorOf` pattern of `*`
|
||||
routes all dependency and plugin repositories through the configured mirror.
|
||||
|
||||
> [!WARNING]
|
||||
> `mvn-repositories-include-central: false` now disables inherited Maven Central
|
||||
> for **both dependencies and plugins**, even in existing workflows that only
|
||||
|
||||
@@ -882,6 +882,181 @@ describe('auth tests', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'*',
|
||||
'central',
|
||||
'external:*',
|
||||
'external:http:*',
|
||||
'*,!internal',
|
||||
'external:*,!internal',
|
||||
'!internal,external:http:*',
|
||||
'external:*,!external:http:*'
|
||||
])('preserves the mirror selector %s and URL colons', mirrorOf => {
|
||||
expect(
|
||||
auth.parseMavenMirrors([
|
||||
'',
|
||||
' \t ',
|
||||
` private : https://[2001:db8::1]:8443/maven : ${mirrorOf} `,
|
||||
'public:https://repo.example.com:443/releases:central'
|
||||
])
|
||||
).toEqual([
|
||||
{
|
||||
id: 'private',
|
||||
url: 'https://[2001:db8::1]:8443/maven',
|
||||
mirrorOf
|
||||
},
|
||||
{
|
||||
id: 'public',
|
||||
url: 'https://repo.example.com:443/releases',
|
||||
mirrorOf: 'central'
|
||||
}
|
||||
]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'https://repo.example.com:8443',
|
||||
'https://repo.example.com:8443/maven',
|
||||
'https://[2001:db8::1]',
|
||||
'https://[2001:db8::1]/maven',
|
||||
'https://[2001:db8::1]:8443',
|
||||
'https://[2001:db8::1]:8443/maven'
|
||||
])('preserves the complete mirror URL %s with an explicit selector', url => {
|
||||
expect(
|
||||
auth.parseMavenMirrors([`private:${url}:external:http:*,!internal`])
|
||||
).toEqual([{id: 'private', url, mirrorOf: 'external:http:*,!internal'}]);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'private',
|
||||
'private:https://repo.example.com',
|
||||
'private:https://repo.example.com:8443',
|
||||
'private:https://repo.example.com:8443/maven',
|
||||
'private:https://[2001:db8::1]',
|
||||
'private:https://[2001:db8::1]/maven',
|
||||
'private:https://[2001:db8::1]:8443',
|
||||
'private:https://[2001:db8::1]:8443/maven',
|
||||
':https://repo.example.com:*',
|
||||
'private::*',
|
||||
'private:https://repo.example.com:',
|
||||
'private: :*',
|
||||
'private:https://repo.example.com: '
|
||||
])('rejects malformed mirror entry %s with a line number', entry => {
|
||||
expect(() => auth.parseMavenMirrors(['', entry])).toThrow(
|
||||
'Invalid mvn-mirrors entry at line 2.'
|
||||
);
|
||||
});
|
||||
|
||||
it('rejects duplicate mirror IDs after trimming', () => {
|
||||
expect(() =>
|
||||
auth.parseMavenMirrors([
|
||||
'private:https://first.example.com:*',
|
||||
' private :https://second.example.com:central'
|
||||
])
|
||||
).toThrow("Duplicate mirror-id 'private' in mvn-mirrors input at line 2");
|
||||
});
|
||||
|
||||
it('leaves settings unchanged for absent or blank mirrors', () => {
|
||||
const servers = credentials('github', 'USERNAME', 'PASSWORD');
|
||||
expect(auth.parseMavenMirrors(['', ' ', '\t'])).toEqual([]);
|
||||
expect(auth.generate(servers, undefined, undefined, [])).toBe(
|
||||
auth.generate(servers)
|
||||
);
|
||||
expect(auth.generate(servers)).not.toContain('<mirrors>');
|
||||
});
|
||||
|
||||
it('generates public mirrors without credentials or repository profiles', () => {
|
||||
const mirrors = auth.parseMavenMirrors([
|
||||
'public:https://repo.example.com:external:*',
|
||||
'fallback:https://other.example.com:central'
|
||||
]);
|
||||
const xml = auth.generate([], undefined, undefined, mirrors);
|
||||
expect(parseXmlObject(xml)).toMatchObject({
|
||||
settings: {mirrors: {mirror: mirrors}}
|
||||
});
|
||||
expect(xml).not.toContain('<profiles>');
|
||||
expect(xml).not.toContain('<activeProfiles>');
|
||||
});
|
||||
|
||||
it('escapes all mirror fields as XML text', () => {
|
||||
const mirror = {
|
||||
id: 'private<&>',
|
||||
url: 'https://repo.example.com/maven?a=1&b=<value>',
|
||||
mirrorOf: '*,!internal<&>'
|
||||
};
|
||||
const xml = auth.generate([], undefined, undefined, [mirror]);
|
||||
expect(xml).toContain('<id>private<&></id>');
|
||||
expect(xml).toContain('a=1&b=<value>');
|
||||
expect(xml).toContain('<mirrorOf>*,!internal<&></mirrorOf>');
|
||||
expect(parseXmlObject(xml)).toMatchObject({
|
||||
settings: {mirrors: {mirror}}
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{combined: false, overwrite: true},
|
||||
{combined: true, overwrite: true},
|
||||
{combined: true, overwrite: false}
|
||||
])(
|
||||
'configures mirrors with combined=$combined and overwrite=$overwrite',
|
||||
async ({combined, overwrite}) => {
|
||||
const directory = path.join(m2Dir, 'mirrors');
|
||||
const location = path.join(directory, MVN_SETTINGS_FILE);
|
||||
fs.mkdirSync(directory, {recursive: true});
|
||||
fs.writeFileSync(location, 'EXISTING SETTINGS');
|
||||
const url = 'https://maven.example.com/releases';
|
||||
const inputs: Record<string, string> = {
|
||||
'settings-path': directory,
|
||||
'overwrite-settings': String(overwrite),
|
||||
'mvn-repositories-include-central': 'false',
|
||||
...(combined ? {'gpg-passphrase-env-var': 'GPG_PASSPHRASE'} : {})
|
||||
};
|
||||
const multilineInputs: Record<string, string[]> = {
|
||||
'mvn-server-credentials': ['private:PRIVATE_USERNAME:PRIVATE_TOKEN'],
|
||||
'mvn-mirrors': [`private:${url}:*`],
|
||||
...(combined
|
||||
? {
|
||||
'mvn-repositories': [`private:${url}:false`],
|
||||
'mvn-plugin-repositories': [`private:${url}:false`]
|
||||
}
|
||||
: {})
|
||||
};
|
||||
jest.mocked(core.getInput).mockImplementation(name => inputs[name] ?? '');
|
||||
jest
|
||||
.mocked(core.getMultilineInput)
|
||||
.mockImplementation(name => multilineInputs[name] ?? []);
|
||||
|
||||
await auth.configureAuthentication();
|
||||
|
||||
const xml = fs.readFileSync(location, 'utf8');
|
||||
if (!overwrite) {
|
||||
expect(xml).toBe('EXISTING SETTINGS');
|
||||
return;
|
||||
}
|
||||
expect(parseXmlObject(xml)).toMatchObject({
|
||||
settings: {
|
||||
mirrors: {mirror: {id: 'private', url, mirrorOf: '*'}},
|
||||
servers: {
|
||||
server: {
|
||||
id: 'private',
|
||||
username: '${env.PRIVATE_USERNAME}',
|
||||
password: '${env.PRIVATE_TOKEN}'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
if (combined) {
|
||||
expect(xml).toContain('<repositories>');
|
||||
expect(xml).toContain('<pluginRepositories>');
|
||||
expect(xml).toContain('<gpg.passphraseEnvName>GPG_PASSPHRASE');
|
||||
} else {
|
||||
expect(xml).not.toContain('<profiles>');
|
||||
expect(core.getInput).not.toHaveBeenCalledWith(
|
||||
'mvn-repositories-include-central'
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
it.each(repositoryInputs)(
|
||||
'parses %s while preserving colons in URLs',
|
||||
inputName => {
|
||||
|
||||
@@ -75,6 +75,9 @@ inputs:
|
||||
mvn-plugin-repositories:
|
||||
description: 'Multiline list of Maven plugin repositories in the format `repository-id:repository-url:snapshots-enabled`.'
|
||||
required: false
|
||||
mvn-mirrors:
|
||||
description: 'Multiline list of Maven mirrors in the format `mirror-id:mirror-url:mirror-of`. Use a matching server ID for authentication. Can be used independently of repository inputs.'
|
||||
required: false
|
||||
mvn-repositories-include-central:
|
||||
description: 'Include Maven Central for dependency and plugin repositories in the generated profile. When false, Central is disabled for both types unless that type explicitly declares ID `central`. Has no effect when neither repository list is configured.'
|
||||
required: false
|
||||
|
||||
Vendored
+2
-1
@@ -31040,7 +31040,7 @@ module.exports = {
|
||||
/* harmony export */ gk: () => (/* binding */ INPUT_CACHE),
|
||||
/* harmony export */ wG: () => (/* binding */ INPUT_JOB_STATUS)
|
||||
/* harmony export */ });
|
||||
/* unused harmony exports MACOS_JAVA_CONTENT_POSTFIX, INPUT_JAVA_VERSION, INPUT_JAVA_VERSION_FILE, INPUT_ARCHITECTURE, INPUT_JAVA_PACKAGE, INPUT_DISTRIBUTION, INPUT_JDK_FILE, INPUT_JDK_FILE_DEPRECATED, INPUT_CHECK_LATEST, INPUT_FORCE_DOWNLOAD, INPUT_SET_DEFAULT, INPUT_PROBLEM_MATCHER, INPUT_VERIFY_SIGNATURE, INPUT_VERIFY_SIGNATURE_PUBLIC_KEY, SIGNATURE_VERIFICATION_DOCUMENTATION_URL, SIGNATURE_VERIFICATION_FAILURE_HELP, INPUT_MVN_SERVER_CREDENTIALS, INPUT_MVN_SERVER_REPOSITORY_ORIGINS, INPUT_MVN_REPOSITORIES, INPUT_MVN_PLUGIN_REPOSITORIES, INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL, INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL, INPUT_SERVER_ID, INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_SETTINGS_PATH, INPUT_OVERWRITE_SETTINGS, INPUT_GPG_PRIVATE_KEY, INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME, INPUT_DEFAULT_SERVER_PASSWORD, INPUT_DEFAULT_GPG_PRIVATE_KEY, INPUT_DEFAULT_GPG_PASSPHRASE, MAVEN_GPG_PASSPHRASE_DEFAULT_ENV, GPG_PASSPHRASE_PROFILE_ID, MAVEN_REPOSITORIES_PROFILE_ID, MAVEN_CENTRAL_REPOSITORY_ID, MAVEN_CENTRAL_REPOSITORY_URL, INPUT_CACHE_DEPENDENCY_PATH, INPUT_CACHE_PATH, M2_DIR, MVN_SETTINGS_FILE, MVN_TOOLCHAINS_FILE, INPUT_MVN_TOOLCHAIN_ID, INPUT_MVN_TOOLCHAIN_VENDOR, INPUT_SHOW_DOWNLOAD_PROGRESS, MAVEN_ARGS_ENV, MAVEN_NO_TRANSFER_PROGRESS_FLAG, MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG, DISTRIBUTIONS_ONLY_MAJOR_VERSION */
|
||||
/* unused harmony exports MACOS_JAVA_CONTENT_POSTFIX, INPUT_JAVA_VERSION, INPUT_JAVA_VERSION_FILE, INPUT_ARCHITECTURE, INPUT_JAVA_PACKAGE, INPUT_DISTRIBUTION, INPUT_JDK_FILE, INPUT_JDK_FILE_DEPRECATED, INPUT_CHECK_LATEST, INPUT_FORCE_DOWNLOAD, INPUT_SET_DEFAULT, INPUT_PROBLEM_MATCHER, INPUT_VERIFY_SIGNATURE, INPUT_VERIFY_SIGNATURE_PUBLIC_KEY, SIGNATURE_VERIFICATION_DOCUMENTATION_URL, SIGNATURE_VERIFICATION_FAILURE_HELP, INPUT_MVN_SERVER_CREDENTIALS, INPUT_MVN_SERVER_REPOSITORY_ORIGINS, INPUT_MVN_REPOSITORIES, INPUT_MVN_PLUGIN_REPOSITORIES, INPUT_MVN_MIRRORS, INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL, INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL, INPUT_SERVER_ID, INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_SETTINGS_PATH, INPUT_OVERWRITE_SETTINGS, INPUT_GPG_PRIVATE_KEY, INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME, INPUT_DEFAULT_SERVER_PASSWORD, INPUT_DEFAULT_GPG_PRIVATE_KEY, INPUT_DEFAULT_GPG_PASSPHRASE, MAVEN_GPG_PASSPHRASE_DEFAULT_ENV, GPG_PASSPHRASE_PROFILE_ID, MAVEN_REPOSITORIES_PROFILE_ID, MAVEN_CENTRAL_REPOSITORY_ID, MAVEN_CENTRAL_REPOSITORY_URL, INPUT_CACHE_DEPENDENCY_PATH, INPUT_CACHE_PATH, M2_DIR, MVN_SETTINGS_FILE, MVN_TOOLCHAINS_FILE, INPUT_MVN_TOOLCHAIN_ID, INPUT_MVN_TOOLCHAIN_VENDOR, INPUT_SHOW_DOWNLOAD_PROGRESS, MAVEN_ARGS_ENV, MAVEN_NO_TRANSFER_PROGRESS_FLAG, MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG, DISTRIBUTIONS_ONLY_MAJOR_VERSION */
|
||||
const MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
|
||||
const INPUT_JAVA_VERSION = 'java-version';
|
||||
const INPUT_JAVA_VERSION_FILE = 'java-version-file';
|
||||
@@ -31061,6 +31061,7 @@ const INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials';
|
||||
const INPUT_MVN_SERVER_REPOSITORY_ORIGINS = 'mvn-server-repository-origins';
|
||||
const INPUT_MVN_REPOSITORIES = 'mvn-repositories';
|
||||
const INPUT_MVN_PLUGIN_REPOSITORIES = 'mvn-plugin-repositories';
|
||||
const INPUT_MVN_MIRRORS = 'mvn-mirrors';
|
||||
const INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL = 'mvn-repositories-include-central';
|
||||
const INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL = 'mvn-repositories-prioritize-central';
|
||||
const INPUT_SERVER_ID = 'server-id';
|
||||
|
||||
Vendored
+44
-4
@@ -14,6 +14,7 @@ __webpack_require__.r(__webpack_exports__);
|
||||
/* harmony export */ getInputWithDeprecatedAlias: () => (/* binding */ getInputWithDeprecatedAlias),
|
||||
/* harmony export */ getMavenRepositorySettings: () => (/* binding */ getMavenRepositorySettings),
|
||||
/* harmony export */ getMavenServerSettings: () => (/* binding */ getMavenServerSettings),
|
||||
/* harmony export */ parseMavenMirrors: () => (/* binding */ parseMavenMirrors),
|
||||
/* harmony export */ parseMavenRepositories: () => (/* binding */ parseMavenRepositories),
|
||||
/* harmony export */ parseMavenServerCredentials: () => (/* binding */ parseMavenServerCredentials)
|
||||
/* harmony export */ });
|
||||
@@ -42,6 +43,7 @@ const MAVEN_REPOSITORY_ORIGIN = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^/?#@]+\/?$/;
|
||||
async function configureAuthentication() {
|
||||
const servers = getMavenServerSettings();
|
||||
const repositorySettings = getMavenRepositorySettings();
|
||||
const mirrors = parseMavenMirrors(_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getMultilineInput */ .q3(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_MVN_MIRRORS */ .K));
|
||||
const settingsDirectory = _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .getInput */ .V4(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_SETTINGS_PATH */ .Xh) ||
|
||||
path__WEBPACK_IMPORTED_MODULE_0__.join(os__WEBPACK_IMPORTED_MODULE_4__.homedir(), _constants_js__WEBPACK_IMPORTED_MODULE_7__/* .M2_DIR */ .iT);
|
||||
const overwriteSettings = (0,_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getBooleanInput */ .Vt)(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .INPUT_OVERWRITE_SETTINGS */ .TS, true);
|
||||
@@ -51,7 +53,7 @@ async function configureAuthentication() {
|
||||
if (gpgPrivateKey) {
|
||||
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .setSecret */ .Pq(gpgPrivateKey);
|
||||
}
|
||||
await createAuthenticationSettings(servers, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar, repositorySettings);
|
||||
await createAuthenticationSettings(servers, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar, repositorySettings, mirrors);
|
||||
if (gpgPrivateKey) {
|
||||
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq('Importing private gpg key');
|
||||
const gpgHome = await _gpg_js__WEBPACK_IMPORTED_MODULE_5__/* .importKey */ .Fh(gpgPrivateKey);
|
||||
@@ -222,6 +224,37 @@ function parseMavenRepositories(entries, includeCentral, inputName = _constants_
|
||||
});
|
||||
return repositories;
|
||||
}
|
||||
// only exported for testing purposes
|
||||
function parseMavenMirrors(entries) {
|
||||
const mirrors = [];
|
||||
const mirrorIds = new Set();
|
||||
entries.forEach((entry, index) => {
|
||||
if (!entry.trim()) {
|
||||
return;
|
||||
}
|
||||
const separator = entry.indexOf(':');
|
||||
const remainder = entry.slice(separator + 1).trim();
|
||||
// Protect scheme/authority colons (including IPv6 and ports) before
|
||||
// finding the selector, which may itself contain external:http:*.
|
||||
const urlPrefix = /^[A-Za-z][A-Za-z0-9+.-]*:(?:\/\/(?:[^/?#@\s]*@)?(?:\[[^\]]+\]|[^:/?#\s]+)(?::\d+(?=[/?#:\s]|$))?)?/.exec(remainder)?.[0] ?? '';
|
||||
const fields = /^(.*?):((?:\s*!?external:(?:http:)?\*\s*|[^:,]*)(?:,(?:\s*!?external:(?:http:)?\*\s*|[^:,]*))*)$/.exec(remainder.slice(urlPrefix.length));
|
||||
if (separator < 0 || !fields) {
|
||||
throw new Error(`Invalid mvn-mirrors entry at line ${index + 1}. Expected format: mirror-id:mirror-url:mirror-of`);
|
||||
}
|
||||
const id = entry.slice(0, separator).trim();
|
||||
const url = `${urlPrefix}${fields[1]}`.trim();
|
||||
const mirrorOf = fields[2].trim();
|
||||
if (!id || !url || !mirrorOf) {
|
||||
throw new Error(`Invalid mvn-mirrors entry at line ${index + 1}. mirror-id, mirror URL, and mirror-of are required`);
|
||||
}
|
||||
if (mirrorIds.has(id)) {
|
||||
throw new Error(`Duplicate mirror-id '${id}' in mvn-mirrors input at line ${index + 1}`);
|
||||
}
|
||||
mirrorIds.add(id);
|
||||
mirrors.push({ id, url, mirrorOf });
|
||||
});
|
||||
return mirrors;
|
||||
}
|
||||
function generateRepositorySection(customRepositories, settings, element) {
|
||||
if (!customRepositories.length && settings.includeCentral) {
|
||||
return [];
|
||||
@@ -253,15 +286,15 @@ function generateRepositorySection(customRepositories, settings, element) {
|
||||
lines.push(` </${container}>`);
|
||||
return lines;
|
||||
}
|
||||
async function createAuthenticationSettings(servers, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar = undefined, repositorySettings = undefined) {
|
||||
async function createAuthenticationSettings(servers, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar = undefined, repositorySettings = undefined, mirrors = []) {
|
||||
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq(`Creating ${_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .MVN_SETTINGS_FILE */ .vO} with server-id: ${servers.map(server => server.id).join(', ')}`);
|
||||
// when an alternate m2 location is specified use only that location (no .m2 directory)
|
||||
// otherwise use the home/.m2/ path
|
||||
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .mkdirP */ .U$(settingsDirectory);
|
||||
await write(settingsDirectory, generate(servers, gpgPassphraseEnvVar, repositorySettings), overwriteSettings);
|
||||
await write(settingsDirectory, generate(servers, gpgPassphraseEnvVar, repositorySettings, mirrors), overwriteSettings);
|
||||
}
|
||||
// only exported for testing purposes
|
||||
function generate(servers, gpgPassphraseEnvVar, repositorySettings) {
|
||||
function generate(servers, gpgPassphraseEnvVar, repositorySettings, mirrors = []) {
|
||||
// The maven-gpg-plugin reads the passphrase from the environment variable
|
||||
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE).
|
||||
// Only configure it when the requested env var name differs from that default;
|
||||
@@ -289,6 +322,13 @@ function generate(servers, gpgPassphraseEnvVar, repositorySettings) {
|
||||
lines.push(' </server>');
|
||||
}
|
||||
lines.push(' </servers>');
|
||||
if (mirrors.length) {
|
||||
lines.push(' <mirrors>');
|
||||
for (const mirror of mirrors) {
|
||||
lines.push(' <mirror>', ` <id>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(mirror.id)}</id>`, ` <url>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(mirror.url)}</url>`, ` <mirrorOf>${(0,_xml_js__WEBPACK_IMPORTED_MODULE_8__/* .escapeXmlText */ .I)(mirror.mirrorOf)}</mirrorOf>`, ' </mirror>');
|
||||
}
|
||||
lines.push(' </mirrors>');
|
||||
}
|
||||
if (repositorySettings || includeGpgPassphraseProfile) {
|
||||
lines.push(' <profiles>');
|
||||
if (repositorySettings) {
|
||||
|
||||
Vendored
+2
@@ -31040,6 +31040,7 @@ module.exports = {
|
||||
/* harmony export */ GL: () => (/* binding */ INPUT_CACHE_JDK),
|
||||
/* harmony export */ H5: () => (/* binding */ INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL),
|
||||
/* harmony export */ I9: () => (/* binding */ INPUT_FORCE_DOWNLOAD),
|
||||
/* harmony export */ K: () => (/* binding */ INPUT_MVN_MIRRORS),
|
||||
/* harmony export */ K$: () => (/* binding */ GPG_PASSPHRASE_PROFILE_ID),
|
||||
/* harmony export */ LS: () => (/* binding */ INPUT_ARCHITECTURE),
|
||||
/* harmony export */ MM: () => (/* binding */ INPUT_MVN_SERVER_CREDENTIALS),
|
||||
@@ -31111,6 +31112,7 @@ const INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials';
|
||||
const INPUT_MVN_SERVER_REPOSITORY_ORIGINS = 'mvn-server-repository-origins';
|
||||
const INPUT_MVN_REPOSITORIES = 'mvn-repositories';
|
||||
const INPUT_MVN_PLUGIN_REPOSITORIES = 'mvn-plugin-repositories';
|
||||
const INPUT_MVN_MIRRORS = 'mvn-mirrors';
|
||||
const INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL = 'mvn-repositories-include-central';
|
||||
const INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL = 'mvn-repositories-prioritize-central';
|
||||
const INPUT_SERVER_ID = 'server-id';
|
||||
|
||||
@@ -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)
|
||||
@@ -1090,6 +1091,73 @@ 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. 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. 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).
|
||||
|
||||
Generated
+4
-4
@@ -4320,13 +4320,13 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/handlebars": {
|
||||
"version": "4.7.9",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.9.tgz",
|
||||
"integrity": "sha512-4E71E0rpOaQuJR2A3xDZ+GM1HyWYv1clR58tC8emQNeQe3RH7MAzSbat+V0wG78LQBo6m6bzSG/L4pBuCsgnUQ==",
|
||||
"version": "4.7.10",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.10.tgz",
|
||||
"integrity": "sha512-P5VJMVM7qgBn6vjXMw8WG9uVI+ncf2pi72j4de4yz5ZULLj2RGqLYaKOYGsgyrViQ0tePOVlN1tDCCXXtFqXKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5",
|
||||
"minimist": "^1.2.8",
|
||||
"neo-async": "^2.6.2",
|
||||
"source-map": "^0.6.1",
|
||||
"wordwrap": "^1.0.0"
|
||||
|
||||
+79
-4
@@ -30,11 +30,20 @@ export interface MavenRepositorySettings {
|
||||
prioritizeCentral: boolean;
|
||||
}
|
||||
|
||||
export interface MavenMirror {
|
||||
id: string;
|
||||
url: string;
|
||||
mirrorOf: string;
|
||||
}
|
||||
|
||||
const MAVEN_REPOSITORY_ORIGIN = /^[A-Za-z][A-Za-z0-9+.-]*:\/\/[^/?#@]+\/?$/;
|
||||
|
||||
export async function configureAuthentication() {
|
||||
const servers = getMavenServerSettings();
|
||||
const repositorySettings = getMavenRepositorySettings();
|
||||
const mirrors = parseMavenMirrors(
|
||||
core.getMultilineInput(constants.INPUT_MVN_MIRRORS)
|
||||
);
|
||||
const settingsDirectory =
|
||||
core.getInput(constants.INPUT_SETTINGS_PATH) ||
|
||||
path.join(os.homedir(), constants.M2_DIR);
|
||||
@@ -60,7 +69,8 @@ export async function configureAuthentication() {
|
||||
settingsDirectory,
|
||||
overwriteSettings,
|
||||
gpgPassphraseEnvVar,
|
||||
repositorySettings
|
||||
repositorySettings,
|
||||
mirrors
|
||||
);
|
||||
|
||||
if (gpgPrivateKey) {
|
||||
@@ -333,6 +343,55 @@ export function parseMavenRepositories(
|
||||
return repositories;
|
||||
}
|
||||
|
||||
// only exported for testing purposes
|
||||
export function parseMavenMirrors(entries: string[]): MavenMirror[] {
|
||||
const mirrors: MavenMirror[] = [];
|
||||
const mirrorIds = new Set<string>();
|
||||
|
||||
entries.forEach((entry, index) => {
|
||||
if (!entry.trim()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const separator = entry.indexOf(':');
|
||||
const remainder = entry.slice(separator + 1).trim();
|
||||
// Protect scheme/authority colons (including IPv6 and ports) before
|
||||
// finding the selector, which may itself contain external:http:*.
|
||||
const urlPrefix =
|
||||
/^[A-Za-z][A-Za-z0-9+.-]*:(?:\/\/(?:[^/?#@\s]*@)?(?:\[[^\]]+\]|[^:/?#\s]+)(?::\d+(?=[/?#:\s]|$))?)?/.exec(
|
||||
remainder
|
||||
)?.[0] ?? '';
|
||||
const fields =
|
||||
/^(.*?):((?:\s*!?external:(?:http:)?\*\s*|[^:,]*)(?:,(?:\s*!?external:(?:http:)?\*\s*|[^:,]*))*)$/.exec(
|
||||
remainder.slice(urlPrefix.length)
|
||||
);
|
||||
if (separator < 0 || !fields) {
|
||||
throw new Error(
|
||||
`Invalid mvn-mirrors entry at line ${index + 1}. Expected format: mirror-id:mirror-url:mirror-of`
|
||||
);
|
||||
}
|
||||
|
||||
const id = entry.slice(0, separator).trim();
|
||||
const url = `${urlPrefix}${fields[1]}`.trim();
|
||||
const mirrorOf = fields[2].trim();
|
||||
if (!id || !url || !mirrorOf) {
|
||||
throw new Error(
|
||||
`Invalid mvn-mirrors entry at line ${index + 1}. mirror-id, mirror URL, and mirror-of are required`
|
||||
);
|
||||
}
|
||||
if (mirrorIds.has(id)) {
|
||||
throw new Error(
|
||||
`Duplicate mirror-id '${id}' in mvn-mirrors input at line ${index + 1}`
|
||||
);
|
||||
}
|
||||
|
||||
mirrorIds.add(id);
|
||||
mirrors.push({id, url, mirrorOf});
|
||||
});
|
||||
|
||||
return mirrors;
|
||||
}
|
||||
|
||||
function generateRepositorySection(
|
||||
customRepositories: MavenRepository[],
|
||||
settings: MavenRepositorySettings,
|
||||
@@ -388,7 +447,8 @@ export async function createAuthenticationSettings(
|
||||
settingsDirectory: string,
|
||||
overwriteSettings: boolean,
|
||||
gpgPassphraseEnvVar: string | undefined = undefined,
|
||||
repositorySettings: MavenRepositorySettings | undefined = undefined
|
||||
repositorySettings: MavenRepositorySettings | undefined = undefined,
|
||||
mirrors: MavenMirror[] = []
|
||||
) {
|
||||
core.info(
|
||||
`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${servers.map(server => server.id).join(', ')}`
|
||||
@@ -398,7 +458,7 @@ export async function createAuthenticationSettings(
|
||||
await io.mkdirP(settingsDirectory);
|
||||
await write(
|
||||
settingsDirectory,
|
||||
generate(servers, gpgPassphraseEnvVar, repositorySettings),
|
||||
generate(servers, gpgPassphraseEnvVar, repositorySettings, mirrors),
|
||||
overwriteSettings
|
||||
);
|
||||
}
|
||||
@@ -407,7 +467,8 @@ export async function createAuthenticationSettings(
|
||||
export function generate(
|
||||
servers: MavenServerCredentials[],
|
||||
gpgPassphraseEnvVar?: string | undefined,
|
||||
repositorySettings?: MavenRepositorySettings | undefined
|
||||
repositorySettings?: MavenRepositorySettings | undefined,
|
||||
mirrors: MavenMirror[] = []
|
||||
) {
|
||||
// The maven-gpg-plugin reads the passphrase from the environment variable
|
||||
// named by the `gpg.passphraseEnvName` property (default MAVEN_GPG_PASSPHRASE).
|
||||
@@ -447,6 +508,20 @@ export function generate(
|
||||
}
|
||||
lines.push(' </servers>');
|
||||
|
||||
if (mirrors.length) {
|
||||
lines.push(' <mirrors>');
|
||||
for (const mirror of mirrors) {
|
||||
lines.push(
|
||||
' <mirror>',
|
||||
` <id>${escapeXmlText(mirror.id)}</id>`,
|
||||
` <url>${escapeXmlText(mirror.url)}</url>`,
|
||||
` <mirrorOf>${escapeXmlText(mirror.mirrorOf)}</mirrorOf>`,
|
||||
' </mirror>'
|
||||
);
|
||||
}
|
||||
lines.push(' </mirrors>');
|
||||
}
|
||||
|
||||
if (repositorySettings || includeGpgPassphraseProfile) {
|
||||
lines.push(' <profiles>');
|
||||
if (repositorySettings) {
|
||||
|
||||
@@ -20,6 +20,7 @@ export const INPUT_MVN_SERVER_REPOSITORY_ORIGINS =
|
||||
'mvn-server-repository-origins';
|
||||
export const INPUT_MVN_REPOSITORIES = 'mvn-repositories';
|
||||
export const INPUT_MVN_PLUGIN_REPOSITORIES = 'mvn-plugin-repositories';
|
||||
export const INPUT_MVN_MIRRORS = 'mvn-mirrors';
|
||||
export const INPUT_MVN_REPOSITORIES_INCLUDE_CENTRAL =
|
||||
'mvn-repositories-include-central';
|
||||
export const INPUT_MVN_REPOSITORIES_PRIORITIZE_CENTRAL =
|
||||
|
||||
Reference in New Issue
Block a user