mirror of
https://github.com/renovatebot/github-action.git
synced 2025-12-27 12:43:37 +00:00
feat: add passing of Renovate environment variables
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. Closes #136.
This commit is contained in:
parent
846f705b78
commit
008f05800b
8 changed files with 110 additions and 42 deletions
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
|
|
@ -48,6 +48,8 @@ jobs:
|
||||||
run: npm run build
|
run: npm run build
|
||||||
- name: Renovate test
|
- name: Renovate test
|
||||||
uses: ./
|
uses: ./
|
||||||
|
env:
|
||||||
|
LOG_LEVEL: debug
|
||||||
with:
|
with:
|
||||||
configurationFile: ${{ matrix.configurationFile }}
|
configurationFile: ${{ matrix.configurationFile }}
|
||||||
token: ${{ secrets.RENOVATE_TOKEN }}
|
token: ${{ secrets.RENOVATE_TOKEN }}
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@ GitHub Action to run Renovate self-hosted.
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
|
Options can be passed using the inputs of this action or the corresponding environment variables. When both are passed, the input takes precedence over the environment variable. For the available environment variables see the Renovate [Self-Hosted Configuration](https://docs.renovatebot.com/self-hosted-configuration/) and [Self-Hosting](https://docs.renovatebot.com/self-hosting/) docs.
|
||||||
|
|
||||||
## `configurationFile`
|
## `configurationFile`
|
||||||
|
|
||||||
Configuration file to configure Renovate. The supported configurations files can be one of the configuration files listed in the Renovate Docs for [Configuration Options](https://docs.renovatebot.com/configuration-options/) or a JavaScript file that exports a configuration object. For both of these options, an example can be found in the [example](./example) directory.
|
Configuration file to configure Renovate. The supported configurations files can be one of the configuration files listed in the Renovate Docs for [Configuration Options](https://docs.renovatebot.com/configuration-options/) or a JavaScript file that exports a configuration object. For both of these options, an example can be found in the [example](./example) directory.
|
||||||
|
|
@ -81,7 +83,7 @@ jobs:
|
||||||
Instead of using a Personal Access Token (PAT) that is tied to a particular user you can use a [GitHub App](https://docs.github.com/en/developers/apps/building-github-apps) where permissions can be even better tuned. [Create a new app](https://docs.github.com/en/developers/apps/creating-a-github-app) and give it the following permissions:
|
Instead of using a Personal Access Token (PAT) that is tied to a particular user you can use a [GitHub App](https://docs.github.com/en/developers/apps/building-github-apps) where permissions can be even better tuned. [Create a new app](https://docs.github.com/en/developers/apps/creating-a-github-app) and give it the following permissions:
|
||||||
|
|
||||||
| Permission | Level |
|
| Permission | Level |
|
||||||
|-----------------|---------------------|
|
| --------------- | -------------- |
|
||||||
| `Contents` | `Read & write` |
|
| `Contents` | `Read & write` |
|
||||||
| `Metadata` | `Read-only` |
|
| `Metadata` | `Read-only` |
|
||||||
| `Pull requests` | `Read & write` |
|
| `Pull requests` | `Read & write` |
|
||||||
|
|
@ -121,5 +123,5 @@ jobs:
|
||||||
uses: renovatebot/github-action@v21.30.0
|
uses: renovatebot/github-action@v21.30.0
|
||||||
with:
|
with:
|
||||||
configurationFile: example/renovate-config.js
|
configurationFile: example/renovate-config.js
|
||||||
token: "x-access-token:${{ steps.get_token.outputs.app_token }}"
|
token: 'x-access-token:${{ steps.get_token.outputs.app_token }}'
|
||||||
```
|
```
|
||||||
|
|
|
||||||
10
action.yml
10
action.yml
|
|
@ -6,14 +6,16 @@ branding:
|
||||||
color: blue
|
color: blue
|
||||||
inputs:
|
inputs:
|
||||||
configurationFile:
|
configurationFile:
|
||||||
description: 'Configuration file to configure Renovate'
|
description: |
|
||||||
|
Configuration file to configure Renovate. Either use this input or the
|
||||||
|
'RENOVATE_CONFIG_FILE' environment variable.
|
||||||
required: false
|
required: false
|
||||||
default: src/config.js
|
|
||||||
token:
|
token:
|
||||||
description: |
|
description: |
|
||||||
GitHub personal access token that Renovate should use. This should be
|
GitHub personal access token that Renovate should use. This should be
|
||||||
configured using a Secret.
|
configured using a Secret. Either use this input or the 'RENOVATE_TOKEN'
|
||||||
required: true
|
environment variable.
|
||||||
|
required: false
|
||||||
runs:
|
runs:
|
||||||
using: node12
|
using: node12
|
||||||
main: dist/index.js
|
main: dist/index.js
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@ module.exports = {
|
||||||
branchPrefix: 'test-renovate/',
|
branchPrefix: 'test-renovate/',
|
||||||
dryRun: true,
|
dryRun: true,
|
||||||
gitAuthor: 'Renovate Bot <bot@renovateapp.com>',
|
gitAuthor: 'Renovate Bot <bot@renovateapp.com>',
|
||||||
logLevel: 'debug',
|
|
||||||
onboarding: false,
|
onboarding: false,
|
||||||
platform: 'github',
|
platform: 'github',
|
||||||
includeForks: true,
|
includeForks: true,
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
"branchPrefix": "test-renovate/",
|
"branchPrefix": "test-renovate/",
|
||||||
"dryRun": true,
|
"dryRun": true,
|
||||||
"gitAuthor": "Renovate Bot <bot@renovateapp.com>",
|
"gitAuthor": "Renovate Bot <bot@renovateapp.com>",
|
||||||
"logLevel": "debug",
|
|
||||||
"onboarding": false,
|
"onboarding": false,
|
||||||
"platform": "github",
|
"platform": "github",
|
||||||
"includeForks": true,
|
"includeForks": true,
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import Renovate from './renovate';
|
||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const input = new Input();
|
const input = new Input();
|
||||||
const renovate = new Renovate(input.configurationFile, input.token);
|
const renovate = new Renovate(input);
|
||||||
|
|
||||||
await renovate.runDockerContainer();
|
await renovate.runDockerContainer();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
||||||
74
src/input.ts
74
src/input.ts
|
|
@ -1,20 +1,78 @@
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
interface EnvironmentVariable {
|
||||||
|
key: string;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
class Input {
|
class Input {
|
||||||
readonly configurationFile = core.getInput('configurationFile', {
|
readonly options = {
|
||||||
required: true,
|
envRegex: /^(?:RENOVATE_\w+|LOG_LEVEL)$/,
|
||||||
});
|
configurationFile: {
|
||||||
readonly token = core.getInput('token', { required: true });
|
input: 'configurationFile',
|
||||||
|
env: 'RENOVATE_CONFIG_FILE',
|
||||||
|
},
|
||||||
|
token: {
|
||||||
|
input: 'token',
|
||||||
|
env: 'RENOVATE_TOKEN',
|
||||||
|
},
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
private readonly _environmentVariables: Map<string, string>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.validate();
|
this._environmentVariables = new Map(
|
||||||
|
Object.entries(process.env).filter(([key]) =>
|
||||||
|
this.options.envRegex.test(key)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
this.setEnvironmentVariable(
|
||||||
|
this.options.token.input,
|
||||||
|
this.options.token.env
|
||||||
|
);
|
||||||
|
this.setEnvironmentVariable(
|
||||||
|
this.options.configurationFile.input,
|
||||||
|
this.options.configurationFile.env
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): void {
|
configurationFile(): string {
|
||||||
if (this.token === '') {
|
return path.resolve(
|
||||||
throw new Error('input.token MUST NOT be empty');
|
this._environmentVariables.get(this.options.configurationFile.env)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to environment variables.
|
||||||
|
*
|
||||||
|
* @note The environment variable for the configuration file is filtered out
|
||||||
|
* and is available with `configurationFile()` instead.
|
||||||
|
*/
|
||||||
|
toEnvironmentVariables(): EnvironmentVariable[] {
|
||||||
|
return [...this._environmentVariables].map(([key, value]) => ({
|
||||||
|
key,
|
||||||
|
value,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private setEnvironmentVariable(input: string, env: string) {
|
||||||
|
const optionalInput = core.getInput(input);
|
||||||
|
if (optionalInput === '' && !this._environmentVariables.has(env)) {
|
||||||
|
throw new Error(
|
||||||
|
[
|
||||||
|
`'${input}' MUST be passed using its input or the '${env}'`,
|
||||||
|
'environment variable',
|
||||||
|
].join(' ')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optionalInput !== '') {
|
||||||
|
this._environmentVariables.set(env, optionalInput);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Input;
|
export default Input;
|
||||||
|
export { EnvironmentVariable, Input };
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,16 @@
|
||||||
import Docker from './docker';
|
import Docker from './docker';
|
||||||
|
import { Input } from './input';
|
||||||
import { exec } from '@actions/exec';
|
import { exec } from '@actions/exec';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
|
||||||
class Renovate {
|
class Renovate {
|
||||||
private configFileEnv = 'RENOVATE_CONFIG_FILE';
|
|
||||||
private tokenEnv = 'RENOVATE_TOKEN';
|
|
||||||
private dockerGroupName = 'docker';
|
private dockerGroupName = 'docker';
|
||||||
private configFileMountDir = '/github-action';
|
private configFileMountDir = '/github-action';
|
||||||
|
|
||||||
private configFile: string;
|
|
||||||
private docker: Docker;
|
private docker: Docker;
|
||||||
|
|
||||||
constructor(configFile: string, private token: string) {
|
constructor(private input: Input) {
|
||||||
this.configFile = path.resolve(configFile);
|
|
||||||
|
|
||||||
this.validateArguments();
|
this.validateArguments();
|
||||||
|
|
||||||
this.docker = new Docker();
|
this.docker = new Docker();
|
||||||
|
|
@ -22,18 +18,28 @@ class Renovate {
|
||||||
|
|
||||||
async runDockerContainer(): Promise<void> {
|
async runDockerContainer(): Promise<void> {
|
||||||
const renovateDockerUser = 'ubuntu';
|
const renovateDockerUser = 'ubuntu';
|
||||||
const githubActionsDockerGroupId = this.getDockerGroupId();
|
|
||||||
const commandArguments = [
|
const dockerArguments = [
|
||||||
|
...this.input.toEnvironmentVariables(),
|
||||||
|
{
|
||||||
|
key: this.input.options.configurationFile.env,
|
||||||
|
value: this.configFileMountPath(),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
.map((e) => {
|
||||||
|
const quotedValue = /\s/.test(e.value) ? `'${e.value}'` : e.value;
|
||||||
|
return `--env ${e.key}=${quotedValue}`;
|
||||||
|
})
|
||||||
|
.concat([
|
||||||
|
`--volume ${this.input.configurationFile()}:${this.configFileMountPath()}`,
|
||||||
|
'--volume /var/run/docker.sock:/var/run/docker.sock',
|
||||||
|
'--volume /tmp:/tmp',
|
||||||
|
`--user ${renovateDockerUser}:${this.getDockerGroupId()}`,
|
||||||
'--rm',
|
'--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(),
|
this.docker.image(),
|
||||||
];
|
]);
|
||||||
const command = `docker run ${commandArguments.join(' ')}`;
|
|
||||||
|
const command = `docker run ${dockerArguments.join(' ')}`;
|
||||||
|
|
||||||
const code = await exec(command);
|
const code = await exec(command);
|
||||||
if (code !== 0) {
|
if (code !== 0) {
|
||||||
|
|
@ -71,15 +77,15 @@ class Renovate {
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateArguments(): void {
|
private validateArguments(): void {
|
||||||
if (!fs.existsSync(this.configFile)) {
|
if (!fs.existsSync(this.input.configurationFile())) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not locate configuration file '${this.configFile}'.`
|
`Could not locate configuration file '${this.input.configurationFile()}'.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private configFileName(): string {
|
private configFileName(): string {
|
||||||
return path.basename(this.configFile);
|
return path.basename(this.input.configurationFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
private configFileMountPath(): string {
|
private configFileMountPath(): string {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue