mirror of
https://github.com/actions/labeler.git
synced 2025-12-11 03:58:05 +00:00
🧹 Add basic unit tests (#148)
This is not intended to be a comprehensive test suite; I'm just trying to get us started by adding tests for some of the most important functionality. This necessitated some minor refactoring. Previously, `main.ts` just directly invoked the main entrypoint function `run()`, which made it impossible to unit test the module without causing the side-effects of `run`. As a workaround I created a new module `labeler.ts`, which just exports the functions we want to test without executing the main entrypoint, and simplified `main.ts` so that it only imports the entrypoint and executes it. It's basically just a re-org. The diff makes it look way more complicated than it is.
This commit is contained in:
29
__tests__/labeler.test.ts
Normal file
29
__tests__/labeler.test.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { checkGlobs } from '../src/labeler'
|
||||||
|
|
||||||
|
import * as core from "@actions/core";
|
||||||
|
|
||||||
|
jest.mock("@actions/core");
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
jest.spyOn(core, "getInput").mockImplementation((name, options) => {
|
||||||
|
return jest.requireActual("@actions/core").getInput(name, options);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const matchConfig = [{ any: ["*.txt"] }];
|
||||||
|
|
||||||
|
describe('checkGlobs', () => {
|
||||||
|
it('returns true when our pattern does match changed files', () => {
|
||||||
|
const changedFiles = ["foo.txt", "bar.txt"];
|
||||||
|
const result = checkGlobs(changedFiles, matchConfig);
|
||||||
|
|
||||||
|
expect(result).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns false when our pattern does not match changed files', () => {
|
||||||
|
const changedFiles = ["foo.docx"];
|
||||||
|
const result = checkGlobs(changedFiles, matchConfig);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
describe("TODO - Add a test suite", () => {
|
|
||||||
it("TODO - Add a test", async () => {});
|
|
||||||
});
|
|
||||||
259
src/labeler.ts
Normal file
259
src/labeler.ts
Normal file
@@ -0,0 +1,259 @@
|
|||||||
|
import * as core from "@actions/core";
|
||||||
|
import * as github from "@actions/github";
|
||||||
|
import * as yaml from "js-yaml";
|
||||||
|
import { Minimatch, IMinimatch } from "minimatch";
|
||||||
|
|
||||||
|
interface MatchConfig {
|
||||||
|
all?: string[];
|
||||||
|
any?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
type StringOrMatchConfig = string | MatchConfig;
|
||||||
|
|
||||||
|
export async function run() {
|
||||||
|
try {
|
||||||
|
const token = core.getInput("repo-token", { required: true });
|
||||||
|
const configPath = core.getInput("configuration-path", { required: true });
|
||||||
|
const syncLabels = !!core.getInput("sync-labels", { required: false });
|
||||||
|
|
||||||
|
const prNumber = getPrNumber();
|
||||||
|
if (!prNumber) {
|
||||||
|
console.log("Could not get pull request number from context, exiting");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new github.GitHub(token);
|
||||||
|
|
||||||
|
const { data: pullRequest } = await client.pulls.get({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
pull_number: prNumber
|
||||||
|
});
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
labels.push(label);
|
||||||
|
} else if (pullRequest.labels.find(l => l.name === label)) {
|
||||||
|
labelsToRemove.push(label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labels.length > 0) {
|
||||||
|
await addLabels(client, prNumber, labels);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (syncLabels && labelsToRemove.length) {
|
||||||
|
await removeLabels(client, prNumber, labelsToRemove);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
core.error(error);
|
||||||
|
core.setFailed(error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPrNumber(): number | undefined {
|
||||||
|
const pullRequest = github.context.payload.pull_request;
|
||||||
|
if (!pullRequest) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return pullRequest.number;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getChangedFiles(
|
||||||
|
client: github.GitHub,
|
||||||
|
prNumber: number
|
||||||
|
): Promise<string[]> {
|
||||||
|
const listFilesOptions = client.pulls.listFiles.endpoint.merge({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
pull_number: prNumber
|
||||||
|
});
|
||||||
|
|
||||||
|
const listFilesResponse = await client.paginate(listFilesOptions);
|
||||||
|
const changedFiles = listFilesResponse.map(f => f.filename);
|
||||||
|
|
||||||
|
core.debug("found changed files:");
|
||||||
|
for (const file of changedFiles) {
|
||||||
|
core.debug(" " + file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return changedFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLabelGlobs(
|
||||||
|
client: github.GitHub,
|
||||||
|
configurationPath: string
|
||||||
|
): Promise<Map<string, StringOrMatchConfig[]>> {
|
||||||
|
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,StringOrMatchConfig[]>` or throw if yaml is malformed:
|
||||||
|
return getLabelGlobMapFromObject(configObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchContent(
|
||||||
|
client: github.GitHub,
|
||||||
|
repoPath: string
|
||||||
|
): Promise<string> {
|
||||||
|
const response: any = await client.repos.getContents({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
path: repoPath,
|
||||||
|
ref: github.context.sha
|
||||||
|
});
|
||||||
|
|
||||||
|
return Buffer.from(response.data.content, response.data.encoding).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return labelGlobs;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toMatchConfig(config: StringOrMatchConfig): MatchConfig {
|
||||||
|
if (typeof config === "string") {
|
||||||
|
return {
|
||||||
|
any: [config]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPattern(matcher: IMinimatch): string {
|
||||||
|
return (matcher.negate ? "!" : "") + matcher.pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function checkGlobs(
|
||||||
|
changedFiles: string[],
|
||||||
|
globs: StringOrMatchConfig[]
|
||||||
|
): boolean {
|
||||||
|
for (const glob of globs) {
|
||||||
|
core.debug(` checking pattern ${JSON.stringify(glob)}`);
|
||||||
|
const matchConfig = toMatchConfig(glob);
|
||||||
|
if (checkMatch(changedFiles, matchConfig)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMatch(changedFile: string, matchers: IMinimatch[]): 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// equivalent to "Array.some()" but expanded for debugging and clarity
|
||||||
|
function checkAny(changedFiles: string[], globs: string[]): boolean {
|
||||||
|
const matchers = globs.map(g => new Minimatch(g));
|
||||||
|
core.debug(` checking "any" patterns`);
|
||||||
|
for (const changedFile of changedFiles) {
|
||||||
|
if (isMatch(changedFile, matchers)) {
|
||||||
|
core.debug(` "any" patterns matched against ${changedFile}`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.debug(` "any" patterns did not match any files`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// equivalent to "Array.every()" but expanded for debugging and clarity
|
||||||
|
function checkAll(changedFiles: string[], globs: string[]): boolean {
|
||||||
|
const matchers = globs.map(g => new Minimatch(g));
|
||||||
|
core.debug(` checking "all" patterns`);
|
||||||
|
for (const changedFile of changedFiles) {
|
||||||
|
if (!isMatch(changedFile, matchers)) {
|
||||||
|
core.debug(` "all" patterns did not match against ${changedFile}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core.debug(` "all" patterns matched all files`);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean {
|
||||||
|
if (matchConfig.all !== undefined) {
|
||||||
|
if (!checkAll(changedFiles, matchConfig.all)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matchConfig.any !== undefined) {
|
||||||
|
if (!checkAny(changedFiles, matchConfig.any)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function addLabels(
|
||||||
|
client: github.GitHub,
|
||||||
|
prNumber: number,
|
||||||
|
labels: string[]
|
||||||
|
) {
|
||||||
|
await client.issues.addLabels({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
labels: labels
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function removeLabels(
|
||||||
|
client: github.GitHub,
|
||||||
|
prNumber: number,
|
||||||
|
labels: string[]
|
||||||
|
) {
|
||||||
|
await Promise.all(
|
||||||
|
labels.map(label =>
|
||||||
|
client.issues.removeLabel({
|
||||||
|
owner: github.context.repo.owner,
|
||||||
|
repo: github.context.repo.repo,
|
||||||
|
issue_number: prNumber,
|
||||||
|
name: label
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
260
src/main.ts
260
src/main.ts
@@ -1,261 +1,3 @@
|
|||||||
import * as core from "@actions/core";
|
import { run } from "./labeler";
|
||||||
import * as github from "@actions/github";
|
|
||||||
import * as yaml from "js-yaml";
|
|
||||||
import { Minimatch, IMinimatch } from "minimatch";
|
|
||||||
|
|
||||||
interface MatchConfig {
|
|
||||||
all?: string[];
|
|
||||||
any?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
type StringOrMatchConfig = string | MatchConfig;
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
try {
|
|
||||||
const token = core.getInput("repo-token", { required: true });
|
|
||||||
const configPath = core.getInput("configuration-path", { required: true });
|
|
||||||
const syncLabels = !!core.getInput("sync-labels", { required: false });
|
|
||||||
|
|
||||||
const prNumber = getPrNumber();
|
|
||||||
if (!prNumber) {
|
|
||||||
console.log("Could not get pull request number from context, exiting");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const client = new github.GitHub(token);
|
|
||||||
|
|
||||||
const { data: pullRequest } = await client.pulls.get({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
pull_number: prNumber
|
|
||||||
});
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
labels.push(label);
|
|
||||||
} else if (pullRequest.labels.find(l => l.name === label)) {
|
|
||||||
labelsToRemove.push(label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (labels.length > 0) {
|
|
||||||
await addLabels(client, prNumber, labels);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (syncLabels && labelsToRemove.length) {
|
|
||||||
await removeLabels(client, prNumber, labelsToRemove);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
core.error(error);
|
|
||||||
core.setFailed(error.message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPrNumber(): number | undefined {
|
|
||||||
const pullRequest = github.context.payload.pull_request;
|
|
||||||
if (!pullRequest) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return pullRequest.number;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getChangedFiles(
|
|
||||||
client: github.GitHub,
|
|
||||||
prNumber: number
|
|
||||||
): Promise<string[]> {
|
|
||||||
const listFilesOptions = client.pulls.listFiles.endpoint.merge({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
pull_number: prNumber
|
|
||||||
});
|
|
||||||
|
|
||||||
const listFilesResponse = await client.paginate(listFilesOptions);
|
|
||||||
const changedFiles = listFilesResponse.map(f => f.filename);
|
|
||||||
|
|
||||||
core.debug("found changed files:");
|
|
||||||
for (const file of changedFiles) {
|
|
||||||
core.debug(" " + file);
|
|
||||||
}
|
|
||||||
|
|
||||||
return changedFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getLabelGlobs(
|
|
||||||
client: github.GitHub,
|
|
||||||
configurationPath: string
|
|
||||||
): Promise<Map<string, StringOrMatchConfig[]>> {
|
|
||||||
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,StringOrMatchConfig[]>` or throw if yaml is malformed:
|
|
||||||
return getLabelGlobMapFromObject(configObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchContent(
|
|
||||||
client: github.GitHub,
|
|
||||||
repoPath: string
|
|
||||||
): Promise<string> {
|
|
||||||
const response: any = await client.repos.getContents({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
path: repoPath,
|
|
||||||
ref: github.context.sha
|
|
||||||
});
|
|
||||||
|
|
||||||
return Buffer.from(response.data.content, response.data.encoding).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
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)`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return labelGlobs;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toMatchConfig(config: StringOrMatchConfig): MatchConfig {
|
|
||||||
if (typeof config === "string") {
|
|
||||||
return {
|
|
||||||
any: [config]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
function printPattern(matcher: IMinimatch): string {
|
|
||||||
return (matcher.negate ? "!" : "") + matcher.pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkGlobs(
|
|
||||||
changedFiles: string[],
|
|
||||||
globs: StringOrMatchConfig[]
|
|
||||||
): boolean {
|
|
||||||
for (const glob of globs) {
|
|
||||||
core.debug(` checking pattern ${JSON.stringify(glob)}`);
|
|
||||||
const matchConfig = toMatchConfig(glob);
|
|
||||||
if (checkMatch(changedFiles, matchConfig)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isMatch(changedFile: string, matchers: IMinimatch[]): 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// equivalent to "Array.some()" but expanded for debugging and clarity
|
|
||||||
function checkAny(changedFiles: string[], globs: string[]): boolean {
|
|
||||||
const matchers = globs.map(g => new Minimatch(g));
|
|
||||||
core.debug(` checking "any" patterns`);
|
|
||||||
for (const changedFile of changedFiles) {
|
|
||||||
if (isMatch(changedFile, matchers)) {
|
|
||||||
core.debug(` "any" patterns matched against ${changedFile}`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(` "any" patterns did not match any files`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// equivalent to "Array.every()" but expanded for debugging and clarity
|
|
||||||
function checkAll(changedFiles: string[], globs: string[]): boolean {
|
|
||||||
const matchers = globs.map(g => new Minimatch(g));
|
|
||||||
core.debug(` checking "all" patterns`);
|
|
||||||
for (const changedFile of changedFiles) {
|
|
||||||
if (!isMatch(changedFile, matchers)) {
|
|
||||||
core.debug(` "all" patterns did not match against ${changedFile}`);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
core.debug(` "all" patterns matched all files`);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkMatch(changedFiles: string[], matchConfig: MatchConfig): boolean {
|
|
||||||
if (matchConfig.all !== undefined) {
|
|
||||||
if (!checkAll(changedFiles, matchConfig.all)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matchConfig.any !== undefined) {
|
|
||||||
if (!checkAny(changedFiles, matchConfig.any)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addLabels(
|
|
||||||
client: github.GitHub,
|
|
||||||
prNumber: number,
|
|
||||||
labels: string[]
|
|
||||||
) {
|
|
||||||
await client.issues.addLabels({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
issue_number: prNumber,
|
|
||||||
labels: labels
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function removeLabels(
|
|
||||||
client: github.GitHub,
|
|
||||||
prNumber: number,
|
|
||||||
labels: string[]
|
|
||||||
) {
|
|
||||||
await Promise.all(
|
|
||||||
labels.map(label =>
|
|
||||||
client.issues.removeLabel({
|
|
||||||
owner: github.context.repo.owner,
|
|
||||||
repo: github.context.repo.repo,
|
|
||||||
issue_number: prNumber,
|
|
||||||
name: label
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
run();
|
||||||
|
|||||||
Reference in New Issue
Block a user