88
99import { RestEndpointMethodTypes } from '@octokit/plugin-rest-endpoint-methods' ;
1010
11- import { parseCommitMessage } from '../../../commit-message/parse.js' ;
1211import { AuthenticatedGitClient } from '../../../utils/git/authenticated-git-client.js' ;
1312import { GithubApiMergeMethod , GithubApiMergeStrategyConfig } from '../../config/index.js' ;
1413import { PullRequest } from '../pull-request.js' ;
1514
16- import { MergeStrategy } from './strategy.js' ;
1715import { isGithubApiError } from '../../../utils/git/github.js' ;
1816import { FatalMergeToolError , MergeConflictsFatalError } from '../failures.js' ;
1917import { Prompt } from '../../../utils/prompt.js' ;
18+ import { AutosquashMergeStrategy } from './autosquash-merge.js' ;
2019
2120/** Type describing the parameters for the Octokit `merge` API endpoint. */
2221type OctokitMergeParams = RestEndpointMethodTypes [ 'pulls' ] [ 'merge' ] [ 'parameters' ] ;
2322
24- type OctokitPullRequestCommitsList =
25- RestEndpointMethodTypes [ 'pulls' ] [ 'listCommits' ] [ 'response' ] [ 'data' ] ;
26-
2723/** Separator between commit message header and body. */
2824const COMMIT_HEADER_SEPARATOR = '\n\n' ;
2925
@@ -34,10 +30,10 @@ const COMMIT_HEADER_SEPARATOR = '\n\n';
3430 * target branches using the local Git instance. The benefit is that the Github merged state
3531 * is properly set, but a notable downside is that PRs cannot use fixup or squash commits.
3632 */
37- export class GithubApiMergeStrategy extends MergeStrategy {
33+ export class GithubApiMergeStrategy extends AutosquashMergeStrategy {
3834 constructor (
3935 git : AuthenticatedGitClient ,
40- private _config : GithubApiMergeStrategyConfig ,
36+ private config : GithubApiMergeStrategyConfig ,
4137 ) {
4238 super ( git ) ;
4339 }
@@ -52,12 +48,20 @@ export class GithubApiMergeStrategy extends MergeStrategy {
5248 */
5349 override async merge ( pullRequest : PullRequest ) : Promise < void > {
5450 const { githubTargetBranch, prNumber, needsCommitMessageFixup, targetBranches} = pullRequest ;
55- const method = this . _getMergeActionFromPullRequest ( pullRequest ) ;
51+ const method = this . getMergeActionFromPullRequest ( pullRequest ) ;
5652 const cherryPickTargetBranches = targetBranches . filter ( ( b ) => b !== githubTargetBranch ) ;
5753
54+ // Squash and Merge will create a single commit message and thus we can use the API to merge.
55+ if (
56+ method === 'rebase-with-fixup' &&
57+ ( pullRequest . needsCommitMessageFixup || ( await this . hasFixupOrSquashCommits ( pullRequest ) ) )
58+ ) {
59+ return super . merge ( pullRequest ) ;
60+ }
61+
5862 const mergeOptions : OctokitMergeParams = {
5963 pull_number : prNumber ,
60- merge_method : method ,
64+ merge_method : method === 'rebase-with-fixup' ? 'rebase' : method ,
6165 ...this . git . remoteParams ,
6266 } ;
6367
@@ -195,10 +199,7 @@ export class GithubApiMergeStrategy extends MergeStrategy {
195199 * behavior here so that we have a default commit message that can be fixed up.
196200 */
197201 private async _getDefaultSquashCommitMessage ( pullRequest : PullRequest ) : Promise < string > {
198- const commits = ( await this . _getPullRequestCommitMessages ( pullRequest ) ) . map ( ( message ) => ( {
199- message,
200- parsed : parseCommitMessage ( message ) ,
201- } ) ) ;
202+ const commits = await this . getPullRequestCommits ( pullRequest ) ;
202203 const messageBase = `${ pullRequest . title } ${ COMMIT_HEADER_SEPARATOR } ` ;
203204 if ( commits . length <= 1 ) {
204205 return `${ messageBase } ${ commits [ 0 ] . parsed . body } ` ;
@@ -207,23 +208,21 @@ export class GithubApiMergeStrategy extends MergeStrategy {
207208 return `${ messageBase } ${ joinedMessages } ` ;
208209 }
209210
210- /** Gets all commit messages of commits in the pull request. */
211- private async _getPullRequestCommitMessages ( { prNumber} : PullRequest ) {
212- const allCommits = await this . git . github . paginate ( this . git . github . pulls . listCommits , {
213- ...this . git . remoteParams ,
214- pull_number : prNumber ,
215- } ) ;
216- return allCommits . map ( ( { commit} ) => commit . message ) ;
217- }
218-
219211 /** Determines the merge action from the given pull request. */
220- private _getMergeActionFromPullRequest ( { labels} : PullRequest ) : GithubApiMergeMethod {
221- if ( this . _config . labels ) {
222- const matchingLabel = this . _config . labels . find ( ( { pattern} ) => labels . includes ( pattern ) ) ;
212+ private getMergeActionFromPullRequest ( { labels} : PullRequest ) : GithubApiMergeMethod {
213+ if ( this . config . labels ) {
214+ const matchingLabel = this . config . labels . find ( ( { pattern} ) => labels . includes ( pattern ) ) ;
223215 if ( matchingLabel !== undefined ) {
224216 return matchingLabel . method ;
225217 }
226218 }
227- return this . _config . default ;
219+ return this . config . default ;
220+ }
221+
222+ /** Checks whether the pull request contains fixup or squash commits. */
223+ private async hasFixupOrSquashCommits ( pullRequest : PullRequest ) : Promise < boolean > {
224+ const commits = await this . getPullRequestCommits ( pullRequest ) ;
225+
226+ return commits . some ( ( { parsed : { isFixup, isSquash} } ) => isFixup || isSquash ) ;
228227 }
229228}
0 commit comments