Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enable to add label by title #109

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 75 additions & 12 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14545,17 +14545,31 @@ function run() {
console.log("Could not get pull request number from context, exiting");
return;
}
const prTitle = getPrTitle();
core.info(`prTitle: ${prTitle}`);
const client = new github.GitHub(token);
const { data: pullRequest } = yield client.pulls.get({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
pull_number: prNumber
});
const labels = [];
const labelsToRemove = [];
// add label based on title
const labelTitleRegex = yield getLabelTitleRegex(client, configPath);
for (const [label, regexs] of labelTitleRegex.entries()) {
core.debug(`processing ${label}`);
if (checkRegexs(prTitle, regexs)) {
labels.push(label);
}
else if (pullRequest.labels.find(l => l.name === label)) {
labelsToRemove.push(label);
}
}
// add label based on changed files
core.debug(`fetching changed files for pr #${prNumber}`);
const changedFiles = yield getChangedFiles(client, prNumber);
const labelGlobs = yield getLabelGlobs(client, configPath);
const labels = [];
const labelsToRemove = [];
for (const [label, globs] of labelGlobs.entries()) {
core.debug(`processing ${label}`);
if (checkGlobs(changedFiles, globs)) {
Expand Down Expand Up @@ -14585,6 +14599,13 @@ function getPrNumber() {
}
return pullRequest.number;
}
function getPrTitle() {
const pullRequest = github.context.payload.pull_request;
if (!pullRequest) {
return '';
}
return pullRequest.title;
}
function getChangedFiles(client, prNumber) {
return __awaiter(this, void 0, void 0, function* () {
const listFilesOptions = client.pulls.listFiles.endpoint.merge({
Expand Down Expand Up @@ -14623,19 +14644,53 @@ function fetchContent(client, repoPath) {
}
function getLabelGlobMapFromObject(configObject) {
const labelGlobs = new Map();
for (const label in configObject) {
if (typeof configObject[label] === "string") {
labelGlobs.set(label, [configObject[label]]);
}
else if (configObject[label] instanceof Array) {
labelGlobs.set(label, configObject[label]);
}
else {
throw Error(`found unexpected type for label ${label} (should be string or array of globs)`);
for (const configType in configObject) {
if (configType == "changed_file") {
for (const label in configObject["changed_file"]) {
const val = configObject["changed_file"][label];
if (typeof val === "string") {
labelGlobs.set(label, [val]);
}
else if (val instanceof Array) {
labelGlobs.set(label, val);
}
else {
throw Error(`found unexpected type for label ${label} (should be string or array of globs)`);
}
}
}
}
return labelGlobs;
}
function getLabelTitleRegex(client, configurationPath) {
return __awaiter(this, void 0, void 0, function* () {
const configurationContent = yield fetchContent(client, configurationPath);
// loads (hopefully) a `{[label:string]: string | StringOrMatchConfig[]}`, but is `any`:
const configObject = yaml.safeLoad(configurationContent);
// transform `any` => `Map<string,RegExp[]>` or throw if yaml is malformed:
return getLabelTitleRegexMapFromObject(configObject);
});
}
function getLabelTitleRegexMapFromObject(configObject) {
const titleRegexs = new Map();
for (const configType in configObject) {
if (configType == "title") {
for (const label in configObject["title"]) {
const val = configObject["title"][label];
if (typeof val === "string") {
titleRegexs.set(label, [new RegExp(val, 'i')]);
}
else if (val instanceof Array) {
titleRegexs.set(label, val.map(regexStr => new RegExp(regexStr, 'i')));
}
else {
throw Error(`found unexpected type for label ${label} (should be string or array of regex)`);
}
}
}
}
return titleRegexs;
}
function toMatchConfig(config) {
if (typeof config === "string") {
return {
Expand All @@ -14657,6 +14712,14 @@ function checkGlobs(changedFiles, globs) {
}
return false;
}
function checkRegexs(prTitle, regexs) {
for (const regex of regexs) {
if (regex.test(prTitle)) {
return true;
}
}
return false;
}
function isMatch(changedFile, matchers) {
core.debug(` matching patterns against file ${changedFile}`);
for (const matcher of matchers) {
Expand Down Expand Up @@ -29691,7 +29754,7 @@ module.exports = new Schema({
/***/ 954:
/***/ (function(module) {

module.exports = {"_args":[["@octokit/[email protected]","/Users/dakale/dev/GitHub/actions/labeler"]],"_from":"@octokit/[email protected]","_id":"@octokit/[email protected]","_inBundle":false,"_integrity":"sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==","_location":"/@octokit/rest","_phantomChildren":{"@octokit/types":"2.14.0","deprecation":"2.3.1","once":"1.4.0","os-name":"3.1.0"},"_requested":{"type":"version","registry":true,"raw":"@octokit/[email protected]","name":"@octokit/rest","escapedName":"@octokit%2frest","scope":"@octokit","rawSpec":"16.43.1","saveSpec":null,"fetchSpec":"16.43.1"},"_requiredBy":["/@actions/github"],"_resolved":"https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz","_spec":"16.43.1","_where":"/Users/dakale/dev/GitHub/actions/labeler","author":{"name":"Gregor Martynus","url":"https://github.com/gr2m"},"bugs":{"url":"https://github.com/octokit/rest.js/issues"},"bundlesize":[{"path":"./dist/octokit-rest.min.js.gz","maxSize":"33 kB"}],"contributors":[{"name":"Mike de Boer","email":"[email protected]"},{"name":"Fabian Jakobs","email":"[email protected]"},{"name":"Joe Gallo","email":"[email protected]"},{"name":"Gregor Martynus","url":"https://github.com/gr2m"}],"dependencies":{"@octokit/auth-token":"^2.4.0","@octokit/plugin-paginate-rest":"^1.1.1","@octokit/plugin-request-log":"^1.0.0","@octokit/plugin-rest-endpoint-methods":"2.4.0","@octokit/request":"^5.2.0","@octokit/request-error":"^1.0.2","atob-lite":"^2.0.0","before-after-hook":"^2.0.0","btoa-lite":"^1.0.0","deprecation":"^2.0.0","lodash.get":"^4.4.2","lodash.set":"^4.3.2","lodash.uniq":"^4.5.0","octokit-pagination-methods":"^1.1.0","once":"^1.4.0","universal-user-agent":"^4.0.0"},"description":"GitHub REST API client for Node.js","devDependencies":{"@gimenete/type-writer":"^0.1.3","@octokit/auth":"^1.1.1","@octokit/fixtures-server":"^5.0.6","@octokit/graphql":"^4.2.0","@types/node":"^13.1.0","bundlesize":"^0.18.0","chai":"^4.1.2","compression-webpack-plugin":"^3.1.0","cypress":"^3.0.0","glob":"^7.1.2","http-proxy-agent":"^4.0.0","lodash.camelcase":"^4.3.0","lodash.merge":"^4.6.1","lodash.upperfirst":"^4.3.1","lolex":"^5.1.2","mkdirp":"^1.0.0","mocha":"^7.0.1","mustache":"^4.0.0","nock":"^11.3.3","npm-run-all":"^4.1.2","nyc":"^15.0.0","prettier":"^1.14.2","proxy":"^1.0.0","semantic-release":"^17.0.0","sinon":"^8.0.0","sinon-chai":"^3.0.0","sort-keys":"^4.0.0","string-to-arraybuffer":"^1.0.0","string-to-jsdoc-comment":"^1.0.0","typescript":"^3.3.1","webpack":"^4.0.0","webpack-bundle-analyzer":"^3.0.0","webpack-cli":"^3.0.0"},"files":["index.js","index.d.ts","lib","plugins"],"homepage":"https://github.com/octokit/rest.js#readme","keywords":["octokit","github","rest","api-client"],"license":"MIT","name":"@octokit/rest","nyc":{"ignore":["test"]},"publishConfig":{"access":"public"},"release":{"publish":["@semantic-release/npm",{"path":"@semantic-release/github","assets":["dist/*","!dist/*.map.gz"]}]},"repository":{"type":"git","url":"git+https://github.com/octokit/rest.js.git"},"scripts":{"build":"npm-run-all build:*","build:browser":"npm-run-all build:browser:*","build:browser:development":"webpack --mode development --entry . --output-library=Octokit --output=./dist/octokit-rest.js --profile --json > dist/bundle-stats.json","build:browser:production":"webpack --mode production --entry . --plugin=compression-webpack-plugin --output-library=Octokit --output-path=./dist --output-filename=octokit-rest.min.js --devtool source-map","build:ts":"npm run -s update-endpoints:typescript","coverage":"nyc report --reporter=html && open coverage/index.html","generate-bundle-report":"webpack-bundle-analyzer dist/bundle-stats.json --mode=static --no-open --report dist/bundle-report.html","lint":"prettier --check '{lib,plugins,scripts,test}/**/*.{js,json,ts}' 'docs/*.{js,json}' 'docs/src/**/*' index.js README.md package.json","lint:fix":"prettier --write '{lib,plugins,scripts,test}/**/*.{js,json,ts}' 'docs/*.{js,json}' 'docs/src/**/*' index.js README.md package.json","postvalidate:ts":"tsc --noEmit --target es6 test/typescript-validate.ts","prebuild:browser":"mkdirp dist/","pretest":"npm run -s lint","prevalidate:ts":"npm run -s build:ts","start-fixtures-server":"octokit-fixtures-server","test":"nyc mocha test/mocha-node-setup.js \"test/*/**/*-test.js\"","test:browser":"cypress run --browser chrome","update-endpoints":"npm-run-all update-endpoints:*","update-endpoints:fetch-json":"node scripts/update-endpoints/fetch-json","update-endpoints:typescript":"node scripts/update-endpoints/typescript","validate:ts":"tsc --target es6 --noImplicitAny index.d.ts"},"types":"index.d.ts","version":"16.43.1"};
module.exports = {"_args":[["@octokit/[email protected]","/Users/masato-naka/repos/MasatoNaka/labeler"]],"_from":"@octokit/[email protected]","_id":"@octokit/[email protected]","_inBundle":false,"_integrity":"sha512-gfFKwRT/wFxq5qlNjnW2dh+qh74XgTQ2B179UX5K1HYCluioWj8Ndbgqw2PVqa1NnVJkGHp2ovMpVn/DImlmkw==","_location":"/@octokit/rest","_phantomChildren":{"@octokit/types":"2.14.0","deprecation":"2.3.1","once":"1.4.0","os-name":"3.1.0"},"_requested":{"type":"version","registry":true,"raw":"@octokit/[email protected]","name":"@octokit/rest","escapedName":"@octokit%2frest","scope":"@octokit","rawSpec":"16.43.1","saveSpec":null,"fetchSpec":"16.43.1"},"_requiredBy":["/@actions/github"],"_resolved":"https://registry.npmjs.org/@octokit/rest/-/rest-16.43.1.tgz","_spec":"16.43.1","_where":"/Users/masato-naka/repos/MasatoNaka/labeler","author":{"name":"Gregor Martynus","url":"https://github.com/gr2m"},"bugs":{"url":"https://github.com/octokit/rest.js/issues"},"bundlesize":[{"path":"./dist/octokit-rest.min.js.gz","maxSize":"33 kB"}],"contributors":[{"name":"Mike de Boer","email":"[email protected]"},{"name":"Fabian Jakobs","email":"[email protected]"},{"name":"Joe Gallo","email":"[email protected]"},{"name":"Gregor Martynus","url":"https://github.com/gr2m"}],"dependencies":{"@octokit/auth-token":"^2.4.0","@octokit/plugin-paginate-rest":"^1.1.1","@octokit/plugin-request-log":"^1.0.0","@octokit/plugin-rest-endpoint-methods":"2.4.0","@octokit/request":"^5.2.0","@octokit/request-error":"^1.0.2","atob-lite":"^2.0.0","before-after-hook":"^2.0.0","btoa-lite":"^1.0.0","deprecation":"^2.0.0","lodash.get":"^4.4.2","lodash.set":"^4.3.2","lodash.uniq":"^4.5.0","octokit-pagination-methods":"^1.1.0","once":"^1.4.0","universal-user-agent":"^4.0.0"},"description":"GitHub REST API client for Node.js","devDependencies":{"@gimenete/type-writer":"^0.1.3","@octokit/auth":"^1.1.1","@octokit/fixtures-server":"^5.0.6","@octokit/graphql":"^4.2.0","@types/node":"^13.1.0","bundlesize":"^0.18.0","chai":"^4.1.2","compression-webpack-plugin":"^3.1.0","cypress":"^3.0.0","glob":"^7.1.2","http-proxy-agent":"^4.0.0","lodash.camelcase":"^4.3.0","lodash.merge":"^4.6.1","lodash.upperfirst":"^4.3.1","lolex":"^5.1.2","mkdirp":"^1.0.0","mocha":"^7.0.1","mustache":"^4.0.0","nock":"^11.3.3","npm-run-all":"^4.1.2","nyc":"^15.0.0","prettier":"^1.14.2","proxy":"^1.0.0","semantic-release":"^17.0.0","sinon":"^8.0.0","sinon-chai":"^3.0.0","sort-keys":"^4.0.0","string-to-arraybuffer":"^1.0.0","string-to-jsdoc-comment":"^1.0.0","typescript":"^3.3.1","webpack":"^4.0.0","webpack-bundle-analyzer":"^3.0.0","webpack-cli":"^3.0.0"},"files":["index.js","index.d.ts","lib","plugins"],"homepage":"https://github.com/octokit/rest.js#readme","keywords":["octokit","github","rest","api-client"],"license":"MIT","name":"@octokit/rest","nyc":{"ignore":["test"]},"publishConfig":{"access":"public"},"release":{"publish":["@semantic-release/npm",{"path":"@semantic-release/github","assets":["dist/*","!dist/*.map.gz"]}]},"repository":{"type":"git","url":"git+https://github.com/octokit/rest.js.git"},"scripts":{"build":"npm-run-all build:*","build:browser":"npm-run-all build:browser:*","build:browser:development":"webpack --mode development --entry . --output-library=Octokit --output=./dist/octokit-rest.js --profile --json > dist/bundle-stats.json","build:browser:production":"webpack --mode production --entry . --plugin=compression-webpack-plugin --output-library=Octokit --output-path=./dist --output-filename=octokit-rest.min.js --devtool source-map","build:ts":"npm run -s update-endpoints:typescript","coverage":"nyc report --reporter=html && open coverage/index.html","generate-bundle-report":"webpack-bundle-analyzer dist/bundle-stats.json --mode=static --no-open --report dist/bundle-report.html","lint":"prettier --check '{lib,plugins,scripts,test}/**/*.{js,json,ts}' 'docs/*.{js,json}' 'docs/src/**/*' index.js README.md package.json","lint:fix":"prettier --write '{lib,plugins,scripts,test}/**/*.{js,json,ts}' 'docs/*.{js,json}' 'docs/src/**/*' index.js README.md package.json","postvalidate:ts":"tsc --noEmit --target es6 test/typescript-validate.ts","prebuild:browser":"mkdirp dist/","pretest":"npm run -s lint","prevalidate:ts":"npm run -s build:ts","start-fixtures-server":"octokit-fixtures-server","test":"nyc mocha test/mocha-node-setup.js \"test/*/**/*-test.js\"","test:browser":"cypress run --browser chrome","update-endpoints":"npm-run-all update-endpoints:*","update-endpoints:fetch-json":"node scripts/update-endpoints/fetch-json","update-endpoints:typescript":"node scripts/update-endpoints/typescript","validate:ts":"tsc --target es6 --noImplicitAny index.d.ts"},"types":"index.d.ts","version":"16.43.1"};

/***/ }),

Expand Down
107 changes: 96 additions & 11 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ async function run() {
return;
}

const prTitle = getPrTitle();
core.info(`prTitle: ${prTitle}`);

const client = new github.GitHub(token);

const { data: pullRequest } = await client.pulls.get({
Expand All @@ -30,15 +33,31 @@ async function run() {
pull_number: prNumber
});

const labels: string[] = [];
const labelsToRemove: string[] = [];

// add label based on title
const labelTitleRegex: Map<string, RegExp[]> = await getLabelTitleRegex(
client,
configPath
);
for (const [label, regexs] of labelTitleRegex.entries()) {
core.debug(`processing ${label}`);
if (checkRegexs(prTitle, regexs)) {
labels.push(label);
} else if (pullRequest.labels.find(l => l.name === label)) {
labelsToRemove.push(label);
}
}

// add label based on changed files
core.debug(`fetching changed files for pr #${prNumber}`);
const changedFiles: string[] = await getChangedFiles(client, prNumber);
const labelGlobs: Map<string, StringOrMatchConfig[]> = await getLabelGlobs(
client,
configPath
);

const labels: string[] = [];
const labelsToRemove: string[] = [];
for (const [label, globs] of labelGlobs.entries()) {
core.debug(`processing ${label}`);
if (checkGlobs(changedFiles, globs)) {
Expand Down Expand Up @@ -70,6 +89,15 @@ function getPrNumber(): number | undefined {
return pullRequest.number;
}

function getPrTitle(): string {
const pullRequest = github.context.payload.pull_request;
if (!pullRequest) {
return '';
}

return pullRequest.title;
}

async function getChangedFiles(
client: github.GitHub,
prNumber: number
Expand Down Expand Up @@ -125,21 +153,66 @@ function getLabelGlobMapFromObject(
configObject: any
): Map<string, StringOrMatchConfig[]> {
const labelGlobs: Map<string, StringOrMatchConfig[]> = new Map();
for (const label in configObject) {
if (typeof configObject[label] === "string") {
labelGlobs.set(label, [configObject[label]]);
} else if (configObject[label] instanceof Array) {
labelGlobs.set(label, configObject[label]);
} else {
throw Error(
`found unexpected type for label ${label} (should be string or array of globs)`
);
for (const configType in configObject) {
if (configType == "changed_file") {
for (const label in configObject["changed_file"]) {
const val = configObject["changed_file"][label]
if (typeof val === "string") {
labelGlobs.set(label, [val]);
} else if (val instanceof Array) {
labelGlobs.set(label, val);
} else {
throw Error(
`found unexpected type for label ${label} (should be string or array of globs)`
);
}
}
}
}

return labelGlobs;
}

async function getLabelTitleRegex(
client: github.GitHub,
configurationPath: string
): Promise<Map<string, RegExp[]>> {
const configurationContent: string = await fetchContent(
client,
configurationPath
);

// loads (hopefully) a `{[label:string]: string | StringOrMatchConfig[]}`, but is `any`:
const configObject: any = yaml.safeLoad(configurationContent);

// transform `any` => `Map<string,RegExp[]>` or throw if yaml is malformed:
return getLabelTitleRegexMapFromObject(configObject);
}

function getLabelTitleRegexMapFromObject(
configObject: any
): Map<string, RegExp[]> {
const titleRegexs: Map<string, RegExp[]> = new Map();
for (const configType in configObject) {
if (configType == "title") {
for (const label in configObject["title"]) {
const val = configObject["title"][label];
if (typeof val === "string") {
titleRegexs.set(label, [new RegExp(val, 'i')]);
} else if (val instanceof Array) {
titleRegexs.set(label, val.map(regexStr => new RegExp(regexStr, 'i')) );
} else {
throw Error(
`found unexpected type for label ${label} (should be string or array of regex)`
);
}
}
}
}

return titleRegexs;
}

function toMatchConfig(config: StringOrMatchConfig): MatchConfig {
if (typeof config === "string") {
return {
Expand Down Expand Up @@ -168,6 +241,18 @@ function checkGlobs(
return false;
}

function checkRegexs(
prTitle: string,
regexs: RegExp[]
): boolean {
for (const regex of regexs) {
if (regex.test(prTitle)) {
return true;
}
}
return false;
}

function isMatch(changedFile: string, matchers: IMinimatch[]): boolean {
core.debug(` matching patterns against file ${changedFile}`);
for (const matcher of matchers) {
Expand Down