cody web: do not include ignored files in context (#59907)

This commit is contained in:
Taras Yemets 2024-02-02 17:07:33 +02:00 committed by GitHub
parent 2be0a6d73d
commit daf29d1412
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 99 additions and 21 deletions

View File

@ -25,6 +25,7 @@ All notable changes to Sourcegraph are documented in this file.
- Expiry to access tokens. Users can now select a maximum timespan for which a token is valid. Tokens will automatically lose access after this period. Default timeframes and an override to allow access tokens without expiration can be configured in the `auth.accessTokens` section of the site configuration. [#59565](https://github.com/sourcegraph/sourcegraph/pull/59565)
- Gerrit code host connections now support an 'exclude' field that prevents repos in this list from being synced. [#59739](https://github.com/sourcegraph/sourcegraph/pull/59739)
- Limit the number of active access tokens for a user. By default users are able to have 25 active access tokens. This limit can be configured using the `maxTokensPerUser` setting in the `auth.accessTokens` section of the site configuration. [#59731](https://github.com/sourcegraph/sourcegraph/pull/59731)
- Add experimental support for .cody/ignore when retrieving remote context. To enable it, set `experimentalFeatures.codyContextIgnore: true` in the site configuration. [#59836](https://github.com/sourcegraph/sourcegraph/pull/59836), [#59907](https://github.com/sourcegraph/sourcegraph/pull/59907)
### Changed

View File

@ -203,6 +203,7 @@ ts_project(
"src/cody/chat/index.tsx",
"src/cody/components/ChatUI/ChatUi.tsx",
"src/cody/components/ChatUI/index.tsx",
"src/cody/components/ChatUI/useIsFileIgnored.ts",
"src/cody/components/CodeMirrorEditor.ts",
"src/cody/components/CodyIcon.tsx",
"src/cody/components/CodyLogo.tsx",
@ -1799,6 +1800,7 @@ ts_project(
"//:node_modules/graphql", # keep
"//:node_modules/history",
"//:node_modules/http-status-codes",
"//:node_modules/ignore",
"//:node_modules/is-absolute-url",
"//:node_modules/js-cookie",
"//:node_modules/js-yaml",

View File

@ -34,6 +34,8 @@ import { GettingStarted } from '../GettingStarted'
import { ScopeSelector } from '../ScopeSelector'
import type { ScopeSelectorProps } from '../ScopeSelector/ScopeSelector'
import { useIsFileIgnored } from './useIsFileIgnored'
import styles from './ChatUi.module.scss'
export const SCROLL_THRESHOLD = 100
@ -82,6 +84,8 @@ export const ChatUI: React.FC<IChatUIProps> = ({ codyChatStore, isCodyChatPage,
const onSubmit = useCallback((text: string) => submitMessage(text), [submitMessage])
const onEdit = useCallback((text: string) => editMessage(text), [editMessage])
const isFileIgnored = useIsFileIgnored()
const scopeSelectorProps: ScopeSelectorProps = useMemo(
() => ({
scope,
@ -92,6 +96,7 @@ export const ChatUI: React.FC<IChatUIProps> = ({ codyChatStore, isCodyChatPage,
transcriptHistory,
className: 'mt-2',
authenticatedUser,
isFileIgnored,
}),
[
scope,
@ -101,6 +106,7 @@ export const ChatUI: React.FC<IChatUIProps> = ({ codyChatStore, isCodyChatPage,
logTranscriptEvent,
transcriptHistory,
authenticatedUser,
isFileIgnored,
]
)

View File

@ -0,0 +1,57 @@
import { useCallback, useEffect, useState } from 'react'
import type { Ignore } from 'ignore'
import { useLocation } from 'react-router-dom'
import { useQuery, gql } from '@sourcegraph/http-client'
import type { CodyIgnoreContentResult, CodyIgnoreContentVariables } from '../../../graphql-operations'
import { parseBrowserRepoURL } from '../../../util/url'
const CODY_IGNORE_CONTENT = gql`
query CodyIgnoreContent($repoName: String!, $repoRev: String!, $filePath: String!) {
repository(name: $repoName) {
commit(rev: $repoRev) {
blob(path: $filePath) {
content
}
}
}
}
`
const CODY_IGNORE_PATH = '.cody/ignore'
export const useIsFileIgnored = (): ((path: string) => boolean) => {
const location = useLocation()
const { repoName, revision } = parseBrowserRepoURL(location.pathname + location.search + location.hash)
const { data } = useQuery<CodyIgnoreContentResult, CodyIgnoreContentVariables>(CODY_IGNORE_CONTENT, {
skip: !window.context?.experimentalFeatures.codyContextIgnore,
variables: { repoName, repoRev: revision || '', filePath: CODY_IGNORE_PATH },
})
const [ignoreManager, setIgnoreManager] = useState<Ignore>()
const content = data?.repository?.commit?.blob?.content
useEffect(() => {
const loadIgnore = async (): Promise<void> => {
if (content) {
const ignore = (await import('ignore')).default
setIgnoreManager(ignore().add(content))
}
}
void loadIgnore()
}, [content])
const isFileIgnored = useCallback(
(path: string): boolean => {
if (ignoreManager) {
return ignoreManager.ignores(path)
}
return false
},
[ignoreManager]
)
return isFileIgnored
}

View File

@ -6,9 +6,9 @@ import type { AuthenticatedUser } from '@sourcegraph/shared/src/auth'
import { H4, H5, RadioButton, Text, Button, Grid, Icon, Link } from '@sourcegraph/wildcard'
import { CodyColorIcon, CodySpeechBubbleIcon } from '../chat/CodyPageIcon'
import type { CodyChatStore } from '../useCodyChat'
import { ScopeSelector } from './ScopeSelector'
import { ScopeSelectorProps } from './ScopeSelector/ScopeSelector'
import styles from './GettingStarted.module.scss'
@ -19,15 +19,7 @@ const DEFAULT_VERTICAL_OFFSET = '1rem'
/* eslint-disable @sourcegraph/sourcegraph/check-help-links */
export const GettingStarted: React.FC<
Pick<
CodyChatStore,
| 'scope'
| 'logTranscriptEvent'
| 'transcriptHistory'
| 'setScope'
| 'toggleIncludeInferredRepository'
| 'toggleIncludeInferredFile'
> & {
ScopeSelectorProps & {
isCodyChatPage?: boolean
submitInput: (input: string, submitType: 'user' | 'suggestion' | 'example') => void
authenticatedUser: AuthenticatedUser | null

View File

@ -29,6 +29,7 @@ export interface ScopeSelectorProps {
// rather than collapsing or flipping position.
encourageOverlap?: boolean
authenticatedUser: AuthenticatedUser | null
isFileIgnored: (path: string) => boolean
}
export const ScopeSelector: React.FC<ScopeSelectorProps> = React.memo(function ScopeSelectorComponent({
@ -42,6 +43,7 @@ export const ScopeSelector: React.FC<ScopeSelectorProps> = React.memo(function S
renderHint,
encourageOverlap,
authenticatedUser,
isFileIgnored,
}) {
const [loadReposStatus, { data: newReposStatusData, previousData: previousReposStatusData }] = useLazyQuery<
ReposStatusResult,
@ -52,6 +54,14 @@ export const ScopeSelector: React.FC<ScopeSelectorProps> = React.memo(function S
const activeEditor = useMemo(() => scope.editor.getActiveTextEditor(), [scope.editor])
const isCurrentFileIgnored = activeEditor?.filePath ? isFileIgnored(activeEditor.filePath) : false
const inferredFilePath = (!isCurrentFileIgnored && activeEditor?.filePath) || null
useEffect(() => {
if (isCurrentFileIgnored && scope.includeInferredFile) {
setScope({ ...scope, includeInferredFile: false, includeInferredRepository: true })
}
}, [isCurrentFileIgnored, scope, setScope])
useEffect(() => {
const repoNames = [...scope.repositories]
@ -122,7 +132,7 @@ export const ScopeSelector: React.FC<ScopeSelectorProps> = React.memo(function S
includeInferredRepository={scope.includeInferredRepository}
includeInferredFile={scope.includeInferredFile}
inferredRepository={inferredRepository}
inferredFilePath={activeEditor?.filePath || null}
inferredFilePath={inferredFilePath}
additionalRepositories={additionalRepositories}
addRepository={addRepository}
resetScope={resetScope}
@ -133,9 +143,10 @@ export const ScopeSelector: React.FC<ScopeSelectorProps> = React.memo(function S
transcriptHistory={transcriptHistory}
authenticatedUser={authenticatedUser}
/>
{scope.includeInferredFile && activeEditor?.filePath && (
{scope.includeInferredFile && inferredFilePath && (
<Text size="small" className="ml-2 mb-0 align-self-center">
{getFileName(activeEditor.filePath)}
{getFileName(inferredFilePath)}
</Text>
)}
</div>

View File

@ -351,6 +351,7 @@
"http-status-codes": "^2.1.4",
"https-browserify": "^1.0.0",
"https-proxy-agent": "^5.0.1",
"ignore": "^5.3.0",
"is-absolute-url": "^3.0.3",
"isomorphic-fetch": "^3.0.0",
"iterare": "^1.2.1",

View File

@ -271,6 +271,9 @@ importers:
https-proxy-agent:
specifier: ^5.0.1
version: 5.0.1
ignore:
specifier: ^5.3.0
version: 5.3.0
is-absolute-url:
specifier: ^3.0.3
version: 3.0.3
@ -3886,7 +3889,7 @@ packages:
debug: 4.3.4
espree: 9.6.1
globals: 13.23.0
ignore: 5.2.4
ignore: 5.3.0
import-fresh: 3.3.0
js-yaml: 4.1.0
minimatch: 3.1.2
@ -8227,7 +8230,7 @@ packages:
'@typescript-eslint/scope-manager': 5.4.0
debug: 4.3.4
eslint: 8.52.0
ignore: 5.2.4
ignore: 5.3.0
regexpp: 3.2.0
semver: 7.5.4
tsutils: 3.21.0(typescript@5.2.2)
@ -8301,7 +8304,7 @@ packages:
stylelint: ^14.3.0
dependencies:
'@manypkg/find-root': 1.1.0
ignore: 5.2.4
ignore: 5.3.0
postcss-value-parser: 4.2.0
stylelint: 14.3.0
dev: true
@ -11129,7 +11132,7 @@ packages:
debug: 4.3.4
eslint: 8.52.0
graphemer: 1.4.0
ignore: 5.2.4
ignore: 5.3.0
natural-compare: 1.4.0
semver: 7.5.4
ts-api-utils: 1.0.3(typescript@5.2.2)
@ -15415,7 +15418,7 @@ packages:
glob-parent: 6.0.2
globals: 13.23.0
graphemer: 1.4.0
ignore: 5.2.4
ignore: 5.3.0
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
@ -16488,7 +16491,7 @@ packages:
array-union: 2.1.0
dir-glob: 3.0.1
fast-glob: 3.2.11
ignore: 5.2.4
ignore: 5.3.0
merge2: 1.4.1
slash: 3.0.0
dev: true
@ -16499,7 +16502,7 @@ packages:
dependencies:
dir-glob: 3.0.1
fast-glob: 3.2.11
ignore: 5.2.4
ignore: 5.3.0
merge2: 1.4.1
slash: 4.0.0
@ -17279,6 +17282,11 @@ packages:
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
dev: true
/ignore@5.3.0:
resolution: {integrity: sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==}
engines: {node: '>= 4'}
/image-size@1.0.2:
resolution: {integrity: sha512-xfOoWjceHntRb3qFCrh5ZFORYH8XCdYpASltMhZ/Q0KZiOwjdE/Yl2QCiWdwD+lygV5bMCvauzgu5PxBX/Yerg==}
@ -23540,7 +23548,7 @@ packages:
globby: 11.1.0
globjoin: 0.1.4
html-tags: 3.1.0
ignore: 5.2.4
ignore: 5.3.0
import-lazy: 4.0.0
imurmurhash: 0.1.4
is-plain-object: 5.0.0