Merge pull request #33 from actions/master

Merge master into releases/v1
This commit is contained in:
Konrad Pabjan 2020-01-02 11:32:54 -05:00 committed by GitHub
commit b74d5a6a96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 394 additions and 16 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
dist/index.js -diff -merge
dist/index.js linguist-generated=true

View File

@ -1,5 +1,5 @@
name: Main workflow name: Main workflow
on: [push] on: [push, pull_request]
jobs: jobs:
run: run:
name: Run name: Run

1
.gitignore vendored
View File

@ -93,3 +93,4 @@ typings/
# DynamoDB Local files # DynamoDB Local files
.dynamodb/ .dynamodb/
.vscode/

128
README.md
View File

@ -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:
@ -45,7 +45,7 @@ jobs:
strategy: strategy:
matrix: matrix:
# test against latest update of each major Java version, as well as specific updates of LTS versions: # test against latest update of each major Java version, as well as specific updates of LTS versions:
java: [ 1.6, 6.0.83, 7, 7.0.181, 8, 8.0.192, 9.0,x, 10, 11.0.x, 11.0.3, 12, 13 ] java: [ 1.6, 6.0.83, 7, 7.0.181, 8, 8.0.192, 9.0.x, 10, 11.0.x, 11.0.3, 12, 13 ]
name: Java ${{ matrix.java }} sample name: Java ${{ matrix.java }} sample
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@master
@ -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)

144
__tests__/auth.test.ts Normal file
View File

@ -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.&amp;&lt;&gt;&quot;&apos;&apos;&quot;&gt;&lt;&amp;}</password>
</server>
</servers>
</settings>
`);
});
});

View File

@ -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'

BIN
dist/index.js generated vendored

Binary file not shown.

BIN
dist/unzip vendored Normal file

Binary file not shown.

6
package-lock.json generated
View File

@ -2289,9 +2289,9 @@
"dev": true "dev": true
}, },
"handlebars": { "handlebars": {
"version": "4.1.2", "version": "4.5.3",
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.3.tgz",
"integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==", "integrity": "sha512-3yPecJoJHK/4c6aZhSvxOyG4vJKDshV36VHp0iVCDVh7o9w2vwi3NSnL2MMPj3YdduqaBcu7cGbggJQM0br9xA==",
"dev": true, "dev": true,
"requires": { "requires": {
"neo-async": "^2.6.0", "neo-async": "^2.6.0",

View File

@ -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": {

74
src/auth.ts Normal file
View File

@ -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, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
// 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'
});
}

View File

@ -266,8 +266,17 @@ function normalizeVersion(version: string): string {
} }
} }
// Add trailing .x if it is missing if (version.endsWith('-ea')) {
if (version.split('.').length != 3) { // convert e.g. 14-ea to 14.0.0-ea
if (version.indexOf('.') == -1) {
version = version.slice(0, version.length - 3) + '.0.0-ea';
}
// match anything in -ea.X (semver won't do .x matching on pre-release versions)
if (version[0] >= '0' && version[0] <= '9') {
version = '>=' + version;
}
} else if (version.split('.').length < 3) {
// For non-ea versions, add trailing .x if it is missing
if (version[version.length - 1] != 'x') { if (version[version.length - 1] != 'x') {
version = version + '.x'; version = version + '.x';
} }

View File

@ -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);
} }