Change the structure of the config

This commit is contained in:
Josh Dales
2023-03-24 21:08:59 -04:00
parent 5d0a66ed59
commit e51b118725
2 changed files with 114 additions and 71 deletions

View File

@@ -3,10 +3,7 @@ import * as github from '@actions/github';
import {Minimatch} from 'minimatch'; import {Minimatch} from 'minimatch';
export interface ChangedFilesMatchConfig { export interface ChangedFilesMatchConfig {
changedFiles?: { changedFiles?: string[];
all?: string[];
any?: string[];
};
} }
type ClientType = ReturnType<typeof github.getOctokit>; type ClientType = ReturnType<typeof github.getOctokit>;
@@ -35,60 +32,17 @@ export async function getChangedFiles(
export function toChangedFilesMatchConfig( export function toChangedFilesMatchConfig(
config: any config: any
): ChangedFilesMatchConfig { ): ChangedFilesMatchConfig {
if (!config['changed-files']) { if (!config['changed-files'] || !config['changed-files'].length) {
return {}; return {};
} }
const changedFilesConfig = config['changed-files']; const changedFilesConfig = config['changed-files'];
// If the value provided is a string or an array of strings then default to `any` matching return {
if (typeof changedFilesConfig === 'string') { changedFiles: Array.isArray(changedFilesConfig)
return { ? changedFilesConfig
changedFiles: { : [changedFilesConfig]
any: [changedFilesConfig]
}
};
}
const changedFilesMatchConfig = {
changedFiles: {}
}; };
if (Array.isArray(changedFilesConfig)) {
if (
changedFilesConfig.length &&
changedFilesConfig.every(entry => typeof entry === 'string')
) {
changedFilesMatchConfig.changedFiles = {
any: changedFilesConfig
};
} else {
// If it is not an array of strings then it should be array of further config options
// so assign them to our `changedFilesMatchConfig`
changedFilesMatchConfig.changedFiles = changedFilesConfig.reduce(
(updatedMatchConfig, configValue) => {
if (!configValue) {
return updatedMatchConfig;
}
Object.entries(configValue).forEach(([key, value]) => {
if (key === 'any' || key === 'all') {
updatedMatchConfig[key] = Array.isArray(value) ? value : [value];
}
});
return updatedMatchConfig;
},
{}
);
}
}
// If no items were added to `changedFiles` then return an empty object
if (!Object.keys(changedFilesMatchConfig.changedFiles).length) {
return {};
}
return changedFilesMatchConfig;
} }
function printPattern(matcher: Minimatch): string { function printPattern(matcher: Minimatch): string {

View File

@@ -5,13 +5,16 @@ import * as yaml from 'js-yaml';
import { import {
ChangedFilesMatchConfig, ChangedFilesMatchConfig,
getChangedFiles, getChangedFiles,
toChangedFilesMatchConfig, toChangedFilesMatchConfig
checkAny,
checkAll
} from './changedFiles'; } from './changedFiles';
import {checkBranch, toBranchMatchConfig, BranchMatchConfig} from './branch'; import {checkBranch, toBranchMatchConfig, BranchMatchConfig} from './branch';
export type MatchConfig = ChangedFilesMatchConfig & BranchMatchConfig; export type BaseMatchConfig = BranchMatchConfig & ChangedFilesMatchConfig;
export type MatchConfig = {
any?: BaseMatchConfig[];
all?: BaseMatchConfig[];
};
type ClientType = ReturnType<typeof github.getOctokit>; type ClientType = ReturnType<typeof github.getOctokit>;
@@ -105,7 +108,7 @@ async function fetchContent(
return Buffer.from(response.data.content, response.data.encoding).toString(); return Buffer.from(response.data.content, response.data.encoding).toString();
} }
function getLabelConfigMapFromObject( export function getLabelConfigMapFromObject(
configObject: any configObject: any
): Map<string, MatchConfig[]> { ): Map<string, MatchConfig[]> {
const labelMap: Map<string, MatchConfig[]> = new Map(); const labelMap: Map<string, MatchConfig[]> = new Map();
@@ -119,15 +122,51 @@ function getLabelConfigMapFromObject(
`found unexpected type for label ${label} (should be array of config options)` `found unexpected type for label ${label} (should be array of config options)`
); );
} }
const matchConfigs = configOptions.reduce<MatchConfig[]>(
(updatedConfig, configValue) => {
if (!configValue) {
return updatedConfig;
}
Object.entries(configValue).forEach(([key, value]) => {
// If the top level `any` or `all` keys are provided then set them, and convert their values to
// our config objects.
if (key === 'any' || key === 'all') {
if (Array.isArray(value)) {
const newConfigs = value.map(toMatchConfig);
updatedConfig.push({[key]: newConfigs});
}
} else if (
// These are the keys that we accept and know how to process
['changed-files', 'head-branch', 'base-branch'].includes(key)
) {
const newMatchConfig = toMatchConfig({[key]: value});
// Find or set the `any` key so that we can add these properties to that rule,
// Or create a new `any` key and add that to our array of configs.
const indexOfAny = updatedConfig.findIndex(mc => !!mc['any']);
if (indexOfAny >= 0) {
updatedConfig[indexOfAny].any?.push(newMatchConfig);
} else {
updatedConfig.push({any: [newMatchConfig]});
}
} else {
// Log the key that we don't know what to do with.
core.info(`An unknown config option was under ${label}: ${key}`);
}
});
return updatedConfig;
},
[]
);
const matchConfigs = configOptions.map(toMatchConfig);
labelMap.set(label, matchConfigs); labelMap.set(label, matchConfigs);
} }
return labelMap; return labelMap;
} }
export function toMatchConfig(config: any): MatchConfig { export function toMatchConfig(config: any): BaseMatchConfig {
const changedFilesConfig = toChangedFilesMatchConfig(config); const changedFilesConfig = toChangedFilesMatchConfig(config);
const branchConfig = toBranchMatchConfig(config); const branchConfig = toBranchMatchConfig(config);
@@ -156,30 +195,80 @@ function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean {
return false; return false;
} }
if (matchConfig.changedFiles?.all) { if (matchConfig.all) {
if (!checkAll(changedFiles, matchConfig.changedFiles.all)) { // check the options and if anything fails then return false
if (!checkAll(matchConfig.all, changedFiles)) {
return false; return false;
} }
} }
if (matchConfig.changedFiles?.any) { if (matchConfig.any) {
if (!checkAny(changedFiles, matchConfig.changedFiles.any)) { // Check all the various options if any pass return true
return false; if (checkAny(matchConfig.any, changedFiles)) {
return true;
} }
} }
if (matchConfig.headBranch) { return true;
if (!checkBranch(matchConfig.headBranch, 'head')) { }
return false;
// equivalent to "Array.some()" but expanded for debugging and clarity
export function checkAny(
matchConfigs: BaseMatchConfig[],
_changedFiles: string[]
): boolean {
core.debug(` checking "any" patterns`);
for (const matchConfig of matchConfigs) {
if (matchConfig.baseBranch) {
if (checkBranch(matchConfig.baseBranch, 'base')) {
return true;
}
}
// if (matchConfig.changedFiles) {
// if (checkFiles(matchConfig.changedFiles, changedFiles)) {
// return true;
// }
// }
if (matchConfig.headBranch) {
if (checkBranch(matchConfig.headBranch, 'head')) {
return true;
}
} }
} }
if (matchConfig.baseBranch) { core.debug(` "any" patterns did not match any configs`);
if (!checkBranch(matchConfig.baseBranch, 'base')) { return false;
return false; }
// equivalent to "Array.every()" but expanded for debugging and clarity
export function checkAll(
matchConfigs: BaseMatchConfig[],
_changedFiles: string[]
): boolean {
core.debug(` checking "all" patterns`);
for (const matchConfig of matchConfigs) {
if (matchConfig.baseBranch) {
if (!checkBranch(matchConfig.baseBranch, 'base')) {
return false;
}
}
// if (matchConfig.changedFiles) {
// if (checkFiles(matchConfig.changedFiles, changedFiles)) {
// return true;
// }
// }
if (matchConfig.headBranch) {
if (!checkBranch(matchConfig.headBranch, 'head')) {
return false;
}
} }
} }
core.debug(` "all" patterns matched all files`);
return true; return true;
} }