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' ;
@@ -17,13 +16,11 @@ import {MergeStrategy} from './strategy.js';
1716import { isGithubApiError } from '../../../utils/git/github.js' ;
1817import { FatalMergeToolError , MergeConflictsFatalError } from '../failures.js' ;
1918import { Prompt } from '../../../utils/prompt.js' ;
19+ import { AutosquashMergeStrategy } from './autosquash-merge.js' ;
2020
2121/** Type describing the parameters for the Octokit `merge` API endpoint. */
2222type OctokitMergeParams = RestEndpointMethodTypes [ 'pulls' ] [ 'merge' ] [ 'parameters' ] ;
2323
24- type OctokitPullRequestCommitsList =
25- RestEndpointMethodTypes [ 'pulls' ] [ 'listCommits' ] [ 'response' ] [ 'data' ] ;
26-
2724/** Separator between commit message header and body. */
2825const COMMIT_HEADER_SEPARATOR = '\n\n' ;
2926
@@ -37,7 +34,7 @@ const COMMIT_HEADER_SEPARATOR = '\n\n';
3734export class GithubApiMergeStrategy extends MergeStrategy {
3835 constructor (
3936 git : AuthenticatedGitClient ,
40- private _config : GithubApiMergeStrategyConfig ,
37+ private config : GithubApiMergeStrategyConfig ,
4138 ) {
4239 super ( git ) ;
4340 }
@@ -52,12 +49,20 @@ export class GithubApiMergeStrategy extends MergeStrategy {
5249 */
5350 override async merge ( pullRequest : PullRequest ) : Promise < void > {
5451 const { githubTargetBranch, prNumber, needsCommitMessageFixup, targetBranches} = pullRequest ;
55- const method = this . _getMergeActionFromPullRequest ( pullRequest ) ;
52+ const method = this . getMergeActionFromPullRequest ( pullRequest ) ;
5653 const cherryPickTargetBranches = targetBranches . filter ( ( b ) => b !== githubTargetBranch ) ;
5754
55+ // Squash and Merge will create a single commit message and thus we can use the API to merge.
56+ if (
57+ method === 'rebase-with-fixup' &&
58+ ( pullRequest . needsCommitMessageFixup || ( await this . hasFixupOrSquashCommits ( pullRequest ) ) )
59+ ) {
60+ return new AutosquashMergeStrategy ( this . git ) . merge ( pullRequest ) ;
61+ }
62+
5863 const mergeOptions : OctokitMergeParams = {
5964 pull_number : prNumber ,
60- merge_method : method ,
65+ merge_method : method === 'rebase-with-fixup' ? 'rebase' : method ,
6166 ...this . git . remoteParams ,
6267 } ;
6368
@@ -195,10 +200,7 @@ export class GithubApiMergeStrategy extends MergeStrategy {
195200 * behavior here so that we have a default commit message that can be fixed up.
196201 */
197202 private async _getDefaultSquashCommitMessage ( pullRequest : PullRequest ) : Promise < string > {
198- const commits = ( await this . _getPullRequestCommitMessages ( pullRequest ) ) . map ( ( message ) => ( {
199- message,
200- parsed : parseCommitMessage ( message ) ,
201- } ) ) ;
203+ const commits = await this . getPullRequestCommits ( pullRequest ) ;
202204 const messageBase = `${ pullRequest . title } ${ COMMIT_HEADER_SEPARATOR } ` ;
203205 if ( commits . length <= 1 ) {
204206 return `${ messageBase } ${ commits [ 0 ] . parsed . body } ` ;
@@ -207,23 +209,21 @@ export class GithubApiMergeStrategy extends MergeStrategy {
207209 return `${ messageBase } ${ joinedMessages } ` ;
208210 }
209211
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-
219212 /** 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 ) ) ;
213+ private getMergeActionFromPullRequest ( { labels} : PullRequest ) : GithubApiMergeMethod {
214+ if ( this . config . labels ) {
215+ const matchingLabel = this . config . labels . find ( ( { pattern} ) => labels . includes ( pattern ) ) ;
223216 if ( matchingLabel !== undefined ) {
224217 return matchingLabel . method ;
225218 }
226219 }
227- return this . _config . default ;
220+ return this . config . default ;
221+ }
222+
223+ /** Checks whether the pull request contains fixup or squash commits. */
224+ private async hasFixupOrSquashCommits ( pullRequest : PullRequest ) : Promise < boolean > {
225+ const commits = await this . getPullRequestCommits ( pullRequest ) ;
226+
227+ return commits . some ( ( { parsed : { isFixup, isSquash} } ) => isFixup || isSquash ) ;
228228 }
229229}
0 commit comments