[Svelte]: UI Updates for Perforce Depots and Git Repos (#64014)

Introduces basic (and incomplete) UI support for perforce, including displaying changelist ids,
listing changelists, and removing references to commits and branches.
This commit is contained in:
Jason Hawk Harris 2024-08-02 21:47:20 -05:00 committed by GitHub
parent 4caad25380
commit b0702f3c3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 285 additions and 145 deletions

View File

@ -20,4 +20,8 @@ fragment Commit on GitCommit {
...Avatar_Person
}
}
perforceChangelist {
cid
canonicalURL
}
}

View File

@ -45,7 +45,7 @@
{/if}
</div>
<div class="title">
<a class="subject" href={commit.canonicalURL}>{commit.subject}</a>
<a class="subject" href={commit.perforceChangelist?.canonicalURL ?? commit.canonicalURL}>{commit.subject}</a>
{#if !alwaysExpanded && commit.body && !$isViewportMobile}
<Button
variant="secondary"
@ -59,7 +59,7 @@
</div>
<div class="author">
{#if !committerIsAuthor}authored by <strong>{author.person.name}</strong> and{/if}
committed by <strong>{committer.person.name}</strong>
{commit.perforceChangelist ? 'submitted' : 'committed'} by <strong>{committer.person.name}</strong>
<Timestamp date={commitDate} />
</div>
{#if commit.body}

View File

@ -28,6 +28,10 @@ fragment RevPickerGitCommit on GitCommit {
oid
subject
abbreviatedOID
perforceChangelist {
cid
canonicalURL
}
...RepositoryGitRevAuthor
}

View File

@ -28,6 +28,7 @@
<script lang="ts">
import type { Placement } from '@floating-ui/dom'
import type { ComponentProps } from 'svelte'
import type { HTMLButtonAttributes } from 'svelte/elements'
import { goto } from '$app/navigation'
@ -44,7 +45,6 @@
import Picker from './Picker.svelte'
import RepositoryRevPickerItem from './RepositoryRevPickerItem.svelte'
import type { ComponentProps } from 'svelte'
type $$Props = HTMLButtonAttributes & {
repoURL: string
@ -53,6 +53,7 @@
defaultBranch: string
display?: ComponentProps<ButtonGroup>['display']
placement?: Placement
isPerforceDepot: boolean
onSelect?: (revision: string) => void
getRepositoryTags: (query: string) => PromiseLike<RepositoryTags>
getRepositoryCommits: (query: string) => PromiseLike<RepositoryCommits>
@ -65,6 +66,8 @@
export let defaultBranch: $$Props['defaultBranch']
export let placement: $$Props['placement'] = 'right-start'
export let display: $$Props['display'] = undefined
export let isPerforceDepot: $$Props['isPerforceDepot']
/**
* Optional handler for revision selection.
* If not provided, the default handler will replace the revision in the current URL.
@ -121,68 +124,83 @@
<div slot="content" class="content" let:toggle>
<Tabs>
<TabPanel title="Branches" shortcut={branchesHotkey}>
<Picker
name="branches"
seeAllItemsURL={`${repoURL}/-/branches`}
getData={getRepositoryBranches}
toOption={branch => ({ value: branch.id, label: branch.displayName })}
onSelect={branch => {
toggle(false)
onSelect(branch.abbrevName)
}}
let:value
>
<RepositoryRevPickerItem
icon={ILucideGitBranch}
label={value.displayName}
author={value.target.commit?.author}
{#if !isPerforceDepot}
<TabPanel title="Branches" shortcut={branchesHotkey}>
<Picker
name="branches"
seeAllItemsURL={`${repoURL}/-/branches`}
getData={getRepositoryBranches}
toOption={branch => ({ value: branch.id, label: branch.displayName })}
onSelect={branch => {
toggle(false)
onSelect(branch.abbrevName)
}}
let:value
>
<svelte:fragment slot="title">
<Icon icon={ILucideGitBranch} inline aria-hidden="true" />
<Badge variant="link">{value.displayName}</Badge>
{#if value.displayName === defaultBranch}
<Badge variant="secondary" small>DEFAULT</Badge>
{/if}
</svelte:fragment>
</RepositoryRevPickerItem>
</Picker>
</TabPanel>
<TabPanel title="Tags" shortcut={tagsHotkey}>
<RepositoryRevPickerItem
icon={ILucideGitBranch}
label={value.displayName}
author={value.target.commit?.author}
>
<svelte:fragment slot="title">
<Icon icon={ILucideGitBranch} inline aria-hidden="true" />
<Badge variant="link">{value.displayName}</Badge>
{#if value.displayName === defaultBranch}
<Badge variant="secondary" small>DEFAULT</Badge>
{/if}
</svelte:fragment>
</RepositoryRevPickerItem>
</Picker>
</TabPanel>
<TabPanel title="Tags" shortcut={tagsHotkey}>
<Picker
name="tags"
seeAllItemsURL={`${repoURL}/-/tags`}
getData={getRepositoryTags}
toOption={tag => ({ value: tag.id, label: tag.displayName })}
onSelect={tag => {
toggle(false)
onSelect(tag.abbrevName)
}}
let:value
>
<RepositoryRevPickerItem
icon={ILucideTag}
label={value.displayName}
author={value.target.commit?.author}
/>
</Picker>
</TabPanel>
{/if}
<TabPanel title={isPerforceDepot ? 'Changelists' : 'Commits'} shortcut={commitsHotkey}>
<!-- TODO: seeAllItemsURL should point to /-/changelists for perforce, but that doesn't exist yet -->
<Picker
name="tags"
seeAllItemsURL={`${repoURL}/-/tags`}
getData={getRepositoryTags}
toOption={tag => ({ value: tag.id, label: tag.displayName })}
onSelect={tag => {
toggle(false)
onSelect(tag.abbrevName)
}}
let:value
>
<RepositoryRevPickerItem
icon={ILucideTag}
label={value.displayName}
author={value.target.commit?.author}
/>
</Picker>
</TabPanel>
<TabPanel title="Commits" shortcut={commitsHotkey}>
<Picker
name="commits"
name={isPerforceDepot ? 'changelists' : 'commits'}
seeAllItemsURL={`${repoURL}/-/commits`}
getData={getRepositoryCommits}
toOption={commit => ({ value: commit.id, label: commit.oid })}
toOption={commit => {
return isPerforceDepot && commit.perforceChangelist
? { value: commit.id, label: commit.perforceChangelist.cid }
: { value: commit.id, label: commit.oid }
}}
onSelect={commit => {
toggle(false)
onSelect(commit.oid)
if (isPerforceDepot && commit.perforceChangelist) {
onSelect(`changelist/${commit?.perforceChangelist?.cid}`)
} else {
onSelect(commit.oid)
}
}}
let:value
>
<RepositoryRevPickerItem label="" author={value.author}>
<svelte:fragment slot="title">
<Icon icon={ILucideGitCommitVertical} inline aria-hidden="true" />
<Badge variant="link">{value.abbreviatedOID}</Badge>
<span class="rev-badge"
><Badge variant="link">
{value.perforceChangelist?.cid ?? value.abbreviatedOID}
</Badge></span
>
<span class="commit-subject">{value.subject}</span>
</svelte:fragment>
</RepositoryRevPickerItem>
@ -200,6 +218,14 @@
text-align: left;
}
.rev-badge {
display: contents;
:global([data-badge]) {
// Always show the full (abbreviated) changelist ID or commit hash
flex-shrink: 0;
}
}
.close-button {
border-left: 1px solid var(--secondary);
}

View File

@ -31,6 +31,11 @@ export const svelteKitRoutes: SvelteKitRoute[] = [
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/commits(?:/.*)?/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/[path=commit_or_changelist]/[...revspec]',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/(?:commit|changelist)(?:/.*)?/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/branches',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/branches/?$'),
@ -41,11 +46,6 @@ export const svelteKitRoutes: SvelteKitRoute[] = [
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/branches/all/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/commit/[...revspec]',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/commit(?:/.*)?/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/compare/[...rangeSpec]',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/compare(?:/.*)?/?$'),

View File

@ -0,0 +1,5 @@
import type { ParamMatcher } from '@sveltejs/kit'
export const match: ParamMatcher = param => {
return param === 'commit' || param === 'changelist'
}

View File

@ -215,6 +215,7 @@
revision={data.revision}
commitID={data.resolvedRevision.commitID}
defaultBranch={data.defaultBranch}
isPerforceDepot={data.isPerforceDepot}
getRepositoryBranches={data.getRepoBranches}
getRepositoryCommits={data.getRepoCommits}
getRepositoryTags={data.getRepoTags}

View File

@ -5,13 +5,12 @@
import { navigating } from '$app/stores'
import Commit from '$lib/Commit.svelte'
import LoadingSpinner from '$lib/LoadingSpinner.svelte'
import RepositoryRevPicker from '$lib/repo/RepositoryRevPicker.svelte'
import { getHumanNameForCodeHost } from '$lib/repo/shared/codehost'
import Scroller, { type Capture as ScrollerCapture } from '$lib/Scroller.svelte'
import CodeHostIcon from '$lib/search/CodeHostIcon.svelte'
import { Alert, Badge } from '$lib/wildcard'
import RepositoryRevPicker from '$lib/repo/RepositoryRevPicker.svelte'
import type { PageData, Snapshot } from './$types'
export let data: PageData
@ -61,9 +60,13 @@
<header>
<h2>
Commit History
{#if data.path}
in <code>{data.path}</code>
{#if commits && commits[0]?.perforceChangelist !== null}
Changelists
{:else}
Commit History
{#if data.path}
in <code>{data.path}</code>
{/if}
{/if}
</h2>
<div>
@ -73,6 +76,7 @@
commitID={data.resolvedRevision.commitID}
defaultBranch={data.defaultBranch}
placement="bottom-start"
isPerforceDepot={data.isPerforceDepot}
getRepositoryBranches={data.getRepoBranches}
getRepositoryCommits={data.getRepoCommits}
getRepositoryTags={data.getRepoTags}
@ -90,11 +94,27 @@
</div>
<ul class="actions">
<li>
{#if commit.perforceChangelist}
Changelist ID:
{/if}
<Badge variant="link">
<a href={commit.canonicalURL} title="View commit">{commit.abbreviatedOID}</a>
{#if commit.perforceChangelist}
<a href={commit.perforceChangelist?.canonicalURL} title="View changelist"
>{commit.perforceChangelist?.cid}</a
>
{:else}
<a href={commit.canonicalURL} title="View commit">{commit.abbreviatedOID}</a>
{/if}
</Badge>
</li>
<li><a href="/{data.repoName}@{commit.oid}">Browse files</a></li>
<li>
<a
href={commit.perforceChangelist
? `/${data.repoName}@changelist/${commit.perforceChangelist.cid}`
: `/${data.repoName}@${commit.oid}`}>Browse files</a
>
</li>
{#each commit.externalURLs as { url, serviceKind }}
<li>
<a href={url}>

View File

@ -30,6 +30,10 @@ query CommitsPage_CommitsQuery(
ancestors(first: $first, afterCursor: $afterCursor, path: $path) {
...CommitsPage_GitCommitConnection
}
perforceChangelist {
cid
canonicalURL
}
}
}
}

View File

@ -48,6 +48,7 @@
export let data: LayoutData
const menuOpen = writable(false)
const navEntries: MenuEntry[] = [
{ path: '', icon: ILucideCode, label: 'Code', visibility: 'user', preserveRevision: true },
{
@ -61,6 +62,21 @@
{ path: '/-/tags', icon: ILucideTag, label: 'Tags', visibility: 'user' },
{ path: '/-/stats/contributors', icon: ILucideUsers, label: 'Contributors', visibility: 'user' },
]
const perforceNavEntries: MenuEntry[] = navEntries
.map(entry => {
// Replace commits with changelists
if (entry.label === 'Commits') {
return {
// TODO: this should direct the user to a "changelists" page
path: '/-/commits',
icon: ILucideGitCommitVertical,
label: 'Changelists',
visibility: 'user',
} satisfies MenuEntry
}
return entry
})
.filter(entry => entry.label !== 'Branches')
const menuEntries: MenuEntry[] = [
{ path: '/-/compare', icon: ILucideGitCompare, label: 'Compare', visibility: 'user' },
{ path: '/-/own', icon: ILucideUsers, label: 'Ownership', visibility: 'admin' },
@ -85,7 +101,7 @@
setRepositoryPageContext(repositoryContext)
$: viewableNavEntries = navEntries.filter(
$: viewableNavEntries = (data.isPerforceDepot ? perforceNavEntries : navEntries).filter(
entry => entry.visibility === 'user' || (entry.visibility === 'admin' && data.user?.siteAdmin)
)
$: visibleNavEntryCount = viewableNavEntries.length
@ -118,6 +134,7 @@
function isActive(href: string, url: URL): boolean {
return href === data.repoURL ? isCodePage(data.repoURL, $page.url.pathname) : url.pathname.startsWith(href)
}
$: tabs = navEntriesToShow.map(entry => ({
id: entry.label,
title: entry.label,
@ -129,6 +146,7 @@
$: ({ repoName, revision } = data)
$: query = `repo:${repositoryInsertText({ repository: repoName })}${revision ? `@${revision}` : ''} `
$: queryState = queryStateStore({ query }, $settings)
function handleSearchSubmit(): void {
TELEMETRY_RECORDER.recordEvent('search', 'submit', {
metadata: { source: TELEMETRY_SEARCH_SOURCE_TYPE['repo'] },

View File

@ -52,6 +52,7 @@ export const load: LayoutLoad = async ({ params, url, depends }) => {
displayRevision: displayRevision(revision, resolvedRepository),
defaultBranch: resolvedRepository.defaultBranch?.abbrevName || 'HEAD',
resolvedRepository: resolvedRepository,
isPerforceDepot: resolvedRepository.externalRepository.serviceType === 'perforce',
// Repository pickers queries (branch, tags and commits)
getRepoBranches: (searchTerm: string) =>

View File

@ -60,6 +60,8 @@
repositoryContext.set({})
})
$: changelistId = data.commit.perforceChangelist?.cid
</script>
<svelte:head>
@ -70,26 +72,38 @@
{#if data.commit}
<Scroller bind:this={scroller} margin={600} on:more={diffQuery?.fetchMore}>
<div class="header">
<div class="info"><Commit commit={data.commit} alwaysExpanded={!$isViewportMobile} /></div>
<div class="info">
<Commit commit={data.commit} alwaysExpanded={!$isViewportMobile} />
</div>
<ul class="actions">
<li>
<span>Commit:</span>
<Badge variant="secondary"><code>{data.commit.abbreviatedOID}</code></Badge>&nbsp;<CopyButton
value={data.commit.abbreviatedOID}
/>
</li>
<li>
<span>{pluralize('Parent', data.commit.parents.length)}:</span>
{#each data.commit.parents as parent}
<Badge variant="link"><a href={parent.canonicalURL}>{parent.abbreviatedOID}</a></Badge
>&nbsp;<CopyButton value={parent.abbreviatedOID} />{' '}
{/each}
</li>
<li>
<a href="/{data.repoName}@{data.commit.oid}"
>Browse files at <Badge variant="link">{data.commit.abbreviatedOID}</Badge></a
>
<span>{data.isPerforceDepot ? 'Changelist ID:' : 'Commit:'}</span>
<Badge variant="secondary"
><code>{data.isPerforceDepot ? changelistId : data.commit.abbreviatedOID}</code></Badge
>&nbsp;<CopyButton value={data.commit.abbreviatedOID} />
</li>
{#if !data.isPerforceDepot}
<li>
<span>{pluralize('Parent', data.commit.parents.length)}:</span>
{#each data.commit.parents as parent}
<Badge variant="link">
<a href={parent.canonicalURL}>{parent.abbreviatedOID}</a>
</Badge>&nbsp;<CopyButton value={parent.abbreviatedOID} />{' '}
{/each}
</li>
<li>
<a href="/{data.repoName}@{data.commit.oid}">
Browse files at
<Badge variant="link">{data.commit.abbreviatedOID}</Badge>
</a>
</li>
{:else}
<li>
<a href={`/${data.repoName}@changelist/${data.commit.perforceChangelist?.cid}`}
>Browse files
</a>
</li>
{/if}
{#each data.commit.externalURLs as { url, serviceKind }}
<li>
<a href={url}>

View File

@ -4,22 +4,30 @@ import { IncrementalRestoreStrategy, getGraphQLClient, infinityQuery } from '$li
import { parseRepoRevision } from '$lib/shared'
import type { PageLoad } from './$types'
import { CommitPage_CommitQuery, CommitPage_DiffQuery } from './page.gql'
import { CommitPage_CommitQuery, CommitPage_DiffQuery, CommitPage_Changelist, CommitPage_Commit } from './page.gql'
const PAGE_SIZE = 20
export const load: PageLoad = async ({ params }) => {
const client = getGraphQLClient()
const { repoName } = parseRepoRevision(params.repo)
const result = await client.query(CommitPage_CommitQuery, { repoName, revspec: params.revspec })
if (result.error) {
error(500, `Unable to load commit data: ${result.error}`)
async function getCommit(): Promise<CommitPage_Commit | null> {
if (params.path === 'changelist') {
const result = await client.query(CommitPage_Changelist, { repoName, changelistId: params.revspec })
if (result.error) {
error(500, `Unable to load changelist data: ${result.error}`)
}
return result.data?.repository?.changelist?.commit ?? null
} else {
const result = await client.query(CommitPage_CommitQuery, { repoName, revspec: params.revspec })
if (result.error) {
error(500, `Unable to load commit data: ${result.error}`)
}
return result.data?.repository?.commit ?? null
}
}
const commit = result.data?.repository?.commit
const commit = await getCommit()
if (!commit) {
error(404, 'Commit not found')
}

View File

@ -0,0 +1,68 @@
query CommitPage_CommitQuery($repoName: String!, $revspec: String!) {
repository(name: $repoName) {
id
commit(rev: $revspec) {
...CommitPage_Commit
}
}
}
query CommitPage_Changelist($repoName: String!, $changelistId: String!) {
repository(name: $repoName) {
sourceType
changelist(cid: $changelistId) {
__typename
...PerforceChangelistFields
}
}
}
fragment PerforceChangelistFields on PerforceChangelist {
cid
canonicalURL
commit {
...CommitPage_Commit
}
}
fragment CommitPage_Commit on GitCommit {
id
oid
perforceChangelist {
cid
canonicalURL
}
parents {
id
oid
abbreviatedOID
canonicalURL
}
externalURLs {
url
serviceKind
}
...Commit
__typename
}
query CommitPage_DiffQuery($repoName: String!, $base: String, $head: String, $first: Int, $after: String) {
repository(name: $repoName) {
id
comparison(base: $base, head: $head) {
fileDiffs(first: $first, after: $after) {
...CommitPage_DiffConnection
}
}
}
}
fragment CommitPage_DiffConnection on FileDiffConnection {
nodes {
...FileDiff_Diff
}
pageInfo {
endCursor
hasNextPage
}
}

View File

@ -1,41 +0,0 @@
query CommitPage_CommitQuery($repoName: String!, $revspec: String!) {
repository(name: $repoName) {
id
commit(rev: $revspec) {
id
oid
parents {
id
oid
abbreviatedOID
canonicalURL
}
externalURLs {
url
serviceKind
}
...Commit
}
}
}
query CommitPage_DiffQuery($repoName: String!, $base: String, $head: String, $first: Int, $after: String) {
repository(name: $repoName) {
id
comparison(base: $base, head: $head) {
fileDiffs(first: $first, after: $after) {
...CommitPage_DiffConnection
}
}
}
}
fragment CommitPage_DiffConnection on FileDiffConnection {
nodes {
...FileDiff_Diff
}
pageInfo {
endCursor
hasNextPage
}
}

View File

@ -109,6 +109,7 @@
commitID={data.base?.commitID || ''}
defaultBranch={data.defaultBranch}
placement="bottom-start"
isPerforceDepot={data.isPerforceDepot}
onSelect={revision => handleSelect(revision, data.head?.revision || '')}
getRepositoryBranches={data.getRepoBranches}
getRepositoryCommits={data.getRepoCommits}
@ -125,6 +126,7 @@
commitID={data.head?.commitID || ''}
defaultBranch={data.defaultBranch}
placement="bottom-start"
isPerforceDepot={data.isPerforceDepot}
onSelect={revision => handleSelect(data.base?.revision || '', revision)}
getRepositoryBranches={data.getRepoBranches}
getRepositoryCommits={data.getRepoCommits}

View File

@ -31,6 +31,11 @@ export const svelteKitRoutes: SvelteKitRoute[] = [
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/commits(?:/.*)?/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/[path=commit_or_changelist]/[...revspec]',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/(?:commit|changelist)(?:/.*)?/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/branches',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/branches/?$'),
@ -41,11 +46,6 @@ export const svelteKitRoutes: SvelteKitRoute[] = [
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/branches/all/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/commit/[...revspec]',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/commit(?:/.*)?/?$'),
isRepoRoot: false,
},
{
id: '/[...repo=reporev]/-/compare/[...rangeSpec]',
pattern: new RegExp('^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/compare(?:/.*)?/?$'),

View File

@ -263,9 +263,15 @@ func patternForRouteId(routeId string) (string, error) {
continue
}
// We don't use params within a segement, e.g.
// foo-[bar]-[[baz]], so for simplicity we don't support that.
if strings.Contains(segment, "[") {
if segment == "[path=commit_or_changelist]" {
// TODO(camdencheek): clean this up.
// We don't generally support arbitrary matchers,
// but for the one case we use this right now this just hard-codes it.
b.WriteString(`/(?:commit|changelist)`)
continue
} else if strings.Contains(segment, "[") {
// We don't use params within a segement, e.g.
// foo-[bar]-[[baz]], so for simplicity we don't support that.
return "", errors.New("params within a segment are not supported")
}

View File

@ -38,6 +38,11 @@ var svelteKitRoutes = []svelteKitRoute{
Pattern: regexp.MustCompile("^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/commits(?:/.*)?/?$"),
Tag: tags.EnableOptIn | tags.EnableRollout,
},
{
Id: "/[...repo=reporev]/-/[path=commit_or_changelist]/[...revspec]",
Pattern: regexp.MustCompile("^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/(?:commit|changelist)(?:/.*)?/?$"),
Tag: tags.EnableOptIn | tags.EnableRollout,
},
{
Id: "/[...repo=reporev]/-/branches",
Pattern: regexp.MustCompile("^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/branches/?$"),
@ -48,11 +53,6 @@ var svelteKitRoutes = []svelteKitRoute{
Pattern: regexp.MustCompile("^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/branches/all/?$"),
Tag: tags.EnableOptIn | tags.EnableRollout,
},
{
Id: "/[...repo=reporev]/-/commit/[...revspec]",
Pattern: regexp.MustCompile("^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/commit(?:/.*)?/?$"),
Tag: tags.EnableOptIn | tags.EnableRollout,
},
{
Id: "/[...repo=reporev]/-/compare/[...rangeSpec]",
Pattern: regexp.MustCompile("^/(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,})))(?:@(?:(?:(?:[^@/-]|(?:[^/@]{2,}))/)*(?:[^@/-]|(?:[^/@]{2,}))))?/-/compare(?:/.*)?/?$"),