Skip to content

Commit 88f3803

Browse files
author
Naka Masato
committed
enable to add label by title
1 parent 9794b14 commit 88f3803

File tree

2 files changed

+171
-23
lines changed

2 files changed

+171
-23
lines changed

dist/index.js

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14545,17 +14545,31 @@ function run() {
1454514545
console.log("Could not get pull request number from context, exiting");
1454614546
return;
1454714547
}
14548+
const prTitle = getPrTitle();
14549+
core.info(`prTitle: ${prTitle}`);
1454814550
const client = new github.GitHub(token);
1454914551
const { data: pullRequest } = yield client.pulls.get({
1455014552
owner: github.context.repo.owner,
1455114553
repo: github.context.repo.repo,
1455214554
pull_number: prNumber
1455314555
});
14556+
const labels = [];
14557+
const labelsToRemove = [];
14558+
// add label based on title
14559+
const labelTitleRegex = yield getLabelTitleRegex(client, configPath);
14560+
for (const [label, regexs] of labelTitleRegex.entries()) {
14561+
core.debug(`processing ${label}`);
14562+
if (checkRegexs(prTitle, regexs)) {
14563+
labels.push(label);
14564+
}
14565+
else if (pullRequest.labels.find(l => l.name === label)) {
14566+
labelsToRemove.push(label);
14567+
}
14568+
}
14569+
// add label based on changed files
1455414570
core.debug(`fetching changed files for pr #${prNumber}`);
1455514571
const changedFiles = yield getChangedFiles(client, prNumber);
1455614572
const labelGlobs = yield getLabelGlobs(client, configPath);
14557-
const labels = [];
14558-
const labelsToRemove = [];
1455914573
for (const [label, globs] of labelGlobs.entries()) {
1456014574
core.debug(`processing ${label}`);
1456114575
if (checkGlobs(changedFiles, globs)) {
@@ -14585,6 +14599,13 @@ function getPrNumber() {
1458514599
}
1458614600
return pullRequest.number;
1458714601
}
14602+
function getPrTitle() {
14603+
const pullRequest = github.context.payload.pull_request;
14604+
if (!pullRequest) {
14605+
return '';
14606+
}
14607+
return pullRequest.title;
14608+
}
1458814609
function getChangedFiles(client, prNumber) {
1458914610
return __awaiter(this, void 0, void 0, function* () {
1459014611
const listFilesOptions = client.pulls.listFiles.endpoint.merge({
@@ -14623,19 +14644,53 @@ function fetchContent(client, repoPath) {
1462314644
}
1462414645
function getLabelGlobMapFromObject(configObject) {
1462514646
const labelGlobs = new Map();
14626-
for (const label in configObject) {
14627-
if (typeof configObject[label] === "string") {
14628-
labelGlobs.set(label, [configObject[label]]);
14629-
}
14630-
else if (configObject[label] instanceof Array) {
14631-
labelGlobs.set(label, configObject[label]);
14632-
}
14633-
else {
14634-
throw Error(`found unexpected type for label ${label} (should be string or array of globs)`);
14647+
for (const configType in configObject) {
14648+
if (configType == "changed_file") {
14649+
for (const label in configObject["changed_file"]) {
14650+
const val = configObject["changed_file"][label];
14651+
if (typeof val === "string") {
14652+
labelGlobs.set(label, [val]);
14653+
}
14654+
else if (val instanceof Array) {
14655+
labelGlobs.set(label, val);
14656+
}
14657+
else {
14658+
throw Error(`found unexpected type for label ${label} (should be string or array of globs)`);
14659+
}
14660+
}
1463514661
}
1463614662
}
1463714663
return labelGlobs;
1463814664
}
14665+
function getLabelTitleRegex(client, configurationPath) {
14666+
return __awaiter(this, void 0, void 0, function* () {
14667+
const configurationContent = yield fetchContent(client, configurationPath);
14668+
// loads (hopefully) a `{[label:string]: string | StringOrMatchConfig[]}`, but is `any`:
14669+
const configObject = yaml.safeLoad(configurationContent);
14670+
// transform `any` => `Map<string,RegExp[]>` or throw if yaml is malformed:
14671+
return getLabelTitleRegexMapFromObject(configObject);
14672+
});
14673+
}
14674+
function getLabelTitleRegexMapFromObject(configObject) {
14675+
const titleRegexs = new Map();
14676+
for (const configType in configObject) {
14677+
if (configType == "title") {
14678+
for (const label in configObject["title"]) {
14679+
const val = configObject["title"][label];
14680+
if (typeof val === "string") {
14681+
titleRegexs.set(label, [new RegExp(val, 'i')]);
14682+
}
14683+
else if (val instanceof Array) {
14684+
titleRegexs.set(label, val.map(regexStr => new RegExp(regexStr, 'i')));
14685+
}
14686+
else {
14687+
throw Error(`found unexpected type for label ${label} (should be string or array of regex)`);
14688+
}
14689+
}
14690+
}
14691+
}
14692+
return titleRegexs;
14693+
}
1463914694
function toMatchConfig(config) {
1464014695
if (typeof config === "string") {
1464114696
return {
@@ -14657,6 +14712,14 @@ function checkGlobs(changedFiles, globs) {
1465714712
}
1465814713
return false;
1465914714
}
14715+
function checkRegexs(prTitle, regexs) {
14716+
for (const regex of regexs) {
14717+
if (regex.test(prTitle)) {
14718+
return true;
14719+
}
14720+
}
14721+
return false;
14722+
}
1466014723
function isMatch(changedFile, matchers) {
1466114724
core.debug(` matching patterns against file ${changedFile}`);
1466214725
for (const matcher of matchers) {
@@ -29691,7 +29754,7 @@ module.exports = new Schema({
2969129754
/***/ 954:
2969229755
/***/ (function(module) {
2969329756

29694-
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"};
29757+
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"};
2969529758

2969629759
/***/ }),
2969729760

src/main.ts

Lines changed: 96 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ async function run() {
2222
return;
2323
}
2424

25+
const prTitle = getPrTitle();
26+
core.info(`prTitle: ${prTitle}`);
27+
2528
const client = new github.GitHub(token);
2629

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

36+
const labels: string[] = [];
37+
const labelsToRemove: string[] = [];
38+
39+
// add label based on title
40+
const labelTitleRegex: Map<string, RegExp[]> = await getLabelTitleRegex(
41+
client,
42+
configPath
43+
);
44+
for (const [label, regexs] of labelTitleRegex.entries()) {
45+
core.debug(`processing ${label}`);
46+
if (checkRegexs(prTitle, regexs)) {
47+
labels.push(label);
48+
} else if (pullRequest.labels.find(l => l.name === label)) {
49+
labelsToRemove.push(label);
50+
}
51+
}
52+
53+
// add label based on changed files
3354
core.debug(`fetching changed files for pr #${prNumber}`);
3455
const changedFiles: string[] = await getChangedFiles(client, prNumber);
3556
const labelGlobs: Map<string, StringOrMatchConfig[]> = await getLabelGlobs(
3657
client,
3758
configPath
3859
);
3960

40-
const labels: string[] = [];
41-
const labelsToRemove: string[] = [];
4261
for (const [label, globs] of labelGlobs.entries()) {
4362
core.debug(`processing ${label}`);
4463
if (checkGlobs(changedFiles, globs)) {
@@ -70,6 +89,15 @@ function getPrNumber(): number | undefined {
7089
return pullRequest.number;
7190
}
7291

92+
function getPrTitle(): string {
93+
const pullRequest = github.context.payload.pull_request;
94+
if (!pullRequest) {
95+
return '';
96+
}
97+
98+
return pullRequest.title;
99+
}
100+
73101
async function getChangedFiles(
74102
client: github.GitHub,
75103
prNumber: number
@@ -125,21 +153,66 @@ function getLabelGlobMapFromObject(
125153
configObject: any
126154
): Map<string, StringOrMatchConfig[]> {
127155
const labelGlobs: Map<string, StringOrMatchConfig[]> = new Map();
128-
for (const label in configObject) {
129-
if (typeof configObject[label] === "string") {
130-
labelGlobs.set(label, [configObject[label]]);
131-
} else if (configObject[label] instanceof Array) {
132-
labelGlobs.set(label, configObject[label]);
133-
} else {
134-
throw Error(
135-
`found unexpected type for label ${label} (should be string or array of globs)`
136-
);
156+
for (const configType in configObject) {
157+
if (configType == "changed_file") {
158+
for (const label in configObject["changed_file"]) {
159+
const val = configObject["changed_file"][label]
160+
if (typeof val === "string") {
161+
labelGlobs.set(label, [val]);
162+
} else if (val instanceof Array) {
163+
labelGlobs.set(label, val);
164+
} else {
165+
throw Error(
166+
`found unexpected type for label ${label} (should be string or array of globs)`
167+
);
168+
}
169+
}
137170
}
138171
}
139172

140173
return labelGlobs;
141174
}
142175

176+
async function getLabelTitleRegex(
177+
client: github.GitHub,
178+
configurationPath: string
179+
): Promise<Map<string, RegExp[]>> {
180+
const configurationContent: string = await fetchContent(
181+
client,
182+
configurationPath
183+
);
184+
185+
// loads (hopefully) a `{[label:string]: string | StringOrMatchConfig[]}`, but is `any`:
186+
const configObject: any = yaml.safeLoad(configurationContent);
187+
188+
// transform `any` => `Map<string,RegExp[]>` or throw if yaml is malformed:
189+
return getLabelTitleRegexMapFromObject(configObject);
190+
}
191+
192+
function getLabelTitleRegexMapFromObject(
193+
configObject: any
194+
): Map<string, RegExp[]> {
195+
const titleRegexs: Map<string, RegExp[]> = new Map();
196+
for (const configType in configObject) {
197+
if (configType == "title") {
198+
for (const label in configObject["title"]) {
199+
const val = configObject["title"][label];
200+
if (typeof val === "string") {
201+
titleRegexs.set(label, [new RegExp(val, 'i')]);
202+
} else if (val instanceof Array) {
203+
titleRegexs.set(label, val.map(regexStr => new RegExp(regexStr, 'i')) );
204+
} else {
205+
throw Error(
206+
`found unexpected type for label ${label} (should be string or array of regex)`
207+
);
208+
}
209+
}
210+
}
211+
}
212+
213+
return titleRegexs;
214+
}
215+
143216
function toMatchConfig(config: StringOrMatchConfig): MatchConfig {
144217
if (typeof config === "string") {
145218
return {
@@ -168,6 +241,18 @@ function checkGlobs(
168241
return false;
169242
}
170243

244+
function checkRegexs(
245+
prTitle: string,
246+
regexs: RegExp[]
247+
): boolean {
248+
for (const regex of regexs) {
249+
if (regex.test(prTitle)) {
250+
return true;
251+
}
252+
}
253+
return false;
254+
}
255+
171256
function isMatch(changedFile: string, matchers: IMinimatch[]): boolean {
172257
core.debug(` matching patterns against file ${changedFile}`);
173258
for (const matcher of matchers) {

0 commit comments

Comments
 (0)