|
| 1 | +import type { CancellationToken } from 'vscode'; |
1 | 2 | import type { Container } from '../container'; |
2 | 3 | import type { GitBranch } from '../git/models/branch'; |
3 | 4 | import type { Repository } from '../git/models/repository'; |
| 5 | +import { getSettledValue } from '../system/promise'; |
4 | 6 | import type { ViewsWithRepositoryFolders } from '../views/viewBase'; |
5 | 7 | import type { PartialStepState, StepGenerator, StepState } from './quickCommand'; |
6 | 8 | import { endSteps, QuickCommand, StepResultBreak } from './quickCommand'; |
7 | | -import { pickBranchOrTagStep, pickBranchStep, pickRepositoryStep } from './quickCommand.steps'; |
| 9 | +import { pickBranchStep, pickOrResetBranchStep, pickRepositoryStep } from './quickCommand.steps'; |
8 | 10 |
|
9 | 11 | interface Context { |
10 | 12 | repos: Repository[]; |
@@ -84,25 +86,68 @@ export class ChangeBranchMergeTargetCommand extends QuickCommand { |
84 | 86 | state.branch = branches.name; |
85 | 87 | } |
86 | 88 |
|
87 | | - const result = yield* pickBranchOrTagStep(state, context, { |
| 89 | + if (!state.mergeBranch) { |
| 90 | + state.mergeBranch = await this.container.git |
| 91 | + .branches(state.repo.path) |
| 92 | + .getBaseBranchName?.(state.branch); |
| 93 | + } |
| 94 | + |
| 95 | + const gitBranch = await state.repo.git.branches().getBranch(state.branch); |
| 96 | + const detectedMergeTarget = gitBranch && (await getDetectedMergeTarget(this.container, gitBranch)); |
| 97 | + |
| 98 | + const result = yield* pickOrResetBranchStep(state, context, { |
88 | 99 | picked: state.mergeBranch, |
89 | 100 | placeholder: 'Pick a merge target branch', |
90 | | - value: undefined, |
91 | | - filter: { |
92 | | - branches: (branch: GitBranch) => branch.remote && branch.name !== state.branch, |
93 | | - tags: () => false, |
94 | | - }, |
| 101 | + filter: (branch: GitBranch) => branch.remote && branch.name !== state.branch, |
| 102 | + resetTitle: 'Reset Merge Target', |
| 103 | + resetDescription: `Reset to "${detectedMergeTarget}"`, |
95 | 104 | }); |
96 | 105 | if (result === StepResultBreak) { |
97 | 106 | continue; |
98 | 107 | } |
99 | | - if (result && state.branch) { |
| 108 | + if (state.branch) { |
100 | 109 | await this.container.git |
101 | 110 | .branches(state.repo.path) |
102 | | - .setUserMergeTargetBranchName?.(state.branch, result.name); |
| 111 | + .setUserMergeTargetBranchName?.(state.branch, result?.name); |
103 | 112 | } |
104 | 113 |
|
105 | 114 | endSteps(state); |
106 | 115 | } |
107 | 116 | } |
108 | 117 | } |
| 118 | + |
| 119 | +async function getDetectedMergeTarget( |
| 120 | + container: Container, |
| 121 | + branch: GitBranch, |
| 122 | + options?: { cancellation?: CancellationToken }, |
| 123 | +): Promise<string | undefined> { |
| 124 | + const [baseResult, defaultResult, targetResult] = await Promise.allSettled([ |
| 125 | + container.git.branches(branch.repoPath).getBaseBranchName?.(branch.name), |
| 126 | + container.git.branches(branch.repoPath).getDefaultBranchName(branch.getRemoteName()), |
| 127 | + container.git.branches(branch.repoPath).getTargetBranchName?.(branch.name), |
| 128 | + ]); |
| 129 | + |
| 130 | + const baseBranchName = getSettledValue(baseResult); |
| 131 | + const defaultBranchName = getSettledValue(defaultResult); |
| 132 | + const targetMaybeResult = getSettledValue(targetResult); |
| 133 | + const localValue = targetMaybeResult || baseBranchName || defaultBranchName; |
| 134 | + if (localValue) { |
| 135 | + return localValue; |
| 136 | + } |
| 137 | + |
| 138 | + // only if nothing found locally, try value from integration |
| 139 | + return getIntegrationDefaultBranchName(container, branch.repoPath, options); |
| 140 | +} |
| 141 | + |
| 142 | +async function getIntegrationDefaultBranchName( |
| 143 | + container: Container, |
| 144 | + repoPath: string, |
| 145 | + options?: { cancellation?: CancellationToken }, |
| 146 | +): Promise<string | undefined> { |
| 147 | + const remote = await container.git.remotes(repoPath).getBestRemoteWithIntegration(); |
| 148 | + if (remote == null) return undefined; |
| 149 | + |
| 150 | + const integration = await remote.getIntegration(); |
| 151 | + const defaultBranch = await integration?.getDefaultBranch?.(remote.provider.repoDesc, options); |
| 152 | + return defaultBranch && `${remote.name}/${defaultBranch?.name}`; |
| 153 | +} |
0 commit comments