Use config-file for both remote and local config-files
This commit is contained in:
@@ -71,22 +71,21 @@ or by inlining these options in your workflow file.
|
||||
|
||||
### config-file
|
||||
|
||||
A string representing the path to a configuraton file local to the repo.
|
||||
|
||||
**Possible values**: A string representing an absolute path to a file.
|
||||
|
||||
**Example**: `config-file: ./.github/dependency-review-config.yml`.
|
||||
|
||||
### remote-config-file
|
||||
|
||||
A string representing the path to a configuraton file in an external repo. It follows the
|
||||
A string representing the path to a configuraton file. The
|
||||
configuration file can be local to the repo, or can be a file in an
|
||||
external repo. If you are referencing a configuration file located in an
|
||||
external repository, you can use the
|
||||
`OWNER/REPOSITORY/FILENAME@BRANCH` syntax.
|
||||
|
||||
If the file is located in a private repository, use the [remote-config-repo-token](#remote-config-repo-token) parameter of the action to specify a token that has read access to the repository.
|
||||
If the configuration file is located in an external private
|
||||
repository, use the [external-repository-token](#external-repository-token) parameter of the action to specify a token that has read access to the repository.
|
||||
|
||||
**Possible values**: A string representing a path to a file located in another repository:
|
||||
**Possible values**: A string representing an absolute path to a file,
|
||||
or a file located in another repository:
|
||||
|
||||
**Example**: `config-file: github/octorepo/dependency-review-config.yml@main`
|
||||
**Example**: `config-file: ./.github/dependency-review-config.yml # local file`.
|
||||
|
||||
**Example**: `config-file: github/octorepo/dependency-review-config.yml@main # external repo`
|
||||
|
||||
### fail-on-severity
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {expect, test, beforeEach} from '@jest/globals'
|
||||
import {readConfig, readConfigFile} from '../src/config'
|
||||
import {readConfig, parseConfigFile} from '../src/config'
|
||||
import {getRefs} from '../src/git-refs'
|
||||
import * as Utils from '../src/utils'
|
||||
|
||||
@@ -97,13 +97,13 @@ test('it raises an error when no refs are provided and the event is not a pull r
|
||||
})
|
||||
|
||||
test.skip('it reads an external config file', async () => {
|
||||
let options = readConfigFile('./__tests__/fixtures/config-allow-sample.yml')
|
||||
let options = parseConfigFile('./__tests__/fixtures/config-allow-sample.yml')
|
||||
expect(options.fail_on_severity).toEqual('critical')
|
||||
expect(options.allow_licenses).toEqual(['BSD', 'GPL 2'])
|
||||
})
|
||||
|
||||
test.skip('raises an error when the the config file was not found', () => {
|
||||
expect(() => readConfigFile('fixtures/i-dont-exist')).toThrow()
|
||||
expect(() => parseConfigFile('fixtures/i-dont-exist')).toThrow()
|
||||
})
|
||||
|
||||
test('it parses options from both sources', async () => {
|
||||
|
||||
@@ -35,9 +35,6 @@ inputs:
|
||||
remote-config-repo-token:
|
||||
description: A token for fetching external configuration file if it lives in another repository. It is required if the repository is private
|
||||
required: false
|
||||
remote-config-file:
|
||||
description: 'Path to the configuration file in another repository.'
|
||||
required: false
|
||||
|
||||
runs:
|
||||
using: 'node16'
|
||||
|
||||
+43
-38
@@ -27421,7 +27421,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
||||
exports.getRepoConfig = exports.readConfigFile = exports.readInlineConfig = exports.readConfig = void 0;
|
||||
exports.parseConfigFile = exports.readConfigFile = exports.readInlineConfig = exports.readConfig = void 0;
|
||||
const fs = __importStar(__nccwpck_require__(7147));
|
||||
const path_1 = __importDefault(__nccwpck_require__(1017));
|
||||
const yaml_1 = __importDefault(__nccwpck_require__(4083));
|
||||
@@ -27456,24 +27456,17 @@ function validateLicenses(key, licenses) {
|
||||
}
|
||||
function readConfig() {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const remoteConfigFile = getOptionalInput('remote-config-file');
|
||||
const repoConfigFile = getOptionalInput('config-file');
|
||||
const inlineConfig = readInlineConfig();
|
||||
let remoteConfig = {};
|
||||
let repoConfig = {};
|
||||
if (remoteConfigFile !== undefined) {
|
||||
const fileContents = readConfigFile(yield getRemoteConfig(remoteConfigFile));
|
||||
remoteConfig = Object.assign(Object.assign({}, remoteConfig), fileContents);
|
||||
const configFile = getOptionalInput('config-file');
|
||||
if (configFile !== undefined) {
|
||||
const externalConfig = yield readConfigFile(configFile);
|
||||
// the reasoning behind reading the inline config when an external
|
||||
// config file is provided is that we still want to allow users to
|
||||
// pass inline options in the presence of an external config file.
|
||||
// TO DO check order of precedence
|
||||
return Object.assign(Object.assign({}, inlineConfig), externalConfig);
|
||||
}
|
||||
if (repoConfigFile !== undefined) {
|
||||
const fileContents = readConfigFile(getRepoConfig(repoConfigFile));
|
||||
repoConfig = Object.assign(Object.assign({}, repoConfig), fileContents);
|
||||
}
|
||||
// the reasoning behind reading the inline config when an external
|
||||
// config file is provided is that we still want to allow users to
|
||||
// pass inline options in the presence of an external config file.
|
||||
// TO DO check order of precedence
|
||||
return Object.assign(Object.assign(Object.assign({}, inlineConfig), remoteConfig), repoConfig);
|
||||
return inlineConfig;
|
||||
});
|
||||
}
|
||||
exports.readConfig = readConfig;
|
||||
@@ -27517,7 +27510,33 @@ function readInlineConfig() {
|
||||
};
|
||||
}
|
||||
exports.readInlineConfig = readInlineConfig;
|
||||
function readConfigFile(configData) {
|
||||
function readConfigFile(filePath) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||
let data;
|
||||
const pieces = format.exec(filePath);
|
||||
try {
|
||||
if ((pieces === null || pieces === void 0 ? void 0 : pieces.groups) && pieces.length === 5) {
|
||||
data = yield getRemoteConfig({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref
|
||||
});
|
||||
}
|
||||
else {
|
||||
data = fs.readFileSync(path_1.default.resolve(filePath), 'utf-8');
|
||||
}
|
||||
return parseConfigFile(data);
|
||||
}
|
||||
catch (error) {
|
||||
core.debug(error);
|
||||
throw new Error('Unable to fetch config file');
|
||||
}
|
||||
});
|
||||
}
|
||||
exports.readConfigFile = readConfigFile;
|
||||
function parseConfigFile(configData) {
|
||||
try {
|
||||
const data = yaml_1.default.parse(configData);
|
||||
for (const key of Object.keys(data)) {
|
||||
@@ -27537,32 +27556,18 @@ function readConfigFile(configData) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
exports.readConfigFile = readConfigFile;
|
||||
function getRepoConfig(filePath) {
|
||||
try {
|
||||
return fs.readFileSync(path_1.default.resolve(filePath), 'utf-8');
|
||||
}
|
||||
catch (error) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
exports.getRepoConfig = getRepoConfig;
|
||||
function getRemoteConfig(configFile) {
|
||||
exports.parseConfigFile = parseConfigFile;
|
||||
function getRemoteConfig(configOpts) {
|
||||
return __awaiter(this, void 0, void 0, function* () {
|
||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||
const pieces = format.exec(configFile);
|
||||
if (pieces === null || pieces.groups === undefined || pieces.length < 5) {
|
||||
throw new Error('Invalid remote-config-file value. Expected format: OWNER/REPOSITORY/FILENAME@BRANCH ');
|
||||
}
|
||||
try {
|
||||
const { data } = yield (0, utils_1.octokitClient)('remote-config-repo-token', false).rest.repos.getContent({
|
||||
mediaType: {
|
||||
format: 'raw'
|
||||
},
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref
|
||||
owner: configOpts.owner,
|
||||
repo: configOpts.repo,
|
||||
path: configOpts.path,
|
||||
ref: configOpts.ref
|
||||
});
|
||||
// When using mediaType.format = 'raw', the response.data is a string but this is not reflected
|
||||
// in the return type of getContent. So we're casting the return value to a string.
|
||||
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+44
-42
@@ -48,27 +48,18 @@ function validateLicenses(
|
||||
}
|
||||
|
||||
export async function readConfig(): Promise<ConfigurationOptions> {
|
||||
const remoteConfigFile = getOptionalInput('remote-config-file')
|
||||
const repoConfigFile = getOptionalInput('config-file')
|
||||
|
||||
const inlineConfig = readInlineConfig()
|
||||
let remoteConfig: ConfigurationOptions = {}
|
||||
let repoConfig: ConfigurationOptions = {}
|
||||
|
||||
if (remoteConfigFile !== undefined) {
|
||||
const fileContents = readConfigFile(await getRemoteConfig(remoteConfigFile))
|
||||
remoteConfig = {...remoteConfig, ...fileContents}
|
||||
const configFile = getOptionalInput('config-file')
|
||||
if (configFile !== undefined) {
|
||||
const externalConfig = await readConfigFile(configFile)
|
||||
// the reasoning behind reading the inline config when an external
|
||||
// config file is provided is that we still want to allow users to
|
||||
// pass inline options in the presence of an external config file.
|
||||
// TO DO check order of precedence
|
||||
return {...inlineConfig, ...externalConfig}
|
||||
}
|
||||
|
||||
if (repoConfigFile !== undefined) {
|
||||
const fileContents = readConfigFile(getRepoConfig(repoConfigFile))
|
||||
repoConfig = {...repoConfig, ...fileContents}
|
||||
}
|
||||
// the reasoning behind reading the inline config when an external
|
||||
// config file is provided is that we still want to allow users to
|
||||
// pass inline options in the presence of an external config file.
|
||||
// TO DO check order of precedence
|
||||
return {...inlineConfig, ...remoteConfig, ...repoConfig}
|
||||
return inlineConfig
|
||||
}
|
||||
|
||||
export function readInlineConfig(): ConfigurationOptions {
|
||||
@@ -119,7 +110,34 @@ export function readInlineConfig(): ConfigurationOptions {
|
||||
}
|
||||
}
|
||||
|
||||
export function readConfigFile(configData: string): ConfigurationOptions {
|
||||
export async function readConfigFile(
|
||||
filePath: string
|
||||
): Promise<ConfigurationOptions> {
|
||||
const format = new RegExp(
|
||||
'(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)'
|
||||
)
|
||||
let data: string
|
||||
|
||||
const pieces = format.exec(filePath)
|
||||
try {
|
||||
if (pieces?.groups && pieces.length === 5) {
|
||||
data = await getRemoteConfig({
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref
|
||||
})
|
||||
} else {
|
||||
data = fs.readFileSync(path.resolve(filePath), 'utf-8')
|
||||
}
|
||||
return parseConfigFile(data)
|
||||
} catch (error) {
|
||||
core.debug(error as string)
|
||||
throw new Error('Unable to fetch config file')
|
||||
}
|
||||
}
|
||||
|
||||
export function parseConfigFile(configData: string): ConfigurationOptions {
|
||||
try {
|
||||
const data = YAML.parse(configData)
|
||||
for (const key of Object.keys(data)) {
|
||||
@@ -139,25 +157,9 @@ export function readConfigFile(configData: string): ConfigurationOptions {
|
||||
}
|
||||
}
|
||||
|
||||
export function getRepoConfig(filePath: string): string {
|
||||
try {
|
||||
return fs.readFileSync(path.resolve(filePath), 'utf-8')
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
async function getRemoteConfig(configFile: string): Promise<string> {
|
||||
const format = new RegExp(
|
||||
'(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)'
|
||||
)
|
||||
|
||||
const pieces = format.exec(configFile)
|
||||
if (pieces === null || pieces.groups === undefined || pieces.length < 5) {
|
||||
throw new Error(
|
||||
'Invalid remote-config-file value. Expected format: OWNER/REPOSITORY/FILENAME@BRANCH '
|
||||
)
|
||||
}
|
||||
async function getRemoteConfig(configOpts: {
|
||||
[key: string]: string
|
||||
}): Promise<string> {
|
||||
try {
|
||||
const {data} = await octokitClient(
|
||||
'remote-config-repo-token',
|
||||
@@ -166,10 +168,10 @@ async function getRemoteConfig(configFile: string): Promise<string> {
|
||||
mediaType: {
|
||||
format: 'raw'
|
||||
},
|
||||
owner: pieces.groups.owner,
|
||||
repo: pieces.groups.repo,
|
||||
path: pieces.groups.path,
|
||||
ref: pieces.groups.ref
|
||||
owner: configOpts.owner,
|
||||
repo: configOpts.repo,
|
||||
path: configOpts.path,
|
||||
ref: configOpts.ref
|
||||
})
|
||||
|
||||
// When using mediaType.format = 'raw', the response.data is a string but this is not reflected
|
||||
|
||||
Reference in New Issue
Block a user