Merge pull request #298108 from microsoft/dev/mjbvz/other-meadowlark

Port git extension to use esbuild
This commit is contained in:
Matt Bierner
2026-03-02 09:11:02 -08:00
committed by GitHub
31 changed files with 190 additions and 46 deletions

View File

@@ -3,5 +3,5 @@ test/**
out/**
tsconfig*.json
build/**
extension.webpack.config.js
esbuild*.mts
package-lock.json

View File

@@ -0,0 +1,20 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as path from 'node:path';
import { run } from '../esbuild-extension-common.mts';
const srcDir = path.join(import.meta.dirname, 'src');
const outDir = path.join(import.meta.dirname, 'dist');
run({
platform: 'node',
entryPoints: {
'main': path.join(srcDir, 'main.ts'),
'askpass-main': path.join(srcDir, 'askpass-main.ts'),
'git-editor-main': path.join(srcDir, 'git-editor-main.ts'),
},
srcDir,
outdir: outDir,
}, process.argv);

View File

@@ -1,17 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// @ts-check
import withDefaults from '../shared.webpack.config.mjs';
export default withDefaults({
context: import.meta.dirname,
entry: {
main: './src/main.ts',
['askpass-main']: './src/askpass-main.ts',
['git-editor-main']: './src/git-editor-main.ts'
}
});
export const StripOutSourceMaps = ['dist/askpass-main.js'];

View File

@@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { Command, Disposable, Event, EventEmitter, SourceControlActionButton, Uri, workspace, l10n, LogOutputChannel } from 'vscode';
import { Branch, RefType, Status } from './api/git';
import type { Branch } from './api/git';
import { RefType, Status } from './api/git.constants';
import { OperationKind } from './operation';
import { CommitCommandsCenter } from './postCommitCommands';
import { Repository } from './repository';

View File

@@ -5,7 +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, RefQuery, BranchProtectionProvider, InitOptions, SourceControlHistoryItemDetailsProvider, GitErrorCodes, CloneOptions, CommitShortStat, DiffChange, Worktree, RepositoryKind, RepositoryAccessDetails } from './git';
import type { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, LogOptions, APIState, CommitOptions, CredentialsProvider, BranchQuery, PushErrorHandler, PublishEvent, FetchOptions, RemoteSourceProvider, RemoteSourcePublisher, PostCommitCommandsProvider, RefQuery, BranchProtectionProvider, InitOptions, SourceControlHistoryItemDetailsProvider, CloneOptions, CommitShortStat, DiffChange, Worktree, RepositoryKind, RepositoryAccessDetails } from './git';
import { ForcePushMode, GitErrorCodes, RefType, Status } from './git.constants';
import { Event, SourceControlInputBox, Uri, SourceControl, Disposable, commands, CancellationToken } from 'vscode';
import { combinedDisposable, filterEvent, mapEvent } from '../util';
import { toGitUri } from '../uri';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Model } from '../model';
import { GitExtension, Repository, API } from './git';
import type { GitExtension, Repository, API } from './git';
import { ApiRepository, ApiImpl } from './api1';
import { Event, EventEmitter } from 'vscode';
import { CloneManager } from '../cloneManager';

View File

@@ -0,0 +1,98 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import type * as git from './git';
export type ForcePushMode = git.ForcePushMode;
export type RefType = git.RefType;
export type Status = git.Status;
export type GitErrorCodes = git.GitErrorCodes;
export const ForcePushMode = Object.freeze({
Force: 0,
ForceWithLease: 1,
ForceWithLeaseIfIncludes: 2,
}) satisfies typeof git.ForcePushMode;
export const RefType = Object.freeze({
Head: 0,
RemoteHead: 1,
Tag: 2,
}) satisfies typeof git.RefType;
export const Status = Object.freeze({
INDEX_MODIFIED: 0,
INDEX_ADDED: 1,
INDEX_DELETED: 2,
INDEX_RENAMED: 3,
INDEX_COPIED: 4,
MODIFIED: 5,
DELETED: 6,
UNTRACKED: 7,
IGNORED: 8,
INTENT_TO_ADD: 9,
INTENT_TO_RENAME: 10,
TYPE_CHANGED: 11,
ADDED_BY_US: 12,
ADDED_BY_THEM: 13,
DELETED_BY_US: 14,
DELETED_BY_THEM: 15,
BOTH_ADDED: 16,
BOTH_DELETED: 17,
BOTH_MODIFIED: 18,
}) satisfies typeof git.Status;
export const GitErrorCodes = Object.freeze({
BadConfigFile: 'BadConfigFile',
BadRevision: 'BadRevision',
AuthenticationFailed: 'AuthenticationFailed',
NoUserNameConfigured: 'NoUserNameConfigured',
NoUserEmailConfigured: 'NoUserEmailConfigured',
NoRemoteRepositorySpecified: 'NoRemoteRepositorySpecified',
NotAGitRepository: 'NotAGitRepository',
NotASafeGitRepository: 'NotASafeGitRepository',
NotAtRepositoryRoot: 'NotAtRepositoryRoot',
Conflict: 'Conflict',
StashConflict: 'StashConflict',
UnmergedChanges: 'UnmergedChanges',
PushRejected: 'PushRejected',
ForcePushWithLeaseRejected: 'ForcePushWithLeaseRejected',
ForcePushWithLeaseIfIncludesRejected: 'ForcePushWithLeaseIfIncludesRejected',
RemoteConnectionError: 'RemoteConnectionError',
DirtyWorkTree: 'DirtyWorkTree',
CantOpenResource: 'CantOpenResource',
GitNotFound: 'GitNotFound',
CantCreatePipe: 'CantCreatePipe',
PermissionDenied: 'PermissionDenied',
CantAccessRemote: 'CantAccessRemote',
RepositoryNotFound: 'RepositoryNotFound',
RepositoryIsLocked: 'RepositoryIsLocked',
BranchNotFullyMerged: 'BranchNotFullyMerged',
NoRemoteReference: 'NoRemoteReference',
InvalidBranchName: 'InvalidBranchName',
BranchAlreadyExists: 'BranchAlreadyExists',
NoLocalChanges: 'NoLocalChanges',
NoStashFound: 'NoStashFound',
LocalChangesOverwritten: 'LocalChangesOverwritten',
NoUpstreamBranch: 'NoUpstreamBranch',
IsInSubmodule: 'IsInSubmodule',
WrongCase: 'WrongCase',
CantLockRef: 'CantLockRef',
CantRebaseMultipleBranches: 'CantRebaseMultipleBranches',
PatchDoesNotApply: 'PatchDoesNotApply',
NoPathFound: 'NoPathFound',
UnknownPath: 'UnknownPath',
EmptyCommitMessage: 'EmptyCommitMessage',
BranchFastForwardRejected: 'BranchFastForwardRejected',
BranchNotYetBorn: 'BranchNotYetBorn',
TagConflict: 'TagConflict',
CherryPickEmpty: 'CherryPickEmpty',
CherryPickConflict: 'CherryPickConflict',
WorktreeContainsChanges: 'WorktreeContainsChanges',
WorktreeAlreadyExists: 'WorktreeAlreadyExists',
WorktreeBranchAlreadyUsed: 'WorktreeBranchAlreadyUsed',
}) satisfies Record<keyof typeof git.GitErrorCodes, string>;

View File

@@ -6,7 +6,8 @@
import { LogOutputChannel, SourceControlArtifactProvider, SourceControlArtifactGroup, SourceControlArtifact, Event, EventEmitter, ThemeIcon, l10n, workspace, Uri, Disposable, Command } from 'vscode';
import { coalesce, dispose, filterEvent, IDisposable, isCopilotWorktree } from './util';
import { Repository } from './repository';
import { Ref, RefType, Worktree } from './api/git';
import type { Ref, Worktree } from './api/git';
import { RefType } from './api/git.constants';
import { OperationKind } from './operation';
/**

View File

@@ -6,7 +6,7 @@
import { window, InputBoxOptions, Uri, Disposable, workspace, QuickPickOptions, l10n, LogOutputChannel } from 'vscode';
import { IDisposable, EmptyDisposable, toDisposable, extractFilePathFromArgs } from './util';
import { IIPCHandler, IIPCServer } from './ipc/ipcServer';
import { CredentialsProvider, Credentials } from './api/git';
import type { CredentialsProvider, Credentials } from './api/git';
import { ITerminalEnvironmentProvider } from './terminal';
import { AskpassPaths } from './askpassManager';

View File

@@ -6,7 +6,7 @@
import { workspace, Disposable, EventEmitter, Memento, window, MessageItem, ConfigurationTarget, Uri, ConfigurationChangeEvent, l10n, env } from 'vscode';
import { Repository } from './repository';
import { eventToPromise, filterEvent, onceEvent } from './util';
import { GitErrorCodes } from './api/git';
import { GitErrorCodes } from './api/git.constants';
export class AutoFetcher {

View File

@@ -13,7 +13,7 @@ import { fromGitUri, isGitUri, toGitUri } from './uri';
import { emojify, ensureEmojis } from './emoji';
import { getWorkingTreeAndIndexDiffInformation, getWorkingTreeDiffInformation } from './staging';
import { provideSourceControlHistoryItemAvatar, provideSourceControlHistoryItemHoverCommands, provideSourceControlHistoryItemMessageLinks } from './historyItemDetailsProvider';
import { AvatarQuery, AvatarQueryCommit } from './api/git';
import type { AvatarQuery, AvatarQueryCommit } from './api/git';
import { LRUCache } from './cache';
import { AVATAR_SIZE, getCommitHover, getHoverCommitHashCommands, processHoverRemoteCommands } from './hover';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, Event, EventEmitter, Uri, workspace } from 'vscode';
import { BranchProtection, BranchProtectionProvider } from './api/git';
import type { BranchProtection, BranchProtectionProvider } from './api/git';
import { dispose, filterEvent } from './util';
export interface IBranchProtectionProviderRegistry {

View File

@@ -8,7 +8,8 @@ import * as path from 'path';
import { Command, commands, Disposable, MessageOptions, Position, QuickPickItem, Range, SourceControlResourceState, TextDocumentShowOptions, TextEditor, Uri, ViewColumn, window, workspace, WorkspaceEdit, WorkspaceFolder, TimelineItem, env, Selection, TextDocumentContentProvider, InputBoxValidationSeverity, TabInputText, TabInputTextMerge, QuickPickItemKind, TextDocument, LogOutputChannel, l10n, Memento, UIKind, QuickInputButton, ThemeIcon, SourceControlHistoryItem, SourceControl, InputBoxValidationMessage, Tab, TabInputNotebook, QuickInputButtonLocation, languages, SourceControlArtifact, ProgressLocation } from 'vscode';
import TelemetryReporter from '@vscode/extension-telemetry';
import { uniqueNamesGenerator, adjectives, animals, colors, NumberDictionary } from '@joaomoreno/unique-names-generator';
import { ForcePushMode, GitErrorCodes, RefType, Status, CommitOptions, RemoteSourcePublisher, Remote, Branch, Ref } from './api/git';
import type { CommitOptions, RemoteSourcePublisher, Remote, Branch, Ref } from './api/git';
import { ForcePushMode, GitErrorCodes, RefType, Status } from './api/git.constants';
import { Git, GitError, Repository as GitRepository, Stash, Worktree } from './git';
import { Model } from './model';
import { GitResourceGroup, Repository, Resource, ResourceGroupType } from './repository';
@@ -106,6 +107,8 @@ class RefItem implements QuickPickItem {
return `refs/remotes/${this.ref.name}`;
case RefType.Tag:
return `refs/tags/${this.ref.name}`;
default:
throw new Error('Unknown ref type');
}
}
get refName(): string | undefined { return this.ref.name; }

View File

@@ -9,7 +9,8 @@ import { Repository, GitResourceGroup } from './repository';
import { Model } from './model';
import { debounce } from './decorators';
import { filterEvent, dispose, anyEvent, PromiseSource, combinedDisposable, runAndSubscribeEvent } from './util';
import { Change, GitErrorCodes, Status } from './api/git';
import type { Change } from './api/git';
import { GitErrorCodes, Status } from './api/git.constants';
function equalSourceControlHistoryItemRefs(ref1?: SourceControlHistoryItemRef, ref2?: SourceControlHistoryItemRef): boolean {
if (ref1 === ref2) {

View File

@@ -5,7 +5,7 @@
import * as path from 'path';
import * as vscode from 'vscode';
import { RefType } from './api/git';
import { RefType } from './api/git.constants';
import { Model } from './model';
export class GitEditSessionIdentityProvider implements vscode.EditSessionIdentityProvider, vscode.Disposable {

View File

@@ -13,7 +13,8 @@ import { EventEmitter } from 'events';
import * as filetype from 'file-type';
import { assign, groupBy, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent, splitInChunks, Limiter, Versions, isWindows, pathEquals, isMacintosh, isDescendant, relativePathWithNoFallback, Mutable } from './util';
import { CancellationError, CancellationToken, ConfigurationChangeEvent, LogOutputChannel, Progress, Uri, workspace } from 'vscode';
import { Commit as ApiCommit, Ref, RefType, Branch, Remote, ForcePushMode, GitErrorCodes, LogOptions, Change, Status, CommitOptions, RefQuery as ApiRefQuery, InitOptions, DiffChange, Worktree as ApiWorktree } from './api/git';
import type { Commit as ApiCommit, Ref, Branch, Remote, LogOptions, Change, CommitOptions, RefQuery as ApiRefQuery, InitOptions, DiffChange, Worktree as ApiWorktree } from './api/git';
import { RefType, ForcePushMode, GitErrorCodes, Status } from './api/git.constants';
import * as byline from 'byline';
import { StringDecoder } from 'string_decoder';
@@ -1073,7 +1074,7 @@ function parseGitChanges(repositoryRoot: string, raw: string): Change[] {
let uri = originalUri;
let renameUri = originalUri;
let status = Status.UNTRACKED;
let status: Status = Status.UNTRACKED;
// Copy or Rename status comes with a number (ex: 'R100').
// We don't need the number, we use only first character of the status.
@@ -1138,7 +1139,7 @@ function parseGitChangesRaw(repositoryRoot: string, raw: string): DiffChange[] {
let uri = originalUri;
let renameUri = originalUri;
let status = Status.UNTRACKED;
let status: Status = Status.UNTRACKED;
switch (change[0]) {
case 'A':

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Command, Disposable } from 'vscode';
import { AvatarQuery, SourceControlHistoryItemDetailsProvider } from './api/git';
import type { AvatarQuery, SourceControlHistoryItemDetailsProvider } from './api/git';
import { Repository } from './repository';
import { ApiRepository } from './api/api1';

View File

@@ -8,7 +8,8 @@ import { CancellationToken, Disposable, Event, EventEmitter, FileDecoration, Fil
import { Repository, Resource } from './repository';
import { IDisposable, deltaHistoryItemRefs, dispose, filterEvent, subject, truncate } from './util';
import { toMultiFileDiffEditorUris } from './uri';
import { AvatarQuery, AvatarQueryCommit, Branch, LogOptions, Ref, RefType } from './api/git';
import type { AvatarQuery, AvatarQueryCommit, Branch, LogOptions, Ref } from './api/git';
import { RefType } from './api/git.constants';
import { emojify, ensureEmojis } from './emoji';
import { Commit } from './git';
import { OperationKind, OperationResult } from './operation';

View File

@@ -12,7 +12,7 @@ import { GitDecorations } from './decorationProvider';
import { Askpass } from './askpass';
import { toDisposable, filterEvent, eventToPromise } from './util';
import TelemetryReporter from '@vscode/extension-telemetry';
import { GitExtension } from './api/git';
import type { GitExtension } from './api/git';
import { GitProtocolHandler } from './protocolHandler';
import { GitExtensionImpl } from './api/extension';
import * as path from 'path';

View File

@@ -12,7 +12,7 @@ import { Git } from './git';
import * as path from 'path';
import * as fs from 'fs';
import { fromGitUri } from './uri';
import { APIState as State, CredentialsProvider, PushErrorHandler, PublishEvent, RemoteSourcePublisher, PostCommitCommandsProvider, BranchProtectionProvider, SourceControlHistoryItemDetailsProvider } from './api/git';
import type { APIState as State, CredentialsProvider, PushErrorHandler, PublishEvent, RemoteSourcePublisher, PostCommitCommandsProvider, BranchProtectionProvider, SourceControlHistoryItemDetailsProvider } from './api/git';
import { Askpass } from './askpass';
import { IPushErrorHandlerRegistry } from './pushError';
import { ApiRepository } from './api/api1';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Command, commands, Disposable, Event, EventEmitter, Memento, Uri, workspace, l10n } from 'vscode';
import { PostCommitCommandsProvider } from './api/git';
import type { PostCommitCommandsProvider } from './api/git';
import { IRepositoryResolver, Repository } from './repository';
import { ApiRepository } from './api/api1';
import { dispose } from './util';

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vscode';
import { PushErrorHandler } from './api/git';
import type { PushErrorHandler } from './api/git';
export interface IPushErrorHandlerRegistry {
registerPushErrorHandler(provider: PushErrorHandler): Disposable;

View File

@@ -7,7 +7,7 @@ import { FileType, l10n, LogOutputChannel, QuickDiffProvider, Uri, workspace } f
import { IRepositoryResolver, Repository } from './repository';
import { isDescendant, pathEquals } from './util';
import { toGitUri } from './uri';
import { Status } from './api/git';
import { Status } from './api/git.constants';
export class GitQuickDiffProvider implements QuickDiffProvider {
readonly label = l10n.t('Git Local Changes (Working Tree)');

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { Disposable, Event } from 'vscode';
import { RemoteSourcePublisher } from './api/git';
import type { RemoteSourcePublisher } from './api/git';
export interface IRemoteSourcePublisherRegistry {
readonly onDidAddRemoteSourcePublisher: Event<RemoteSourcePublisher>;

View File

@@ -11,7 +11,8 @@ import picomatch from 'picomatch';
import { CancellationError, CancellationToken, CancellationTokenSource, Command, commands, Disposable, Event, EventEmitter, ExcludeSettingOptions, FileDecoration, l10n, LogLevel, LogOutputChannel, Memento, ProgressLocation, ProgressOptions, RelativePattern, scm, SourceControl, SourceControlInputBox, SourceControlInputBoxValidation, SourceControlInputBoxValidationType, SourceControlResourceDecorations, SourceControlResourceGroup, SourceControlResourceState, TabInputNotebookDiff, TabInputTextDiff, TabInputTextMultiDiff, ThemeColor, ThemeIcon, Uri, window, workspace, WorkspaceEdit } from 'vscode';
import { ActionButton } from './actionButton';
import { ApiRepository } from './api/api1';
import { Branch, BranchQuery, Change, CommitOptions, DiffChange, FetchOptions, ForcePushMode, GitErrorCodes, LogOptions, Ref, RefType, Remote, RepositoryKind, Status } from './api/git';
import type { Branch, BranchQuery, Change, CommitOptions, DiffChange, FetchOptions, LogOptions, Ref, Remote, RepositoryKind } from './api/git';
import { ForcePushMode, GitErrorCodes, RefType, Status } from './api/git.constants';
import { AutoFetcher } from './autofetch';
import { GitBranchProtectionProvider, IBranchProtectionProviderRegistry } from './branchProtection';
import { debounce, memoize, sequentialize, throttle } from './decorators';

View File

@@ -5,7 +5,7 @@
import { LogOutputChannel, Memento, Uri, workspace } from 'vscode';
import { LRUCache } from './cache';
import { Remote, RepositoryAccessDetails } from './api/git';
import type { Remote, RepositoryAccessDetails } from './api/git';
import { isDescendant } from './util';
export interface RepositoryCacheInfo {

View File

@@ -6,7 +6,8 @@
import { Disposable, Command, EventEmitter, Event, workspace, Uri, l10n } from 'vscode';
import { Repository } from './repository';
import { anyEvent, dispose, filterEvent } from './util';
import { Branch, RefType, RemoteSourcePublisher } from './api/git';
import type { Branch, RemoteSourcePublisher } from './api/git';
import { RefType } from './api/git.constants';
import { IRemoteSourcePublisherRegistry } from './remotePublisher';
import { CheckoutOperation, CheckoutTrackingOperation, OperationKind } from './operation';

View File

@@ -9,7 +9,8 @@ import { workspace, commands, window, Uri, WorkspaceEdit, Range, TextDocument, e
import * as cp from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { GitExtension, API, Repository, Status } from '../api/git';
import type { GitExtension, API, Repository } from '../api/git';
import { Status } from '../api/git.constants';
import { eventToPromise } from '../util';
suite('git smoke test', function () {

View File

@@ -12,7 +12,7 @@ import { CommandCenter } from './commands';
import { OperationKind, OperationResult } from './operation';
import { truncate } from './util';
import { provideSourceControlHistoryItemAvatar, provideSourceControlHistoryItemHoverCommands, provideSourceControlHistoryItemMessageLinks } from './historyItemDetailsProvider';
import { AvatarQuery, AvatarQueryCommit } from './api/git';
import type { AvatarQuery, AvatarQueryCommit } from './api/git';
import { getCommitHover, getHoverCommitHashCommands, processHoverRemoteCommands } from './hover';
export class GitTimelineItem extends TimelineItem {

View File

@@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { Uri } from 'vscode';
import { Change, Status } from './api/git';
import type { Change } from './api/git';
import { Status } from './api/git.constants';
export interface GitUriParams {
path: string;