-
- Notifications
You must be signed in to change notification settings - Fork 6.2k
Add API for Code Search #23004
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add API for Code Search #23004
Changes from 7 commits
5dc8607 cf92c04 00d39b6 b79d510 ffb826d 0c1de08 7e4d68c 2dc5e99 e52de71 8f36b93 9bfaaa8 File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // Copyright 2023 The Gitea Authors. All rights reserved. | ||
| // SPDX-License-Identifier: MIT | ||
| | ||
| package structs | ||
| | ||
| import ( | ||
| "time" | ||
| ) | ||
| | ||
| // IndexerResult a search result to display | ||
| type IndexerResult struct { | ||
| RepoID int64 `json:"repo_id"` | ||
| Filename string `json:"filename"` | ||
| CommitID string `json:"commit_id"` | ||
| Updated time.Time `json:"updated"` | ||
| Language string `json:"language"` | ||
| Color string `json:"color"` | ||
| LineNumbers []int `json:"line_numbers"` | ||
| FormattedLines string `json:"formated_lines"` | ||
| } | ||
| | ||
| // IndexerSearchResultLanguages result of top languages count in search results | ||
| type IndexerSearchResultLanguages struct { | ||
| Language string `json:"language"` | ||
| Color string `json:"color"` | ||
| Count int `json:"count"` | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| // Copyright 2023 The Gitea Authors. All rights reserved. | ||
| // SPDX-License-Identifier: MIT | ||
| | ||
| package repo | ||
| | ||
| import ( | ||
| "net/http" | ||
| | ||
| "code.gitea.io/gitea/modules/context" | ||
| code_indexer "code.gitea.io/gitea/modules/indexer/code" | ||
| "code.gitea.io/gitea/modules/setting" | ||
| api "code.gitea.io/gitea/modules/structs" | ||
| "code.gitea.io/gitea/routers/api/v1/utils" | ||
| "code.gitea.io/gitea/services/convert" | ||
| ) | ||
| | ||
| // CodeSearch Performs a code search on a Repo | ||
| func CodeSearch(ctx *context.APIContext) { | ||
| // swagger:operation GET /repos/{owner}/{repo}/code_search repository repoCodeSearch | ||
| // --- | ||
| // summary: Performs a code search on a Repo | ||
| // produces: | ||
| // - application/json | ||
| // parameters: | ||
| // - name: owner | ||
| // in: path | ||
| // description: owner of the repo | ||
| // type: string | ||
| // required: true | ||
| // - name: repo | ||
| // in: path | ||
| // description: name of the repo | ||
| // type: string | ||
| // required: true | ||
| // - name: keyword | ||
| // in: query | ||
| // description: the keyword the search for | ||
| // type: string | ||
| // - name: language | ||
| // in: query | ||
| // description: filter results by language | ||
| // type: string | ||
| // - name: match | ||
| // in: query | ||
| // description: only exact match (defaults to true) | ||
| // type: boolean | ||
| // - name: page | ||
| // in: query | ||
| // description: page number of results to return (1-based) | ||
| // type: integer | ||
| // - name: limit | ||
| // in: query | ||
| // description: page size of results | ||
| // type: string | ||
| // responses: | ||
| // "200": | ||
| // "$ref": "#/responses/RepoCodeSearch" | ||
| // "422": | ||
| // description: "The keyword is empty" | ||
| // schema: | ||
| // type: string | ||
| if !setting.Indexer.RepoIndexerEnabled { | ||
| ctx.Error(http.StatusInternalServerError, "IndexerNotEnabled", "The Code Indexer is not enabled on this server") | ||
| ||
| return | ||
| } | ||
| | ||
| language := ctx.FormTrim("language") | ||
| keyword := ctx.FormTrim("keyword") | ||
| isMatch := !ctx.FormOptionalBool("match").IsFalse() | ||
| | ||
| if keyword == "" { | ||
| ctx.Error(http.StatusUnprocessableEntity, "KeywordEmpty", "The keyword can't be empty") | ||
| return | ||
| } | ||
| | ||
| listOptions := utils.GetListOptions(ctx) | ||
| | ||
| if listOptions.Page <= 0 { | ||
| listOptions.Page = 1 | ||
| } | ||
| | ||
| total, searchResults, searchResultLanguages, err := code_indexer.PerformSearch(ctx, []int64{ctx.Repo.Repository.ID}, | ||
| language, keyword, listOptions.Page, listOptions.PageSize, isMatch) | ||
| if err != nil { | ||
| ctx.InternalServerError(err) | ||
| return | ||
| } | ||
| | ||
| response := api.RepoCodeSearchAPIResponse{ | ||
| Total: total, | ||
| SearchResults: convert.ToIndexerSearchResultList(searchResults), | ||
| SearchResultLanguages: convert.ToIndexerSearchResultLanguagesList(searchResultLanguages), | ||
| } | ||
| | ||
| pager := context.NewPagination(total, listOptions.PageSize, listOptions.Page, 5) | ||
| | ||
| ctx.SetLinkHeader(pager.Paginater.TotalPages(), listOptions.PageSize) | ||
| ctx.SetTotalCountHeader(int64(pager.Paginater.TotalPages())) | ||
| ctx.JSON(http.StatusOK, response) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| // Copyright 2023 The Gitea Authors. All rights reserved. | ||
| // SPDX-License-Identifier: MIT | ||
| | ||
| package convert | ||
| | ||
| import ( | ||
| code_indexer "code.gitea.io/gitea/modules/indexer/code" | ||
| api "code.gitea.io/gitea/modules/structs" | ||
| ) | ||
| | ||
| // ToIndexerSearchResult converts IndexerSearch to API format | ||
| func ToIndexerSearchResult(result *code_indexer.Result) *api.IndexerResult { | ||
| return &api.IndexerResult{ | ||
| RepoID: result.RepoID, | ||
| Filename: result.Filename, | ||
| CommitID: result.CommitID, | ||
| Updated: result.UpdatedUnix.AsTime(), | ||
| Language: result.Language, | ||
| Color: result.Color, | ||
| LineNumbers: result.LineNumbers, | ||
| FormattedLines: result.FormattedLines, | ||
| } | ||
| } | ||
| | ||
| // ToIndexerSearchResultLanguages converts IndexerSearch to API format | ||
| func ToIndexerSearchResultLanguages(result *code_indexer.SearchResultLanguages) *api.IndexerSearchResultLanguages { | ||
| return &api.IndexerSearchResultLanguages{ | ||
| Language: result.Language, | ||
| Color: result.Color, | ||
| Count: result.Count, | ||
| } | ||
| } | ||
| | ||
| // ToIndexerSearchResultList convert list of *code_indexer.Result to list of *api.IndexerResult | ||
| func ToIndexerSearchResultList(results []*code_indexer.Result) []*api.IndexerResult { | ||
| convertedResults := make([]*api.IndexerResult, len(results)) | ||
| for i := range results { | ||
| convertedResults[i] = ToIndexerSearchResult(results[i]) | ||
| } | ||
| return convertedResults | ||
| } | ||
| | ||
| // ToIndexerSearchResultLanguagesList convert list of *code_indexer.SearchResultLanguages to list of *api.IndexerSearchResultLanguages | ||
| func ToIndexerSearchResultLanguagesList(results []*code_indexer.SearchResultLanguages) []*api.IndexerSearchResultLanguages { | ||
| convertedResults := make([]*api.IndexerSearchResultLanguages, len(results)) | ||
| for i := range results { | ||
| convertedResults[i] = ToIndexerSearchResultLanguages(results[i]) | ||
| } | ||
| return convertedResults | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.