Skip to content

Commit 891375f

Browse files
committed
feat(ng-dev): automatically close linked issues for non-main branches
When a pull request is merged into a non-main branch, GitHub does not automatically close the linked issues. This change ensures that linked issues are closed when a PR is merged into any branch, not just the main branch. This is achieved by fetching the closing issue references for a pull request and then iterating through them to close any that are not already closed. This is handled in the merge strategies to ensure it happens after a successful merge.
1 parent 43cd9ca commit 891375f

File tree

5 files changed

+68
-1
lines changed

5 files changed

+68
-1
lines changed

ng-dev/pr/common/fetch-pull-request.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
PullRequestState,
1414
StatusState,
1515
CommentAuthorAssociation,
16+
IssueState,
1617
} from '@octokit/graphql-schema';
1718
import {getPendingPrs, getPr, getPrFiles, getPrComments} from '../../utils/github.js';
1819
import {alias, types as graphqlTypes, onUnion, optional, params} from 'typed-graphqlify';
@@ -133,6 +134,17 @@ export const PR_SCHEMA = {
133134
author: {
134135
login: graphqlTypes.string,
135136
},
137+
closingIssuesReferences: params(
138+
{first: 100},
139+
{
140+
nodes: [
141+
{
142+
number: graphqlTypes.number,
143+
state: graphqlTypes.custom<IssueState>(),
144+
},
145+
],
146+
},
147+
),
136148
};
137149

138150
export type PullRequestFromGithub = typeof PR_SCHEMA;

ng-dev/pr/merge/pull-request.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,16 @@ import {TEMP_PR_HEAD_BRANCH} from './strategies/strategy.js';
1818
import {mergeLabels} from '../common/labels/merge.js';
1919
import {PullRequestValidationFailure} from '../common/validation/validation-failure.js';
2020
import {AuthenticatedGitClient} from '../../utils/git/authenticated-git-client.js';
21-
import {GithubConfig, NgDevConfig, CaretakerConfig, GoogleSyncConfig} from '../../utils/config.js';
21+
import {GithubConfig, NgDevConfig} from '../../utils/config.js';
2222
import {PullRequestConfig, PullRequestValidationConfig} from '../config/index.js';
2323
import {targetLabels} from '../common/labels/target.js';
24+
import {IssueState} from '@octokit/graphql-schema';
25+
26+
/** Interface describing a pull request's closing issue references. */
27+
export interface PullRequestClosingIssuesReferences {
28+
number: number;
29+
state: IssueState;
30+
}
2431

2532
/** Interface that describes a pull request. */
2633
export interface PullRequest {
@@ -52,6 +59,8 @@ export interface PullRequest {
5259
validationFailures: PullRequestValidationFailure[];
5360
/** The SHA for the latest commit in the pull request. */
5461
headSha: string;
62+
/** A list of issues that will be closed by the pull request. */
63+
closingIssuesReferences: PullRequestClosingIssuesReferences[];
5564
}
5665

5766
/**
@@ -155,5 +164,6 @@ export async function loadAndValidatePullRequest(
155164
title: prData.title,
156165
commitCount: prData.commits.totalCount,
157166
headSha: prData.headRefOid,
167+
closingIssuesReferences: prData.closingIssuesReferences.nodes,
158168
};
159169
}

ng-dev/pr/merge/strategies/api-merge.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ export class GithubApiMergeStrategy extends AutosquashMergeStrategy {
152152
);
153153
}
154154

155+
// When a pull request is merged, GitHub automatically closes any linked issues.
156+
// This is not the case when the pull request is not merged into the main branch.
157+
// This is why we need to manually close the linked issues.
158+
if (githubTargetBranch !== this.git.mainBranchName) {
159+
await this.closeLinkedIssues(pullRequest);
160+
}
161+
155162
// Workaround for fatal: refusing to fetch into branch 'refs/heads/merge_pr_target_main' checked out at ...
156163
// Cannot find where but `merge_pr_target_main` is being set as the current branch.
157164
// TODO: remove after finding the root cause.

ng-dev/pr/merge/strategies/autosquash-merge.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ export class AutosquashMergeStrategy extends MergeStrategy {
100100
pull_number: pullRequest.prNumber,
101101
state: 'closed',
102102
});
103+
104+
// When a pull request is merged, GitHub automatically closes any linked issues.
105+
// This is not the case when the pull request is not merged into the main branch.
106+
// This is why we need to manually close the linked issues.
107+
await this.closeLinkedIssues(pullRequest);
103108
}
104109
}
105110
}

ng-dev/pr/merge/strategies/strategy.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,37 @@ export abstract class MergeStrategy {
226226
`${banchesAndSha.map(([branch, sha]) => `- ${branch}: ${sha}`).join('\n')}`,
227227
});
228228
}
229+
230+
/**
231+
* Manually closes issues linked to a merged Pull Request.
232+
*
233+
* This function addresses the scenario where **GitHub's automatic issue closure feature is skipped**
234+
* because the PR's target branch is *not* the repository's main branch.
235+
*
236+
* It updates any open linked issues to a `closed` state with a `completed` reason.
237+
*
238+
* @note The method is a **no-op** if the PR target is the main branch,
239+
* as GitHub handles issue closure automatically in that case.
240+
*/
241+
protected async closeLinkedIssues({
242+
closingIssuesReferences,
243+
githubTargetBranch,
244+
}: PullRequest): Promise<void> {
245+
if (githubTargetBranch === this.git.mainBranchName) {
246+
return;
247+
}
248+
249+
for (const {number: issue_number, state} of closingIssuesReferences) {
250+
if (state === 'CLOSED') {
251+
continue;
252+
}
253+
254+
await this.git.github.issues.update({
255+
...this.git.remoteParams,
256+
issue_number,
257+
state_reason: 'completed',
258+
state: 'closed',
259+
});
260+
}
261+
}
229262
}

0 commit comments

Comments
 (0)