|
3 | 3 | * Licensed under the MIT License. See License.txt in the project root for license information. |
4 | 4 | *--------------------------------------------------------------------------------------------*/ |
5 | 5 |
|
| 6 | +import { adjectives, animals, colors, NumberDictionary, uniqueNamesGenerator } from '@joaomoreno/unique-names-generator'; |
6 | 7 | import vscode from 'vscode'; |
7 | 8 | import { Repository } from '../../api/api'; |
8 | 9 | import Logger from '../../common/logger'; |
| 10 | +import { BRANCH_RANDOM_NAME_DICTIONARY, BRANCH_WHITESPACE_CHAR, GIT } from '../../common/settingKeys'; |
9 | 11 | import { RepoInfo } from '../common'; |
10 | 12 |
|
11 | 13 | export class GitOperationsManager { |
12 | 14 | constructor(private loggerID: string) { } |
13 | 15 |
|
14 | 16 | async commitAndPushChanges(repoInfo: RepoInfo) { |
15 | 17 | const { repository, remote, baseRef } = repoInfo; |
16 | | - const asyncBranch = `copilot/vscode${Date.now()}`; |
| 18 | + const asyncBranch = await this.generateRandomBranchName(repository, 'copilot'); |
17 | 19 |
|
18 | 20 | try { |
19 | 21 | await repository.createBranch(asyncBranch, true); |
@@ -138,4 +140,54 @@ export class GitOperationsManager { |
138 | 140 | } |
139 | 141 | } |
140 | 142 | } |
| 143 | + |
| 144 | + // Adapted from https://github.com/microsoft/vscode/blob/e35e3b4e057450ea3d90c724fae5e3e9619b96fe/extensions/git/src/commands.ts#L3007 |
| 145 | + private async generateRandomBranchName(repository: Repository, prefix: string): Promise<string> { |
| 146 | + const config = vscode.workspace.getConfiguration(GIT); |
| 147 | + const branchWhitespaceChar = config.get<string>(BRANCH_WHITESPACE_CHAR); |
| 148 | + const branchRandomNameDictionary = config.get<string[]>(BRANCH_RANDOM_NAME_DICTIONARY); |
| 149 | + |
| 150 | + // Default to legacy behaviour if config mismatches core |
| 151 | + if (branchWhitespaceChar === undefined || branchRandomNameDictionary === undefined) { |
| 152 | + return `copilot/vscode${Date.now()}`; |
| 153 | + } |
| 154 | + |
| 155 | + const separator = branchWhitespaceChar; |
| 156 | + const dictionaries: string[][] = []; |
| 157 | + for (const dictionary of branchRandomNameDictionary) { |
| 158 | + if (dictionary.toLowerCase() === 'adjectives') { |
| 159 | + dictionaries.push(adjectives); |
| 160 | + } |
| 161 | + if (dictionary.toLowerCase() === 'animals') { |
| 162 | + dictionaries.push(animals); |
| 163 | + } |
| 164 | + if (dictionary.toLowerCase() === 'colors') { |
| 165 | + dictionaries.push(colors); |
| 166 | + } |
| 167 | + if (dictionary.toLowerCase() === 'numbers') { |
| 168 | + dictionaries.push(NumberDictionary.generate({ length: 3 })); |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + if (dictionaries.length === 0) { |
| 173 | + return ''; |
| 174 | + } |
| 175 | + |
| 176 | + // 5 attempts to generate a random branch name |
| 177 | + for (let index = 0; index < 5; index++) { |
| 178 | + const randomName = `${prefix}/${uniqueNamesGenerator({ |
| 179 | + dictionaries, |
| 180 | + length: dictionaries.length, |
| 181 | + separator |
| 182 | + })}`; |
| 183 | + |
| 184 | + // Check for local ref conflict |
| 185 | + const refs = await repository.getRefs?.({ pattern: `refs/heads/${randomName}` }); |
| 186 | + if (!refs || refs.length === 0) { |
| 187 | + return randomName; |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + return ''; |
| 192 | + } |
141 | 193 | } |
0 commit comments