Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

Commit 8002472

Browse files
authored
remove extension registry UI and related GraphQL API (#45891)
Removes the extension registry UI and the GraphQL API that is necessary for the registry extension UI. Any extensions that already exist locally or remotely can still be used with the enableLegacyExtensions site config flag and by enabling the extensions in your user settings. This change is an intermediate step toward removing the extension registry (except the endpoint that's needed to support pre-4.0 Sourcegraph instances). I think this PR has a 99% chance of going into the 4.4 release (2023-01-20) and not needing to be reverted. Subsequent PRs that actually make it impossible to use local or custom legacy extensions are still pending customer communication and confirmation. I hope we can merge other future PRs there as well, but there is a greater chance we'd need to revert them before 4.4. By making this PR first, it means less of a revert and more progress regardless of what we learn from customers.
1 parent 9527dcc commit 8002472

File tree

166 files changed

+110
-11067
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

166 files changed

+110
-11067
lines changed

CHANGELOG.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ All notable changes to Sourcegraph are documented in this file.
3535

3636
### Removed
3737

38-
-
38+
- The extension registry no longer supports browsing, creating, or updating legacy extensions. Existing extensions may still be enabled or disabled in user settings and may be listed via the API. (The extension API was deprecated in 2022-09 but is still available if the `enableLegacyExtensions` site config experimental features flag is enabled.)
3939

4040
## 4.3.0
4141

client/client-api/src/contribution.ts

-6
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,6 @@ import { Primitive } from 'utility-types'
33
import { KeyPath } from '@sourcegraph/shared/src/api/client/services/settings'
44
import { Expression, TemplateExpression } from '@sourcegraph/template-parser'
55

6-
// NOTE: You must manually keep this file in sync with extension.schema.json#/properties/contributes (and possibly
7-
// extension_schema.go, if your changes are relevant to the subset of this schema used by our Go code).
8-
//
9-
// The available tools for automatically generating the JSON Schema from this file add more complexity than it's
10-
// worth.
11-
126
/**
137
* The given contribution type as it's specified in a package.json (expressions as strings)
148
*/

client/extension-api-types/README.md

-2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,3 @@
22

33
Extensions should use the `sourcegraph` package, not this package. This package is only for client applications
44
that embed Sourcegraph extensions and need to communicate with them.
5-
6-
See [Sourcegraph extensions documentation](https://docs.sourcegraph.com/extensions) for more information.

client/extension-api/README.md

-2
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,3 @@
55
[![sourcegraph: search](https://img.shields.io/badge/sourcegraph-search-brightgreen.svg)](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/tree/packages/extension-api)
66

77
This package contains only the types for the [Sourcegraph extension API](https://unpkg.com/sourcegraph/dist/docs/index.html) ([`sourcegraph.d.ts`](https://github.com/sourcegraph/sourcegraph/blob/main/packages/extension-api/src/sourcegraph.d.ts)).
8-
9-
See [Sourcegraph extensions documentation](https://docs.sourcegraph.com/extensions) for more information.

client/shared/src/codeintel/legacy-extensions/util/api.ts

+4-206
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import * as sourcegraph from '../api'
66
import { cache } from '../util'
77

88
import { graphqlIdToRepoId, queryGraphQL } from './graphql'
9-
import { isDefined, sortUnique } from './helpers'
9+
import { isDefined } from './helpers'
1010
import { parseGitURI } from './uri'
1111

1212
/**
@@ -148,31 +148,6 @@ export class API {
148148
)
149149
}
150150

151-
/**
152-
* Determines via introspection if the GraphQL API has implementations available
153-
*
154-
* TODO(tjdevries) - Remove this when we no longer need to support pre-3.XX releases (not yet released)
155-
*/
156-
public async hasImplementationsField(): Promise<boolean> {
157-
const introspectionQuery = gql`
158-
query LegacyImplementationsIntrospectionQuery {
159-
__type(name: "GitBlobLSIFData") {
160-
fields {
161-
name
162-
}
163-
}
164-
}
165-
`
166-
167-
interface IntrospectionResponse {
168-
__type: { fields: { name: string }[] }
169-
}
170-
171-
return (await queryGraphQL<IntrospectionResponse>(introspectionQuery)).__type.fields.some(
172-
field => field.name === 'implementations'
173-
)
174-
}
175-
176151
/**
177152
* Determines via introspection if the GraphQL API has local code intelligence available
178153
*
@@ -318,183 +293,6 @@ export class API {
318293
return symbolInfoFlexibleToCanonical(symbolInfoFlexible)
319294
}
320295

321-
/**
322-
* Retrieves the revhash of an input rev for a repository. Throws an error if the
323-
* repository is not known to the Sourcegraph instance. Returns undefined if the
324-
* input rev is not known to the Sourcegraph instance.
325-
*
326-
* @param repoName The repository's name.
327-
* @param revision The revision.
328-
*/
329-
public async resolveRev(repoName: string, revision: string): Promise<string | undefined> {
330-
const query = gql`
331-
query LegacyResolveRev($repoName: String!, $rev: String!) {
332-
repository(name: $repoName) {
333-
commit(rev: $rev) {
334-
oid
335-
}
336-
}
337-
}
338-
`
339-
340-
interface Response {
341-
repository: {
342-
commit?: {
343-
oid: string
344-
}
345-
}
346-
}
347-
348-
const data = await queryGraphQL<Response>(query, { repoName, rev: revision })
349-
return data.repository.commit?.oid
350-
}
351-
352-
/**
353-
* Retrieve a sorted and deduplicated list of repository names that contain the
354-
* given search query.
355-
*
356-
* @param searchQuery The input to the search function.
357-
*/
358-
public async findReposViaSearch(searchQuery: string): Promise<string[]> {
359-
const query = gql`
360-
query LegacyCodeIntelSearch($query: String!) {
361-
search(query: $query) {
362-
results {
363-
results {
364-
... on FileMatch {
365-
repository {
366-
name
367-
}
368-
}
369-
}
370-
}
371-
}
372-
}
373-
`
374-
375-
interface Response {
376-
search: {
377-
results: {
378-
results: {
379-
// empty if not a FileMatch
380-
repository?: { name: string }
381-
}[]
382-
}
383-
}
384-
}
385-
386-
const data = await queryGraphQL<Response>(query, { query: searchQuery })
387-
return sortUnique(data.search.results.results.map(result => result.repository?.name)).filter(isDefined)
388-
}
389-
390-
/**
391-
* Retrieve all raw manifests for every extension that exists in the Sourcegraph
392-
* extension registry.
393-
*/
394-
public async getExtensionManifests(): Promise<string[]> {
395-
const query = gql`
396-
query LegacyExtensionManifests {
397-
extensionRegistry {
398-
extensions {
399-
nodes {
400-
extensionID
401-
manifest {
402-
raw
403-
}
404-
}
405-
}
406-
}
407-
}
408-
`
409-
410-
interface Response {
411-
extensionRegistry: {
412-
extensions: {
413-
nodes: {
414-
manifest?: { raw: string }
415-
}[]
416-
}
417-
}
418-
}
419-
420-
const data = await queryGraphQL<Response>(query)
421-
return data.extensionRegistry.extensions.nodes.map(extension => extension.manifest?.raw).filter(isDefined)
422-
}
423-
424-
/**
425-
* Retrieve the version of the Sourcegraph instance.
426-
*/
427-
public async productVersion(): Promise<string> {
428-
const query = gql`
429-
query LegacyProductVersion {
430-
site {
431-
productVersion
432-
}
433-
}
434-
`
435-
436-
interface Response {
437-
site: {
438-
productVersion: string
439-
}
440-
}
441-
442-
const data = await queryGraphQL<Response>(query)
443-
return data.site.productVersion
444-
}
445-
446-
/**
447-
* Retrieve the identifier of the current user.
448-
*
449-
* Note: this method does not throw on an unauthenticated request.
450-
*/
451-
public async getUser(): Promise<string | undefined> {
452-
const query = gql`
453-
query LegacyCurrentUser {
454-
currentUser {
455-
id
456-
}
457-
}
458-
`
459-
460-
interface Response {
461-
currentUser?: { id: string }
462-
}
463-
464-
const data = await queryGraphQL<Response>(query)
465-
return data.currentUser?.id
466-
}
467-
468-
/**
469-
* Creates a `user:all` scoped access token. Returns the newly created token.
470-
*
471-
* @param user The identifier of the user for which to create an access token.
472-
* @param note A note to attach to the access token.
473-
*/
474-
public async createAccessToken(user: string, note: string): Promise<string> {
475-
const query = gql`
476-
mutation LegacyCreateAccessToken($user: ID!, $note: String!, $scopes: [String!]!) {
477-
createAccessToken(user: $user, note: $note, scopes: $scopes) {
478-
token
479-
}
480-
}
481-
`
482-
483-
interface Response {
484-
createAccessToken: {
485-
id: string
486-
token: string
487-
}
488-
}
489-
490-
const data = await queryGraphQL<Response>(query, {
491-
user,
492-
note,
493-
scopes: ['user:all'],
494-
})
495-
return data.createAccessToken.token
496-
}
497-
498296
/**
499297
* Get the content of a file. Throws an error if the repository is not known to
500298
* the Sourcegraph instance. Returns undefined if the input rev or the file is
@@ -673,11 +471,11 @@ export interface RepoCommitPath {
673471
path: string
674472
}
675473

676-
export type LocalCodeIntelPayload = {
474+
type LocalCodeIntelPayload = {
677475
symbols: LocalSymbol[]
678476
} | null
679477

680-
export interface LocalSymbol {
478+
interface LocalSymbol {
681479
hover?: string
682480
def: Range
683481
refs?: Range[]
@@ -703,7 +501,7 @@ const isInRange = (position: sourcegraph.Position, range: Range): boolean => {
703501
}
704502

705503
/** The response envelope for all blob queries. */
706-
export interface GenericBlobResponse<R> {
504+
interface GenericBlobResponse<R> {
707505
repository: { commit: { blob: R | null } | null } | null
708506
}
709507

client/shared/src/commandPalette/CommandList.tsx

+1-4
Original file line numberDiff line numberDiff line change
@@ -261,10 +261,7 @@ export class CommandList extends React.PureComponent<CommandListProps, State> {
261261
) : query.length > 0 ? (
262262
<li className={this.props.noResultsClassName}>No matching commands</li>
263263
) : (
264-
<EmptyCommandList
265-
settingsCascade={this.state.settingsCascade}
266-
sourcegraphURL={this.props.platformContext.sourcegraphURL}
267-
/>
264+
<EmptyCommandList settingsCascade={this.state.settingsCascade} />
268265
)}
269266
</ul>
270267
</div>

client/shared/src/commandPalette/EmptyCommandList.tsx

+2-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react'
22

3-
import { ButtonLink, Text } from '@sourcegraph/wildcard'
3+
import { Text } from '@sourcegraph/wildcard'
44

55
import { onlyDefaultExtensionsAdded } from '../extensions/extensions'
66
import { SettingsCascadeOrError } from '../settings/settings'
@@ -11,13 +11,9 @@ import styles from './EmptyCommandList.module.scss'
1111

1212
interface Props {
1313
settingsCascade?: SettingsCascadeOrError
14-
sourcegraphURL: string
1514
}
1615

17-
export const EmptyCommandList: React.FunctionComponent<React.PropsWithChildren<Props>> = ({
18-
settingsCascade,
19-
sourcegraphURL,
20-
}) => {
16+
export const EmptyCommandList: React.FunctionComponent<React.PropsWithChildren<Props>> = ({ settingsCascade }) => {
2117
// if no settings cascade, default to 'no active extensions'
2218
const onlyDefault = settingsCascade ? onlyDefaultExtensionsAdded(settingsCascade) : false
2319

@@ -32,10 +28,6 @@ export const EmptyCommandList: React.FunctionComponent<React.PropsWithChildren<P
3228
: 'Commands from your installed extensions will be shown when you navigate to certain pages.'}
3329
</Text>
3430

35-
<ButtonLink to={sourcegraphURL + '/extensions'} variant="primary">
36-
Explore extensions
37-
</ButtonLink>
38-
3931
<PuzzleIllustration className={styles.illustration} />
4032
</EmptyCommandListContainer>
4133
)

client/shared/src/extensions/extension.ts

+1-41
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import { asError, ErrorLike, isErrorLike } from '@sourcegraph/common'
22

3-
import * as GQL from '../schema'
43
import { Settings, SettingsCascadeOrError } from '../settings/settings'
54

6-
import { ExtensionManifest, parseExtensionManifestOrError } from './extensionManifest'
5+
import { ExtensionManifest } from './extensionManifest'
76

87
/**
98
* The default fields in the {@link ConfiguredExtension} manifest (i.e., the default value of the
@@ -30,45 +29,6 @@ export interface ConfiguredExtension<K extends keyof ExtensionManifest = Configu
3029
readonly manifest: Pick<ExtensionManifest, K> | null | ErrorLike
3130
}
3231

33-
/**
34-
* Describes a configured extension with an optional associated registry extension. Prefer using
35-
* {@link ConfiguredExtension} when it is not necessary to access the registry extension's metadata.
36-
*
37-
* @template X the registry extension type
38-
*/
39-
export interface ConfiguredRegistryExtension<
40-
X extends Pick<GQL.IRegistryExtension, 'id' | 'url' | 'viewerCanAdminister'> = Pick<
41-
GQL.IRegistryExtension,
42-
'id' | 'url' | 'viewerCanAdminister'
43-
>
44-
> extends ConfiguredExtension<keyof ExtensionManifest> {
45-
/** The extension's metadata on the registry, if this is a registry extension. */
46-
readonly registryExtension?: X
47-
48-
/** The raw extension manifest (JSON), or null if there is none. */
49-
readonly rawManifest: string | null
50-
}
51-
52-
type MinimalRegistryExtension = Pick<GQL.IRegistryExtension, 'extensionID' | 'id' | 'url' | 'viewerCanAdminister'> & {
53-
manifest: { raw: string } | null
54-
}
55-
56-
/**
57-
* Converts to a {@link ConfiguredRegistryExtension} value.
58-
*
59-
* @template X the extension type
60-
*/
61-
export function toConfiguredRegistryExtension<X extends MinimalRegistryExtension>(
62-
extension: X
63-
): ConfiguredRegistryExtension<X> {
64-
return {
65-
id: extension.extensionID,
66-
manifest: extension.manifest ? parseExtensionManifestOrError(extension.manifest.raw) : null,
67-
rawManifest: extension?.manifest?.raw || null,
68-
registryExtension: extension,
69-
}
70-
}
71-
7232
/** Reports whether the given extension is enabled in the settings. */
7333
export function isExtensionEnabled(settings: Settings | ErrorLike | null, extensionID: string): boolean {
7434
return !!settings && !isErrorLike(settings) && !!settings.extensions && !!settings.extensions[extensionID]

0 commit comments

Comments
 (0)