Git - Add getRefs() extension API (#170903)

* Add `getRefs()` extension API

* Cleanup
This commit is contained in:
Ladislau Szomoru 2023-01-11 11:21:23 +01:00 committed by GitHub
parent 82d49f1649
commit 827636e106
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 43 additions and 33 deletions

View file

@ -5,8 +5,8 @@
import { Model } from '../model';
import { Repository as BaseRepository, Resource } from '../repository';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands } from 'vscode';
import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, ForcePushMode, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState, CommitOptions, RefType, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery } from './git';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands, CancellationToken } from 'vscode';
import { combinedDisposable, mapEvent } from '../util';
import { toGitUri } from '../uri';
import { GitExtensionImpl } from './extension';
@ -170,14 +170,18 @@ export class ApiRepository implements Repository {
return this.repository.getBranch(name);
}
getBranches(query: BranchQuery): Promise<Ref[]> {
return this.repository.getBranches(query);
getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise<Ref[]> {
return this.repository.getBranches(query, cancellationToken);
}
setBranchUpstream(name: string, upstream: string): Promise<void> {
return this.repository.setBranchUpstream(name, upstream);
}
getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]> {
return this.repository.getRefs(query, cancellationToken);
}
getMergeBase(ref1: string, ref2: string): Promise<string> {
return this.repository.getMergeBase(ref1, ref2);
}

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Uri, Event, Disposable, ProviderResult, Command } from 'vscode';
import { Uri, Event, Disposable, ProviderResult, Command, CancellationToken } from 'vscode';
export { ProviderResult } from 'vscode';
export interface Git {
@ -156,11 +156,15 @@ export interface FetchOptions {
depth?: number;
}
export interface BranchQuery {
readonly remote?: boolean;
readonly pattern?: string;
readonly count?: number;
export interface RefQuery {
readonly contains?: string;
readonly count?: number;
readonly pattern?: string;
readonly sort?: 'alphabetically' | 'committerdate';
}
export interface BranchQuery extends RefQuery {
readonly remote?: boolean;
}
export interface Repository {
@ -204,9 +208,11 @@ export interface Repository {
createBranch(name: string, checkout: boolean, ref?: string): Promise<void>;
deleteBranch(name: string, force?: boolean): Promise<void>;
getBranch(name: string): Promise<Branch>;
getBranches(query: BranchQuery): Promise<Ref[]>;
getBranches(query: BranchQuery, cancellationToken?: CancellationToken): Promise<Ref[]>;
setBranchUpstream(name: string, upstream: string): Promise<void>;
getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]>;
getMergeBase(ref1: string, ref2: string): Promise<string>;
tag(name: string, upstream: string): Promise<void>;

View file

@ -15,7 +15,7 @@ import * as filetype from 'file-type';
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter, Versions, isWindows } from './util';
import { CancellationError, CancellationToken, ConfigurationChangeEvent, LogOutputChannel, Progress, Uri, workspace } from 'vscode';
import { detectEncoding } from './encoding';
import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, BranchQuery } from './api/git';
import { Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, RefQuery } from './api/git';
import * as byline from 'byline';
import { StringDecoder } from 'string_decoder';
@ -2164,32 +2164,32 @@ export class Repository {
.map(([ref]) => ({ name: ref, type: RefType.Head } as Branch));
}
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate'; contains?: string; pattern?: string; count?: number; cancellationToken?: CancellationToken }): Promise<Ref[]> {
if (opts?.cancellationToken && opts?.cancellationToken.isCancellationRequested) {
async getRefs(query: RefQuery, cancellationToken?: CancellationToken): Promise<Ref[]> {
if (cancellationToken && cancellationToken.isCancellationRequested) {
throw new CancellationError();
}
const args = ['for-each-ref'];
if (opts?.count) {
args.push(`--count=${opts.count}`);
if (query.count) {
args.push(`--count=${query.count}`);
}
if (opts && opts.sort && opts.sort !== 'alphabetically') {
args.push('--sort', `-${opts.sort}`);
if (query.sort && query.sort !== 'alphabetically') {
args.push('--sort', `-${query.sort}`);
}
args.push('--format', '%(refname) %(objectname) %(*objectname)');
if (opts?.pattern) {
args.push(opts.pattern);
if (query.pattern) {
args.push(query.pattern.startsWith('refs/') ? query.pattern : `refs/${query.pattern}`);
}
if (opts?.contains) {
args.push('--contains', opts.contains);
if (query.contains) {
args.push('--contains', query.contains);
}
const result = await this.exec(args, { cancellationToken: opts?.cancellationToken });
const result = await this.exec(args, { cancellationToken });
const fn = (line: string): Ref | null => {
let match: RegExpExecArray | null;
@ -2404,11 +2404,6 @@ export class Repository {
return Promise.reject<Branch>(new Error('No such branch'));
}
async getBranches(query: BranchQuery): Promise<Ref[]> {
const refs = await this.getRefs({ contains: query.contains, pattern: query.pattern ? `refs/${query.pattern}` : undefined, count: query.count });
return refs.filter(value => (value.type !== RefType.Tag) && (query.remote || !value.remote));
}
// TODO: Support core.commentChar
stripCommitMessageComments(message: string): string {
return message.replace(/^\s*#.*$\n?/gm, '').trim();

View file

@ -8,7 +8,7 @@ import * as path from 'path';
import * as picomatch from 'picomatch';
import { CancellationToken, Command, Disposable, Event, EventEmitter, Memento, ProgressLocation, ProgressOptions, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, ThemeColor, Uri, window, workspace, WorkspaceEdit, FileDecoration, commands, Tab, TabInputTextDiff, TabInputNotebookDiff, RelativePattern, CancellationTokenSource, LogOutputChannel, LogLevel, CancellationError, l10n } from 'vscode';
import TelemetryReporter from '@vscode/extension-telemetry';
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, Remote, Status, CommitOptions, BranchQuery, FetchOptions } from './api/git';
import { Branch, Change, ForcePushMode, GitErrorCodes, LogOptions, Ref, Remote, Status, CommitOptions, BranchQuery, FetchOptions, RefQuery, RefType } from './api/git';
import { AutoFetcher } from './autofetch';
import { debounce, memoize, throttle } from './decorators';
import { Commit, GitError, Repository as BaseRepository, Stash, Submodule, LogFileOptions, PullOptions } from './git';
@ -1374,12 +1374,17 @@ export class Repository implements Disposable {
return await this.run(Operation.GetBranch, () => this.repository.getBranch(name));
}
async getBranches(query: BranchQuery): Promise<Ref[]> {
return await this.run(Operation.GetBranches, () => this.repository.getBranches(query));
async getBranches(query: BranchQuery = {}, cancellationToken?: CancellationToken): Promise<Ref[]> {
return await this.run(Operation.GetBranches, async () => {
const refs = await this.getRefs(query, cancellationToken);
return refs.filter(value => (value.type === RefType.Head || value.type === RefType.RemoteHead) && (query.remote || !value.remote));
});
}
async getRefs(opts?: { sort?: 'alphabetically' | 'committerdate'; contains?: string; pattern?: string; count?: number; cancellationToken?: CancellationToken }): Promise<Ref[]> {
return await this.run(Operation.GetRefs, () => this.repository.getRefs(opts));
async getRefs(query: RefQuery = {}, cancellationToken?: CancellationToken): Promise<Ref[]> {
return await this.run(Operation.GetRefs, () => {
return this.repository.getRefs(query, cancellationToken);
});
}
async getRemoteRefs(remote: string, opts?: { heads?: boolean; tags?: boolean }): Promise<Ref[]> {
@ -2001,7 +2006,7 @@ export class Repository implements Disposable {
const [resourceGroups, refs] =
await Promise.all([
this.getStatus(cancellationToken),
this.repository.getRefs({ sort, cancellationToken })]);
this.repository.getRefs({ sort }, cancellationToken)]);
this._refs = refs!;
this._updateResourceGroupsState(resourceGroups);