Skip to content

Commit d538309

Browse files
refactor: address pr comments.
1 parent dd6ef68 commit d538309

3 files changed

Lines changed: 87 additions & 20 deletions

File tree

playwright/app.spec.ts

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type PullRequestCreateBody = {
2727
base?: string
2828
}
2929

30+
type BranchesByRepo = Record<string, string[]>
31+
3032
const waitForAppReady = async (page: Page, path = appEntryPath) => {
3133
await page.goto(path)
3234
await expect(page.getByRole('heading', { name: '@knighted/develop' })).toBeVisible()
@@ -147,6 +149,28 @@ const ensureOpenPrDrawerOpen = async (page: Page) => {
147149
await expect(page.locator('#github-pr-drawer')).toBeVisible()
148150
}
149151

152+
const mockRepositoryBranches = async (
153+
page: Page,
154+
branchesByRepo: BranchesByRepo = {},
155+
) => {
156+
await page.route('https://api.github.com/repos/**/branches**', async route => {
157+
const url = new URL(route.request().url())
158+
const match = url.pathname.match(/^\/repos\/([^/]+)\/([^/]+)\/branches$/)
159+
const repositoryKey = match ? `${match[1]}/${match[2]}` : ''
160+
161+
const branchNames =
162+
branchesByRepo[repositoryKey] && branchesByRepo[repositoryKey].length > 0
163+
? branchesByRepo[repositoryKey]
164+
: ['main']
165+
166+
await route.fulfill({
167+
status: 200,
168+
contentType: 'application/json',
169+
body: JSON.stringify(branchNames.map(name => ({ name }))),
170+
})
171+
})
172+
}
173+
150174
const connectByotWithSingleRepo = async (page: Page) => {
151175
await page.route('https://api.github.com/user/repos**', async route => {
152176
await route.fulfill({
@@ -165,16 +189,9 @@ const connectByotWithSingleRepo = async (page: Page) => {
165189
})
166190
})
167191

168-
await page.route(
169-
'https://api.github.com/repos/knightedcodemonkey/develop/branches**',
170-
async route => {
171-
await route.fulfill({
172-
status: 200,
173-
contentType: 'application/json',
174-
body: JSON.stringify([{ name: 'main' }, { name: 'release' }]),
175-
})
176-
},
177-
)
192+
await mockRepositoryBranches(page, {
193+
'knightedcodemonkey/develop': ['main', 'release'],
194+
})
178195

179196
await page.locator('#github-token-input').fill('github_pat_fake_chat_1234567890')
180197
await page.locator('#github-token-add').click()
@@ -539,6 +556,11 @@ test('BYOT remembers selected repository across reloads', async ({ page }) => {
539556
})
540557
})
541558

559+
await mockRepositoryBranches(page, {
560+
'knightedcodemonkey/develop': ['main', 'release'],
561+
'knightedcodemonkey/css': ['main', 'release/1.x'],
562+
})
563+
542564
await waitForAppReady(page, `${appEntryPath}?feature-ai=true`)
543565

544566
await page.locator('#github-token-input').fill('github_pat_fake_1234567890')
@@ -588,6 +610,10 @@ test('Open PR drawer confirms and submits component/styles filepaths', async ({
588610
})
589611
})
590612

613+
await mockRepositoryBranches(page, {
614+
'knightedcodemonkey/develop': ['main', 'release'],
615+
})
616+
591617
await page.route(
592618
'https://api.github.com/repos/knightedcodemonkey/develop/git/ref/**',
593619
async route => {

src/modules/github-api.js

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -420,19 +420,22 @@ export const listRepositoryBranches = async ({ token, owner, repo, signal }) =>
420420
throw new Error('A GitHub token is required to load branches.')
421421
}
422422

423-
if (typeof owner !== 'string' || !owner || typeof repo !== 'string' || !repo) {
423+
const normalizedOwner = typeof owner === 'string' ? owner.trim() : ''
424+
const normalizedRepo = typeof repo === 'string' ? repo.trim() : ''
425+
426+
if (!normalizedOwner || !normalizedRepo) {
424427
throw new Error('A valid repository owner/name is required to load branches.')
425428
}
426429

427430
const branches = []
428431
const dedupe = new Set()
429-
let nextPageUrl = `${githubApiBaseUrl}/repos/${owner}/${repo}/branches?per_page=100`
430-
let remainingPageBudget = 5
432+
const collectBranchesByPage = async ({ url, remainingPageBudget }) => {
433+
if (!url || remainingPageBudget <= 0) {
434+
return
435+
}
436+
437+
const page = await listBranchesPage({ token, url, signal })
431438

432-
while (nextPageUrl && remainingPageBudget > 0) {
433-
/* Branch pagination depends on the prior Link header response. */
434-
// eslint-disable-next-line no-await-in-loop
435-
const page = await listBranchesPage({ token, url: nextPageUrl, signal })
436439
for (const name of page.branches) {
437440
if (dedupe.has(name)) {
438441
continue
@@ -442,10 +445,17 @@ export const listRepositoryBranches = async ({ token, owner, repo, signal }) =>
442445
branches.push(name)
443446
}
444447

445-
nextPageUrl = page.nextPageUrl
446-
remainingPageBudget -= 1
448+
await collectBranchesByPage({
449+
url: page.nextPageUrl,
450+
remainingPageBudget: remainingPageBudget - 1,
451+
})
447452
}
448453

454+
await collectBranchesByPage({
455+
url: `${githubApiBaseUrl}/repos/${normalizedOwner}/${normalizedRepo}/branches?per_page=100`,
456+
remainingPageBudget: 5,
457+
})
458+
449459
branches.sort((left, right) => left.localeCompare(right))
450460
return branches
451461
}

src/modules/github-pr-drawer.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,8 @@ export const createGitHubPrDrawer = ({
278278
let submitting = false
279279
let pendingAbortController = null
280280
let pendingBranchesAbortController = null
281+
let pendingBranchesRequestKey = ''
282+
let pendingBranchesPromise = null
281283
let resetOnNextOpen = false
282284
const baseBranchesByRepository = new Map()
283285
const submitButtonDefaultLabel =
@@ -398,6 +400,7 @@ export const createGitHubPrDrawer = ({
398400
const cacheKey = toBranchCacheKey(repository)
399401
const nextPreferredBranch =
400402
toSafeText(preferredBranch) || getPreferredBaseBranchForRepository(repository)
403+
const requestKey = `${cacheKey}:${nextPreferredBranch}`
401404

402405
if (!cacheKey) {
403406
renderBaseBranchOptions({ preferredBranch: nextPreferredBranch, branchNames: [] })
@@ -419,13 +422,18 @@ export const createGitHubPrDrawer = ({
419422
return
420423
}
421424

425+
if (pendingBranchesPromise && pendingBranchesRequestKey === requestKey) {
426+
await pendingBranchesPromise
427+
return
428+
}
429+
422430
abortPendingBranchesRequest()
423431
renderBaseBranchOptions({ preferredBranch: nextPreferredBranch, loading: true })
424432

425433
const abortController = new AbortController()
426434
pendingBranchesAbortController = abortController
427435

428-
try {
436+
const runBranchRequest = async () => {
429437
const branches = await listRepositoryBranches({
430438
token,
431439
owner: repository.owner,
@@ -442,6 +450,15 @@ export const createGitHubPrDrawer = ({
442450
preferredBranch: nextPreferredBranch,
443451
branchNames: branches,
444452
})
453+
}
454+
455+
const requestPromise = runBranchRequest()
456+
457+
pendingBranchesRequestKey = requestKey
458+
pendingBranchesPromise = requestPromise
459+
460+
try {
461+
await requestPromise
445462
} catch {
446463
if (abortController.signal.aborted) {
447464
return
@@ -452,6 +469,11 @@ export const createGitHubPrDrawer = ({
452469
if (pendingBranchesAbortController === abortController) {
453470
pendingBranchesAbortController = null
454471
}
472+
473+
if (pendingBranchesPromise === requestPromise) {
474+
pendingBranchesPromise = null
475+
pendingBranchesRequestKey = ''
476+
}
455477
}
456478
}
457479

@@ -577,6 +599,10 @@ export const createGitHubPrDrawer = ({
577599
const selectedRepository = getSelectedRepositoryObject()
578600
syncRepositorySelect({ repositories, selectedRepository })
579601
syncFormForRepository()
602+
if (!open) {
603+
return
604+
}
605+
580606
void loadBaseBranchesForSelectedRepository({
581607
preferredBranch: getFormValues().baseBranch,
582608
})
@@ -778,6 +804,7 @@ export const createGitHubPrDrawer = ({
778804

779805
componentPathInput?.addEventListener('blur', persistCurrentPaths)
780806
stylesPathInput?.addEventListener('blur', persistCurrentPaths)
807+
baseBranchInput?.addEventListener('change', persistCurrentPaths)
781808
baseBranchInput?.addEventListener('blur', persistCurrentPaths)
782809
headBranchInput?.addEventListener('blur', persistCurrentPaths)
783810
prTitleInput?.addEventListener('blur', persistCurrentPaths)
@@ -810,6 +837,10 @@ export const createGitHubPrDrawer = ({
810837
return
811838
}
812839

840+
if (!open) {
841+
return
842+
}
843+
813844
void loadBaseBranchesForSelectedRepository({
814845
preferredBranch: getFormValues().baseBranch,
815846
})

0 commit comments

Comments
 (0)