Added support for GPG
This commit is contained in:
parent
5c87b70ffe
commit
d94db22179
49
README.md
49
README.md
|
@ -29,27 +29,27 @@ Examples of version specifications that the java-version parameter will accept:
|
||||||
- A major Java version
|
- A major Java version
|
||||||
|
|
||||||
e.g. ```6, 7, 8, 9, 10, 11, 12, 13, ...```
|
e.g. ```6, 7, 8, 9, 10, 11, 12, 13, ...```
|
||||||
|
|
||||||
- A semver Java version specification
|
- A semver Java version specification
|
||||||
|
|
||||||
e.g. ```8.0.232, 7.0.181, 11.0.4```
|
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```
|
e.g. ```8.0.x, >11.0.3, >=13.0.1, <8.0.212```
|
||||||
|
|
||||||
- An early access (EA) Java version
|
- An early access (EA) Java version
|
||||||
|
|
||||||
e.g. ```14-ea, 15-ea```
|
e.g. ```14-ea, 15-ea```
|
||||||
|
|
||||||
e.g. ```14.0.0-ea, 15.0.0-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)
|
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.
|
Note that, per semver rules, EA builds will be matched by explicit EA version specifications.
|
||||||
|
|
||||||
- 1.x syntax
|
- 1.x syntax
|
||||||
|
|
||||||
e.g. ```1.8``` (same as ```8```)
|
e.g. ```1.8``` (same as ```8```)
|
||||||
|
|
||||||
e.g. ```1.8.0.212``` (same as ```8.0.212```)
|
e.g. ```1.8.0.212``` (same as ```8.0.212```)
|
||||||
|
|
||||||
|
|
||||||
|
@ -113,39 +113,58 @@ jobs:
|
||||||
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
|
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-username: MAVEN_USERNAME # env variable for username in deploy
|
||||||
server-password: MAVEN_CENTRAL_TOKEN # env variable for token 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
|
- name: Publish to Apache Maven Central
|
||||||
run: mvn deploy
|
run: mvn deploy
|
||||||
env:
|
env:
|
||||||
MAVEN_USERNAME: maven_username123
|
MAVEN_USERNAME: maven_username123
|
||||||
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
|
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.
|
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
|
`settings.xml` file created for the first deploy to GitHub Packages
|
||||||
```xml
|
```xml
|
||||||
<servers>
|
<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>
|
<server>
|
||||||
<id>github</id>
|
<id>github</id>
|
||||||
<username>${env.GITHUB_ACTOR}</username>
|
<username>${env.GITHUB_ACTOR}</username>
|
||||||
<password>${env.GITHUB_TOKEN}</password>
|
<password>${env.GITHUB_TOKEN}</password>
|
||||||
</server>
|
</server>
|
||||||
</servers>
|
<server>
|
||||||
|
<id>gpg.passphrase</id>
|
||||||
|
<passphrase>${env.GPG_PASSPHRASE}</passphrase>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
</settings>
|
||||||
```
|
```
|
||||||
|
|
||||||
`settings.xml` file created for the second deploy to Apache Maven Central
|
`settings.xml` file created for the second deploy to Apache Maven Central
|
||||||
```xml
|
```xml
|
||||||
<servers>
|
<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>
|
<server>
|
||||||
<id>maven</id>
|
<id>maven</id>
|
||||||
<username>${env.MAVEN_USERNAME}</username>
|
<username>${env.MAVEN_USERNAME}</username>
|
||||||
<password>${env.MAVEN_CENTRAL_TOKEN}</password>
|
<password>${env.MAVEN_CENTRAL_TOKEN}</password>
|
||||||
</server>
|
</server>
|
||||||
</servers>
|
<server>
|
||||||
|
<id>gpg.passphrase</id>
|
||||||
|
<passphrase>${env.MAVEN_GPG_PASSPHRASE}</passphrase>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
</settings>
|
||||||
```
|
```
|
||||||
|
|
||||||
***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.
|
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.
|
||||||
|
|
||||||
|
@ -172,7 +191,7 @@ jobs:
|
||||||
PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
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.
|
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.
|
||||||
|
|
||||||
|
|
|
@ -53,7 +53,7 @@ describe('auth tests', () => {
|
||||||
await io.rmRF(altHome);
|
await io.rmRF(altHome);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
it('creates settings.xml with username and password', async () => {
|
it('creates settings.xml with minimal configuration', async () => {
|
||||||
const id = 'packages';
|
const id = 'packages';
|
||||||
const username = 'UNAME';
|
const username = 'UNAME';
|
||||||
const password = 'TOKEN';
|
const password = 'TOKEN';
|
||||||
|
@ -67,6 +67,21 @@ describe('auth tests', () => {
|
||||||
);
|
);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
|
it('creates settings.xml with additional configuration', async () => {
|
||||||
|
const id = 'packages';
|
||||||
|
const username = 'UNAME';
|
||||||
|
const password = 'TOKEN';
|
||||||
|
const gpgPassphrase = 'GPG';
|
||||||
|
|
||||||
|
await auth.configAuthentication(id, username, password, 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 () => {
|
it('overwrites existing settings.xml files', async () => {
|
||||||
const id = 'packages';
|
const id = 'packages';
|
||||||
const username = 'USERNAME';
|
const username = 'USERNAME';
|
||||||
|
@ -86,59 +101,50 @@ describe('auth tests', () => {
|
||||||
);
|
);
|
||||||
}, 100000);
|
}, 100000);
|
||||||
|
|
||||||
it('does not create settings.xml without required parameters', async () => {
|
it('generates valid settings.xml with minimal configuration', () => {
|
||||||
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 id = 'packages';
|
||||||
const username = 'USER';
|
const username = 'USER';
|
||||||
const password = '&<>"\'\'"><&';
|
const password = '&<>"\'\'"><&';
|
||||||
|
|
||||||
expect(auth.generate(id, username, password)).toEqual(`
|
const expectedSettings = `<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||||
<settings>
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<servers>
|
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||||
<server>
|
<servers>
|
||||||
<id>${id}</id>
|
<server>
|
||||||
<username>\${env.${username}}</username>
|
<id>${id}</id>
|
||||||
<password>\${env.&<>"''"><&}</password>
|
<username>\${env.${username}}</username>
|
||||||
</server>
|
<password>\${env.&<>"''"><&}</password>
|
||||||
</servers>
|
</server>
|
||||||
</settings>
|
</servers>
|
||||||
`);
|
</settings>`;
|
||||||
|
|
||||||
|
expect(auth.generate(id, username, password)).toEqual(expectedSettings);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('generates valid settings.xml with additional configuration', () => {
|
||||||
|
const id = 'packages';
|
||||||
|
const username = 'USER';
|
||||||
|
const password = '&<>"\'\'"><&';
|
||||||
|
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.&<>"''"><&}</password>
|
||||||
|
</server>
|
||||||
|
<server>
|
||||||
|
<id>gpg.passphrase</id>
|
||||||
|
<passphrase>\${env.${gpgPassphrase}}</passphrase>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
</settings>`;
|
||||||
|
|
||||||
|
expect(auth.generate(id, username, password, gpgPassphrase)).toEqual(
|
||||||
|
expectedSettings
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import path = require('path');
|
||||||
|
import io = require('@actions/io');
|
||||||
|
import exec = require('@actions/exec');
|
||||||
|
|
||||||
|
jest.mock('@actions/exec', () => {
|
||||||
|
return {
|
||||||
|
exec: jest.fn()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
const tempDir = path.join(__dirname, 'runner', 'temp');
|
||||||
|
process.env['RUNNER_TEMP'] = tempDir;
|
||||||
|
|
||||||
|
import gpg = require('../src/gpg');
|
||||||
|
|
||||||
|
describe('gpg tests', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await io.mkdirP(tempDir);
|
||||||
|
}, 300000);
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
try {
|
||||||
|
await io.rmRF(tempDir);
|
||||||
|
} catch {
|
||||||
|
console.log('Failed to remove test directories');
|
||||||
|
}
|
||||||
|
}, 100000);
|
||||||
|
|
||||||
|
describe('importKey', () => {
|
||||||
|
it('attempts to import private key and returns null key id on failure', async () => {
|
||||||
|
const privateKey = 'KEY CONTENTS';
|
||||||
|
const keyId = await gpg.importKey(privateKey);
|
||||||
|
|
||||||
|
expect(keyId).toBeNull();
|
||||||
|
|
||||||
|
expect(exec.exec).toHaveBeenCalledWith(
|
||||||
|
'gpg',
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('deleteKey', () => {
|
||||||
|
it('deletes private key', async () => {
|
||||||
|
const keyId = 'asdfhjkl';
|
||||||
|
await gpg.deleteKey(keyId);
|
||||||
|
|
||||||
|
expect(exec.exec).toHaveBeenCalledWith(
|
||||||
|
'gpg',
|
||||||
|
expect.anything(),
|
||||||
|
expect.anything()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -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'));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
10
action.yml
10
action.yml
|
@ -36,6 +36,14 @@ inputs:
|
||||||
settings-path:
|
settings-path:
|
||||||
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
|
description: 'Path to where the settings.xml file will be written. Default is ~/.m2.'
|
||||||
required: false
|
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:
|
runs:
|
||||||
using: 'node12'
|
using: 'node12'
|
||||||
main: 'dist/index.js'
|
main: 'dist/setup/index.js'
|
||||||
|
post: 'dist/cleanup/index.js'
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -430,6 +430,74 @@
|
||||||
"@types/yargs": "^13.0.0"
|
"@types/yargs": "^13.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@oozcitak/dom": {
|
||||||
|
"version": "1.15.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/dom/-/dom-1.15.5.tgz",
|
||||||
|
"integrity": "sha512-L6v3Mwb0TaYBYgeYlIeBaHnc+2ZEaDSbFiRm5KmqZQSoBlbPlf+l6aIH/sD5GUf2MYwULw00LT7+dOnEuAEC0A==",
|
||||||
|
"requires": {
|
||||||
|
"@oozcitak/infra": "1.0.5",
|
||||||
|
"@oozcitak/url": "1.0.0",
|
||||||
|
"@oozcitak/util": "8.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@oozcitak/util": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@oozcitak/infra": {
|
||||||
|
"version": "1.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.5.tgz",
|
||||||
|
"integrity": "sha512-o+zZH7M6l5e3FaAWy3ojaPIVN5eusaYPrKm6MZQt0DKNdgXa2wDYExjpP0t/zx+GoQgQKzLu7cfD8rHCLt8JrQ==",
|
||||||
|
"requires": {
|
||||||
|
"@oozcitak/util": "8.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@oozcitak/util": {
|
||||||
|
"version": "8.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.0.0.tgz",
|
||||||
|
"integrity": "sha512-+9Hq6yuoq/3TRV/n/xcpydGBq2qN2/DEDMqNTG7rm95K6ZE2/YY/sPyx62+1n8QsE9O26e5M1URlXsk+AnN9Jw=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@oozcitak/url": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/url/-/url-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-LGrMeSxeLzsdaitxq3ZmBRVOrlRRQIgNNci6L0VRnOKlJFuRIkNm4B+BObXPCJA6JT5bEJtrrwjn30jueHJYZQ==",
|
||||||
|
"requires": {
|
||||||
|
"@oozcitak/infra": "1.0.3",
|
||||||
|
"@oozcitak/util": "1.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@oozcitak/infra": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/infra/-/infra-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-9O2wxXGnRzy76O1XUxESxDGsXT5kzETJPvYbreO4mv6bqe1+YSuux2cZTagjJ/T4UfEwFJz5ixanOqB0QgYAag==",
|
||||||
|
"requires": {
|
||||||
|
"@oozcitak/util": "1.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@oozcitak/util": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-dFwFqcKrQnJ2SapOmRD1nQWEZUtbtIy9Y6TyJquzsalWNJsKIPxmTI0KG6Ypyl8j7v89L2wixH9fQDNrF78hKg=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@oozcitak/util": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-4n8B1cWlJleSOSba5gxsMcN4tO8KkkcvXhNWW+ADqvq9Xj+Lrl9uCa90GRpjekqQJyt84aUX015DG81LFpZYXA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"@oozcitak/util": {
|
||||||
|
"version": "8.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@oozcitak/util/-/util-8.3.3.tgz",
|
||||||
|
"integrity": "sha512-Ufpab7G5PfnEhQyy5kDg9C8ltWJjsVT1P/IYqacjstaqydG4Q21HAT2HUZQYBrC/a1ZLKCz87pfydlDvv8y97w=="
|
||||||
|
},
|
||||||
"@types/babel__core": {
|
"@types/babel__core": {
|
||||||
"version": "7.1.3",
|
"version": "7.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz",
|
||||||
|
@ -4955,6 +5023,16 @@
|
||||||
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
|
"integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"xmlbuilder2": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/xmlbuilder2/-/xmlbuilder2-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-PI710tmtVlQ5VmwzbRTuhmVhKnj9pM8Si+iOZCV2g2SNo3gCrpzR2Ka9wNzZtqfD+mnP+xkrqoNy0sjKZqP4Dg==",
|
||||||
|
"requires": {
|
||||||
|
"@oozcitak/dom": "1.15.5",
|
||||||
|
"@oozcitak/infra": "1.0.5",
|
||||||
|
"@oozcitak/util": "8.3.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"y18n": {
|
"y18n": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
"description": "setup java action",
|
"description": "setup java action",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "ncc build src/setup-java.ts",
|
"build": "ncc build -o dist/setup src/setup-java.ts && ncc build -o dist/cleanup src/cleanup-java.ts",
|
||||||
"format": "prettier --write **/*.ts",
|
"format": "prettier --write **/*.ts",
|
||||||
"format-check": "prettier --check **/*.ts",
|
"format-check": "prettier --check **/*.ts",
|
||||||
"prerelease": "npm run-script build",
|
"prerelease": "npm run-script build",
|
||||||
"release": "git add -f dist/index.js",
|
"release": "git add -f dist/setup/index.js dist/cleanup/index.js",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -29,7 +29,8 @@
|
||||||
"@actions/http-client": "^1.0.6",
|
"@actions/http-client": "^1.0.6",
|
||||||
"@actions/io": "^1.0.0",
|
"@actions/io": "^1.0.0",
|
||||||
"@actions/tool-cache": "^1.3.1",
|
"@actions/tool-cache": "^1.3.1",
|
||||||
"semver": "^6.1.1"
|
"semver": "^6.1.1",
|
||||||
|
"xmlbuilder2": "^2.1.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^24.0.13",
|
"@types/jest": "^24.0.13",
|
||||||
|
|
82
src/auth.ts
82
src/auth.ts
|
@ -3,60 +3,72 @@ import * as os from 'os';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
|
import {create as xmlCreate} from 'xmlbuilder2';
|
||||||
|
|
||||||
export const M2_DIR = '.m2';
|
export const M2_DIR = '.m2';
|
||||||
export const SETTINGS_FILE = 'settings.xml';
|
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(
|
export async function configAuthentication(
|
||||||
id = DEFAULT_ID,
|
id: string,
|
||||||
username = DEFAULT_USERNAME,
|
username: string,
|
||||||
password = DEFAULT_PASSWORD
|
password: string,
|
||||||
|
gpgPassphrase: string | undefined = undefined
|
||||||
) {
|
) {
|
||||||
console.log(
|
console.log(
|
||||||
`creating ${SETTINGS_FILE} with server-id: ${id};`,
|
`creating ${SETTINGS_FILE} with server-id: ${id};`,
|
||||||
`environment variables: username=\$${username} and password=\$${password}`
|
'environment variables:',
|
||||||
|
`username=\$${username},`,
|
||||||
|
`password=\$${password},`,
|
||||||
|
`and gpg-passphrase=${gpgPassphrase ? '$' + gpgPassphrase : null}`
|
||||||
);
|
);
|
||||||
// when an alternate m2 location is specified use only that location (no .m2 directory)
|
// when an alternate m2 location is specified use only that location (no .m2 directory)
|
||||||
// otherwise use the home/.m2/ path
|
// otherwise use the home/.m2/ path
|
||||||
const directory: string = path.join(
|
const settingsDirectory: string = path.join(
|
||||||
core.getInput('settings-path') || os.homedir(),
|
core.getInput('settings-path') || os.homedir(),
|
||||||
core.getInput('settings-path') ? '' : M2_DIR
|
core.getInput('settings-path') ? '' : M2_DIR
|
||||||
);
|
);
|
||||||
await io.mkdirP(directory);
|
await io.mkdirP(settingsDirectory);
|
||||||
core.debug(`created directory ${directory}`);
|
core.debug(`created directory ${settingsDirectory}`);
|
||||||
await write(directory, generate(id, username, password));
|
await write(
|
||||||
}
|
settingsDirectory,
|
||||||
|
generate(id, username, password, gpgPassphrase)
|
||||||
function escapeXML(value: string) {
|
);
|
||||||
return value
|
|
||||||
.replace(/&/g, '&')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>')
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, ''');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// only exported for testing purposes
|
// only exported for testing purposes
|
||||||
export function generate(
|
export function generate(
|
||||||
id = DEFAULT_ID,
|
id: string,
|
||||||
username = DEFAULT_USERNAME,
|
username: string,
|
||||||
password = DEFAULT_PASSWORD
|
password: string,
|
||||||
|
gpgPassphrase: string | undefined = undefined
|
||||||
) {
|
) {
|
||||||
return `
|
const xmlObj: {[key: string]: any} = {
|
||||||
<settings>
|
settings: {
|
||||||
<servers>
|
'@xmlns': 'http://maven.apache.org/SETTINGS/1.0.0',
|
||||||
<server>
|
'@xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
|
||||||
<id>${escapeXML(id)}</id>
|
'@xsi:schemaLocation':
|
||||||
<username>\${env.${escapeXML(username)}}</username>
|
'http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd',
|
||||||
<password>\${env.${escapeXML(password)}}</password>
|
servers: {
|
||||||
</server>
|
server: [
|
||||||
</servers>
|
{
|
||||||
</settings>
|
id: id,
|
||||||
`;
|
username: `\${env.${username}}`,
|
||||||
|
password: `\${env.${password}}`
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (gpgPassphrase) {
|
||||||
|
const gpgServer = {
|
||||||
|
id: 'gpg.passphrase',
|
||||||
|
passphrase: `\${env.${gpgPassphrase}}`
|
||||||
|
};
|
||||||
|
xmlObj.settings.servers.server.push(gpgServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return xmlCreate(xmlObj).end({headless: true, prettyPrint: true, width: 80});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function write(directory: string, settings: string) {
|
async function write(directory: string, settings: string) {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
import * as core from '@actions/core';
|
||||||
|
import * as gpg from './gpg';
|
||||||
|
|
||||||
|
async function run() {
|
||||||
|
if (core.getInput('gpg-private-key', {required: false})) {
|
||||||
|
console.log('removing private key from keychain');
|
||||||
|
try {
|
||||||
|
const keyFingerprint = core.getState('gpg-private-key-fingerprint');
|
||||||
|
await gpg.deleteKey(keyFingerprint);
|
||||||
|
} catch (error) {
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run();
|
|
@ -0,0 +1,58 @@
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as io from '@actions/io';
|
||||||
|
import * as exec from '@actions/exec';
|
||||||
|
import * as util from './util';
|
||||||
|
import {ExecOptions} from '@actions/exec/lib/interfaces';
|
||||||
|
|
||||||
|
export const PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc');
|
||||||
|
|
||||||
|
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/;
|
||||||
|
|
||||||
|
export async function importKey(privateKey: string) {
|
||||||
|
fs.writeFileSync(PRIVATE_KEY_FILE, privateKey, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
flag: 'w'
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = '';
|
||||||
|
|
||||||
|
const options: ExecOptions = {
|
||||||
|
silent: true,
|
||||||
|
listeners: {
|
||||||
|
stdout: (data: Buffer) => {
|
||||||
|
output += data.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
await exec.exec(
|
||||||
|
'gpg',
|
||||||
|
[
|
||||||
|
'--batch',
|
||||||
|
'--import-options',
|
||||||
|
'import-show',
|
||||||
|
'--import',
|
||||||
|
PRIVATE_KEY_FILE
|
||||||
|
],
|
||||||
|
options
|
||||||
|
);
|
||||||
|
|
||||||
|
await io.rmRF(PRIVATE_KEY_FILE);
|
||||||
|
|
||||||
|
const match = output.match(PRIVATE_KEY_FINGERPRINT_REGEX);
|
||||||
|
return match && match[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deleteKey(keyFingerprint: string) {
|
||||||
|
await exec.exec(
|
||||||
|
'gpg',
|
||||||
|
['--batch', '--yes', '--delete-secret-keys', keyFingerprint],
|
||||||
|
{silent: true}
|
||||||
|
);
|
||||||
|
await exec.exec(
|
||||||
|
'gpg',
|
||||||
|
['--batch', '--yes', '--delete-keys', keyFingerprint],
|
||||||
|
{silent: true}
|
||||||
|
);
|
||||||
|
}
|
|
@ -1,5 +1,3 @@
|
||||||
let tempDirectory = process.env['RUNNER_TEMP'] || '';
|
|
||||||
|
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as io from '@actions/io';
|
import * as io from '@actions/io';
|
||||||
import * as exec from '@actions/exec';
|
import * as exec from '@actions/exec';
|
||||||
|
@ -8,23 +6,10 @@ import * as tc from '@actions/tool-cache';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as semver from 'semver';
|
import * as semver from 'semver';
|
||||||
|
import * as util from './util';
|
||||||
|
|
||||||
const IS_WINDOWS = process.platform === 'win32';
|
const tempDirectory = util.getTempDir();
|
||||||
|
const IS_WINDOWS = util.isWindows();
|
||||||
if (!tempDirectory) {
|
|
||||||
let baseLocation;
|
|
||||||
if (IS_WINDOWS) {
|
|
||||||
// On windows use the USERPROFILE env variable
|
|
||||||
baseLocation = process.env['USERPROFILE'] || 'C:\\';
|
|
||||||
} else {
|
|
||||||
if (process.platform === 'darwin') {
|
|
||||||
baseLocation = '/Users';
|
|
||||||
} else {
|
|
||||||
baseLocation = '/home';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getJava(
|
export async function getJava(
|
||||||
version: string,
|
version: string,
|
||||||
|
|
|
@ -1,10 +1,20 @@
|
||||||
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 auth from './auth';
|
||||||
|
import * as gpg from './gpg';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
|
|
||||||
|
const DEFAULT_ID = 'github';
|
||||||
|
const DEFAULT_USERNAME = 'GITHUB_ACTOR';
|
||||||
|
const DEFAULT_PASSWORD = 'GITHUB_TOKEN';
|
||||||
|
const DEFAULT_GPG_PRIVATE_KEY = undefined;
|
||||||
|
const DEFAULT_GPG_PASSPHRASE = 'GPG_PASSPHRASE';
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
try {
|
try {
|
||||||
|
// Set secrets before use
|
||||||
|
core.setSecret('gpg-private-key');
|
||||||
|
|
||||||
let version = core.getInput('version');
|
let version = core.getInput('version');
|
||||||
if (!version) {
|
if (!version) {
|
||||||
version = core.getInput('java-version', {required: true});
|
version = core.getInput('java-version', {required: true});
|
||||||
|
@ -15,16 +25,28 @@ async function run() {
|
||||||
|
|
||||||
await installer.getJava(version, arch, jdkFile, javaPackage);
|
await installer.getJava(version, arch, jdkFile, javaPackage);
|
||||||
|
|
||||||
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 id = core.getInput('server-id', {required: false}) || DEFAULT_ID;
|
||||||
const username =
|
const username =
|
||||||
core.getInput('server-username', {required: false}) || undefined;
|
core.getInput('server-username', {required: false}) || DEFAULT_USERNAME;
|
||||||
const password =
|
const password =
|
||||||
core.getInput('server-password', {required: false}) || undefined;
|
core.getInput('server-password', {required: false}) || DEFAULT_PASSWORD;
|
||||||
|
const gpgPrivateKey =
|
||||||
|
core.getInput('gpg-private-key', {required: false}) ||
|
||||||
|
DEFAULT_GPG_PRIVATE_KEY;
|
||||||
|
const gpgPassphrase =
|
||||||
|
core.getInput('gpg-passphrase', {required: false}) ||
|
||||||
|
(gpgPrivateKey ? DEFAULT_GPG_PASSPHRASE : undefined);
|
||||||
|
|
||||||
await auth.configAuthentication(id, username, password);
|
await auth.configAuthentication(id, username, password, gpgPassphrase);
|
||||||
|
|
||||||
|
if (gpgPrivateKey) {
|
||||||
|
console.log('importing private key');
|
||||||
|
const keyFingerprint = (await gpg.importKey(gpgPrivateKey)) || '';
|
||||||
|
core.saveState('gpg-private-key-fingerprint', keyFingerprint);
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
core.setFailed(error.message);
|
core.setFailed(error.message);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
export function getTempDir() {
|
||||||
|
let tempDirectory = process.env.RUNNER_TEMP;
|
||||||
|
if (tempDirectory === undefined) {
|
||||||
|
let baseLocation;
|
||||||
|
if (isWindows()) {
|
||||||
|
// On windows use the USERPROFILE env variable
|
||||||
|
baseLocation = process.env['USERPROFILE']
|
||||||
|
? process.env['USERPROFILE']
|
||||||
|
: 'C:\\';
|
||||||
|
} else {
|
||||||
|
if (process.platform === 'darwin') {
|
||||||
|
baseLocation = '/Users';
|
||||||
|
} else {
|
||||||
|
baseLocation = '/home';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tempDirectory = path.join(baseLocation, 'actions', 'temp');
|
||||||
|
}
|
||||||
|
return tempDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isWindows() {
|
||||||
|
return process.platform === 'win32';
|
||||||
|
}
|
Loading…
Reference in New Issue