Skip to content
This repository was archived by the owner on Jan 22, 2019. It is now read-only.

Commit 022124a

Browse files
authored
feat: support running extensions on private code without a private Sourcegraph instance (#249)
1 parent f944aa7 commit 022124a

File tree

15 files changed

+262
-214
lines changed

15 files changed

+262
-214
lines changed

src/libs/github/file_info.ts

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { isDefined, propertyIsDefined } from '@sourcegraph/codeintellify/lib/helpers'
2-
import { Observable, of, zip } from 'rxjs'
2+
import { Observable, of, throwError, zip } from 'rxjs'
33
import { filter, map, switchMap } from 'rxjs/operators'
44
import { GitHubBlobUrl } from '.'
55
import { resolveRev, retryWhenCloneInProgressError } from '../../shared/repo/backend'
66
import { FileInfo } from '../code_intelligence'
7+
import { getCommitIDFromPermalink } from './scrape'
78
import { getDeltaFileName, getDiffResolvedRev, getGitHubState, parseURL } from './util'
89

910
export const resolveDiffFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
@@ -64,21 +65,31 @@ export const resolveDiffFileInfo = (codeView: HTMLElement): Observable<FileInfo>
6465
}))
6566
)
6667

67-
export const resolveFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
68-
of(codeView).pipe(
69-
map(() => {
70-
const { repoPath, filePath, rev } = parseURL()
71-
72-
return { repoPath, filePath, rev }
73-
}),
74-
filter(propertyIsDefined('filePath')),
75-
switchMap(({ repoPath, rev, ...rest }) =>
76-
resolveRev({ repoPath, rev }).pipe(
77-
retryWhenCloneInProgressError(),
78-
map(commitID => ({ ...rest, repoPath, commitID, rev: rev || commitID }))
68+
export const resolveFileInfo = (): Observable<FileInfo> => {
69+
const { repoPath, filePath, rev } = parseURL()
70+
if (!filePath) {
71+
return throwError(
72+
new Error(
73+
`Unable to determine the file path of the current file because the current URL (window.location ${
74+
window.location
75+
}) does not have a file path.`
7976
)
8077
)
81-
)
78+
}
79+
80+
try {
81+
const commitID = getCommitIDFromPermalink()
82+
83+
return of({
84+
repoPath,
85+
filePath,
86+
commitID,
87+
rev: rev || commitID,
88+
})
89+
} catch (error) {
90+
return throwError(error)
91+
}
92+
}
8293

8394
export const resolveSnippetFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
8495
of(codeView).pipe(

src/libs/github/scrape.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { commitIDFromPermalink } from '../../shared/util/dom'
2+
3+
/**
4+
* Get the commit ID from the permalink element on the page.
5+
*/
6+
export function getCommitIDFromPermalink(): string {
7+
return commitIDFromPermalink({
8+
selector: '.js-permalink-shortcut',
9+
hrefRegex: new RegExp('^/.*?/.*?/blob/([0-9a-f]{40})/'),
10+
})
11+
}

src/libs/gitlab/file_info.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { propertyIsDefined } from '@sourcegraph/codeintellify/lib/helpers'
2-
import { Observable, of, zip } from 'rxjs'
3-
import { filter, map, switchMap } from 'rxjs/operators'
1+
import { Observable, of, throwError, zip } from 'rxjs'
2+
import { map, switchMap } from 'rxjs/operators'
43

54
import { resolveRev, retryWhenCloneInProgressError } from '../../shared/repo/backend'
65
import { FileInfo } from '../code_intelligence'
76
import { getBaseCommitIDForCommit, getBaseCommitIDForMergeRequest } from './api'
87
import {
8+
getCommitIDFromPermalink,
99
getCommitPageInfo,
1010
getDiffPageInfo,
1111
getFilePageInfo,
@@ -29,21 +29,31 @@ const ensureRevisionsAreCloned = (files: Observable<FileInfo>): Observable<FileI
2929
/**
3030
* Resolves file information for a page with a single file, not including diffs with only one file.
3131
*/
32-
export const resolveFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
33-
of(undefined).pipe(
34-
map(() => {
35-
const { repoPath, filePath, rev } = getFilePageInfo()
36-
37-
return { repoPath, filePath, rev }
38-
}),
39-
filter(propertyIsDefined('filePath')),
40-
switchMap(({ repoPath, rev, ...rest }) =>
41-
resolveRev({ repoPath, rev }).pipe(
42-
retryWhenCloneInProgressError(),
43-
map(commitID => ({ ...rest, repoPath, commitID, rev: rev || commitID }))
32+
export const resolveFileInfo = (): Observable<FileInfo> => {
33+
const { repoPath, filePath, rev } = getFilePageInfo()
34+
if (!filePath) {
35+
return throwError(
36+
new Error(
37+
`Unable to determine the file path of the current file because the current URL (window.location ${
38+
window.location
39+
}) does not have a file path.`
4440
)
4541
)
46-
)
42+
}
43+
44+
try {
45+
const commitID = getCommitIDFromPermalink()
46+
47+
return of({
48+
repoPath,
49+
filePath,
50+
commitID,
51+
rev,
52+
})
53+
} catch (error) {
54+
return throwError(error)
55+
}
56+
}
4757

4858
/**
4959
* Gets `FileInfo` for a diff file.

src/libs/gitlab/scrape.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { last, take } from 'lodash'
22

3+
import { commitIDFromPermalink } from '../../shared/util/dom'
34
import { FileInfo } from '../code_intelligence'
45

56
export enum GitLabPageKind {
@@ -182,3 +183,13 @@ export function getCommitPageInfo(): GitLabCommitPageInfo {
182183
commitID: last(window.location.pathname.split('/'))!,
183184
}
184185
}
186+
187+
/**
188+
* Get the commit ID from the permalink element on the page.
189+
*/
190+
export function getCommitIDFromPermalink(): string {
191+
return commitIDFromPermalink({
192+
selector: '.js-data-file-blob-permalink-url',
193+
hrefRegex: new RegExp('^/.*?/.*?/blob/([0-9a-f]{40})/'),
194+
})
195+
}

src/libs/phabricator/backend.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -259,17 +259,17 @@ interface CreatePhabricatorRepoOptions {
259259

260260
export const createPhabricatorRepo = memoizeObservable(
261261
(options: CreatePhabricatorRepoOptions): Observable<void> =>
262-
mutateGraphQL(
263-
getContext({ repoKey: options.repoPath, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
264-
`mutation addPhabricatorRepo(
262+
mutateGraphQL({
263+
ctx: getContext({ repoKey: options.repoPath, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
264+
request: `mutation addPhabricatorRepo(
265265
$callsign: String!,
266266
$repoPath: String!
267267
$phabricatorURL: String!
268268
) {
269269
addPhabricatorRepo(callsign: $callsign, uri: $repoPath, url: $phabricatorURL) { alwaysNil }
270270
}`,
271-
options
272-
).pipe(
271+
variables: options,
272+
}).pipe(
273273
map(({ data, errors }) => {
274274
if (!data || (errors && errors.length > 0)) {
275275
throw Object.assign(new Error((errors || []).map(e => e.message).join('\n')), { errors })
@@ -560,9 +560,9 @@ interface ResolveStagingOptions {
560560

561561
export const resolveStagingRev = memoizeObservable(
562562
(options: ResolveStagingOptions): Observable<string | null> =>
563-
mutateGraphQL(
564-
getContext({ repoKey: options.repoName, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
565-
`mutation ResolveStagingRev(
563+
mutateGraphQL({
564+
ctx: getContext({ repoKey: options.repoName, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
565+
request: `mutation ResolveStagingRev(
566566
$repoName: String!,
567567
$diffID: ID!,
568568
$baseRev: String!,
@@ -585,8 +585,8 @@ export const resolveStagingRev = memoizeObservable(
585585
oid
586586
}
587587
}`,
588-
options
589-
).pipe(
588+
variables: options,
589+
}).pipe(
590590
map(({ data, errors }) => {
591591
if (!(data && data.resolvePhabricatorDiff) || (errors && errors.length > 0)) {
592592
throw Object.assign(new Error((errors || []).map(e => e.message).join('\n')), { errors })

src/shared/backend/auth.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,26 @@ import { getPlatformName } from '../util/context'
44
import { memoizeObservable } from '../util/memoize'
55
import { getContext } from './context'
66
import { createAggregateError } from './errors'
7-
import { mutateGraphQLNoRetry } from './graphql'
7+
import { mutateGraphQL } from './graphql'
88

99
/**
1010
* Create an access token for the current user on the currently configured
1111
* sourcegraph instance.
1212
*/
1313
export const createAccessToken = memoizeObservable((userID: GQL.ID) =>
14-
mutateGraphQLNoRetry(
15-
getContext({ repoKey: '' }),
16-
`
14+
mutateGraphQL({
15+
ctx: getContext({ repoKey: '' }),
16+
request: `
1717
mutation CreateAccessToken($userID: ID!, $scopes: [String!]!, $note: String!) {
1818
createAccessToken(user: $userID, scopes: $scopes, note: $note) {
1919
id
2020
token
2121
}
2222
}
2323
`,
24-
{ userID, scopes: ['user:all'], note: `sourcegraph-${getPlatformName()}` },
25-
false
26-
).pipe(
24+
variables: { userID, scopes: ['user:all'], note: `sourcegraph-${getPlatformName()}` },
25+
useAccessToken: false,
26+
}).pipe(
2727
map(({ data, errors }) => {
2828
if (!data || !data.createAccessToken || (errors && errors.length > 0)) {
2929
throw createAggregateError(errors)

src/shared/backend/extensions.ts

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import uuid from 'uuid'
2929
import { Disposable } from 'vscode-languageserver'
3030
import storage, { StorageItems } from '../../browser/storage'
3131
import { ExtensionConnectionInfo, onFirstMessage } from '../messaging'
32+
import { canFetchForURL } from '../util/context'
3233
import { getContext } from './context'
3334
import { createAggregateError, isErrorLike } from './errors'
3435
import { queryGraphQL } from './graphql'
@@ -215,19 +216,19 @@ const configurationCascadeFragment = gql`
215216
*/
216217
export const gqlConfigurationCascade = storage.observeSync('sourcegraphURL').pipe(
217218
switchMap(url =>
218-
queryGraphQL(
219-
getContext({ repoKey: '', isRepoSpecific: false }),
220-
gql`
219+
queryGraphQL({
220+
ctx: getContext({ repoKey: '', isRepoSpecific: false }),
221+
request: gql`
221222
query Configuration {
222223
viewerConfiguration {
223224
...ConfigurationCascadeFields
224225
}
225226
}
226227
${configurationCascadeFragment}
227228
`[graphQLContent],
228-
{},
229-
url
230-
).pipe(
229+
url,
230+
requestMightContainPrivateInfo: false,
231+
}).pipe(
231232
map(({ data, errors }) => {
232233
if (!data || !data.viewerConfiguration) {
233234
throw createAggregateError(errors)
@@ -257,14 +258,25 @@ export function createExtensionsContextController(
257258
distinctUntilChanged((a, b) => isEqual(a, b))
258259
),
259260
updateExtensionSettings,
260-
queryGraphQL: (request, variables) =>
261+
queryGraphQL: (request, variables, requestMightContainPrivateInfo) =>
261262
storage.observeSync('sourcegraphURL').pipe(
262263
take(1),
263264
mergeMap(url =>
264-
queryGraphQL(getContext({ repoKey: '', isRepoSpecific: false }), request, variables, url)
265+
queryGraphQL({
266+
ctx: getContext({ repoKey: '', isRepoSpecific: false }),
267+
request,
268+
variables,
269+
url,
270+
requestMightContainPrivateInfo,
271+
})
265272
)
266273
),
267-
queryLSP: requests => sendLSPHTTPRequests(requests),
274+
queryLSP: canFetchForURL(sourcegraphUrl)
275+
? requests => sendLSPHTTPRequests(requests)
276+
: () =>
277+
throwError(
278+
'The queryLSP command is unavailable because the current repository does not exist on the Sourcegraph instance.'
279+
),
268280
icons: {
269281
Loader: LoadingSpinner as React.ComponentType<{ className: string; onClick?: () => void }>,
270282
Info: InfoIcon as React.ComponentType<{ className: string; onClick?: () => void }>,

0 commit comments

Comments
 (0)