mirror of
https://github.com/renovatebot/github-action.git
synced 2025-12-17 09:22:36 +00:00
feat: add passing of Renovate environment variables (#534)
Inputs may now be provided using environment variables, as well as the existing inputs. None of the inputs are required any more, so it is possible to use only environment variables. Nevertheless all inputs must be provided in some way, either using the input or their corresponding environment variables. BREAKING CHANGE: The `configurationFile` input no longer has a default value. This means that a value for it is now required using the `configurationFile` input or the `RENOVATE_CONFIG_FILE` environment variable. Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
This commit is contained in:
parent
525abe5975
commit
9c8a784d88
8 changed files with 139 additions and 48 deletions
|
|
@ -5,7 +5,7 @@ import Renovate from './renovate';
|
|||
async function run(): Promise<void> {
|
||||
try {
|
||||
const input = new Input();
|
||||
const renovate = new Renovate(input.configurationFile, input.token);
|
||||
const renovate = new Renovate(input);
|
||||
|
||||
await renovate.runDockerContainer();
|
||||
} catch (error) {
|
||||
|
|
|
|||
94
src/input.ts
94
src/input.ts
|
|
@ -1,20 +1,98 @@
|
|||
import * as core from '@actions/core';
|
||||
import path from 'path';
|
||||
|
||||
interface EnvironmentVariable {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
class Input {
|
||||
readonly configurationFile = core.getInput('configurationFile', {
|
||||
required: true,
|
||||
});
|
||||
readonly token = core.getInput('token', { required: true });
|
||||
readonly options = {
|
||||
envRegex: /^(?:RENOVATE_\w+|LOG_LEVEL)$/,
|
||||
configurationFile: {
|
||||
input: 'configurationFile',
|
||||
env: 'RENOVATE_CONFIG_FILE',
|
||||
optional: true,
|
||||
},
|
||||
token: {
|
||||
input: 'token',
|
||||
env: 'RENOVATE_TOKEN',
|
||||
optional: false,
|
||||
},
|
||||
} as const;
|
||||
readonly token: Readonly<EnvironmentVariable>;
|
||||
|
||||
private readonly _environmentVariables: Map<string, string>;
|
||||
private readonly _configurationFile: Readonly<EnvironmentVariable>;
|
||||
|
||||
constructor() {
|
||||
this.validate();
|
||||
this._environmentVariables = new Map(
|
||||
Object.entries(process.env).filter(([key]) =>
|
||||
this.options.envRegex.test(key)
|
||||
)
|
||||
);
|
||||
|
||||
this.token = this.get(
|
||||
this.options.token.input,
|
||||
this.options.token.env,
|
||||
this.options.token.optional
|
||||
);
|
||||
this._configurationFile = this.get(
|
||||
this.options.configurationFile.input,
|
||||
this.options.configurationFile.env,
|
||||
this.options.configurationFile.optional
|
||||
);
|
||||
}
|
||||
|
||||
validate(): void {
|
||||
if (this.token === '') {
|
||||
throw new Error('input.token MUST NOT be empty');
|
||||
configurationFile(): EnvironmentVariable | null {
|
||||
if (this._configurationFile.value !== '') {
|
||||
return {
|
||||
key: this._configurationFile.key,
|
||||
value: path.resolve(this._configurationFile.value),
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to environment variables.
|
||||
*
|
||||
* @note The environment variables listed below are filtered out.
|
||||
* - Token, available with the `token` property.
|
||||
* - Configuration file, available with the `configurationFile()` method.
|
||||
*/
|
||||
toEnvironmentVariables(): EnvironmentVariable[] {
|
||||
return [...this._environmentVariables].map(([key, value]) => ({
|
||||
key,
|
||||
value,
|
||||
}));
|
||||
}
|
||||
|
||||
private get(
|
||||
input: string,
|
||||
env: string,
|
||||
optional: boolean
|
||||
): EnvironmentVariable {
|
||||
const fromInput = core.getInput(input);
|
||||
const fromEnv = this._environmentVariables.get(env);
|
||||
|
||||
if (fromInput === '' && fromEnv === undefined && !optional) {
|
||||
throw new Error(
|
||||
[
|
||||
`'${input}' MUST be passed using its input or the '${env}'`,
|
||||
'environment variable',
|
||||
].join(' ')
|
||||
);
|
||||
}
|
||||
|
||||
this._environmentVariables.delete(env);
|
||||
if (fromInput !== '') {
|
||||
return { key: env, value: fromInput };
|
||||
}
|
||||
return { key: env, value: fromEnv !== undefined ? fromEnv : '' };
|
||||
}
|
||||
}
|
||||
|
||||
export default Input;
|
||||
export { EnvironmentVariable, Input };
|
||||
|
|
|
|||
|
|
@ -1,20 +1,16 @@
|
|||
import Docker from './docker';
|
||||
import { Input } from './input';
|
||||
import { exec } from '@actions/exec';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
class Renovate {
|
||||
private configFileEnv = 'RENOVATE_CONFIG_FILE';
|
||||
private tokenEnv = 'RENOVATE_TOKEN';
|
||||
private dockerGroupName = 'docker';
|
||||
private configFileMountDir = '/github-action';
|
||||
|
||||
private configFile: string;
|
||||
private docker: Docker;
|
||||
|
||||
constructor(configFile: string, private token: string) {
|
||||
this.configFile = path.resolve(configFile);
|
||||
|
||||
constructor(private input: Input) {
|
||||
this.validateArguments();
|
||||
|
||||
this.docker = new Docker();
|
||||
|
|
@ -22,18 +18,30 @@ class Renovate {
|
|||
|
||||
async runDockerContainer(): Promise<void> {
|
||||
const renovateDockerUser = 'ubuntu';
|
||||
const githubActionsDockerGroupId = this.getDockerGroupId();
|
||||
const commandArguments = [
|
||||
|
||||
const dockerArguments = this.input
|
||||
.toEnvironmentVariables()
|
||||
.map((e) => `--env ${e.key}`)
|
||||
.concat([`--env ${this.input.token.key}=${this.input.token.value}`]);
|
||||
|
||||
if (this.input.configurationFile() !== null) {
|
||||
const baseName = path.basename(this.input.configurationFile().value);
|
||||
const mountPath = path.join(this.configFileMountDir, baseName);
|
||||
dockerArguments.push(
|
||||
`--env ${this.input.configurationFile().key}=${mountPath}`,
|
||||
`--volume ${this.input.configurationFile().value}:${mountPath}`
|
||||
);
|
||||
}
|
||||
|
||||
dockerArguments.push(
|
||||
'--volume /var/run/docker.sock:/var/run/docker.sock',
|
||||
'--volume /tmp:/tmp',
|
||||
`--user ${renovateDockerUser}:${this.getDockerGroupId()}`,
|
||||
'--rm',
|
||||
`--env ${this.configFileEnv}=${this.configFileMountPath()}`,
|
||||
`--env ${this.tokenEnv}=${this.token}`,
|
||||
`--volume ${this.configFile}:${this.configFileMountPath()}`,
|
||||
`--volume /var/run/docker.sock:/var/run/docker.sock`,
|
||||
`--volume /tmp:/tmp`,
|
||||
`--user ${renovateDockerUser}:${githubActionsDockerGroupId}`,
|
||||
this.docker.image(),
|
||||
];
|
||||
const command = `docker run ${commandArguments.join(' ')}`;
|
||||
this.docker.image()
|
||||
);
|
||||
|
||||
const command = `docker run ${dockerArguments.join(' ')}`;
|
||||
|
||||
const code = await exec(command);
|
||||
if (code !== 0) {
|
||||
|
|
@ -71,20 +79,21 @@ class Renovate {
|
|||
}
|
||||
|
||||
private validateArguments(): void {
|
||||
if (!fs.existsSync(this.configFile)) {
|
||||
if (/\s/.test(this.input.token.value)) {
|
||||
throw new Error('Token MUST NOT contain whitespace');
|
||||
}
|
||||
|
||||
const configurationFile = this.input.configurationFile();
|
||||
if (
|
||||
configurationFile !== null &&
|
||||
(!fs.existsSync(configurationFile.value) ||
|
||||
!fs.statSync(configurationFile.value).isFile())
|
||||
) {
|
||||
throw new Error(
|
||||
`Could not locate configuration file '${this.configFile}'.`
|
||||
`configuration file '${configurationFile.value}' MUST be an existing file`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private configFileName(): string {
|
||||
return path.basename(this.configFile);
|
||||
}
|
||||
|
||||
private configFileMountPath(): string {
|
||||
return path.join(this.configFileMountDir, this.configFileName());
|
||||
}
|
||||
}
|
||||
|
||||
export default Renovate;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue