Skip to content
This repository was archived by the owner on Sep 19, 2024. It is now read-only.

Assign PR owner to linked issue #273

Merged
merged 7 commits into from
Apr 30, 2023
Merged
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
26 changes: 13 additions & 13 deletions app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,18 @@ default_events:
# - gollum
- issue_comment
- issues
# - label
# - milestone
# - member
# - membership
# - org_block
# - organization
# - page_build
# - project
# - project_card
# - project_column
# - public
# - pull_request
# - label
# - milestone
# - member
# - membership
# - org_block
# - organization
# - page_build
# - project
# - project_card
# - project_column
# - public
- pull_request
# - pull_request_review
# - pull_request_review_comment
# - push
Expand Down Expand Up @@ -82,7 +82,7 @@ default_permissions:

# Pull requests and related comments, assignees, labels, milestones, and merges.
# https://developer.github.com/v3/apps/permissions/#permission-on-pull-requests
# pull_requests: read
pull_requests: read

# Manage the post-receive hooks for a repository.
# https://developer.github.com/v3/apps/permissions/#permission-on-repository-hooks
Expand Down
51 changes: 51 additions & 0 deletions src/handlers/assign/auto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { getBotContext, getLogger } from "../../bindings";
import { addAssignees, getIssueByNumber, getPullRequests } from "../../helpers";
import { gitLinkedIssueParser } from "../../helpers/parser";
import { Payload } from "../../types";

// Check for pull requests linked to their respective issues but not assigned to them
export const checkPullRequests = async () => {
const context = getBotContext();
const logger = getLogger();
const pulls = await getPullRequests(context);

if (pulls.length === 0) {
logger.debug(`No pull requests found at this time`);
return;
}

const payload = context.payload as Payload;

// Loop through the pull requests and assign them to their respective issues if needed
for (const pull of pulls) {
let pullRequestLinked = await gitLinkedIssueParser({
owner: payload.repository.owner.login,
repo: payload.repository.name,
issue_number: pull.number,
});

// if pullRequestLinked is empty, continue
if (pullRequestLinked == "") {
continue;
}

const linkedIssueNumber = pullRequestLinked.substring(pullRequestLinked.lastIndexOf("/") + 1);

// Check if the pull request opener is assigned to the issue
const opener = pull!.user!.login;

let issue = await getIssueByNumber(context, +linkedIssueNumber);

// if issue is already assigned, continue
if (issue!.assignees!.length > 0) {
logger.debug(`Issue already assigned, ignoring...`);
continue;
}

const assignedUsernames = issue!.assignees!.map((assignee) => assignee.login);
if (!assignedUsernames.includes(opener)) {
await addAssignees(+linkedIssueNumber, [opener]);
logger.debug(`Assigned pull request #${pull.number} opener to issue ${linkedIssueNumber}.`);
}
}
};
6 changes: 6 additions & 0 deletions src/handlers/processors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { checkBountiesToUnassign, collectAnalytics, checkWeeklyUpdate } from "./
import { nullHandler } from "./shared";
import { handleComment } from "./comment";
import { handleIssueClosed } from "./payout";
import { checkPullRequests } from "./assign/auto";

export const processors: Record<string, Handler> = {
[GithubEvent.ISSUES_LABELED]: {
Expand Down Expand Up @@ -37,6 +38,11 @@ export const processors: Record<string, Handler> = {
action: [handleIssueClosed],
post: [nullHandler],
},
[GithubEvent.PULL_REQUEST_OPENED]: {
pre: [nullHandler],
action: [checkPullRequests],
post: [nullHandler],
},
};

/**
Expand Down
35 changes: 35 additions & 0 deletions src/helpers/issue.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Context } from "probot";
import { getBotContext, getLogger } from "../bindings";
import { Comment, Payload } from "../types";
import { checkRateLimitGit } from "../utils";
Expand Down Expand Up @@ -187,3 +188,37 @@ export const deleteLabel = async (label: string): Promise<void> => {
logger.debug(`Label deletion failed!, reason: ${e}`);
}
};

// Use `context.octokit.rest` to get the pull requests for the repository
export const getPullRequests = async (context: Context, state: "open" | "closed" | "all" = "open") => {
const logger = getLogger();
const payload = context.payload as Payload;
try {
const { data: pulls } = await context.octokit.rest.pulls.list({
owner: payload.repository.owner.login,
repo: payload.repository.name,
state,
});
return pulls;
} catch (e: unknown) {
logger.debug(`Fetching pull requests failed!, reason: ${e}`);
return [];
}
};

// Get issues by issue number
export const getIssueByNumber = async (context: Context, issue_number: number) => {
const logger = getLogger();
const payload = context.payload as Payload;
try {
const { data: issue } = await context.octokit.rest.issues.get({
owner: payload.repository.owner.login,
repo: payload.repository.name,
issue_number,
});
return issue;
} catch (e: unknown) {
logger.debug(`Fetching issue failed!, reason: ${e}`);
return;
}
};
18 changes: 18 additions & 0 deletions src/helpers/parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,21 @@ export const gitIssueParser = async ({ owner, repo, issue_number }: GitParser):
return true;
}
};

export const gitLinkedIssueParser = async ({ owner, repo, issue_number }: GitParser): Promise<string> => {
try {
const { data } = await axios.get(`https://github.com/${owner}/${repo}/pull/${issue_number}`);
const dom = parse(data);
const devForm = dom.querySelector("[data-target='create-branch.developmentForm']") as HTMLElement;
const linkedPRs = devForm.querySelectorAll(".my-1");

if (linkedPRs.length === 0) {
return "";
}

const prUrl = linkedPRs[0].querySelector("a")?.attrs?.href || "";
return prUrl;
} catch (error) {
return "";
}
};
3 changes: 3 additions & 0 deletions src/types/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ export enum GithubEvent {
// issue_comment
ISSUE_COMMENT_CREATED = "issue_comment.created",
ISSUE_COMMENT_EDITED = "issue_comment.edited",

// pull_request
PULL_REQUEST_OPENED = "pull_request.opened",
}

export enum UserType {
Expand Down