Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,27 +29,27 @@ Examples of version specifications that the java-version parameter will accept:
- A major Java version

e.g. ```6, 7, 8, 9, 10, 11, 12, 13, ...```

- A semver Java version specification

e.g. ```8.0.232, 7.0.181, 11.0.4```

e.g. ```8.0.x, >11.0.3, >=13.0.1, <8.0.212```

- An early access (EA) Java version

e.g. ```14-ea, 15-ea```

e.g. ```14.0.0-ea, 15.0.0-ea```

e.g. ```14.0.0-ea.28, 15.0.0-ea.2``` (syntax for specifying an EA build number)

Note that, per semver rules, EA builds will be matched by explicit EA version specifications.

- 1.x syntax

e.g. ```1.8``` (same as ```8```)

e.g. ```1.8.0.212``` (same as ```8.0.212```)


Expand Down Expand Up @@ -113,12 +113,15 @@ jobs:
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
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase

- name: Publish to Apache Maven Central
run: mvn deploy
run: mvn deploy
env:
MAVEN_USERNAME: maven_username123
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
```

The two `settings.xml` files created from the above example look like the following.
Expand All @@ -131,6 +134,10 @@ The two `settings.xml` files created from the above example look like the follow
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>${env.GPG_PASSPHRASE}</passphrase>
</server>
</servers>
```

Expand All @@ -142,10 +149,14 @@ The two `settings.xml` files created from the above example look like the follow
<username>${env.MAVEN_USERNAME}</username>
<password>${env.MAVEN_CENTRAL_TOKEN}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>${env.MAVEN_GPG_PASSPHRASE}</passphrase>
</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.***
***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.

Expand All @@ -172,7 +183,7 @@ jobs:
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`.***
***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.

Expand Down
116 changes: 102 additions & 14 deletions __tests__/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import io = require('@actions/io');
import fs = require('fs');
import os = require('os');
import path = require('path');
import exec = require('@actions/exec');

// make the os.homedir() call be local to the tests
jest.doMock('os', () => {
Expand All @@ -10,19 +11,32 @@ jest.doMock('os', () => {
};
});

jest.mock('@actions/exec', () => {
return {
exec: jest.fn()
};
});

const tempDir = path.join(__dirname, 'runner', 'temp');
process.env['RUNNER_TEMP'] = tempDir;

import * as auth from '../src/auth';

const m2Dir = path.join(__dirname, auth.M2_DIR);
const gpgHomeDir = auth.GPG_HOME_DIR;
const settingsFile = path.join(m2Dir, auth.SETTINGS_FILE);
const privateKeyFile = path.join(tempDir, auth.PRIVATE_KEY_FILE);

describe('auth tests', () => {
beforeEach(async () => {
await io.rmRF(m2Dir);
await io.mkdirP(tempDir);
}, 300000);

afterAll(async () => {
try {
await io.rmRF(m2Dir);
await io.rmRF(tempDir);
} catch {
console.log('Failed to remove test directories');
}
Expand Down Expand Up @@ -53,7 +67,7 @@ describe('auth tests', () => {
await io.rmRF(altHome);
}, 100000);

it('creates settings.xml with username and password', async () => {
it('creates settings.xml with minimal configuration', async () => {
const id = 'packages';
const username = 'UNAME';
const password = 'TOKEN';
Expand All @@ -67,6 +81,28 @@ describe('auth tests', () => {
);
}, 100000);

it('creates settings.xml with gpg data', async () => {
const id = 'packages';
const username = 'UNAME';
const password = 'TOKEN';
const gpgPrivateKey = 'PRIVATE';
const gpgPassphrase = 'GPG';

await auth.configAuthentication(
id,
username,
password,
gpgPrivateKey,
gpgPassphrase
);

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)
);
}, 100000);

it('overwrites existing settings.xml files', async () => {
const id = 'packages';
const username = 'USERNAME';
Expand Down Expand Up @@ -124,21 +160,73 @@ describe('auth tests', () => {
);
}, 100000);

it('escapes invalid XML inputs', () => {
it('generates valid settings.xml', () => {
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>
`);
const gpgPassphrase = 'PASSPHRASE';

const expectedSettings = `<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}</id>
<username>\${env.${username}}</username>
<password>\${env.&amp;&lt;&gt;"''"&gt;&lt;&amp;}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>\${env.${gpgPassphrase}}</passphrase>
</server>
</servers>
<profiles>
<profile>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.homedir>${gpgHomeDir}</gpg.homedir>
</properties>
</profile>
</profiles>
</settings>`;

expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
expectedSettings
);
});

it('imports gpg private key', async () => {
const id = 'packages';
const username = 'USERNAME';
const password = 'PASSWORD';
const gpgPrivateKey = 'KEY CONTENTS';

await auth.configAuthentication(id, username, password, gpgPrivateKey);

expect(exec.exec).toHaveBeenCalledWith(
'gpg',
expect.anything(),
expect.anything()
);

expect(fs.existsSync(privateKeyFile)).toBe(false);
}, 100000);

it('does not import gpg private key when private key is not set', async () => {
const id = 'packages';
const username = 'USERNAME';
const password = 'PASSWORD';

await auth.configAuthentication(id, username, password);

expect(exec.exec).not.toHaveBeenCalledWith(
'gpg',
expect.anything(),
expect.anything()
);

expect(fs.existsSync(privateKeyFile)).toBe(false);
}, 100000);
});
61 changes: 61 additions & 0 deletions __tests__/util.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import path = require('path');

const env = process.env;

describe('util tests', () => {
beforeEach(() => {
const tempEnv = Object.assign({}, env);
delete tempEnv.RUNNER_TEMP;
delete tempEnv.USERPROFILE;
process.env = tempEnv;
Object.defineProperty(process, 'platform', {value: 'linux'});
});

describe('getTempDir', () => {
it('gets temp dir using env', () => {
process.env['RUNNER_TEMP'] = 'defaulttmp';
const util = require('../src/util');

const tempDir = util.getTempDir();

expect(tempDir).toEqual(process.env['RUNNER_TEMP']);
});

it('gets temp dir for windows using userprofile', () => {
Object.defineProperty(process, 'platform', {value: 'win32'});
process.env['USERPROFILE'] = 'winusertmp';
const util = require('../src/util');

const tempDir = util.getTempDir();

expect(tempDir).toEqual(
path.join(process.env['USERPROFILE'], 'actions', 'temp')
);
});

it('gets temp dir for windows using c drive', () => {
Object.defineProperty(process, 'platform', {value: 'win32'});
const util = require('../src/util');

const tempDir = util.getTempDir();

expect(tempDir).toEqual(path.join('C:\\', 'actions', 'temp'));
});

it('gets temp dir for mac', () => {
Object.defineProperty(process, 'platform', {value: 'darwin'});
const util = require('../src/util');

const tempDir = util.getTempDir();

expect(tempDir).toEqual(path.join('/Users', 'actions', 'temp'));
});

it('gets temp dir for linux', () => {
const util = require('../src/util');
const tempDir = util.getTempDir();

expect(tempDir).toEqual(path.join('/home', 'actions', 'temp'));
});
});
});
7 changes: 7 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ inputs:
settings-path:
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
required: false
gpg-private-key:
description: 'GPG private key to import. Default is empty string.'
required: false
gpg-passphrase:
description: 'Environment variable name for the GPG private key passphrase. Default is
$GPG_PASSPHRASE.'
required: false
runs:
using: 'node12'
main: 'dist/index.js'
Loading