diff --git a/client/build-config/src/webpack/monaco-editor.ts b/client/build-config/src/webpack/monaco-editor.ts index 1872eda7484..e1ca7d62cf9 100644 --- a/client/build-config/src/webpack/monaco-editor.ts +++ b/client/build-config/src/webpack/monaco-editor.ts @@ -26,7 +26,7 @@ export const MONACO_LANGUAGES_AND_FEATURES: Required< 'languages' | 'features' | 'customLanguages' > > = { - languages: ['json', 'yaml'], + languages: ['json', 'yaml', 'lua'], customLanguages: [ { label: 'yaml', diff --git a/client/web/src/enterprise/codeintel/configuration/components/InferenceScriptEditor.tsx b/client/web/src/enterprise/codeintel/configuration/components/InferenceScriptEditor.tsx new file mode 100644 index 00000000000..febedff9cb8 --- /dev/null +++ b/client/web/src/enterprise/codeintel/configuration/components/InferenceScriptEditor.tsx @@ -0,0 +1,119 @@ +import { FunctionComponent, useCallback, useMemo, useState } from 'react' + +import { useHistory } from 'react-router' + +import { ErrorAlert } from '@sourcegraph/branded/src/components/alerts' +import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService' +import { LoadingSpinner, PageHeader, screenReaderAnnounce } from '@sourcegraph/wildcard' + +import { AuthenticatedUser } from '../../../../auth' +import { PageTitle } from '../../../../components/PageTitle' +import { SaveToolbar, SaveToolbarProps, SaveToolbarPropsGenerator } from '../../../../components/SaveToolbar' +import { DynamicallyImportedMonacoSettingsEditor } from '../../../../settings/DynamicallyImportedMonacoSettingsEditor' +import { ThemePreference, useTheme } from '../../../../theme' +import { INFERENCE_SCRIPT, useInferenceScript } from '../hooks/useInferenceScript' +import { useUpdateInferenceScript } from '../hooks/useUpdateInferenceScript' + +import styles from './CodeIntelConfigurationPageHeader.module.scss' + +export interface InferenceScriptEditorProps extends TelemetryProps { + authenticatedUser: AuthenticatedUser | null +} + +export const InferenceScriptEditor: FunctionComponent> = ({ + authenticatedUser, + telemetryService, +}) => { + const { inferenceScript, loadingScript, fetchError } = useInferenceScript() + const { updateInferenceScript, isUpdating, updatingError } = useUpdateInferenceScript() + + const save = useCallback( + async (script: string) => + updateInferenceScript({ + variables: { script }, + refetchQueries: [INFERENCE_SCRIPT], + }).then(() => { + screenReaderAnnounce('Saved successfully') + setDirty(false) + }), + [updateInferenceScript] + ) + + const [dirty, setDirty] = useState() + const history = useHistory() + const isLightTheme = useTheme().enhancedThemePreference === ThemePreference.Light + + const customToolbar = useMemo<{ + saveToolbar: FunctionComponent + propsGenerator: SaveToolbarPropsGenerator<{}> + }>( + () => ({ + saveToolbar: SaveToolbar, + propsGenerator: props => { + const mergedProps = { + ...props, + loading: isUpdating, + } + mergedProps.willShowError = () => !mergedProps.saving + mergedProps.saveDiscardDisabled = () => mergedProps.saving || !dirty + + return mergedProps + }, + }), + [dirty, isUpdating] + ) + + const title = ( + <> + +
+ Code graph inference script, + }, + ]} + description={`Lua script that emits complete and/or partial auto-indexing + job specifications. `} + className="mb-3" + /> +
+ + ) + + if (fetchError) { + return ( + <> + {title} + + + ) + } + + return ( + <> + {title} + {updatingError && } + + {loadingScript ? ( + + ) : ( + + )} + + ) +} diff --git a/client/web/src/enterprise/codeintel/configuration/hooks/useInferenceScript.tsx b/client/web/src/enterprise/codeintel/configuration/hooks/useInferenceScript.tsx new file mode 100644 index 00000000000..2fa79539b3f --- /dev/null +++ b/client/web/src/enterprise/codeintel/configuration/hooks/useInferenceScript.tsx @@ -0,0 +1,27 @@ +import { ApolloError, gql, useQuery } from '@apollo/client' + +import { CodeGraphInferenceScriptResult } from '../../../../graphql-operations' + +interface UseInferenceScriptResult { + inferenceScript: string + loadingScript: boolean + fetchError: ApolloError | undefined +} + +export const INFERENCE_SCRIPT = gql` + query CodeGraphInferenceScript { + codeIntelligenceInferenceScript + } +` + +export const useInferenceScript = (): UseInferenceScriptResult => { + const { data, loading, error } = useQuery(INFERENCE_SCRIPT, { + nextFetchPolicy: 'cache-first', + }) + + return { + inferenceScript: data?.codeIntelligenceInferenceScript ?? '', + loadingScript: loading, + fetchError: error, + } +} diff --git a/client/web/src/enterprise/codeintel/configuration/hooks/useUpdateInferenceScript.tsx b/client/web/src/enterprise/codeintel/configuration/hooks/useUpdateInferenceScript.tsx new file mode 100644 index 00000000000..487c1aa5cf7 --- /dev/null +++ b/client/web/src/enterprise/codeintel/configuration/hooks/useUpdateInferenceScript.tsx @@ -0,0 +1,36 @@ +import { ApolloError, FetchResult, MutationFunctionOptions, OperationVariables } from '@apollo/client' + +import { gql, useMutation } from '@sourcegraph/http-client' + +import { UpdateCodeGraphInferenceScriptResult } from '../../../../graphql-operations' + +const UPDATE_INFERENCE_SCRIPT = gql` + mutation UpdateCodeGraphInferenceScript($script: String!) { + updateCodeIntelligenceInferenceScript(script: $script) { + alwaysNil + } + } +` + +type UpdateInferenceScriptFetchResult = Promise< + FetchResult, Record> +> +interface UpdateInferenceScriptResult { + updateInferenceScript: ( + options?: MutationFunctionOptions | undefined + ) => UpdateInferenceScriptFetchResult + isUpdating: boolean + updatingError: ApolloError | undefined +} + +export const useUpdateInferenceScript = (): UpdateInferenceScriptResult => { + const [updateInferenceScript, { loading, error }] = useMutation( + UPDATE_INFERENCE_SCRIPT + ) + + return { + updateInferenceScript, + isUpdating: loading, + updatingError: error, + } +} diff --git a/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelInferenceConfigurationPage.tsx b/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelInferenceConfigurationPage.tsx new file mode 100644 index 00000000000..997eebf6ab5 --- /dev/null +++ b/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelInferenceConfigurationPage.tsx @@ -0,0 +1,22 @@ +import { FunctionComponent } from 'react' + +import { TelemetryProps } from '@sourcegraph/shared/src/telemetry/telemetryService' + +import { AuthenticatedUser } from '../../../../auth' +import { PageTitle } from '../../../../components/PageTitle' +import { InferenceScriptEditor } from '../components/InferenceScriptEditor' + +export interface CodeIntelInferenceConfigurationPageProps extends TelemetryProps { + authenticatedUser: AuthenticatedUser | null +} + +export const CodeIntelInferenceConfigurationPage: FunctionComponent = ({ + authenticatedUser, + ...props +}) => ( + <> + + + + +) diff --git a/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelRepositoryIndexConfigurationPage.tsx b/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelRepositoryIndexConfigurationPage.tsx index 164658e6917..b64c86a5862 100644 --- a/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelRepositoryIndexConfigurationPage.tsx +++ b/client/web/src/enterprise/codeintel/configuration/pages/CodeIntelRepositoryIndexConfigurationPage.tsx @@ -17,9 +17,13 @@ export interface CodeIntelRepositoryIndexConfigurationPageProps extends ThemePro history: H.History } -export const CodeIntelRepositoryIndexConfigurationPage: FunctionComponent< - React.PropsWithChildren -> = ({ repo, authenticatedUser, history, telemetryService, ...props }) => { +export const CodeIntelRepositoryIndexConfigurationPage: FunctionComponent = ({ + repo, + authenticatedUser, + history, + telemetryService, + ...props +}) => { useEffect(() => telemetryService.logViewEvent('CodeIntelRepositoryIndexConfiguration'), [telemetryService]) return ( diff --git a/client/web/src/enterprise/codeintel/repo/RepositoryCodeIntelArea.tsx b/client/web/src/enterprise/codeintel/repo/RepositoryCodeIntelArea.tsx index 7f1d1888bed..8b16b0b4412 100644 --- a/client/web/src/enterprise/codeintel/repo/RepositoryCodeIntelArea.tsx +++ b/client/web/src/enterprise/codeintel/repo/RepositoryCodeIntelArea.tsx @@ -14,6 +14,7 @@ import { RepositoryFields } from '../../../graphql-operations' import { RouteDescriptor } from '../../../util/contributions' import { CodeIntelConfigurationPageProps } from '../configuration/pages/CodeIntelConfigurationPage' import { CodeIntelConfigurationPolicyPageProps } from '../configuration/pages/CodeIntelConfigurationPolicyPage' +import { CodeIntelInferenceConfigurationPageProps } from '../configuration/pages/CodeIntelInferenceConfigurationPage' import { CodeIntelRepositoryIndexConfigurationPageProps } from '../configuration/pages/CodeIntelRepositoryIndexConfigurationPage' import { CodeIntelIndexesPageProps } from '../indexes/pages/CodeIntelIndexesPage' import { CodeIntelIndexPageProps } from '../indexes/pages/CodeIntelIndexPage' @@ -52,6 +53,11 @@ const CodeIntelConfigurationPage = lazyComponent(() => import('../configuration/pages/CodeIntelInferenceConfigurationPage'), 'CodeIntelInferenceConfigurationPage') + const RepositoryIndexConfigurationPage = lazyComponent< CodeIntelRepositoryIndexConfigurationPageProps, 'CodeIntelRepositoryIndexConfigurationPage' @@ -103,6 +109,11 @@ export const routes: readonly CodeIntelAreaRoute[] = [ exact: true, render: props => , }, + { + path: '/inference-configuration', + exact: true, + render: props => , + }, { path: '/configuration/:id', exact: true, diff --git a/client/web/src/enterprise/site-admin/routes.tsx b/client/web/src/enterprise/site-admin/routes.tsx index df2c473a8b9..6dc72d0e200 100644 --- a/client/web/src/enterprise/site-admin/routes.tsx +++ b/client/web/src/enterprise/site-admin/routes.tsx @@ -159,6 +159,14 @@ export const enterpriseSiteAdminAreaRoutes: readonly SiteAdminAreaRoute[] = ([ ), exact: true, }, + { + path: '/code-graph/inference-configuration', + render: lazyComponent( + () => import('../codeintel/configuration/pages/CodeIntelInferenceConfigurationPage'), + 'CodeIntelInferenceConfigurationPage' + ), + exact: true, + }, // Legacy routes { diff --git a/client/web/src/enterprise/site-admin/sidebaritems.ts b/client/web/src/enterprise/site-admin/sidebaritems.ts index b9404881421..40ab694eb39 100644 --- a/client/web/src/enterprise/site-admin/sidebaritems.ts +++ b/client/web/src/enterprise/site-admin/sidebaritems.ts @@ -112,6 +112,10 @@ const codeIntelGroup: SiteAdminSideBarGroup = { to: '/site-admin/code-graph/configuration', label: 'Configuration', }, + { + to: '/site-admin/code-graph/inference-configuration', + label: 'Inference' + } ], } diff --git a/cmd/frontend/graphqlbackend/codeintel.go b/cmd/frontend/graphqlbackend/codeintel.go index ccf8c73e538..962df252c62 100644 --- a/cmd/frontend/graphqlbackend/codeintel.go +++ b/cmd/frontend/graphqlbackend/codeintel.go @@ -41,6 +41,8 @@ type AutoindexingServiceResolver interface { QueueAutoIndexJobsForRepo(ctx context.Context, args *autoindexinggraphql.QueueAutoIndexJobsForRepoArgs) ([]sharedresolvers.LSIFIndexResolver, error) UpdateRepositoryIndexConfiguration(ctx context.Context, args *autoindexinggraphql.UpdateRepositoryIndexConfigurationArgs) (*sharedresolvers.EmptyResponse, error) RepositorySummary(ctx context.Context, id graphql.ID) (sharedresolvers.CodeIntelRepositorySummaryResolver, error) + CodeIntelligenceInferenceScript(ctx context.Context) (string, error) + UpdateCodeIntelligenceInferenceScript(ctx context.Context, args *autoindexinggraphql.UpdateCodeIntelligenceInferenceScriptArgs) (*EmptyResponse, error) } type UploadsServiceResolver interface { diff --git a/cmd/frontend/graphqlbackend/codeintel.graphql b/cmd/frontend/graphqlbackend/codeintel.graphql index 9d2edc8c25a..a1eadd8fc21 100644 --- a/cmd/frontend/graphqlbackend/codeintel.graphql +++ b/cmd/frontend/graphqlbackend/codeintel.graphql @@ -106,6 +106,12 @@ extend type Mutation { Request support for a particular language. """ requestLanguageSupport(language: String!): EmptyResponse + + """ + Updates the previously set/overrides the default global auto-indexing job inference Lua script + with a new override. + """ + updateCodeIntelligenceInferenceScript(script: String!): EmptyResponse } extend type Query { @@ -269,6 +275,13 @@ extend type Query { Return the languages that this user has requested support for. """ requestedLanguageSupport: [String!]! + + """ + Return the currently set auto-indexing job inference script. Does not return + the value stored in the environment variable or the default shipped scripts, + only the value set via UI/GraphQL. + """ + codeIntelligenceInferenceScript: String! } """ diff --git a/enterprise/cmd/frontend/internal/codeintel/resolvers.go b/enterprise/cmd/frontend/internal/codeintel/resolvers.go index 6cfc7ad1bd4..d4c01fe5078 100644 --- a/enterprise/cmd/frontend/internal/codeintel/resolvers.go +++ b/enterprise/cmd/frontend/internal/codeintel/resolvers.go @@ -175,6 +175,14 @@ func (r *Resolver) PreviewRepositoryFilter(ctx context.Context, args *policiesgr return r.policiesRootResolver.PreviewRepositoryFilter(ctx, args) } +func (r *Resolver) CodeIntelligenceInferenceScript(ctx context.Context) (_ string, err error) { + return r.autoIndexingRootResolver.CodeIntelligenceInferenceScript(ctx) +} + +func (r *Resolver) UpdateCodeIntelligenceInferenceScript(ctx context.Context, args *autoindexinggraphql.UpdateCodeIntelligenceInferenceScriptArgs) (_ *gql.EmptyResponse, err error) { + return &gql.EmptyResponse{}, r.autoIndexingRootResolver.UpdateCodeIntelligenceInferenceScript(ctx, args) +} + func (r *Resolver) PreviewGitObjectFilter(ctx context.Context, id graphql.ID, args *policiesgraphql.PreviewGitObjectFilterArgs) (_ []policiesgraphql.GitObjectFilterPreviewResolver, err error) { return r.policiesRootResolver.PreviewGitObjectFilter(ctx, id, args) } diff --git a/internal/codeintel/autoindexing/internal/inference/service.go b/internal/codeintel/autoindexing/internal/inference/service.go index b386b77247c..3bab20480b5 100644 --- a/internal/codeintel/autoindexing/internal/inference/service.go +++ b/internal/codeintel/autoindexing/internal/inference/service.go @@ -83,7 +83,10 @@ func newService( // will overwrite them (to disable or change default behavior). Each recognizer's generate function // is invoked and the resulting index jobs are combined into a flattened list. func (s *Service) InferIndexJobs(ctx context.Context, repo api.RepoName, commit, overrideScript string) (_ []config.IndexJob, err error) { - ctx, _, endObservation := s.operations.inferIndexJobs.With(ctx, &err, observation.Args{}) + ctx, _, endObservation := s.operations.inferIndexJobs.With(ctx, &err, observation.Args{LogFields: []otelog.Field{ + otelog.String("repo", string(repo)), + otelog.String("commit", commit), + }}) defer endObservation(1, observation.Args{}) functionTable := invocationFunctionTable{ @@ -127,7 +130,10 @@ func (s *Service) InferIndexJobs(ctx context.Context, repo api.RepoName, commit, // will overwrite them (to disable or change default behavior). Each recognizer's hints function is // invoked and the resulting index job hints are combined into a flattened list. func (s *Service) InferIndexJobHints(ctx context.Context, repo api.RepoName, commit, overrideScript string) (_ []config.IndexJobHint, err error) { - ctx, _, endObservation := s.operations.inferIndexJobHints.With(ctx, &err, observation.Args{}) + ctx, _, endObservation := s.operations.inferIndexJobHints.With(ctx, &err, observation.Args{LogFields: []otelog.Field{ + otelog.String("repo", string(repo)), + otelog.String("commit", commit), + }}) defer endObservation(1, observation.Args{}) functionTable := invocationFunctionTable{ diff --git a/internal/codeintel/autoindexing/internal/store/observability.go b/internal/codeintel/autoindexing/internal/store/observability.go index 8585810c64b..d8a042ab66d 100644 --- a/internal/codeintel/autoindexing/internal/store/observability.go +++ b/internal/codeintel/autoindexing/internal/store/observability.go @@ -33,7 +33,8 @@ type operations struct { // Index Configuration getIndexConfigurationByRepositoryID *observation.Operation updateIndexConfigurationByRepositoryID *observation.Operation - + setInferenceScript *observation.Operation + getInferenceScript *observation.Operation // Language Support getLanguagesRequestedBy *observation.Operation setRequestLanguageSupport *observation.Operation @@ -87,6 +88,8 @@ func newOperations(observationContext *observation.Context) *operations { // Index Configuration getIndexConfigurationByRepositoryID: op("GetIndexConfigurationByRepositoryID"), updateIndexConfigurationByRepositoryID: op("UpdateIndexConfigurationByRepositoryID"), + getInferenceScript: op("GetInferenceScript"), + setInferenceScript: op("SetInferenceScript"), // Language Support getLanguagesRequestedBy: op("GetLanguagesRequestedBy"), diff --git a/internal/codeintel/autoindexing/internal/store/store.go b/internal/codeintel/autoindexing/internal/store/store.go index d8d20f0877e..067591a8092 100644 --- a/internal/codeintel/autoindexing/internal/store/store.go +++ b/internal/codeintel/autoindexing/internal/store/store.go @@ -42,6 +42,8 @@ type Store interface { // Index configurations GetIndexConfigurationByRepositoryID(ctx context.Context, repositoryID int) (_ shared.IndexConfiguration, _ bool, err error) UpdateIndexConfigurationByRepositoryID(ctx context.Context, repositoryID int, data []byte) (err error) + GetInferenceScript(ctx context.Context) (script string, err error) + SetInferenceScript(ctx context.Context, script string) (err error) // Language support GetLanguagesRequestedBy(ctx context.Context, userID int) (_ []string, err error) diff --git a/internal/codeintel/autoindexing/internal/store/store_configurations.go b/internal/codeintel/autoindexing/internal/store/store_configurations.go index 38af52c31d4..735474f653f 100644 --- a/internal/codeintel/autoindexing/internal/store/store_configurations.go +++ b/internal/codeintel/autoindexing/internal/store/store_configurations.go @@ -4,6 +4,7 @@ import ( "context" "github.com/sourcegraph/sourcegraph/internal/codeintel/autoindexing/shared" + "github.com/sourcegraph/sourcegraph/internal/database/basestore" "github.com/keegancsmith/sqlf" "github.com/opentracing/opentracing-go/log" @@ -45,3 +46,31 @@ const updateIndexConfigurationByRepositoryIDQuery = ` INSERT INTO lsif_index_configuration (repository_id, data) VALUES (%s, %s) ON CONFLICT (repository_id) DO UPDATE SET data = %s ` + +func (s *store) SetInferenceScript(ctx context.Context, script string) (err error) { + ctx, _, endObservation := s.operations.setInferenceScript.With(ctx, &err, observation.Args{}) + defer endObservation(1, observation.Args{}) + + return s.db.Exec(ctx, sqlf.Sprintf(setInferenceScriptQuery, script)) +} + +const setInferenceScriptQuery = ` +-- source: internal/codeintel/stores/dbstore/configuration.go:GetInferenceScript +INSERT INTO codeintel_inference_scripts(script) +VALUES(%s) +` + +func (s *store) GetInferenceScript(ctx context.Context) (script string, err error) { + ctx, _, endObservation := s.operations.getInferenceScript.With(ctx, &err, observation.Args{}) + defer endObservation(1, observation.Args{}) + + script, _, err = basestore.ScanFirstNullString(s.db.Query(ctx, sqlf.Sprintf(getInferenceScriptQuery))) + return +} + +const getInferenceScriptQuery = ` +-- source: internal/codeintel/stores/dbstore/configuration.go:GetInferenceScript +SELECT script FROM codeintel_inference_scripts +ORDER BY insert_timestamp DESC +LIMIT 1 +` diff --git a/internal/codeintel/autoindexing/mocks_test.go b/internal/codeintel/autoindexing/mocks_test.go index 2eefd5a0717..e4facd92c61 100644 --- a/internal/codeintel/autoindexing/mocks_test.go +++ b/internal/codeintel/autoindexing/mocks_test.go @@ -60,6 +60,9 @@ type MockStore struct { // GetIndexesByIDsFunc is an instance of a mock function object // controlling the behavior of the method GetIndexesByIDs. GetIndexesByIDsFunc *StoreGetIndexesByIDsFunc + // GetInferenceScriptFunc is an instance of a mock function object + // controlling the behavior of the method GetInferenceScript. + GetInferenceScriptFunc *StoreGetInferenceScriptFunc // GetLanguagesRequestedByFunc is an instance of a mock function object // controlling the behavior of the method GetLanguagesRequestedBy. GetLanguagesRequestedByFunc *StoreGetLanguagesRequestedByFunc @@ -95,6 +98,9 @@ type MockStore struct { // QueueRepoRevFunc is an instance of a mock function object controlling // the behavior of the method QueueRepoRev. QueueRepoRevFunc *StoreQueueRepoRevFunc + // SetInferenceScriptFunc is an instance of a mock function object + // controlling the behavior of the method SetInferenceScript. + SetInferenceScriptFunc *StoreSetInferenceScriptFunc // SetRequestLanguageSupportFunc is an instance of a mock function // object controlling the behavior of the method // SetRequestLanguageSupport. @@ -166,6 +172,11 @@ func NewMockStore() *MockStore { return }, }, + GetInferenceScriptFunc: &StoreGetInferenceScriptFunc{ + defaultHook: func(context.Context) (r0 string, r1 error) { + return + }, + }, GetLanguagesRequestedByFunc: &StoreGetLanguagesRequestedByFunc{ defaultHook: func(context.Context, int) (r0 []string, r1 error) { return @@ -221,6 +232,11 @@ func NewMockStore() *MockStore { return }, }, + SetInferenceScriptFunc: &StoreSetInferenceScriptFunc{ + defaultHook: func(context.Context, string) (r0 error) { + return + }, + }, SetRequestLanguageSupportFunc: &StoreSetRequestLanguageSupportFunc{ defaultHook: func(context.Context, int, string) (r0 error) { return @@ -303,6 +319,11 @@ func NewStrictMockStore() *MockStore { panic("unexpected invocation of MockStore.GetIndexesByIDs") }, }, + GetInferenceScriptFunc: &StoreGetInferenceScriptFunc{ + defaultHook: func(context.Context) (string, error) { + panic("unexpected invocation of MockStore.GetInferenceScript") + }, + }, GetLanguagesRequestedByFunc: &StoreGetLanguagesRequestedByFunc{ defaultHook: func(context.Context, int) ([]string, error) { panic("unexpected invocation of MockStore.GetLanguagesRequestedBy") @@ -358,6 +379,11 @@ func NewStrictMockStore() *MockStore { panic("unexpected invocation of MockStore.QueueRepoRev") }, }, + SetInferenceScriptFunc: &StoreSetInferenceScriptFunc{ + defaultHook: func(context.Context, string) error { + panic("unexpected invocation of MockStore.SetInferenceScript") + }, + }, SetRequestLanguageSupportFunc: &StoreSetRequestLanguageSupportFunc{ defaultHook: func(context.Context, int, string) error { panic("unexpected invocation of MockStore.SetRequestLanguageSupport") @@ -424,6 +450,9 @@ func NewMockStoreFrom(i store.Store) *MockStore { GetIndexesByIDsFunc: &StoreGetIndexesByIDsFunc{ defaultHook: i.GetIndexesByIDs, }, + GetInferenceScriptFunc: &StoreGetInferenceScriptFunc{ + defaultHook: i.GetInferenceScript, + }, GetLanguagesRequestedByFunc: &StoreGetLanguagesRequestedByFunc{ defaultHook: i.GetLanguagesRequestedBy, }, @@ -457,6 +486,9 @@ func NewMockStoreFrom(i store.Store) *MockStore { QueueRepoRevFunc: &StoreQueueRepoRevFunc{ defaultHook: i.QueueRepoRev, }, + SetInferenceScriptFunc: &StoreSetInferenceScriptFunc{ + defaultHook: i.SetInferenceScript, + }, SetRequestLanguageSupportFunc: &StoreSetRequestLanguageSupportFunc{ defaultHook: i.SetRequestLanguageSupport, }, @@ -1366,6 +1398,111 @@ func (c StoreGetIndexesByIDsFuncCall) Results() []interface{} { return []interface{}{c.Result0, c.Result1} } +// StoreGetInferenceScriptFunc describes the behavior when the +// GetInferenceScript method of the parent MockStore instance is invoked. +type StoreGetInferenceScriptFunc struct { + defaultHook func(context.Context) (string, error) + hooks []func(context.Context) (string, error) + history []StoreGetInferenceScriptFuncCall + mutex sync.Mutex +} + +// GetInferenceScript delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockStore) GetInferenceScript(v0 context.Context) (string, error) { + r0, r1 := m.GetInferenceScriptFunc.nextHook()(v0) + m.GetInferenceScriptFunc.appendCall(StoreGetInferenceScriptFuncCall{v0, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetInferenceScript +// method of the parent MockStore instance is invoked and the hook queue is +// empty. +func (f *StoreGetInferenceScriptFunc) SetDefaultHook(hook func(context.Context) (string, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetInferenceScript method of the parent MockStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *StoreGetInferenceScriptFunc) PushHook(hook func(context.Context) (string, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *StoreGetInferenceScriptFunc) SetDefaultReturn(r0 string, r1 error) { + f.SetDefaultHook(func(context.Context) (string, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *StoreGetInferenceScriptFunc) PushReturn(r0 string, r1 error) { + f.PushHook(func(context.Context) (string, error) { + return r0, r1 + }) +} + +func (f *StoreGetInferenceScriptFunc) nextHook() func(context.Context) (string, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *StoreGetInferenceScriptFunc) appendCall(r0 StoreGetInferenceScriptFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of StoreGetInferenceScriptFuncCall objects +// describing the invocations of this function. +func (f *StoreGetInferenceScriptFunc) History() []StoreGetInferenceScriptFuncCall { + f.mutex.Lock() + history := make([]StoreGetInferenceScriptFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// StoreGetInferenceScriptFuncCall is an object that describes an invocation +// of method GetInferenceScript on an instance of MockStore. +type StoreGetInferenceScriptFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 string + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c StoreGetInferenceScriptFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c StoreGetInferenceScriptFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + // StoreGetLanguagesRequestedByFunc describes the behavior when the // GetLanguagesRequestedBy method of the parent MockStore instance is // invoked. @@ -2563,6 +2700,111 @@ func (c StoreQueueRepoRevFuncCall) Results() []interface{} { return []interface{}{c.Result0} } +// StoreSetInferenceScriptFunc describes the behavior when the +// SetInferenceScript method of the parent MockStore instance is invoked. +type StoreSetInferenceScriptFunc struct { + defaultHook func(context.Context, string) error + hooks []func(context.Context, string) error + history []StoreSetInferenceScriptFuncCall + mutex sync.Mutex +} + +// SetInferenceScript delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockStore) SetInferenceScript(v0 context.Context, v1 string) error { + r0 := m.SetInferenceScriptFunc.nextHook()(v0, v1) + m.SetInferenceScriptFunc.appendCall(StoreSetInferenceScriptFuncCall{v0, v1, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the SetInferenceScript +// method of the parent MockStore instance is invoked and the hook queue is +// empty. +func (f *StoreSetInferenceScriptFunc) SetDefaultHook(hook func(context.Context, string) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// SetInferenceScript method of the parent MockStore instance invokes the +// hook at the front of the queue and discards it. After the queue is empty, +// the default hook function is invoked for any future action. +func (f *StoreSetInferenceScriptFunc) PushHook(hook func(context.Context, string) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *StoreSetInferenceScriptFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, string) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *StoreSetInferenceScriptFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, string) error { + return r0 + }) +} + +func (f *StoreSetInferenceScriptFunc) nextHook() func(context.Context, string) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *StoreSetInferenceScriptFunc) appendCall(r0 StoreSetInferenceScriptFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of StoreSetInferenceScriptFuncCall objects +// describing the invocations of this function. +func (f *StoreSetInferenceScriptFunc) History() []StoreSetInferenceScriptFuncCall { + f.mutex.Lock() + history := make([]StoreSetInferenceScriptFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// StoreSetInferenceScriptFuncCall is an object that describes an invocation +// of method SetInferenceScript on an instance of MockStore. +type StoreSetInferenceScriptFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c StoreSetInferenceScriptFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c StoreSetInferenceScriptFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + // StoreSetRequestLanguageSupportFunc describes the behavior when the // SetRequestLanguageSupport method of the parent MockStore instance is // invoked. diff --git a/internal/codeintel/autoindexing/observability.go b/internal/codeintel/autoindexing/observability.go index ebba4d3d043..d10415b9c13 100644 --- a/internal/codeintel/autoindexing/observability.go +++ b/internal/codeintel/autoindexing/observability.go @@ -25,6 +25,8 @@ type operations struct { getIndexConfigurationByRepositoryID *observation.Operation updateIndexConfigurationByRepositoryID *observation.Operation inferIndexConfiguration *observation.Operation + setInferenceScript *observation.Operation + getInferenceScript *observation.Operation // Tags getListTags *observation.Operation @@ -80,6 +82,8 @@ func newOperations(observationContext *observation.Context) *operations { getIndexConfigurationByRepositoryID: op("GetIndexConfigurationByRepositoryID"), updateIndexConfigurationByRepositoryID: op("UpdateIndexConfigurationByRepositoryID"), inferIndexConfiguration: op("InferIndexConfiguration"), + getInferenceScript: op("GetInferenceScript"), + setInferenceScript: op("SetInferenceScript"), // Tags getListTags: op("GetListTags"), diff --git a/internal/codeintel/autoindexing/service.go b/internal/codeintel/autoindexing/service.go index 894bd96d658..15a1bcbf1fd 100644 --- a/internal/codeintel/autoindexing/service.go +++ b/internal/codeintel/autoindexing/service.go @@ -8,7 +8,6 @@ import ( "github.com/grafana/regexp" otlog "github.com/opentracing/opentracing-go/log" - traceLog "github.com/opentracing/opentracing-go/log" "github.com/sourcegraph/log" "github.com/sourcegraph/sourcegraph/internal/api" @@ -244,7 +243,7 @@ func (s *Service) GetSupportedByCtags(ctx context.Context, filepath string, repo func (s *Service) SetRequestLanguageSupport(ctx context.Context, userID int, language string) (err error) { ctx, _, endObservation := s.operations.setRequestLanguageSupport.With(ctx, &err, observation.Args{ - LogFields: []traceLog.Field{traceLog.Int("userID", userID), traceLog.String("language", language)}, + LogFields: []otlog.Field{otlog.Int("userID", userID), otlog.String("language", language)}, }) defer endObservation(1, observation.Args{}) @@ -253,7 +252,7 @@ func (s *Service) SetRequestLanguageSupport(ctx context.Context, userID int, lan func (s *Service) GetLanguagesRequestedBy(ctx context.Context, userID int) (_ []string, err error) { ctx, _, endObservation := s.operations.getLanguagesRequestedBy.With(ctx, &err, observation.Args{ - LogFields: []traceLog.Field{traceLog.Int("userID", userID)}, + LogFields: []otlog.Field{otlog.Int("userID", userID)}, }) defer endObservation(1, observation.Args{}) @@ -262,7 +261,7 @@ func (s *Service) GetLanguagesRequestedBy(ctx context.Context, userID int) (_ [] func (s *Service) GetListTags(ctx context.Context, repo api.RepoName, commitObjs ...string) (_ []*gitdomain.Tag, err error) { ctx, _, endObservation := s.operations.getListTags.With(ctx, &err, observation.Args{ - LogFields: []traceLog.Field{traceLog.String("repo", string(repo)), traceLog.String("commitObjs", fmt.Sprintf("%v", commitObjs))}, + LogFields: []otlog.Field{otlog.String("repo", string(repo)), otlog.String("commitObjs", fmt.Sprintf("%v", commitObjs))}, }) defer endObservation(1, observation.Args{}) @@ -281,6 +280,20 @@ func (s *Service) QueueRepoRev(ctx context.Context, repositoryID int, rev string return s.store.QueueRepoRev(ctx, repositoryID, rev) } +func (s *Service) SetInferenceScript(ctx context.Context, script string) (err error) { + ctx, _, endObservation := s.operations.setInferenceScript.With(ctx, &err, observation.Args{}) + defer endObservation(1, observation.Args{}) + + return s.store.SetInferenceScript(ctx, script) +} + +func (s *Service) GetInferenceScript(ctx context.Context) (script string, err error) { + ctx, _, endObservation := s.operations.getInferenceScript.With(ctx, &err, observation.Args{}) + defer endObservation(1, observation.Args{}) + + return s.store.GetInferenceScript(ctx) +} + // QueueIndexes enqueues a set of index jobs for the following repository and commit. If a non-empty // configuration is given, it will be used to determine the set of jobs to enqueue. Otherwise, it will // the configuration will be determined based on the regular index scheduling rules: first read any @@ -337,8 +350,10 @@ func (s *Service) queueIndexForRepositoryAndCommit(ctx context.Context, reposito return s.store.InsertIndexes(ctx, indexes) } -var overrideScript = os.Getenv("SRC_CODEINTEL_INFERENCE_OVERRIDE_SCRIPT") -var maximumIndexJobsPerInferredConfiguration = env.MustGetInt("PRECISE_CODE_INTEL_AUTO_INDEX_MAXIMUM_INDEX_JOBS_PER_INFERRED_CONFIGURATION", 25, "Repositories with a number of inferred auto-index jobs exceeding this threshold will not be auto-indexed.") +var ( + overrideScript = os.Getenv("SRC_CODEINTEL_INFERENCE_OVERRIDE_SCRIPT") + maximumIndexJobsPerInferredConfiguration = env.MustGetInt("PRECISE_CODE_INTEL_AUTO_INDEX_MAXIMUM_INDEX_JOBS_PER_INFERRED_CONFIGURATION", 25, "Repositories with a number of inferred auto-index jobs exceeding this threshold will not be auto-indexed.") +) // inferIndexJobsFromRepositoryStructure collects the result of InferIndexJobs over all registered recognizers. func (s *Service) inferIndexJobsFromRepositoryStructure(ctx context.Context, repositoryID int, commit string, bypassLimit bool) ([]config.IndexJob, error) { @@ -347,7 +362,15 @@ func (s *Service) inferIndexJobsFromRepositoryStructure(ctx context.Context, rep return nil, err } - indexes, err := s.inferenceService.InferIndexJobs(ctx, api.RepoName(repoName), commit, overrideScript) + script, err := s.store.GetInferenceScript(ctx) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch inference script from database") + } + if script == "" { + script = overrideScript + } + + indexes, err := s.inferenceService.InferIndexJobs(ctx, api.RepoName(repoName), commit, script) if err != nil { return nil, err } diff --git a/internal/codeintel/autoindexing/transport/graphql/iface.go b/internal/codeintel/autoindexing/transport/graphql/iface.go index f9c4a647cbc..110aa06b9c6 100644 --- a/internal/codeintel/autoindexing/transport/graphql/iface.go +++ b/internal/codeintel/autoindexing/transport/graphql/iface.go @@ -24,6 +24,8 @@ type AutoIndexingService interface { GetLastIndexScanForRepository(ctx context.Context, repositoryID int) (_ *time.Time, err error) UpdateIndexConfigurationByRepositoryID(ctx context.Context, repositoryID int, data []byte) (err error) DeleteIndexByID(ctx context.Context, id int) (_ bool, err error) + GetInferenceScript(ctx context.Context) (script string, err error) + SetInferenceScript(ctx context.Context, script string) (err error) InferIndexConfiguration(ctx context.Context, repositoryID int, commit string, bypassLimit bool) (_ *config.IndexConfiguration, hints []config.IndexJobHint, err error) QueueIndexes(ctx context.Context, repositoryID int, rev, configuration string, force, bypassLimit bool) (_ []types.Index, err error) diff --git a/internal/codeintel/autoindexing/transport/graphql/mocks_temp.go b/internal/codeintel/autoindexing/transport/graphql/mocks_temp.go index bd19ea23b7b..ad6b79154fc 100644 --- a/internal/codeintel/autoindexing/transport/graphql/mocks_temp.go +++ b/internal/codeintel/autoindexing/transport/graphql/mocks_temp.go @@ -42,6 +42,9 @@ type MockAutoIndexingService struct { // GetIndexesByIDsFunc is an instance of a mock function object // controlling the behavior of the method GetIndexesByIDs. GetIndexesByIDsFunc *AutoIndexingServiceGetIndexesByIDsFunc + // GetInferenceScriptFunc is an instance of a mock function object + // controlling the behavior of the method GetInferenceScript. + GetInferenceScriptFunc *AutoIndexingServiceGetInferenceScriptFunc // GetLanguagesRequestedByFunc is an instance of a mock function object // controlling the behavior of the method GetLanguagesRequestedBy. GetLanguagesRequestedByFunc *AutoIndexingServiceGetLanguagesRequestedByFunc @@ -70,6 +73,9 @@ type MockAutoIndexingService struct { // QueueIndexesFunc is an instance of a mock function object controlling // the behavior of the method QueueIndexes. QueueIndexesFunc *AutoIndexingServiceQueueIndexesFunc + // SetInferenceScriptFunc is an instance of a mock function object + // controlling the behavior of the method SetInferenceScript. + SetInferenceScriptFunc *AutoIndexingServiceSetInferenceScriptFunc // SetRequestLanguageSupportFunc is an instance of a mock function // object controlling the behavior of the method // SetRequestLanguageSupport. @@ -110,6 +116,11 @@ func NewMockAutoIndexingService() *MockAutoIndexingService { return }, }, + GetInferenceScriptFunc: &AutoIndexingServiceGetInferenceScriptFunc{ + defaultHook: func(context.Context) (r0 string, r1 error) { + return + }, + }, GetLanguagesRequestedByFunc: &AutoIndexingServiceGetLanguagesRequestedByFunc{ defaultHook: func(context.Context, int) (r0 []string, r1 error) { return @@ -155,6 +166,11 @@ func NewMockAutoIndexingService() *MockAutoIndexingService { return }, }, + SetInferenceScriptFunc: &AutoIndexingServiceSetInferenceScriptFunc{ + defaultHook: func(context.Context, string) (r0 error) { + return + }, + }, SetRequestLanguageSupportFunc: &AutoIndexingServiceSetRequestLanguageSupportFunc{ defaultHook: func(context.Context, int, string) (r0 error) { return @@ -198,6 +214,11 @@ func NewStrictMockAutoIndexingService() *MockAutoIndexingService { panic("unexpected invocation of MockAutoIndexingService.GetIndexesByIDs") }, }, + GetInferenceScriptFunc: &AutoIndexingServiceGetInferenceScriptFunc{ + defaultHook: func(context.Context) (string, error) { + panic("unexpected invocation of MockAutoIndexingService.GetInferenceScript") + }, + }, GetLanguagesRequestedByFunc: &AutoIndexingServiceGetLanguagesRequestedByFunc{ defaultHook: func(context.Context, int) ([]string, error) { panic("unexpected invocation of MockAutoIndexingService.GetLanguagesRequestedBy") @@ -243,6 +264,11 @@ func NewStrictMockAutoIndexingService() *MockAutoIndexingService { panic("unexpected invocation of MockAutoIndexingService.QueueIndexes") }, }, + SetInferenceScriptFunc: &AutoIndexingServiceSetInferenceScriptFunc{ + defaultHook: func(context.Context, string) error { + panic("unexpected invocation of MockAutoIndexingService.SetInferenceScript") + }, + }, SetRequestLanguageSupportFunc: &AutoIndexingServiceSetRequestLanguageSupportFunc{ defaultHook: func(context.Context, int, string) error { panic("unexpected invocation of MockAutoIndexingService.SetRequestLanguageSupport") @@ -276,6 +302,9 @@ func NewMockAutoIndexingServiceFrom(i AutoIndexingService) *MockAutoIndexingServ GetIndexesByIDsFunc: &AutoIndexingServiceGetIndexesByIDsFunc{ defaultHook: i.GetIndexesByIDs, }, + GetInferenceScriptFunc: &AutoIndexingServiceGetInferenceScriptFunc{ + defaultHook: i.GetInferenceScript, + }, GetLanguagesRequestedByFunc: &AutoIndexingServiceGetLanguagesRequestedByFunc{ defaultHook: i.GetLanguagesRequestedBy, }, @@ -303,6 +332,9 @@ func NewMockAutoIndexingServiceFrom(i AutoIndexingService) *MockAutoIndexingServ QueueIndexesFunc: &AutoIndexingServiceQueueIndexesFunc{ defaultHook: i.QueueIndexes, }, + SetInferenceScriptFunc: &AutoIndexingServiceSetInferenceScriptFunc{ + defaultHook: i.SetInferenceScript, + }, SetRequestLanguageSupportFunc: &AutoIndexingServiceSetRequestLanguageSupportFunc{ defaultHook: i.SetRequestLanguageSupport, }, @@ -885,6 +917,115 @@ func (c AutoIndexingServiceGetIndexesByIDsFuncCall) Results() []interface{} { return []interface{}{c.Result0, c.Result1} } +// AutoIndexingServiceGetInferenceScriptFunc describes the behavior when the +// GetInferenceScript method of the parent MockAutoIndexingService instance +// is invoked. +type AutoIndexingServiceGetInferenceScriptFunc struct { + defaultHook func(context.Context) (string, error) + hooks []func(context.Context) (string, error) + history []AutoIndexingServiceGetInferenceScriptFuncCall + mutex sync.Mutex +} + +// GetInferenceScript delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockAutoIndexingService) GetInferenceScript(v0 context.Context) (string, error) { + r0, r1 := m.GetInferenceScriptFunc.nextHook()(v0) + m.GetInferenceScriptFunc.appendCall(AutoIndexingServiceGetInferenceScriptFuncCall{v0, r0, r1}) + return r0, r1 +} + +// SetDefaultHook sets function that is called when the GetInferenceScript +// method of the parent MockAutoIndexingService instance is invoked and the +// hook queue is empty. +func (f *AutoIndexingServiceGetInferenceScriptFunc) SetDefaultHook(hook func(context.Context) (string, error)) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// GetInferenceScript method of the parent MockAutoIndexingService instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *AutoIndexingServiceGetInferenceScriptFunc) PushHook(hook func(context.Context) (string, error)) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AutoIndexingServiceGetInferenceScriptFunc) SetDefaultReturn(r0 string, r1 error) { + f.SetDefaultHook(func(context.Context) (string, error) { + return r0, r1 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *AutoIndexingServiceGetInferenceScriptFunc) PushReturn(r0 string, r1 error) { + f.PushHook(func(context.Context) (string, error) { + return r0, r1 + }) +} + +func (f *AutoIndexingServiceGetInferenceScriptFunc) nextHook() func(context.Context) (string, error) { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *AutoIndexingServiceGetInferenceScriptFunc) appendCall(r0 AutoIndexingServiceGetInferenceScriptFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// AutoIndexingServiceGetInferenceScriptFuncCall objects describing the +// invocations of this function. +func (f *AutoIndexingServiceGetInferenceScriptFunc) History() []AutoIndexingServiceGetInferenceScriptFuncCall { + f.mutex.Lock() + history := make([]AutoIndexingServiceGetInferenceScriptFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// AutoIndexingServiceGetInferenceScriptFuncCall is an object that describes +// an invocation of method GetInferenceScript on an instance of +// MockAutoIndexingService. +type AutoIndexingServiceGetInferenceScriptFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 string + // Result1 is the value of the 2nd result returned from this method + // invocation. + Result1 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AutoIndexingServiceGetInferenceScriptFuncCall) Args() []interface{} { + return []interface{}{c.Arg0} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c AutoIndexingServiceGetInferenceScriptFuncCall) Results() []interface{} { + return []interface{}{c.Result0, c.Result1} +} + // AutoIndexingServiceGetLanguagesRequestedByFunc describes the behavior // when the GetLanguagesRequestedBy method of the parent // MockAutoIndexingService instance is invoked. @@ -1919,6 +2060,115 @@ func (c AutoIndexingServiceQueueIndexesFuncCall) Results() []interface{} { return []interface{}{c.Result0, c.Result1} } +// AutoIndexingServiceSetInferenceScriptFunc describes the behavior when the +// SetInferenceScript method of the parent MockAutoIndexingService instance +// is invoked. +type AutoIndexingServiceSetInferenceScriptFunc struct { + defaultHook func(context.Context, string) error + hooks []func(context.Context, string) error + history []AutoIndexingServiceSetInferenceScriptFuncCall + mutex sync.Mutex +} + +// SetInferenceScript delegates to the next hook function in the queue and +// stores the parameter and result values of this invocation. +func (m *MockAutoIndexingService) SetInferenceScript(v0 context.Context, v1 string) error { + r0 := m.SetInferenceScriptFunc.nextHook()(v0, v1) + m.SetInferenceScriptFunc.appendCall(AutoIndexingServiceSetInferenceScriptFuncCall{v0, v1, r0}) + return r0 +} + +// SetDefaultHook sets function that is called when the SetInferenceScript +// method of the parent MockAutoIndexingService instance is invoked and the +// hook queue is empty. +func (f *AutoIndexingServiceSetInferenceScriptFunc) SetDefaultHook(hook func(context.Context, string) error) { + f.defaultHook = hook +} + +// PushHook adds a function to the end of hook queue. Each invocation of the +// SetInferenceScript method of the parent MockAutoIndexingService instance +// invokes the hook at the front of the queue and discards it. After the +// queue is empty, the default hook function is invoked for any future +// action. +func (f *AutoIndexingServiceSetInferenceScriptFunc) PushHook(hook func(context.Context, string) error) { + f.mutex.Lock() + f.hooks = append(f.hooks, hook) + f.mutex.Unlock() +} + +// SetDefaultReturn calls SetDefaultHook with a function that returns the +// given values. +func (f *AutoIndexingServiceSetInferenceScriptFunc) SetDefaultReturn(r0 error) { + f.SetDefaultHook(func(context.Context, string) error { + return r0 + }) +} + +// PushReturn calls PushHook with a function that returns the given values. +func (f *AutoIndexingServiceSetInferenceScriptFunc) PushReturn(r0 error) { + f.PushHook(func(context.Context, string) error { + return r0 + }) +} + +func (f *AutoIndexingServiceSetInferenceScriptFunc) nextHook() func(context.Context, string) error { + f.mutex.Lock() + defer f.mutex.Unlock() + + if len(f.hooks) == 0 { + return f.defaultHook + } + + hook := f.hooks[0] + f.hooks = f.hooks[1:] + return hook +} + +func (f *AutoIndexingServiceSetInferenceScriptFunc) appendCall(r0 AutoIndexingServiceSetInferenceScriptFuncCall) { + f.mutex.Lock() + f.history = append(f.history, r0) + f.mutex.Unlock() +} + +// History returns a sequence of +// AutoIndexingServiceSetInferenceScriptFuncCall objects describing the +// invocations of this function. +func (f *AutoIndexingServiceSetInferenceScriptFunc) History() []AutoIndexingServiceSetInferenceScriptFuncCall { + f.mutex.Lock() + history := make([]AutoIndexingServiceSetInferenceScriptFuncCall, len(f.history)) + copy(history, f.history) + f.mutex.Unlock() + + return history +} + +// AutoIndexingServiceSetInferenceScriptFuncCall is an object that describes +// an invocation of method SetInferenceScript on an instance of +// MockAutoIndexingService. +type AutoIndexingServiceSetInferenceScriptFuncCall struct { + // Arg0 is the value of the 1st argument passed to this method + // invocation. + Arg0 context.Context + // Arg1 is the value of the 2nd argument passed to this method + // invocation. + Arg1 string + // Result0 is the value of the 1st result returned from this method + // invocation. + Result0 error +} + +// Args returns an interface slice containing the arguments of this +// invocation. +func (c AutoIndexingServiceSetInferenceScriptFuncCall) Args() []interface{} { + return []interface{}{c.Arg0, c.Arg1} +} + +// Results returns an interface slice containing the results of this +// invocation. +func (c AutoIndexingServiceSetInferenceScriptFuncCall) Results() []interface{} { + return []interface{}{c.Result0} +} + // AutoIndexingServiceSetRequestLanguageSupportFunc describes the behavior // when the SetRequestLanguageSupport method of the parent // MockAutoIndexingService instance is invoked. diff --git a/internal/codeintel/autoindexing/transport/graphql/root_resolver.go b/internal/codeintel/autoindexing/transport/graphql/root_resolver.go index 55e977db2d8..cec71a191cf 100644 --- a/internal/codeintel/autoindexing/transport/graphql/root_resolver.go +++ b/internal/codeintel/autoindexing/transport/graphql/root_resolver.go @@ -40,6 +40,8 @@ type RootResolver interface { GetLastIndexScanForRepository(ctx context.Context, repositoryID int) (_ *time.Time, err error) InferedIndexConfiguration(ctx context.Context, repositoryID int, commit string) (_ *config.IndexConfiguration, _ bool, err error) InferedIndexConfigurationHints(ctx context.Context, repositoryID int, commit string) (_ []config.IndexJobHint, err error) + CodeIntelligenceInferenceScript(ctx context.Context) (script string, err error) + UpdateCodeIntelligenceInferenceScript(ctx context.Context, args *UpdateCodeIntelligenceInferenceScriptArgs) (err error) // Symbols client GetSupportedByCtags(ctx context.Context, filepath string, repoName api.RepoName) (bool, string, error) @@ -282,6 +284,18 @@ func (r *rootResolver) UpdateRepositoryIndexConfiguration(ctx context.Context, a return &sharedresolvers.EmptyResponse{}, nil } +func (r *rootResolver) CodeIntelligenceInferenceScript(ctx context.Context) (script string, err error) { + return r.autoindexSvc.GetInferenceScript(ctx) +} + +type UpdateCodeIntelligenceInferenceScriptArgs struct { + Script string +} + +func (r *rootResolver) UpdateCodeIntelligenceInferenceScript(ctx context.Context, args *UpdateCodeIntelligenceInferenceScriptArgs) (err error) { + return r.autoindexSvc.SetInferenceScript(ctx, args.Script) +} + type GitTreeEntryCodeIntelInfoArgs struct { Repo *types.Repo Path string diff --git a/internal/database/schema.json b/internal/database/schema.json index 0db17e3eca2..f153a22049f 100755 --- a/internal/database/schema.json +++ b/internal/database/schema.json @@ -6278,6 +6278,41 @@ "Constraints": null, "Triggers": [] }, + { + "Name": "codeintel_inference_scripts", + "Comment": "Contains auto-index job inference Lua scripts as an alternative to setting via environment variables.", + "Columns": [ + { + "Name": "insert_timestamp", + "Index": 1, + "TypeName": "timestamp with time zone", + "IsNullable": false, + "Default": "now()", + "CharacterMaximumLength": 0, + "IsIdentity": false, + "IdentityGeneration": "", + "IsGenerated": "NEVER", + "GenerationExpression": "", + "Comment": "" + }, + { + "Name": "script", + "Index": 2, + "TypeName": "text", + "IsNullable": false, + "Default": "", + "CharacterMaximumLength": 0, + "IsIdentity": false, + "IdentityGeneration": "", + "IsGenerated": "NEVER", + "GenerationExpression": "", + "Comment": "" + } + ], + "Indexes": [], + "Constraints": null, + "Triggers": [] + }, { "Name": "codeintel_langugage_support_requests", "Comment": "", diff --git a/internal/database/schema.md b/internal/database/schema.md index 7c31f84e2fe..0f1030124b6 100755 --- a/internal/database/schema.md +++ b/internal/database/schema.md @@ -752,6 +752,17 @@ Indexes: ``` +# Table "public.codeintel_inference_scripts" +``` + Column | Type | Collation | Nullable | Default +------------------+--------------------------+-----------+----------+--------- + insert_timestamp | timestamp with time zone | | not null | now() + script | text | | not null | + +``` + +Contains auto-index job inference Lua scripts as an alternative to setting via environment variables. + # Table "public.codeintel_langugage_support_requests" ``` Column | Type | Collation | Nullable | Default diff --git a/migrations/frontend/1662636054_autoindexing_custom_inference_script/down.sql b/migrations/frontend/1662636054_autoindexing_custom_inference_script/down.sql new file mode 100644 index 00000000000..a2142694bf9 --- /dev/null +++ b/migrations/frontend/1662636054_autoindexing_custom_inference_script/down.sql @@ -0,0 +1,2 @@ +-- Undo the changes made in the up migration +DROP TABLE IF EXISTS codeintel_inference_scripts; diff --git a/migrations/frontend/1662636054_autoindexing_custom_inference_script/metadata.yaml b/migrations/frontend/1662636054_autoindexing_custom_inference_script/metadata.yaml new file mode 100644 index 00000000000..3932f60cdf2 --- /dev/null +++ b/migrations/frontend/1662636054_autoindexing_custom_inference_script/metadata.yaml @@ -0,0 +1,2 @@ +name: autoindexing_persisted_inference_script +parents: [1661502186, 1661507724] diff --git a/migrations/frontend/1662636054_autoindexing_custom_inference_script/up.sql b/migrations/frontend/1662636054_autoindexing_custom_inference_script/up.sql new file mode 100644 index 00000000000..93f80eb573e --- /dev/null +++ b/migrations/frontend/1662636054_autoindexing_custom_inference_script/up.sql @@ -0,0 +1,6 @@ +CREATE TABLE IF NOT EXISTS codeintel_inference_scripts ( + insert_timestamp timestamptz NOT NULL default NOW(), + script text NOT NULL +); + +COMMENT ON table codeintel_inference_scripts IS 'Contains auto-index job inference Lua scripts as an alternative to setting via environment variables.'; diff --git a/migrations/frontend/squashed.sql b/migrations/frontend/squashed.sql index b02ace071c1..bc59d934d78 100755 --- a/migrations/frontend/squashed.sql +++ b/migrations/frontend/squashed.sql @@ -1466,6 +1466,13 @@ CREATE SEQUENCE codeintel_autoindex_queue_id_seq ALTER SEQUENCE codeintel_autoindex_queue_id_seq OWNED BY codeintel_autoindex_queue.id; +CREATE TABLE codeintel_inference_scripts ( + insert_timestamp timestamp with time zone DEFAULT now() NOT NULL, + script text NOT NULL +); + +COMMENT ON TABLE codeintel_inference_scripts IS 'Contains auto-index job inference Lua scripts as an alternative to setting via environment variables.'; + CREATE TABLE codeintel_langugage_support_requests ( id integer NOT NULL, user_id integer NOT NULL,