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

feat: add support for milestone, assignees and requested reviewers #394

Merged
merged 7 commits into from
Nov 5, 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
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
runs-on: ubuntu-latest

# Only run when pull request is merged
# or when a comment containing `/backport` is created by someone other than the
# or when a comment containing `/backport` is created by someone other than the
# https://github.com/backport-action bot user (user id: 97796249). Note that if you use your
# own PAT as `github_token`, that you should replace this id with yours.
if: >
Expand All @@ -105,6 +105,13 @@ jobs:

The action can be configured with the following optional [inputs](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepswith):

### `copy_assignees`

Default: `false` (disabled)

Controls whether to copy the assignees from the original pull request to the backport pull request.
By default, the assignees are not copied.

### `copy_labels_pattern`

Default: `''` (disabled)
Expand All @@ -113,6 +120,21 @@ Regex pattern to match github labels which will be copied from the original pull
Note that labels matching `label_pattern` are excluded.
By default, no labels are copied.

### `copy_milestone`

Default: `false` (disabled)

Controls whether to copy the milestone from the original pull request to the backport pull request.
By default, the milestone is not copied.

### `copy_requested_reviewers`

Default: `false` (disabled)

Controls whether to copy the requested reviewers from the original pull request to the backport pull request.
Note that this does not request reviews from those users who already reviewed the original pull request.
By default, the requested reviewers are not copied.

### `github_token`

Default: `${{ github.token }}`
Expand Down
16 changes: 16 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,27 @@ description: >
Fast and flexible action to cherry-pick commits from labeled pull requests
author: korthout
inputs:
copy_assignees:
description: >
Controls whether to copy the assignees from the original pull request to the backport pull request.
By default, the assignees are not copied.
default: false
copy_labels_pattern:
description: >
Regex pattern to match github labels which will be copied from the original pull request to the backport pull request.
Note that labels matching `label_pattern` are excluded.
By default, no labels are copied.
copy_milestone:
description: >
Controls whether to copy the milestone from the original pull request to the backport pull request.
By default, the milestone is not copied.
default: false
copy_requested_reviewers:
description: >
Controls whether to copy the requested reviewers from the original pull request to the backport pull request.
Note that this does not request reviews from those users who already reviewed the original pull request.
By default, the requested reviewers are not copied.
default: false
github_token:
description: >
Token to authenticate requests to GitHub.
Expand Down
52 changes: 51 additions & 1 deletion src/backport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ export type Config = {
commits: {
merge_commits: "fail" | "skip";
};
copy_milestone: boolean;
copy_assignees: boolean;
copy_requested_reviewers: boolean;
};

enum Output {
Expand Down Expand Up @@ -257,6 +260,53 @@ export class Backport {
}
const new_pr = new_pr_response.data;

if (this.config.copy_milestone == true) {
const milestone = mainpr.milestone?.number;
if (milestone) {
console.info("Setting milestone to " + milestone);
const set_milestone_response = await this.github.setMilestone(
new_pr.number,
milestone,
);
if (set_milestone_response.status != 200) {
console.error(JSON.stringify(set_milestone_response));
}
}
}

if (this.config.copy_assignees == true) {
const assignees = mainpr.assignees.map((label) => label.login);
if (assignees.length > 0) {
console.info("Setting assignees " + assignees);
const set_assignee_response = await this.github.setAssignees(
new_pr.number,
assignees,
);
if (set_assignee_response.status != 201) {
console.error(JSON.stringify(set_assignee_response));
}
}
}

if (this.config.copy_requested_reviewers == true) {
const reviewers = mainpr.requested_reviewers?.map(
(reviewer) => reviewer.login,
);
if (reviewers?.length > 0) {
console.info("Setting reviewers " + reviewers);
const reviewRequest = {
...this.github.getRepo(),
pull_number: new_pr.number,
reviewers: reviewers,
};
const set_reviewers_response =
await this.github.requestReviewers(reviewRequest);
if (set_reviewers_response.status != 201) {
console.error(JSON.stringify(set_reviewers_response));
}
}
}

if (labelsToCopy.length > 0) {
const label_response = await this.github.labelPR(
new_pr.number,
Expand Down Expand Up @@ -377,7 +427,7 @@ export class Backport {
private composeMessageForCreatePRFailed(
response: CreatePullRequestResponse,
): string {
return dedent`Backport branch created but failed to create PR.
return dedent`Backport branch created but failed to create PR.
Request to create PR rejected with status ${response.status}.

(see action log for full response)`;
Expand Down
37 changes: 37 additions & 0 deletions src/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export interface GithubApi {
createPR(pr: CreatePullRequest): Promise<CreatePullRequestResponse>;
labelPR(pr: number, labels: string[]): Promise<LabelPullRequestResponse>;
requestReviewers(request: ReviewRequest): Promise<RequestReviewersResponse>;
setAssignees(pr: number, assignees: string[]): Promise<GenericResponse>;
setMilestone(pr: number, milestone: number): Promise<GenericResponse>;
}

export class Github implements GithubApi {
Expand Down Expand Up @@ -126,6 +128,24 @@ export class Github implements GithubApi {
labels,
});
}

public async setAssignees(pr: number, assignees: string[]) {
console.log(`Set Assignees ${assignees} to #${pr}`);
return this.#octokit.rest.issues.addAssignees({
...this.getRepo(),
issue_number: pr,
assignees,
});
}

public async setMilestone(pr: number, milestone: number) {
console.log(`Set Milestone ${milestone} to #${pr}`);
return this.#octokit.rest.issues.update({
...this.getRepo(),
issue_number: pr,
milestone: milestone,
});
}
}

export type PullRequest = {
Expand All @@ -149,6 +169,18 @@ export type PullRequest = {
login: string;
}[];
commits: number;
milestone: {
number: number;
id: number;
title: string;
};
assignees: {
login: string;
id: number;
}[];
merged_by: {
login: string;
};
};
export type CreatePullRequestResponse = {
status: number;
Expand All @@ -158,6 +190,11 @@ export type CreatePullRequestResponse = {
};
};
export type RequestReviewersResponse = CreatePullRequestResponse;

export type GenericResponse = {
status: number;
};

export type LabelPullRequestResponse = {
status: number;
};
Expand Down
6 changes: 6 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ async function run(): Promise<void> {
const copy_labels_pattern = core.getInput("copy_labels_pattern");
const target_branches = core.getInput("target_branches");
const merge_commits = core.getInput("merge_commits");
const copy_assignees = core.getInput("copy_assignees");
const copy_milestone = core.getInput("copy_milestone");
const copy_requested_reviewers = core.getInput("copy_requested_reviewers");

if (merge_commits != "fail" && merge_commits != "skip") {
const message = `Expected input 'merge_commits' to be either 'fail' or 'skip', but was '${merge_commits}'`;
Expand All @@ -36,6 +39,9 @@ async function run(): Promise<void> {
copy_labels_pattern === "" ? undefined : new RegExp(copy_labels_pattern),
target_branches: target_branches === "" ? undefined : target_branches,
commits: { merge_commits },
copy_assignees: copy_assignees === "true",
copy_milestone: copy_milestone === "true",
copy_requested_reviewers: copy_requested_reviewers === "true",
};
const backport = new Backport(github, config, git);

Expand Down
Loading