diff --git a/README.md b/README.md index 03860b372..a51efa1bf 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,8 @@ For more details, see the full release notes on the [releases page](https://git - `server-password`: Environment variable name for password or token for authentication to the Apache Maven repository. Default is GITHUB_TOKEN. + - `mvn-server-credentials`: Optional multiline list of Maven server credentials in the format `server-id:USERNAME_ENV:PASSWORD_ENV`. When set, this input overrides `server-id`/`server-username`/`server-password` and generates multiple `` entries in `settings.xml`. + - `settings-path`: Maven related setting to point to the directory where the settings.xml file will be written. Default is ~/.m2. - `gpg-private-key`: GPG private key to import. Default is empty string. diff --git a/__tests__/auth.test.ts b/__tests__/auth.test.ts index 06591da7a..f5ebbde2e 100644 --- a/__tests__/auth.test.ts +++ b/__tests__/auth.test.ts @@ -43,9 +43,7 @@ describe('auth tests', () => { await io.rmRF(altHome); // ensure it doesn't already exist await auth.createAuthenticationSettings( - id, - username, - password, + [{id, username, password}], altHome, true ); @@ -56,7 +54,7 @@ describe('auth tests', () => { expect(fs.existsSync(altHome)).toBe(true); expect(fs.existsSync(altSettingsFile)).toBe(true); expect(fs.readFileSync(altSettingsFile, 'utf-8')).toEqual( - auth.generate(id, username, password) + auth.generate([{id, username, password}]) ); await io.rmRF(altHome); @@ -68,9 +66,7 @@ describe('auth tests', () => { const password = 'TOKEN'; await auth.createAuthenticationSettings( - id, - username, - password, + [{id, username, password}], m2Dir, true ); @@ -78,7 +74,7 @@ describe('auth tests', () => { expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(settingsFile)).toBe(true); expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( - auth.generate(id, username, password) + auth.generate([{id, username, password}]) ); }, 100000); @@ -89,9 +85,7 @@ describe('auth tests', () => { const gpgPassphrase = 'GPG'; await auth.createAuthenticationSettings( - id, - username, - password, + [{id, username, password}], m2Dir, true, gpgPassphrase @@ -100,7 +94,7 @@ describe('auth tests', () => { expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(settingsFile)).toBe(true); expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( - auth.generate(id, username, password, gpgPassphrase) + auth.generate([{id, username, password}], gpgPassphrase) ); }, 100000); @@ -115,9 +109,7 @@ describe('auth tests', () => { expect(fs.existsSync(settingsFile)).toBe(true); await auth.createAuthenticationSettings( - id, - username, - password, + [{id, username, password}], m2Dir, true ); @@ -125,7 +117,7 @@ describe('auth tests', () => { expect(fs.existsSync(m2Dir)).toBe(true); expect(fs.existsSync(settingsFile)).toBe(true); expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual( - auth.generate(id, username, password) + auth.generate([{id, username, password}]) ); }, 100000); @@ -140,9 +132,7 @@ describe('auth tests', () => { expect(fs.existsSync(settingsFile)).toBe(true); await auth.createAuthenticationSettings( - id, - username, - password, + [{id, username, password}], m2Dir, false ); @@ -169,7 +159,7 @@ describe('auth tests', () => { `; - expect(auth.generate(id, username, password)).toEqual(expectedSettings); + expect(auth.generate([{id, username, password}])).toEqual(expectedSettings); }); it('generates valid settings.xml with additional configuration', () => { @@ -194,8 +184,80 @@ describe('auth tests', () => { `; - expect(auth.generate(id, username, password, gpgPassphrase)).toEqual( + expect(auth.generate([{id, username, password}], gpgPassphrase)).toEqual( expectedSettings ); }); + + it('generates valid settings.xml for multiple repositories', () => { + const id0 = 'packages0'; + const username0 = 'USER0'; + const password0 = '&<>"\'\'"><&0'; + const id1 = 'packages1'; + const username1 = 'USER1'; + const password1 = '&<>"\'\'"><&1'; + const gpgPassphrase = 'PASSPHRASE'; + + const expectedSettings = ` + + + ${id0} + \${env.${username0}} + \${env.&<>"''"><&0} + + + ${id1} + \${env.${username1}} + \${env.&<>"''"><&1} + + + gpg.passphrase + \${env.${gpgPassphrase}} + + +`; + + expect( + auth.generate( + [ + {id: id0, username: username0, password: password0}, + {id: id1, username: username1, password: password1} + ], + gpgPassphrase + ) + ).toEqual(expectedSettings); + }); + + it('parses mvn-server-credentials multiline entries', () => { + const parsed = auth.parseMavenServerCredentials([ + 'releases:RELEASE_USER:RELEASE_TOKEN', + 'snapshots:SNAPSHOT_USER:SNAPSHOT_TOKEN' + ]); + + expect(parsed).toEqual([ + {id: 'releases', username: 'RELEASE_USER', password: 'RELEASE_TOKEN'}, + { + id: 'snapshots', + username: 'SNAPSHOT_USER', + password: 'SNAPSHOT_TOKEN' + } + ]); + }); + + it('fails on invalid mvn-server-credentials format', () => { + expect(() => + auth.parseMavenServerCredentials(['releases:RELEASE_USER']) + ).toThrow('Expected format: server-id:USERNAME_ENV:PASSWORD_ENV'); + }); + + it('fails on duplicate server ids in mvn-server-credentials', () => { + expect(() => + auth.parseMavenServerCredentials([ + 'releases:RELEASE_USER:RELEASE_TOKEN', + 'releases:OTHER_USER:OTHER_TOKEN' + ]) + ).toThrow("Duplicate server-id 'releases'"); + }); }); diff --git a/action.yml b/action.yml index d5f46bbed..5f357e440 100644 --- a/action.yml +++ b/action.yml @@ -41,6 +41,9 @@ inputs: authentication to the Apache Maven repository. Default is $GITHUB_TOKEN' required: false default: 'GITHUB_TOKEN' + mvn-server-credentials: + description: 'Optional multiline list of Maven server credentials in the format "server-id:USERNAME_ENV:PASSWORD_ENV". When provided, this overrides server-id/server-username/server-password and writes multiple entries in settings.xml.' + required: false settings-path: description: 'Path to where the settings.xml file will be written. Default is ~/.m2.' required: false diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 0c3278164..089486fea 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -52241,7 +52241,7 @@ else { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; +exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_MVN_SERVER_CREDENTIALS = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; @@ -52250,6 +52250,7 @@ exports.INPUT_JAVA_PACKAGE = 'java-package'; exports.INPUT_DISTRIBUTION = 'distribution'; exports.INPUT_JDK_FILE = 'jdkFile'; exports.INPUT_CHECK_LATEST = 'check-latest'; +exports.INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials'; exports.INPUT_SERVER_ID = 'server-id'; exports.INPUT_SERVER_USERNAME = 'server-username'; exports.INPUT_SERVER_PASSWORD = 'server-password'; diff --git a/dist/setup/index.js b/dist/setup/index.js index 33056027d..79db1a45c 100644 --- a/dist/setup/index.js +++ b/dist/setup/index.js @@ -77676,7 +77676,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.generate = exports.createAuthenticationSettings = exports.configureAuthentication = void 0; +exports.parseMavenServerCredentials = exports.generate = exports.createAuthenticationSettings = exports.configureAuthentication = void 0; const path = __importStar(__nccwpck_require__(16928)); const core = __importStar(__nccwpck_require__(37484)); const io = __importStar(__nccwpck_require__(94994)); @@ -77688,9 +77688,7 @@ const gpg = __importStar(__nccwpck_require__(88343)); const util_1 = __nccwpck_require__(54527); function configureAuthentication() { return __awaiter(this, void 0, void 0, function* () { - const id = core.getInput(constants.INPUT_SERVER_ID); - const username = core.getInput(constants.INPUT_SERVER_USERNAME); - const password = core.getInput(constants.INPUT_SERVER_PASSWORD); + const mvnSettings = getMavenServerSettings(); const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR); const overwriteSettings = (0, util_1.getBooleanInput)(constants.INPUT_OVERWRITE_SETTINGS, true); @@ -77701,7 +77699,7 @@ function configureAuthentication() { if (gpgPrivateKey) { core.setSecret(gpgPrivateKey); } - yield createAuthenticationSettings(id, username, password, settingsDirectory, overwriteSettings, gpgPassphrase); + yield createAuthenticationSettings(mvnSettings, settingsDirectory, overwriteSettings, gpgPassphrase); if (gpgPrivateKey) { core.info('Importing private gpg key'); const keyFingerprint = (yield gpg.importKey(gpgPrivateKey)) || ''; @@ -77710,34 +77708,37 @@ function configureAuthentication() { }); } exports.configureAuthentication = configureAuthentication; -function createAuthenticationSettings(id, username, password, settingsDirectory, overwriteSettings, gpgPassphrase = undefined) { +function createAuthenticationSettings(mvnSettings, settingsDirectory, overwriteSettings, gpgPassphrase = undefined) { return __awaiter(this, void 0, void 0, function* () { - core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`); + core.info(`Creating ${constants.MVN_SETTINGS_FILE}`); // when an alternate m2 location is specified use only that location (no .m2 directory) // otherwise use the home/.m2/ path yield io.mkdirP(settingsDirectory); - yield write(settingsDirectory, generate(id, username, password, gpgPassphrase), overwriteSettings); + yield write(settingsDirectory, generate(mvnSettings, gpgPassphrase), overwriteSettings); }); } exports.createAuthenticationSettings = createAuthenticationSettings; // only exported for testing purposes -function generate(id, username, password, gpgPassphrase) { +function generate(mvnSettings, gpgPassphrase) { const xmlObj = { settings: { '@xmlns': 'http://maven.apache.org/SETTINGS/1.0.0', '@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance', '@xsi:schemaLocation': 'http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd', servers: { - server: [ - { - id: id, - username: `\${env.${username}}`, - password: `\${env.${password}}` - } - ] + server: [] } } }; + for (const mvnSetting of mvnSettings) { + if (mvnSetting.username && mvnSetting.password) { + xmlObj.settings.servers.server.push({ + id: mvnSetting.id, + username: `\${env.${mvnSetting.username}}`, + password: `\${env.${mvnSetting.password}}` + }); + } + } if (gpgPassphrase) { const gpgServer = { id: 'gpg.passphrase', @@ -77752,6 +77753,42 @@ function generate(id, username, password, gpgPassphrase) { }); } exports.generate = generate; +function getMavenServerSettings() { + const multilineEntries = core + .getMultilineInput(constants.INPUT_MVN_SERVER_CREDENTIALS) + .map(entry => entry.trim()) + .filter(Boolean); + if (multilineEntries.length > 0) { + return parseMavenServerCredentials(multilineEntries); + } + const id = core.getInput(constants.INPUT_SERVER_ID); + const username = core.getInput(constants.INPUT_SERVER_USERNAME); + const password = core.getInput(constants.INPUT_SERVER_PASSWORD); + return [{ id, username, password }]; +} +// only exported for testing purposes +function parseMavenServerCredentials(entries) { + const parsed = entries.map((entry, index) => { + const parts = entry.split(':'); + if (parts.length !== 3) { + throw new Error(`Invalid mvn-server-credentials entry at line ${index + 1}. Expected format: server-id:USERNAME_ENV:PASSWORD_ENV`); + } + const [id, username, password] = parts.map(part => part.trim()); + if (!id || !username || !password) { + throw new Error(`Invalid mvn-server-credentials entry at line ${index + 1}. server-id, username env, and password env are required`); + } + return { id, username, password }; + }); + const ids = new Set(); + for (const setting of parsed) { + if (ids.has(setting.id)) { + throw new Error(`Duplicate server-id '${setting.id}' in mvn-server-credentials input`); + } + ids.add(setting.id); + } + return parsed; +} +exports.parseMavenServerCredentials = parseMavenServerCredentials; function write(directory, settings, overwriteSettings) { return __awaiter(this, void 0, void 0, function* () { const location = path.join(directory, constants.MVN_SETTINGS_FILE); @@ -78000,7 +78037,7 @@ function isProbablyGradleDaemonProblem(packageManager, error) { "use strict"; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; +exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_MVN_SERVER_CREDENTIALS = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0; exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; exports.INPUT_JAVA_VERSION = 'java-version'; exports.INPUT_JAVA_VERSION_FILE = 'java-version-file'; @@ -78009,6 +78046,7 @@ exports.INPUT_JAVA_PACKAGE = 'java-package'; exports.INPUT_DISTRIBUTION = 'distribution'; exports.INPUT_JDK_FILE = 'jdkFile'; exports.INPUT_CHECK_LATEST = 'check-latest'; +exports.INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials'; exports.INPUT_SERVER_ID = 'server-id'; exports.INPUT_SERVER_USERNAME = 'server-username'; exports.INPUT_SERVER_PASSWORD = 'server-password'; diff --git a/docs/advanced-usage.md b/docs/advanced-usage.md index f4838b349..3d01609d2 100644 --- a/docs/advanced-usage.md +++ b/docs/advanced-usage.md @@ -437,6 +437,57 @@ The two `settings.xml` files created from the above example look like the follow If you don't want to overwrite the `settings.xml` file, you can set `overwrite-settings: false` +### Multiple repositories + +When release and snapshot artifacts are deployed to different repositories, you can configure multiple Maven servers in one run. + +Use `mvn-server-credentials` with one entry per line in the format: +`server-id:USERNAME_ENV:PASSWORD_ENV` + +#### YAML example +```yaml +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v6 + - name: Set up Apache Maven repositories + uses: actions/setup-java@v5 + with: + distribution: 'temurin' + java-version: '21' + mvn-server-credentials: | + releases:ARTIFACTORY_USERNAME:ARTIFACTORY_TOKEN + snapshots:SNAPSHOT_ARTIFACTORY_USERNAME:SNAPSHOT_ARTIFACTORY_TOKEN + gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} + gpg-passphrase: MAVEN_GPG_PASSPHRASE +``` + +Generated `settings.xml`: +```xml + + + + releases + ${env.ARTIFACTORY_USERNAME} + ${env.ARTIFACTORY_TOKEN} + + + snapshots + ${env.SNAPSHOT_ARTIFACTORY_USERNAME} + ${env.SNAPSHOT_ARTIFACTORY_TOKEN} + + + gpg.passphrase + ${env.MAVEN_GPG_PASSPHRASE} + + + +``` + ### Extra setup for pom.xml: The Maven GPG Plugin configuration in the pom.xml file should contain the following structure to avoid possible issues like `Inappropriate ioctl for device` or `gpg: signing failed: No such file or directory`: diff --git a/src/auth.ts b/src/auth.ts index c8ea6291c..35b5628a8 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -9,11 +9,10 @@ import {create as xmlCreate} from 'xmlbuilder2'; import * as constants from './constants'; import * as gpg from './gpg'; import {getBooleanInput} from './util'; +import {MvnSettingDefinition} from './mvn.setting.definition'; export async function configureAuthentication() { - const id = core.getInput(constants.INPUT_SERVER_ID); - const username = core.getInput(constants.INPUT_SERVER_USERNAME); - const password = core.getInput(constants.INPUT_SERVER_PASSWORD); + const mvnSettings = getMavenServerSettings(); const settingsDirectory = core.getInput(constants.INPUT_SETTINGS_PATH) || path.join(os.homedir(), constants.M2_DIR); @@ -33,9 +32,7 @@ export async function configureAuthentication() { } await createAuthenticationSettings( - id, - username, - password, + mvnSettings, settingsDirectory, overwriteSettings, gpgPassphrase @@ -49,29 +46,25 @@ export async function configureAuthentication() { } export async function createAuthenticationSettings( - id: string, - username: string, - password: string, + mvnSettings: MvnSettingDefinition[], settingsDirectory: string, overwriteSettings: boolean, gpgPassphrase: string | undefined = undefined ) { - core.info(`Creating ${constants.MVN_SETTINGS_FILE} with server-id: ${id}`); + core.info(`Creating ${constants.MVN_SETTINGS_FILE}`); // when an alternate m2 location is specified use only that location (no .m2 directory) // otherwise use the home/.m2/ path await io.mkdirP(settingsDirectory); await write( settingsDirectory, - generate(id, username, password, gpgPassphrase), + generate(mvnSettings, gpgPassphrase), overwriteSettings ); } // only exported for testing purposes export function generate( - id: string, - username: string, - password: string, + mvnSettings: MvnSettingDefinition[], gpgPassphrase?: string | undefined ) { const xmlObj: {[key: string]: any} = { @@ -81,17 +74,21 @@ export function generate( '@xsi:schemaLocation': 'http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd', servers: { - server: [ - { - id: id, - username: `\${env.${username}}`, - password: `\${env.${password}}` - } - ] + server: [] } } }; + for (const mvnSetting of mvnSettings) { + if (mvnSetting.username && mvnSetting.password) { + xmlObj.settings.servers.server.push({ + id: mvnSetting.id, + username: `\${env.${mvnSetting.username}}`, + password: `\${env.${mvnSetting.password}}` + }); + } + } + if (gpgPassphrase) { const gpgServer = { id: 'gpg.passphrase', @@ -107,6 +104,61 @@ export function generate( }); } +function getMavenServerSettings(): MvnSettingDefinition[] { + const multilineEntries = core + .getMultilineInput(constants.INPUT_MVN_SERVER_CREDENTIALS) + .map(entry => entry.trim()) + .filter(Boolean); + + if (multilineEntries.length > 0) { + return parseMavenServerCredentials(multilineEntries); + } + + const id = core.getInput(constants.INPUT_SERVER_ID); + const username = core.getInput(constants.INPUT_SERVER_USERNAME); + const password = core.getInput(constants.INPUT_SERVER_PASSWORD); + return [{id, username, password}]; +} + +// only exported for testing purposes +export function parseMavenServerCredentials( + entries: string[] +): MvnSettingDefinition[] { + const parsed = entries.map((entry, index) => { + const parts = entry.split(':'); + if (parts.length !== 3) { + throw new Error( + `Invalid mvn-server-credentials entry at line ${ + index + 1 + }. Expected format: server-id:USERNAME_ENV:PASSWORD_ENV` + ); + } + + const [id, username, password] = parts.map(part => part.trim()); + if (!id || !username || !password) { + throw new Error( + `Invalid mvn-server-credentials entry at line ${ + index + 1 + }. server-id, username env, and password env are required` + ); + } + + return {id, username, password}; + }); + + const ids = new Set(); + for (const setting of parsed) { + if (ids.has(setting.id)) { + throw new Error( + `Duplicate server-id '${setting.id}' in mvn-server-credentials input` + ); + } + ids.add(setting.id); + } + + return parsed; +} + async function write( directory: string, settings: string, diff --git a/src/constants.ts b/src/constants.ts index 93af286f8..8d4eb76f9 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -6,6 +6,7 @@ export const INPUT_JAVA_PACKAGE = 'java-package'; export const INPUT_DISTRIBUTION = 'distribution'; export const INPUT_JDK_FILE = 'jdkFile'; export const INPUT_CHECK_LATEST = 'check-latest'; +export const INPUT_MVN_SERVER_CREDENTIALS = 'mvn-server-credentials'; export const INPUT_SERVER_ID = 'server-id'; export const INPUT_SERVER_USERNAME = 'server-username'; export const INPUT_SERVER_PASSWORD = 'server-password'; diff --git a/src/mvn.setting.definition.ts b/src/mvn.setting.definition.ts new file mode 100644 index 000000000..3e2c41de9 --- /dev/null +++ b/src/mvn.setting.definition.ts @@ -0,0 +1,6 @@ +export interface MvnSettingDefinition { + id: string; + username?: string; + password?: string; + gpgPassphrase?: string; +}