mirror of
https://github.com/actions/labeler.git
synced 2025-12-13 13:07:24 +00:00
[Beta] Implement the new structure of the match object for the changed-files section (#680)
* Implement the new structure of the match object for changed files section * Replace inner loops with the find method
This commit is contained in:
@@ -3,11 +3,25 @@ import * as github from '@actions/github';
|
||||
import {Minimatch} from 'minimatch';
|
||||
|
||||
export interface ChangedFilesMatchConfig {
|
||||
changedFiles?: string[];
|
||||
changedFiles?: ChangedFilesGlobPatternsConfig[];
|
||||
}
|
||||
|
||||
interface ChangedFilesGlobPatternsConfig {
|
||||
AnyGlobToAnyFile?: string[];
|
||||
AnyGlobToAllFiles?: string[];
|
||||
AllGlobsToAnyFile?: string[];
|
||||
AllGlobsToAllFiles?: string[];
|
||||
}
|
||||
|
||||
type ClientType = ReturnType<typeof github.getOctokit>;
|
||||
|
||||
const ALLOWED_FILES_CONFIG_KEYS = [
|
||||
'AnyGlobToAnyFile',
|
||||
'AnyGlobToAllFiles',
|
||||
'AllGlobsToAnyFile',
|
||||
'AllGlobsToAllFiles'
|
||||
];
|
||||
|
||||
export async function getChangedFiles(
|
||||
client: ClientType,
|
||||
prNumber: number
|
||||
@@ -35,76 +49,305 @@ export function toChangedFilesMatchConfig(
|
||||
if (!config['changed-files'] || !config['changed-files'].length) {
|
||||
return {};
|
||||
}
|
||||
const changedFilesConfigs = Array.isArray(config['changed-files'])
|
||||
? config['changed-files']
|
||||
: [config['changed-files']];
|
||||
|
||||
const changedFilesConfig = config['changed-files'];
|
||||
const validChangedFilesConfigs: ChangedFilesGlobPatternsConfig[] = [];
|
||||
|
||||
changedFilesConfigs.forEach(changedFilesConfig => {
|
||||
if (!isObject(changedFilesConfig)) {
|
||||
throw new Error(
|
||||
`The "changed-files" section must have a valid config structure. Please read the action documentation for more information`
|
||||
);
|
||||
}
|
||||
|
||||
const changedFilesConfigKeys = Object.keys(changedFilesConfig);
|
||||
const invalidKeys = changedFilesConfigKeys.filter(
|
||||
key => !ALLOWED_FILES_CONFIG_KEYS.includes(key)
|
||||
);
|
||||
|
||||
if (invalidKeys.length) {
|
||||
throw new Error(
|
||||
`Unknown config options were under "changed-files": ${invalidKeys.join(
|
||||
', '
|
||||
)}`
|
||||
);
|
||||
}
|
||||
|
||||
changedFilesConfigKeys.forEach(key => {
|
||||
validChangedFilesConfigs.push({
|
||||
[key]: Array.isArray(changedFilesConfig[key])
|
||||
? changedFilesConfig[key]
|
||||
: [changedFilesConfig[key]]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
changedFiles: Array.isArray(changedFilesConfig)
|
||||
? changedFilesConfig
|
||||
: [changedFilesConfig]
|
||||
changedFiles: validChangedFilesConfigs
|
||||
};
|
||||
}
|
||||
|
||||
function isObject(obj: unknown): obj is object {
|
||||
return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
|
||||
}
|
||||
|
||||
function printPattern(matcher: Minimatch): string {
|
||||
return (matcher.negate ? '!' : '') + matcher.pattern;
|
||||
}
|
||||
|
||||
function isAnyMatch(changedFile: string, matchers: Minimatch[]): boolean {
|
||||
core.debug(` matching patterns against file ${changedFile}`);
|
||||
for (const matcher of matchers) {
|
||||
core.debug(` - ${printPattern(matcher)}`);
|
||||
if (matcher.match(changedFile)) {
|
||||
core.debug(` ${printPattern(matcher)} matched`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(` no patterns matched`);
|
||||
return false;
|
||||
}
|
||||
|
||||
function isAllMatch(changedFile: string, matchers: Minimatch[]): boolean {
|
||||
core.debug(` matching patterns against file ${changedFile}`);
|
||||
for (const matcher of matchers) {
|
||||
core.debug(` - ${printPattern(matcher)}`);
|
||||
if (!matcher.match(changedFile)) {
|
||||
core.debug(` ${printPattern(matcher)} did not match`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(` all patterns matched`);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function checkAnyChangedFiles(
|
||||
changedFiles: string[],
|
||||
globs: string[]
|
||||
globPatternsConfigs: ChangedFilesGlobPatternsConfig[]
|
||||
): boolean {
|
||||
const matchers = globs.map(g => new Minimatch(g));
|
||||
for (const changedFile of changedFiles) {
|
||||
if (isAnyMatch(changedFile, matchers)) {
|
||||
core.debug(` "any" patterns matched against ${changedFile}`);
|
||||
return true;
|
||||
core.debug(` checking "changed-files" patterns`);
|
||||
|
||||
for (const globPatternsConfig of globPatternsConfigs) {
|
||||
if (globPatternsConfig.AnyGlobToAnyFile) {
|
||||
if (
|
||||
checkIfAnyGlobMatchesAnyFile(
|
||||
changedFiles,
|
||||
globPatternsConfig.AnyGlobToAnyFile
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" matched`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (globPatternsConfig.AnyGlobToAllFiles) {
|
||||
if (
|
||||
checkIfAnyGlobMatchesAllFiles(
|
||||
changedFiles,
|
||||
globPatternsConfig.AnyGlobToAllFiles
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" matched`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (globPatternsConfig.AllGlobsToAnyFile) {
|
||||
if (
|
||||
checkIfAllGlobsMatchAnyFile(
|
||||
changedFiles,
|
||||
globPatternsConfig.AllGlobsToAnyFile
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" matched`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (globPatternsConfig.AllGlobsToAllFiles) {
|
||||
if (
|
||||
checkIfAllGlobsMatchAllFiles(
|
||||
changedFiles,
|
||||
globPatternsConfig.AllGlobsToAllFiles
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" matched`);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(` "any" patterns did not match any files`);
|
||||
core.debug(` "changed-files" did not match`);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkAllChangedFiles(
|
||||
changedFiles: string[],
|
||||
globPatternsConfigs: ChangedFilesGlobPatternsConfig[]
|
||||
): boolean {
|
||||
core.debug(` checking "changed-files" patterns`);
|
||||
|
||||
for (const globPatternsConfig of globPatternsConfigs) {
|
||||
if (globPatternsConfig.AnyGlobToAnyFile) {
|
||||
if (
|
||||
!checkIfAnyGlobMatchesAnyFile(
|
||||
changedFiles,
|
||||
globPatternsConfig.AnyGlobToAnyFile
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" did not match`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (globPatternsConfig.AnyGlobToAllFiles) {
|
||||
if (
|
||||
!checkIfAnyGlobMatchesAllFiles(
|
||||
changedFiles,
|
||||
globPatternsConfig.AnyGlobToAllFiles
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" did not match`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (globPatternsConfig.AllGlobsToAnyFile) {
|
||||
if (
|
||||
!checkIfAllGlobsMatchAnyFile(
|
||||
changedFiles,
|
||||
globPatternsConfig.AllGlobsToAnyFile
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" did not match`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (globPatternsConfig.AllGlobsToAllFiles) {
|
||||
if (
|
||||
!checkIfAllGlobsMatchAllFiles(
|
||||
changedFiles,
|
||||
globPatternsConfig.AllGlobsToAllFiles
|
||||
)
|
||||
) {
|
||||
core.debug(` "changed-files" did not match`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(` "changed-files" patterns matched`);
|
||||
return true;
|
||||
}
|
||||
|
||||
export function checkIfAnyGlobMatchesAnyFile(
|
||||
changedFiles: string[],
|
||||
globs: string[]
|
||||
): boolean {
|
||||
core.debug(` checking "AnyGlobToAnyFile" config patterns`);
|
||||
const matchers = globs.map(g => new Minimatch(g));
|
||||
|
||||
for (const matcher of matchers) {
|
||||
const matchedFile = changedFiles.find(changedFile => {
|
||||
core.debug(
|
||||
` checking "${printPattern(
|
||||
matcher
|
||||
)}" pattern against ${changedFile}`
|
||||
);
|
||||
|
||||
return matcher.match(changedFile);
|
||||
});
|
||||
|
||||
if (matchedFile) {
|
||||
core.debug(
|
||||
` "${printPattern(matcher)}" pattern matched ${matchedFile}`
|
||||
);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(` none of the patterns matched any of the files`);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkIfAllGlobsMatchAnyFile(
|
||||
changedFiles: string[],
|
||||
globs: string[]
|
||||
): boolean {
|
||||
core.debug(` checking "AllGlobsToAnyFile" config patterns`);
|
||||
const matchers = globs.map(g => new Minimatch(g));
|
||||
|
||||
for (const changedFile of changedFiles) {
|
||||
if (!isAllMatch(changedFile, matchers)) {
|
||||
core.debug(` "all" patterns did not match against ${changedFile}`);
|
||||
const mismatchedGlob = matchers.find(matcher => {
|
||||
core.debug(
|
||||
` checking "${printPattern(
|
||||
matcher
|
||||
)}" pattern against ${changedFile}`
|
||||
);
|
||||
|
||||
return !matcher.match(changedFile);
|
||||
});
|
||||
|
||||
if (mismatchedGlob) {
|
||||
core.debug(
|
||||
` "${printPattern(
|
||||
mismatchedGlob
|
||||
)}" pattern did not match ${changedFile}`
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
core.debug(` all patterns matched ${changedFile}`);
|
||||
return true;
|
||||
}
|
||||
|
||||
core.debug(` none of the files matched all patterns`);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkIfAnyGlobMatchesAllFiles(
|
||||
changedFiles: string[],
|
||||
globs: string[]
|
||||
): boolean {
|
||||
core.debug(` checking "AnyGlobToAllFiles" config patterns`);
|
||||
const matchers = globs.map(g => new Minimatch(g));
|
||||
|
||||
for (const matcher of matchers) {
|
||||
const mismatchedFile = changedFiles.find(changedFile => {
|
||||
core.debug(
|
||||
` checking "${printPattern(
|
||||
matcher
|
||||
)}" pattern against ${changedFile}`
|
||||
);
|
||||
|
||||
return !matcher.match(changedFile);
|
||||
});
|
||||
|
||||
if (mismatchedFile) {
|
||||
core.debug(
|
||||
` "${printPattern(
|
||||
matcher
|
||||
)}" pattern did not match ${mismatchedFile}`
|
||||
);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
core.debug(` "${printPattern(matcher)}" pattern matched all files`);
|
||||
return true;
|
||||
}
|
||||
|
||||
core.debug(` none of the patterns matched all files`);
|
||||
return false;
|
||||
}
|
||||
|
||||
export function checkIfAllGlobsMatchAllFiles(
|
||||
changedFiles: string[],
|
||||
globs: string[]
|
||||
): boolean {
|
||||
core.debug(` checking "AllGlobsToAllFiles" config patterns`);
|
||||
const matchers = globs.map(g => new Minimatch(g));
|
||||
|
||||
for (const changedFile of changedFiles) {
|
||||
const mismatchedGlob = matchers.find(matcher => {
|
||||
core.debug(
|
||||
` checking "${printPattern(
|
||||
matcher
|
||||
)}" pattern against ${changedFile}`
|
||||
);
|
||||
|
||||
return !matcher.match(changedFile);
|
||||
});
|
||||
|
||||
if (mismatchedGlob) {
|
||||
core.debug(
|
||||
` "${printPattern(
|
||||
mismatchedGlob
|
||||
)}" pattern did not match ${changedFile}`
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
core.debug(` "all" patterns matched all files`);
|
||||
core.debug(` all patterns matched all files`);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user