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

Commit

Permalink
feat: support running extensions on private code without a private So…
Browse files Browse the repository at this point in the history
…urcegraph instance (#249)
  • Loading branch information
chrismwendt committed Oct 18, 2018
1 parent f944aa7 commit 022124a
Show file tree
Hide file tree
Showing 15 changed files with 262 additions and 214 deletions.
39 changes: 25 additions & 14 deletions src/libs/github/file_info.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { isDefined, propertyIsDefined } from '@sourcegraph/codeintellify/lib/helpers'
import { Observable, of, zip } from 'rxjs'
import { Observable, of, throwError, zip } from 'rxjs'
import { filter, map, switchMap } from 'rxjs/operators'
import { GitHubBlobUrl } from '.'
import { resolveRev, retryWhenCloneInProgressError } from '../../shared/repo/backend'
import { FileInfo } from '../code_intelligence'
import { getCommitIDFromPermalink } from './scrape'
import { getDeltaFileName, getDiffResolvedRev, getGitHubState, parseURL } from './util'

export const resolveDiffFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
Expand Down Expand Up @@ -64,21 +65,31 @@ export const resolveDiffFileInfo = (codeView: HTMLElement): Observable<FileInfo>
}))
)

export const resolveFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
of(codeView).pipe(
map(() => {
const { repoPath, filePath, rev } = parseURL()

return { repoPath, filePath, rev }
}),
filter(propertyIsDefined('filePath')),
switchMap(({ repoPath, rev, ...rest }) =>
resolveRev({ repoPath, rev }).pipe(
retryWhenCloneInProgressError(),
map(commitID => ({ ...rest, repoPath, commitID, rev: rev || commitID }))
export const resolveFileInfo = (): Observable<FileInfo> => {
const { repoPath, filePath, rev } = parseURL()
if (!filePath) {
return throwError(
new Error(
`Unable to determine the file path of the current file because the current URL (window.location ${
window.location
}) does not have a file path.`
)
)
)
}

try {
const commitID = getCommitIDFromPermalink()

return of({
repoPath,
filePath,
commitID,
rev: rev || commitID,
})
} catch (error) {
return throwError(error)
}
}

export const resolveSnippetFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
of(codeView).pipe(
Expand Down
11 changes: 11 additions & 0 deletions src/libs/github/scrape.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { commitIDFromPermalink } from '../../shared/util/dom'

/**
* Get the commit ID from the permalink element on the page.
*/
export function getCommitIDFromPermalink(): string {
return commitIDFromPermalink({
selector: '.js-permalink-shortcut',
hrefRegex: new RegExp('^/.*?/.*?/blob/([0-9a-f]{40})/'),
})
}
42 changes: 26 additions & 16 deletions src/libs/gitlab/file_info.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { propertyIsDefined } from '@sourcegraph/codeintellify/lib/helpers'
import { Observable, of, zip } from 'rxjs'
import { filter, map, switchMap } from 'rxjs/operators'
import { Observable, of, throwError, zip } from 'rxjs'
import { map, switchMap } from 'rxjs/operators'

import { resolveRev, retryWhenCloneInProgressError } from '../../shared/repo/backend'
import { FileInfo } from '../code_intelligence'
import { getBaseCommitIDForCommit, getBaseCommitIDForMergeRequest } from './api'
import {
getCommitIDFromPermalink,
getCommitPageInfo,
getDiffPageInfo,
getFilePageInfo,
Expand All @@ -29,21 +29,31 @@ const ensureRevisionsAreCloned = (files: Observable<FileInfo>): Observable<FileI
/**
* Resolves file information for a page with a single file, not including diffs with only one file.
*/
export const resolveFileInfo = (codeView: HTMLElement): Observable<FileInfo> =>
of(undefined).pipe(
map(() => {
const { repoPath, filePath, rev } = getFilePageInfo()

return { repoPath, filePath, rev }
}),
filter(propertyIsDefined('filePath')),
switchMap(({ repoPath, rev, ...rest }) =>
resolveRev({ repoPath, rev }).pipe(
retryWhenCloneInProgressError(),
map(commitID => ({ ...rest, repoPath, commitID, rev: rev || commitID }))
export const resolveFileInfo = (): Observable<FileInfo> => {
const { repoPath, filePath, rev } = getFilePageInfo()
if (!filePath) {
return throwError(
new Error(
`Unable to determine the file path of the current file because the current URL (window.location ${
window.location
}) does not have a file path.`
)
)
)
}

try {
const commitID = getCommitIDFromPermalink()

return of({
repoPath,
filePath,
commitID,
rev,
})
} catch (error) {
return throwError(error)
}
}

/**
* Gets `FileInfo` for a diff file.
Expand Down
11 changes: 11 additions & 0 deletions src/libs/gitlab/scrape.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { last, take } from 'lodash'

import { commitIDFromPermalink } from '../../shared/util/dom'
import { FileInfo } from '../code_intelligence'

export enum GitLabPageKind {
Expand Down Expand Up @@ -182,3 +183,13 @@ export function getCommitPageInfo(): GitLabCommitPageInfo {
commitID: last(window.location.pathname.split('/'))!,
}
}

/**
* Get the commit ID from the permalink element on the page.
*/
export function getCommitIDFromPermalink(): string {
return commitIDFromPermalink({
selector: '.js-data-file-blob-permalink-url',
hrefRegex: new RegExp('^/.*?/.*?/blob/([0-9a-f]{40})/'),
})
}
20 changes: 10 additions & 10 deletions src/libs/phabricator/backend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,17 +259,17 @@ interface CreatePhabricatorRepoOptions {

export const createPhabricatorRepo = memoizeObservable(
(options: CreatePhabricatorRepoOptions): Observable<void> =>
mutateGraphQL(
getContext({ repoKey: options.repoPath, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
`mutation addPhabricatorRepo(
mutateGraphQL({
ctx: getContext({ repoKey: options.repoPath, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
request: `mutation addPhabricatorRepo(
$callsign: String!,
$repoPath: String!
$phabricatorURL: String!
) {
addPhabricatorRepo(callsign: $callsign, uri: $repoPath, url: $phabricatorURL) { alwaysNil }
}`,
options
).pipe(
variables: options,
}).pipe(
map(({ data, errors }) => {
if (!data || (errors && errors.length > 0)) {
throw Object.assign(new Error((errors || []).map(e => e.message).join('\n')), { errors })
Expand Down Expand Up @@ -560,9 +560,9 @@ interface ResolveStagingOptions {

export const resolveStagingRev = memoizeObservable(
(options: ResolveStagingOptions): Observable<string | null> =>
mutateGraphQL(
getContext({ repoKey: options.repoName, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
`mutation ResolveStagingRev(
mutateGraphQL({
ctx: getContext({ repoKey: options.repoName, blacklist: [DEFAULT_SOURCEGRAPH_URL] }),
request: `mutation ResolveStagingRev(
$repoName: String!,
$diffID: ID!,
$baseRev: String!,
Expand All @@ -585,8 +585,8 @@ export const resolveStagingRev = memoizeObservable(
oid
}
}`,
options
).pipe(
variables: options,
}).pipe(
map(({ data, errors }) => {
if (!(data && data.resolvePhabricatorDiff) || (errors && errors.length > 0)) {
throw Object.assign(new Error((errors || []).map(e => e.message).join('\n')), { errors })
Expand Down
14 changes: 7 additions & 7 deletions src/shared/backend/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,26 @@ import { getPlatformName } from '../util/context'
import { memoizeObservable } from '../util/memoize'
import { getContext } from './context'
import { createAggregateError } from './errors'
import { mutateGraphQLNoRetry } from './graphql'
import { mutateGraphQL } from './graphql'

/**
* Create an access token for the current user on the currently configured
* sourcegraph instance.
*/
export const createAccessToken = memoizeObservable((userID: GQL.ID) =>
mutateGraphQLNoRetry(
getContext({ repoKey: '' }),
`
mutateGraphQL({
ctx: getContext({ repoKey: '' }),
request: `
mutation CreateAccessToken($userID: ID!, $scopes: [String!]!, $note: String!) {
createAccessToken(user: $userID, scopes: $scopes, note: $note) {
id
token
}
}
`,
{ userID, scopes: ['user:all'], note: `sourcegraph-${getPlatformName()}` },
false
).pipe(
variables: { userID, scopes: ['user:all'], note: `sourcegraph-${getPlatformName()}` },
useAccessToken: false,
}).pipe(
map(({ data, errors }) => {
if (!data || !data.createAccessToken || (errors && errors.length > 0)) {
throw createAggregateError(errors)
Expand Down
30 changes: 21 additions & 9 deletions src/shared/backend/extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import uuid from 'uuid'
import { Disposable } from 'vscode-languageserver'
import storage, { StorageItems } from '../../browser/storage'
import { ExtensionConnectionInfo, onFirstMessage } from '../messaging'
import { canFetchForURL } from '../util/context'
import { getContext } from './context'
import { createAggregateError, isErrorLike } from './errors'
import { queryGraphQL } from './graphql'
Expand Down Expand Up @@ -215,19 +216,19 @@ const configurationCascadeFragment = gql`
*/
export const gqlConfigurationCascade = storage.observeSync('sourcegraphURL').pipe(
switchMap(url =>
queryGraphQL(
getContext({ repoKey: '', isRepoSpecific: false }),
gql`
queryGraphQL({
ctx: getContext({ repoKey: '', isRepoSpecific: false }),
request: gql`
query Configuration {
viewerConfiguration {
...ConfigurationCascadeFields
}
}
${configurationCascadeFragment}
`[graphQLContent],
{},
url
).pipe(
url,
requestMightContainPrivateInfo: false,
}).pipe(
map(({ data, errors }) => {
if (!data || !data.viewerConfiguration) {
throw createAggregateError(errors)
Expand Down Expand Up @@ -257,14 +258,25 @@ export function createExtensionsContextController(
distinctUntilChanged((a, b) => isEqual(a, b))
),
updateExtensionSettings,
queryGraphQL: (request, variables) =>
queryGraphQL: (request, variables, requestMightContainPrivateInfo) =>
storage.observeSync('sourcegraphURL').pipe(
take(1),
mergeMap(url =>
queryGraphQL(getContext({ repoKey: '', isRepoSpecific: false }), request, variables, url)
queryGraphQL({
ctx: getContext({ repoKey: '', isRepoSpecific: false }),
request,
variables,
url,
requestMightContainPrivateInfo,
})
)
),
queryLSP: requests => sendLSPHTTPRequests(requests),
queryLSP: canFetchForURL(sourcegraphUrl)
? requests => sendLSPHTTPRequests(requests)
: () =>
throwError(
'The queryLSP command is unavailable because the current repository does not exist on the Sourcegraph instance.'
),
icons: {
Loader: LoadingSpinner as React.ComponentType<{ className: string; onClick?: () => void }>,
Info: InfoIcon as React.ComponentType<{ className: string; onClick?: () => void }>,
Expand Down
Loading

0 comments on commit 022124a

Please sign in to comment.