Skip to content

Commit

Permalink
Adds commit search support for GitHub
Browse files Browse the repository at this point in the history
Hides unsupported search options
  • Loading branch information
eamodio committed Feb 8, 2022
1 parent 58e4fb2 commit 239320a
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 52 deletions.
8 changes: 7 additions & 1 deletion package.json
Expand Up @@ -10013,7 +10013,13 @@
},
{
"view": "gitlens.views.searchAndCompare",
"contents": "Search for commits by [message](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22message%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [author](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22author%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [SHA](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22commit%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [file](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22file%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), or [changes](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22change%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D)\n\n[Search Commits...](command:gitlens.views.searchAndCompare.searchCommits)"
"contents": "Search for commits by [message](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22message%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [author](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22author%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [SHA](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22commit%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [file](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22file%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), or [changes](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22change%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D)\n\n[Search Commits...](command:gitlens.views.searchAndCompare.searchCommits)",
"when": "!gitlens:hasVirtualFolders"
},
{
"view": "gitlens.views.searchAndCompare",
"contents": "Search for commits by [message](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22message%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), [author](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22author%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D), or [SHA](command:gitlens.views.searchAndCompare.searchCommits?%7B%22search%22%3A%7B%22pattern%22%3A%22commit%3A%22%7D%2C%22prefillOnly%22%3Atrue%7D)\n\n[Search Commits...](command:gitlens.views.searchAndCompare.searchCommits)",
"when": "gitlens:hasVirtualFolders"
},
{
"view": "gitlens.views.searchAndCompare",
Expand Down
37 changes: 22 additions & 15 deletions src/commands/git/search.ts
@@ -1,5 +1,6 @@
import { GlyphChars } from '../../constants';
import { ContextKeys, GlyphChars } from '../../constants';
import { Container } from '../../container';
import { getContext } from '../../context';
import { GitCommit, GitLog, Repository } from '../../git/models';
import { searchOperators, SearchOperators, SearchPattern } from '../../git/search';
import { ActionQuickPickItem, QuickPickItemOfT } from '../../quickpicks/items/common';
Expand All @@ -25,6 +26,7 @@ interface Context {
repos: Repository[];
associatedView: ViewsWithRepositoryFolders;
commit: GitCommit | undefined;
hasVirtualFolders: boolean;
resultsKey: string | undefined;
resultsPromise: Promise<GitLog | undefined> | undefined;
title: string;
Expand Down Expand Up @@ -96,6 +98,7 @@ export class SearchGitCommand extends QuickCommand<State> {
repos: this.container.git.openRepositories,
associatedView: this.container.searchAndCompareView,
commit: undefined,
hasVirtualFolders: getContext<boolean>(ContextKeys.HasVirtualFolders, false),
resultsKey: undefined,
resultsPromise: undefined,
title: this.title,
Expand Down Expand Up @@ -263,29 +266,33 @@ export class SearchGitCommand extends QuickCommand<State> {
{
label: searchOperatorToTitleMap.get('')!,
description: `pattern or message: pattern or =: pattern ${GlyphChars.Dash} use quotes to search for phrases`,
item: 'message:',
item: 'message:' as const,
},
{
label: searchOperatorToTitleMap.get('author:')!,
description: 'author: pattern or @: pattern',
item: 'author:',
item: 'author:' as const,
},
{
label: searchOperatorToTitleMap.get('commit:')!,
description: 'commit: sha or #: sha',
item: 'commit:',
item: 'commit:' as const,
},
{
label: searchOperatorToTitleMap.get('file:')!,
description: 'file: glob or ?: glob',
item: 'file:',
},
{
label: searchOperatorToTitleMap.get('change:')!,
description: 'change: pattern or ~: pattern',
item: 'change:',
},
];
context.hasVirtualFolders
? undefined
: {
label: searchOperatorToTitleMap.get('file:')!,
description: 'file: glob or ?: glob',
item: 'file:' as const,
},
context.hasVirtualFolders
? undefined
: {
label: searchOperatorToTitleMap.get('change:')!,
description: 'change: pattern or ~: pattern',
item: 'change:' as const,
},
].filter(<T>(i?: T): i is T => i != null);

const matchCaseButton = new QuickCommandButtons.MatchCaseToggle(state.matchCase);
const matchAllButton = new QuickCommandButtons.MatchAllToggle(state.matchAll);
Expand Down
10 changes: 4 additions & 6 deletions src/env/node/git/localGitProvider.ts
Expand Up @@ -2095,7 +2095,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
async getLogForSearch(
repoPath: string,
search: SearchPattern,
options?: { limit?: number; ordering?: string | null; skip?: number },
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null; skip?: number },
): Promise<GitLog | undefined> {
search = { matchAll: false, matchCase: false, matchRegex: true, ...search };

Expand Down Expand Up @@ -2216,7 +2216,7 @@ export class LocalGitProvider implements GitProvider, Disposable {
private getLogForSearchMoreFn(
log: GitLog,
search: SearchPattern,
options?: { limit?: number; ordering?: string | null },
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null },
): (limit: number | undefined) => Promise<GitLog> {
return async (limit: number | undefined) => {
limit = limit ?? this.container.config.advanced.maxSearchItems ?? 0;
Expand All @@ -2226,10 +2226,8 @@ export class LocalGitProvider implements GitProvider, Disposable {
limit: limit,
skip: log.count,
});
if (moreLog == null) {
// If we can't find any more, assume we have everything
return { ...log, hasMore: false };
}
// If we can't find any more, assume we have everything
if (moreLog == null) return { ...log, hasMore: false };

const commits = new Map([...log.commits, ...moreLog.commits]);

Expand Down
6 changes: 5 additions & 1 deletion src/git/gitProvider.ts
Expand Up @@ -283,7 +283,11 @@ export interface GitProvider extends Disposable {
getLogForSearch(
repoPath: string,
search: SearchPattern,
options?: { limit?: number | undefined; ordering?: string | null | undefined; skip?: number | undefined },
options?: {
limit?: number | undefined;
ordering?: 'date' | 'author-date' | 'topo' | null | undefined;
skip?: number | undefined;
},
): Promise<GitLog | undefined>;
getLogForFile(
repoPath: string,
Expand Down
2 changes: 1 addition & 1 deletion src/git/gitProviderService.ts
Expand Up @@ -1224,7 +1224,7 @@ export class GitProviderService implements Disposable {
async getLogForSearch(
repoPath: string | Uri,
search: SearchPattern,
options?: { limit?: number; ordering?: string | null; skip?: number },
options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo' | null; skip?: number },
): Promise<GitLog | undefined> {
const { provider, path } = this.getProvider(repoPath);
return provider.getLogForSearch(path, search, options);
Expand Down
84 changes: 81 additions & 3 deletions src/premium/github/github.ts
Expand Up @@ -1528,6 +1528,84 @@ export class GitHubApi {
}
}

@debug<GitHubApi['searchCommits']>({ args: { 0: '<token>' } })
async searchCommits(
token: string,
query: string,
options?: {
cursor?: string;
limit?: number;
order?: 'asc' | 'desc' | undefined;
sort?: 'author-date' | 'committer-date' | undefined;
},
): Promise<GitHubPagedResult<GitHubCommit> | undefined> {
const cc = Logger.getCorrelationContext();

const limit = Math.min(100, options?.limit ?? 100);

let page;
let pageSize;
let previousCount;
if (options?.cursor != null) {
[page, pageSize, previousCount] = options.cursor.split(' ', 3);
page = parseInt(page, 10);
// TODO@eamodio need to figure out how allow different page sizes if the limit changes
pageSize = parseInt(pageSize, 10);
previousCount = parseInt(previousCount, 10);
} else {
page = 1;
pageSize = limit;
previousCount = 0;
}

try {
const rsp = await this.request(token, 'GET /search/commits', {
q: query,
sort: options?.sort,
order: options?.order,
per_page: pageSize,
page: page,
});

const data = rsp?.data;
if (data == null) return undefined;

const commits = data.items.map<GitHubCommit>(result => ({
oid: result.sha,
parents: { nodes: result.parents.map(p => ({ oid: p.sha! })) },
message: result.commit.message,
author: {
avatarUrl: result.author?.avatar_url ?? undefined,
date: result.commit.author?.date ?? result.commit.author?.date ?? new Date().toString(),
email: result.author?.email ?? result.commit.author?.email ?? undefined,
name: result.author?.name ?? result.commit.author?.name ?? '',
},
committer: {
date: result.commit.committer?.date ?? result.committer?.date ?? new Date().toString(),
email: result.committer?.email ?? result.commit.committer?.email ?? undefined,
name: result.committer?.name ?? result.commit.committer?.name ?? '',
},
}));

const count = previousCount + data.items.length;
const hasMore = data.incomplete_results || data.total_count > count;

return {
pageInfo: {
startCursor: `${page} ${pageSize} ${previousCount}`,
endCursor: hasMore ? `${page + 1} ${pageSize} ${count}` : undefined,
hasPreviousPage: data.total_count > 0 && page > 1,
hasNextPage: hasMore,
},
totalCount: data.total_count,
values: commits,
};
} catch (ex) {
debugger;
return this.handleRequestError(ex, cc, undefined);
}
}

private _octokits = new Map<string, Octokit>();
private octokit(token: string, options?: ConstructorParameters<typeof Octokit>[0]): Octokit {
let octokit = this._octokits.get(token);
Expand Down Expand Up @@ -1665,9 +1743,9 @@ export interface GitHubCommit {
oid: string;
parents: { nodes: { oid: string }[] };
message: string;
additions: number | undefined;
changedFiles: number | undefined;
deletions: number | undefined;
additions?: number | undefined;
changedFiles?: number | undefined;
deletions?: number | undefined;
author: { avatarUrl: string | undefined; date: string; email: string | undefined; name: string };
committer: { date: string; email: string | undefined; name: string };

Expand Down

0 comments on commit 239320a

Please sign in to comment.