Merge pull request #29 from clarkbw/maven-auth
Adding maven auth support
This commit is contained in:
commit
d8ada524fc
|
@ -0,0 +1,2 @@
|
||||||
|
dist/index.js -diff -merge
|
||||||
|
dist/index.js linguist-generated=true
|
|
@ -93,3 +93,4 @@ typings/
|
||||||
|
|
||||||
# DynamoDB Local files
|
# DynamoDB Local files
|
||||||
.dynamodb/
|
.dynamodb/
|
||||||
|
.vscode/
|
||||||
|
|
126
README.md
126
README.md
|
@ -13,7 +13,7 @@ This action sets up a java environment for use in actions by:
|
||||||
|
|
||||||
See [action.yml](action.yml)
|
See [action.yml](action.yml)
|
||||||
|
|
||||||
Basic:
|
## Basic
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
@ -25,7 +25,7 @@ steps:
|
||||||
- run: java -cp java HelloWorldApp
|
- run: java -cp java HelloWorldApp
|
||||||
```
|
```
|
||||||
|
|
||||||
From local file:
|
## Local file
|
||||||
```yaml
|
```yaml
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v1
|
- uses: actions/checkout@v1
|
||||||
|
@ -37,7 +37,7 @@ steps:
|
||||||
- run: java -cp java HelloWorldApp
|
- run: java -cp java HelloWorldApp
|
||||||
```
|
```
|
||||||
|
|
||||||
Matrix Testing:
|
## Matrix Testing
|
||||||
```yaml
|
```yaml
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -56,6 +56,126 @@ jobs:
|
||||||
- run: java -cp java HelloWorldApp
|
- run: java -cp java HelloWorldApp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Publishing using Apache Maven
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Set up JDK 1.8
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 1.8
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: mvn -B package --file pom.xml
|
||||||
|
|
||||||
|
- name: Publish to GitHub Packages Apache Maven
|
||||||
|
run: mvn deploy
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password
|
||||||
|
|
||||||
|
- name: Set up Apache Maven Central
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with: # running setup-java again overwrites the settings.xml
|
||||||
|
java-version: 1.8
|
||||||
|
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
|
||||||
|
server-username: MAVEN_USERNAME # env variable for username in deploy
|
||||||
|
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
|
||||||
|
|
||||||
|
- name: Publish to Apache Maven Central
|
||||||
|
run: mvn deploy
|
||||||
|
env:
|
||||||
|
MAVEN_USERNAME: maven_username123
|
||||||
|
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
|
||||||
|
```
|
||||||
|
|
||||||
|
The two `settings.xml` files created from the above example look like the following.
|
||||||
|
|
||||||
|
`settings.xml` file created for the first deploy to GitHub Packages
|
||||||
|
```xml
|
||||||
|
<servers>
|
||||||
|
<server>
|
||||||
|
<id>github</id>
|
||||||
|
<username>${env.GITHUB_ACTOR}</username>
|
||||||
|
<password>${env.GITHUB_TOKEN}</password>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
```
|
||||||
|
|
||||||
|
`settings.xml` file created for the second deploy to Apache Maven Central
|
||||||
|
```xml
|
||||||
|
<servers>
|
||||||
|
<server>
|
||||||
|
<id>maven</id>
|
||||||
|
<username>${env.MAVEN_USERNAME}</username>
|
||||||
|
<password>${env.MAVEN_CENTRAL_TOKEN}</password>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
```
|
||||||
|
|
||||||
|
***NOTE: The `settings.xml` file is created in the Actions $HOME directory. If you have an existing `settings.xml` file at that location, it will be overwritten. See below for using the `settings-path` to change your `settings.xml` file location.***
|
||||||
|
|
||||||
|
See the help docs on [Publishing a Package](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-apache-maven-for-use-with-github-packages#publishing-a-package) for more information on the `pom.xml` file.
|
||||||
|
|
||||||
|
## Publishing using Gradle
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
|
||||||
|
- name: Set up JDK 1.8
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
|
||||||
|
- name: Build with Gradle
|
||||||
|
run: gradle build
|
||||||
|
|
||||||
|
- name: Publish to GitHub Packages
|
||||||
|
run: gradle publish
|
||||||
|
env:
|
||||||
|
USERNAME: ${{ github.actor }}
|
||||||
|
PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
```
|
||||||
|
|
||||||
|
***NOTE: The `USERNAME` and `PASSWORD` need to correspond to the credentials environment variables used in the publishing section of your `build.gradle`.***
|
||||||
|
|
||||||
|
See the help docs on [Publishing a Package with Gradle](https://help.github.com/en/github/managing-packages-with-github-packages/configuring-gradle-for-use-with-github-packages#example-using-gradle-groovy-for-a-single-package-in-a-repository) for more information on the `build.gradle` configuration file.
|
||||||
|
|
||||||
|
## Apache Maven with a settings path
|
||||||
|
|
||||||
|
When using an Actions self-hosted runner with multiple shared runners the default `$HOME` directory can be shared by a number runners at the same time which could overwrite existing settings file. Setting the `settings-path` variable allows you to choose a unique location for your settings file.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v1
|
||||||
|
- name: Set up JDK 1.8 for Shared Runner
|
||||||
|
uses: actions/setup-java@v1
|
||||||
|
with:
|
||||||
|
java-version: 1.8
|
||||||
|
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
|
||||||
|
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||||
|
|
||||||
|
- name: Build with Maven
|
||||||
|
run: mvn -B package --file pom.xml
|
||||||
|
|
||||||
|
- name: Publish to GitHub Packages Apache Maven
|
||||||
|
run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
```
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
The scripts and documentation in this project are released under the [MIT License](LICENSE)
|
The scripts and documentation in this project are released under the [MIT License](LICENSE)
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
import io = require('@actions/io');
|
||||||
|
import fs = require('fs');
|
||||||
|
import os = require('os');
|
||||||
|
import path = require('path');
|
||||||
|
|
||||||
|
// make the os.homedir() call be local to the tests
|
||||||
|
jest.doMock('os', () => {
|
||||||
|
return {
|
||||||
|
homedir: jest.fn(() => __dirname)
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
import * as auth from '../src/auth';
|
||||||
|
|
||||||
|
const m2Dir = path.join(__dirname, auth.M2_DIR);
|
||||||
|
const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE);
|
||||||
|
|
||||||
|
describe('auth tests', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await io.rmRF(m2Dir);
|
||||||
|
}, 300000);
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
try {
|
||||||
|
await io.rmRF(m2Dir);
|
||||||
|
} catch {
|
||||||
|
console.log('Failed to remove test directories');
|
||||||
|
}
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('creates settings.xml in alternate locations', async () => {
|
||||||
|
const id = 'packages';
|
||||||
|
const username = 'UNAMI';
|
||||||
|
const password = 'TOLKIEN';
|
||||||
|
|
||||||
|
const altHome = path.join(__dirname, 'runner', 'settings');
|
||||||
|
const altSettingsFile = path.join(altHome, auth.SETTINGS_FILE);
|
||||||
|
process.env[`INPUT_SETTINGS-PATH`] = altHome;
|
||||||
|
await io.rmRF(altHome); // ensure it doesn't already exist
|
||||||
|
|
||||||
|
await auth.configAuthentication(id, username, password);
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(false);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(false);
|
||||||
|
|
||||||
|
expect(fs.existsSync(altHome)).toBe(true);
|
||||||
|
expect(fs.existsSync(altSettingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(altSettingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate(id, username, password)
|
||||||
|
);
|
||||||
|
|
||||||
|
delete process.env[`INPUT_SETTINGS-PATH`];
|
||||||
|
await io.rmRF(altHome);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('creates settings.xml with username and password', async () => {
|
||||||
|
const id = 'packages';
|
||||||
|
const username = 'UNAME';
|
||||||
|
const password = 'TOKEN';
|
||||||
|
|
||||||
|
await auth.configAuthentication(id, username, password);
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate(id, username, password)
|
||||||
|
);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('overwrites existing settings.xml files', async () => {
|
||||||
|
const id = 'packages';
|
||||||
|
const username = 'USERNAME';
|
||||||
|
const password = 'PASSWORD';
|
||||||
|
|
||||||
|
fs.mkdirSync(m2Dir, {recursive: true});
|
||||||
|
fs.writeFileSync(settingsFile, 'FAKE FILE');
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
|
||||||
|
await auth.configAuthentication(id, username, password);
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate(id, username, password)
|
||||||
|
);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('does not create settings.xml without required parameters', async () => {
|
||||||
|
await auth.configAuthentication('FOO');
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate('FOO', auth.DEFAULT_USERNAME, auth.DEFAULT_PASSWORD)
|
||||||
|
);
|
||||||
|
|
||||||
|
await auth.configAuthentication(undefined, 'BAR', undefined);
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate(auth.DEFAULT_ID, 'BAR', auth.DEFAULT_PASSWORD)
|
||||||
|
);
|
||||||
|
|
||||||
|
await auth.configAuthentication(undefined, undefined, 'BAZ');
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate(auth.DEFAULT_ID, auth.DEFAULT_USERNAME, 'BAZ')
|
||||||
|
);
|
||||||
|
|
||||||
|
await auth.configAuthentication();
|
||||||
|
|
||||||
|
expect(fs.existsSync(m2Dir)).toBe(true);
|
||||||
|
expect(fs.existsSync(settingsFile)).toBe(true);
|
||||||
|
expect(fs.readFileSync(settingsFile, 'utf-8')).toEqual(
|
||||||
|
auth.generate(
|
||||||
|
auth.DEFAULT_ID,
|
||||||
|
auth.DEFAULT_USERNAME,
|
||||||
|
auth.DEFAULT_PASSWORD
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
it('escapes invalid XML inputs', () => {
|
||||||
|
const id = 'packages';
|
||||||
|
const username = 'USER';
|
||||||
|
const password = '&<>"\'\'"><&';
|
||||||
|
|
||||||
|
expect(auth.generate(id, username, password)).toEqual(`
|
||||||
|
<settings>
|
||||||
|
<servers>
|
||||||
|
<server>
|
||||||
|
<id>${id}</id>
|
||||||
|
<username>\${env.${username}}</username>
|
||||||
|
<password>\${env.&<>"''"><&}</password>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
</settings>
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
26
action.yml
26
action.yml
|
@ -1,9 +1,11 @@
|
||||||
name: 'Setup Java JDK'
|
name: 'Setup Java JDK'
|
||||||
description: 'Set up a specific version of the Java JDK and add the command-line tools to the PATH'
|
description: 'Set up a specific version of the Java JDK and add the
|
||||||
|
command-line tools to the PATH'
|
||||||
author: 'GitHub'
|
author: 'GitHub'
|
||||||
inputs:
|
inputs:
|
||||||
java-version:
|
java-version:
|
||||||
description: 'The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)'
|
description: 'The Java version to make available on the path. Takes a whole
|
||||||
|
or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)'
|
||||||
required: true
|
required: true
|
||||||
java-package:
|
java-package:
|
||||||
description: 'The package type (jre, jdk, jdk+fx)'
|
description: 'The package type (jre, jdk, jdk+fx)'
|
||||||
|
@ -14,7 +16,23 @@ inputs:
|
||||||
required: false
|
required: false
|
||||||
default: 'x64'
|
default: 'x64'
|
||||||
jdkFile:
|
jdkFile:
|
||||||
description: 'Path to where the compressed JDK is located. The path could be in your source repository or a local path on the agent.'
|
description: 'Path to where the compressed JDK is located. The path could
|
||||||
|
be in your source repository or a local path on the agent.'
|
||||||
|
required: false
|
||||||
|
server-id:
|
||||||
|
description: 'ID of the distributionManagement repository in the pom.xml
|
||||||
|
file. Default is `github`'
|
||||||
|
required: false
|
||||||
|
server-username:
|
||||||
|
description: 'Environment variable name for the username for authentication
|
||||||
|
to the Apache Maven repository. Default is $GITHUB_ACTOR'
|
||||||
|
required: false
|
||||||
|
server-password:
|
||||||
|
description: 'Environment variable name for password or token for
|
||||||
|
authentication to the Apache Maven repository. Default is $GITHUB_TOKEN'
|
||||||
|
required: false
|
||||||
|
settings-path:
|
||||||
|
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
|
||||||
required: false
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
|
|
Binary file not shown.
|
@ -5,10 +5,11 @@
|
||||||
"description": "setup java action",
|
"description": "setup java action",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "tsc",
|
"build": "ncc build src/setup-java.ts",
|
||||||
"format": "prettier --write **/*.ts",
|
"format": "prettier --write **/*.ts",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format-check": "prettier --check **/*.ts",
|
||||||
"release": "ncc build && git add -f dist/",
|
"prerelease": "npm run-script build",
|
||||||
|
"release": "git add -f dist/index.js",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as os from 'os';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
|
||||||
|
export const M2_DIR = '.m2';
|
||||||
|
export const SETTINGS_FILE = 'settings.xml';
|
||||||
|
|
||||||
|
export const DEFAULT_ID = 'github';
|
||||||
|
export const DEFAULT_USERNAME = 'GITHUB_ACTOR';
|
||||||
|
export const DEFAULT_PASSWORD = 'GITHUB_TOKEN';
|
||||||
|
|
||||||
|
export async function configAuthentication(
|
||||||
|
id = DEFAULT_ID,
|
||||||
|
username = DEFAULT_USERNAME,
|
||||||
|
password = DEFAULT_PASSWORD
|
||||||
|
) {
|
||||||
|
console.log(
|
||||||
|
`creating ${SETTINGS_FILE} with server-id: ${id};`,
|
||||||
|
`environment variables: username=\$${username} and password=\$${password}`
|
||||||
|
);
|
||||||
|
// when an alternate m2 location is specified use only that location (no .m2 directory)
|
||||||
|
// otherwise use the home/.m2/ path
|
||||||
|
const directory: string = path.join(
|
||||||
|
core.getInput('settings-path') || os.homedir(),
|
||||||
|
core.getInput('settings-path') ? '' : M2_DIR
|
||||||
|
);
|
||||||
|
await io.mkdirP(directory);
|
||||||
|
core.debug(`created directory ${directory}`);
|
||||||
|
await write(directory, generate(id, username, password));
|
||||||
|
}
|
||||||
|
|
||||||
|
function escapeXML(value: string) {
|
||||||
|
return value
|
||||||
|
.replace(/&/g, '&')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''');
|
||||||
|
}
|
||||||
|
|
||||||
|
// only exported for testing purposes
|
||||||
|
export function generate(
|
||||||
|
id = DEFAULT_ID,
|
||||||
|
username = DEFAULT_USERNAME,
|
||||||
|
password = DEFAULT_PASSWORD
|
||||||
|
) {
|
||||||
|
return `
|
||||||
|
<settings>
|
||||||
|
<servers>
|
||||||
|
<server>
|
||||||
|
<id>${escapeXML(id)}</id>
|
||||||
|
<username>\${env.${escapeXML(username)}}</username>
|
||||||
|
<password>\${env.${escapeXML(password)}}</password>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
</settings>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function write(directory: string, settings: string) {
|
||||||
|
const location = path.join(directory, SETTINGS_FILE);
|
||||||
|
if (fs.existsSync(location)) {
|
||||||
|
console.warn(`overwriting existing file ${location}`);
|
||||||
|
} else {
|
||||||
|
console.log(`writing ${location}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fs.writeFileSync(location, settings, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
flag: 'w'
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as installer from './installer';
|
import * as installer from './installer';
|
||||||
|
import * as auth from './auth';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
|
@ -16,6 +17,14 @@ async function run() {
|
||||||
|
|
||||||
const matchersPath = path.join(__dirname, '..', '.github');
|
const matchersPath = path.join(__dirname, '..', '.github');
|
||||||
console.log(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);
|
console.log(`##[add-matcher]${path.join(matchersPath, 'java.json')}`);
|
||||||
|
|
||||||
|
const id = core.getInput('server-id', {required: false}) || undefined;
|
||||||
|
const username =
|
||||||
|
core.getInput('server-username', {required: false}) || undefined;
|
||||||
|
const password =
|
||||||
|
core.getInput('server-password', {required: false}) || undefined;
|
||||||
|
|
||||||
|
await auth.configAuthentication(id, username, password);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue