|
12 | 12 | // See the License for the specific language governing permissions and |
13 | 13 | // limitations under the License. |
14 | 14 |
|
15 | | -import {commitAndPush} from 'code-suggester/build/src/github/commit-and-push'; |
| 15 | +import { |
| 16 | + createTree, |
| 17 | + generateTreeObjects, |
| 18 | +} from 'code-suggester/build/src/github/commit-and-push'; |
16 | 19 | import {addLabels} from 'code-suggester/build/src/github/labels'; |
17 | 20 | import {setupLogger} from 'code-suggester/build/src/logger'; |
18 | 21 |
|
@@ -1275,27 +1278,7 @@ export class GitHub { |
1275 | 1278 | updates: Update[], |
1276 | 1279 | options?: CreatePullRequestOptions |
1277 | 1280 | ): Promise<PullRequest> => { |
1278 | | - const changes = await this.buildChangeSet(updates, refBranch); |
1279 | | - |
1280 | | - // create release branch |
1281 | | - const pullRequestBranchSha = await this.forkBranch( |
1282 | | - pullRequest.headBranchName, |
1283 | | - refBranch |
1284 | | - ); |
1285 | | - |
1286 | | - // commit and push changeset |
1287 | | - await commitAndPush( |
1288 | | - this.octokit, |
1289 | | - pullRequestBranchSha, |
1290 | | - changes, |
1291 | | - { |
1292 | | - branch: pullRequest.headBranchName, |
1293 | | - repo: this.repository.repo, |
1294 | | - owner: this.repository.owner, |
1295 | | - }, |
1296 | | - message, |
1297 | | - true |
1298 | | - ); |
| 1281 | + await this.upsertReleaseBranch(pullRequest, refBranch, message, updates); |
1299 | 1282 |
|
1300 | 1283 | // create pull request, unless one already exists |
1301 | 1284 | let pullRequestNumber: number; |
@@ -1334,6 +1317,131 @@ export class GitHub { |
1334 | 1317 | } |
1335 | 1318 | ); |
1336 | 1319 |
|
| 1320 | + upsertReleaseBranch = wrapAsync( |
| 1321 | + async ( |
| 1322 | + pullRequest: PullRequest, |
| 1323 | + refBranch: string, |
| 1324 | + message: string, |
| 1325 | + updates: Update[] |
| 1326 | + ): Promise<void> => { |
| 1327 | + this.logger.debug( |
| 1328 | + { |
| 1329 | + pullRequest: pullRequest.headBranchName, |
| 1330 | + refBranch: refBranch, |
| 1331 | + message: message, |
| 1332 | + updates: updates.length, |
| 1333 | + }, |
| 1334 | + 'upserting release branch' |
| 1335 | + ); |
| 1336 | + |
| 1337 | + const changes = await this.buildChangeSet(updates, refBranch); |
| 1338 | + |
| 1339 | + const refSHA = await this.getBranchSha(refBranch); |
| 1340 | + |
| 1341 | + this.logger.debug( |
| 1342 | + { |
| 1343 | + refBranch: refBranch, |
| 1344 | + refSHA: refSHA, |
| 1345 | + changes: changes.size, |
| 1346 | + }, |
| 1347 | + 'found ref branch SHA' |
| 1348 | + ); |
| 1349 | + |
| 1350 | + if (!refSHA) { |
| 1351 | + throw new Error( |
| 1352 | + `could not find branch ${refBranch} in repository ${this.repository.owner}/${this.repository.repo}` |
| 1353 | + ); |
| 1354 | + } |
| 1355 | + |
| 1356 | + const tree = generateTreeObjects(changes); |
| 1357 | + |
| 1358 | + const treeSha = await createTree( |
| 1359 | + this.octokit, |
| 1360 | + this.repository, |
| 1361 | + refSHA, |
| 1362 | + tree |
| 1363 | + ); |
| 1364 | + |
| 1365 | + this.logger.debug( |
| 1366 | + { |
| 1367 | + treeSha: treeSha, |
| 1368 | + }, |
| 1369 | + 'created tree' |
| 1370 | + ); |
| 1371 | + |
| 1372 | + const {data: newCommit} = await this.octokit.git.createCommit({ |
| 1373 | + ...this.repository, |
| 1374 | + message, |
| 1375 | + tree: treeSha, |
| 1376 | + parents: [refSHA], |
| 1377 | + }); |
| 1378 | + |
| 1379 | + this.logger.debug( |
| 1380 | + { |
| 1381 | + newCommit: newCommit.sha, |
| 1382 | + }, |
| 1383 | + 'created commit' |
| 1384 | + ); |
| 1385 | + |
| 1386 | + const ref = `heads/${pullRequest.headBranchName}`; |
| 1387 | + try { |
| 1388 | + // try to update existing branch |
| 1389 | + await this.octokit.git.updateRef({ |
| 1390 | + ...this.repository, |
| 1391 | + ref, |
| 1392 | + sha: newCommit.sha, |
| 1393 | + force: true, |
| 1394 | + }); |
| 1395 | + |
| 1396 | + this.logger.debug( |
| 1397 | + { |
| 1398 | + ref: ref, |
| 1399 | + newCommit: newCommit.sha, |
| 1400 | + }, |
| 1401 | + 'updated existing branch' |
| 1402 | + ); |
| 1403 | + } catch (error) { |
| 1404 | + if (this.isRefDoesNotExistError(error)) { |
| 1405 | + this.logger.debug( |
| 1406 | + { |
| 1407 | + ref: ref, |
| 1408 | + }, |
| 1409 | + 'branch does not exist, creating it' |
| 1410 | + ); |
| 1411 | + |
| 1412 | + // branch doesn't exist, create it |
| 1413 | + await this.octokit.git.createRef({ |
| 1414 | + ...this.repository, |
| 1415 | + ref: `refs/${ref}`, |
| 1416 | + sha: newCommit.sha, |
| 1417 | + }); |
| 1418 | + |
| 1419 | + this.logger.debug( |
| 1420 | + { |
| 1421 | + ref: ref, |
| 1422 | + newCommit: newCommit.sha, |
| 1423 | + }, |
| 1424 | + 'created new branch' |
| 1425 | + ); |
| 1426 | + } else { |
| 1427 | + throw error; |
| 1428 | + } |
| 1429 | + } |
| 1430 | + } |
| 1431 | + ); |
| 1432 | + |
| 1433 | + isRefDoesNotExistError = (error: unknown): boolean => { |
| 1434 | + return ( |
| 1435 | + (error && |
| 1436 | + typeof error === 'object' && |
| 1437 | + 'status' in error && |
| 1438 | + error.status === 422 && |
| 1439 | + 'message' in error && |
| 1440 | + typeof error.message === 'string' && |
| 1441 | + error.message.includes('does not exist')) === true |
| 1442 | + ); |
| 1443 | + }; |
| 1444 | + |
1337 | 1445 | /** |
1338 | 1446 | * Fetch a pull request given the pull number |
1339 | 1447 | * @param {number} number The pull request number |
|
0 commit comments