diff --git a/package.json b/package.json
index 9e1d06ef64..555909cd86 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,7 @@
},
{
"command": "tfvc.Undo",
- "when": "scmProvider == tfvc",
+ "when": "scmProvider == tfvc && scmResourceGroup != conflicts",
"group": "1_modification@1"
},
{
@@ -90,9 +90,19 @@
"when": "scmProvider == tfvc && scmResourceGroup == included",
"group": "1_modification@2"
},
+ {
+ "command": "tfvc.ResolveTakeTheirs",
+ "when": "scmProvider == tfvc && scmResourceGroup == conflicts",
+ "group": "1_modification@1"
+ },
+ {
+ "command": "tfvc.ResolveKeepYours",
+ "when": "scmProvider == tfvc && scmResourceGroup == conflicts",
+ "group": "1_modification@2"
+ },
{
"command": "tfvc.Undo",
- "when": "scmProvider == tfvc",
+ "when": "scmProvider == tfvc && scmResourceGroup != conflicts",
"group": "inline@1"
},
{
@@ -104,6 +114,16 @@
"command": "tfvc.Exclude",
"when": "scmProvider == tfvc && scmResourceGroup == included",
"group": "inline@2"
+ },
+ {
+ "command": "tfvc.ResolveTakeTheirs",
+ "when": "scmProvider == tfvc && scmResourceGroup == conflicts",
+ "group": "inline@1"
+ },
+ {
+ "command": "tfvc.ResolveKeepYours",
+ "when": "scmProvider == tfvc && scmResourceGroup == conflicts",
+ "group": "inline@2"
}
]
},
@@ -275,6 +295,24 @@
"dark": "resources/icons/dark/refresh.svg"
}
},
+ {
+ "command": "tfvc.ResolveKeepYours",
+ "title": "Resolve: Keep Yours",
+ "category": "TFVC",
+ "icon": {
+ "light": "resources/icons/light/resolve-keepyours.svg",
+ "dark": "resources/icons/dark/resolve-keepyours.svg"
+ }
+ },
+ {
+ "command": "tfvc.ResolveTakeTheirs",
+ "title": "Resolve: Take Theirs",
+ "category": "TFVC",
+ "icon": {
+ "light": "resources/icons/light/resolve-taketheirs.svg",
+ "dark": "resources/icons/dark/resolve-taketheirs.svg"
+ }
+ },
{
"command": "tfvc.Sync",
"title": "Sync",
diff --git a/resources/icons/dark/resolve-keepyours.svg b/resources/icons/dark/resolve-keepyours.svg
new file mode 100644
index 0000000000..d9be7332a6
--- /dev/null
+++ b/resources/icons/dark/resolve-keepyours.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/resources/icons/dark/resolve-taketheirs.svg b/resources/icons/dark/resolve-taketheirs.svg
new file mode 100644
index 0000000000..4903b53afb
--- /dev/null
+++ b/resources/icons/dark/resolve-taketheirs.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/resources/icons/light/resolve-keepyours.svg b/resources/icons/light/resolve-keepyours.svg
new file mode 100644
index 0000000000..5bb18de3c1
--- /dev/null
+++ b/resources/icons/light/resolve-keepyours.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/resources/icons/light/resolve-taketheirs.svg b/resources/icons/light/resolve-taketheirs.svg
new file mode 100644
index 0000000000..724be9ef09
--- /dev/null
+++ b/resources/icons/light/resolve-taketheirs.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/src/extension.ts b/src/extension.ts
index 71e0b3edcb..f2457d3c1d 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -8,6 +8,7 @@ import { commands, Disposable, ExtensionContext } from "vscode";
import { CommandNames, TfvcCommandNames } from "./helpers/constants";
import { ExtensionManager } from "./extensionmanager";
import { TfvcSCMProvider } from "./tfvc/tfvcscmprovider";
+import { AutoResolveType } from "./tfvc/interfaces";
let _extensionManager: ExtensionManager;
let _scmProvider: TfvcSCMProvider;
@@ -62,6 +63,12 @@ export async function activate(context: ExtensionContext) {
}));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Refresh, () => _extensionManager.Tfvc.TfvcRefresh()));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ShowOutput, () => _extensionManager.Tfvc.TfvcShowOutput()));
+ context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ResolveKeepYours, (...args) => {
+ _extensionManager.Tfvc.TfvcResolve(args ? args[0] : undefined, AutoResolveType.KeepYours);
+ }));
+ context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ResolveTakeTheirs, (...args) => {
+ _extensionManager.Tfvc.TfvcResolve(args ? args[0] : undefined, AutoResolveType.TakeTheirs);
+ }));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Checkin, () => _extensionManager.Tfvc.TfvcCheckin()));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Sync, () => _extensionManager.Tfvc.TfvcSync()));
}
diff --git a/src/helpers/constants.ts b/src/helpers/constants.ts
index 116b35ef86..68f69d5976 100644
--- a/src/helpers/constants.ts
+++ b/src/helpers/constants.ts
@@ -44,6 +44,8 @@ export class TfvcCommandNames {
static OpenDiff: string = TfvcCommandNames.CommandPrefix + "OpenDiff";
static OpenFile: string = TfvcCommandNames.CommandPrefix + "OpenFile";
static Refresh: string = TfvcCommandNames.CommandPrefix + "Refresh";
+ static ResolveKeepYours: string = TfvcCommandNames.CommandPrefix + "ResolveKeepYours";
+ static ResolveTakeTheirs: string = TfvcCommandNames.CommandPrefix + "ResolveTakeTheirs";
static ShowOutput: string = TfvcCommandNames.CommandPrefix + "ShowOutput";
static Status: string = TfvcCommandNames.CommandPrefix + "Status";
static Sync: string = TfvcCommandNames.CommandPrefix + "Sync";
diff --git a/src/helpers/strings.ts b/src/helpers/strings.ts
index d8dec0ce31..82ab6f534f 100644
--- a/src/helpers/strings.ts
+++ b/src/helpers/strings.ts
@@ -67,6 +67,7 @@ export class Strings {
static UndoChanges: string = "Undo Changes";
static NoChangesToCheckin: string = "There are no changes to checkin. Changes must be added to the 'Included' section to be checked in.";
static AllFilesUpToDate: string = "All files are up to date.";
+ static CommandRequiresFileContext: string = "This command requires a file context and can only be executed from the TFVC viewlet window.";
// TFVC viewlet Strings
static ExcludedGroupName: string = "Excluded changes";
@@ -85,5 +86,14 @@ export class Strings {
static ConflictAlreadyDeleted: string = "ALREADY DELETED";
static ConflictAlreadyExists: string = "ALREADY EXISTS";
static ConflictDeletedLocally: string = "DELETED LOCALLY";
+
+ // TFVC AutoResolveType Strings
+ static AutoResolveTypeAutoMerge: string = "Auto Merge";
+ static AutoResolveTypeDeleteConflict: string = "Delete Conflict";
+ static AutoResolveTypeKeepYours: string = "Keep Yours";
+ static AutoResolveTypeKeepYoursRenameTheirs: string = "Keep Yours Rename Theirs";
+ static AutoResolveTypeOverwriteLocal: string = "Overwrite Local";
+ static AutoResolveTypeTakeTheirs: string = "Take Theirs";
+
}
/* tslint:enable:variable-name */
diff --git a/src/tfvc/commands/commandhelper.ts b/src/tfvc/commands/commandhelper.ts
index a80854162f..2a352520b4 100644
--- a/src/tfvc/commands/commandhelper.ts
+++ b/src/tfvc/commands/commandhelper.ts
@@ -13,6 +13,12 @@ import { TfvcError, TfvcErrorCodes } from "../tfvcerror";
import { IExecutionResult } from "../interfaces";
export class CommandHelper {
+ public static RequireArgument(argument: any, argumentName: string) {
+ if (!argument) {
+ throw TfvcError.CreateArgumentMissingError(argumentName);
+ }
+ }
+
public static RequireStringArgument(argument: string, argumentName: string) {
if (!argument || argument.trim().length === 0) {
throw TfvcError.CreateArgumentMissingError(argumentName);
diff --git a/src/tfvc/commands/resolveconflicts.ts b/src/tfvc/commands/resolveconflicts.ts
new file mode 100644
index 0000000000..5dd6dbd94a
--- /dev/null
+++ b/src/tfvc/commands/resolveconflicts.ts
@@ -0,0 +1,69 @@
+/*---------------------------------------------------------------------------------------------
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the MIT License. See License.txt in the project root for license information.
+*--------------------------------------------------------------------------------------------*/
+"use strict";
+
+import { TeamServerContext} from "../../contexts/servercontext";
+import { AutoResolveType, IArgumentProvider, IExecutionResult, ITfvcCommand, IConflict } from "../interfaces";
+import { ConflictType } from "../scm/status";
+import { ArgumentBuilder } from "./argumentbuilder";
+import { CommandHelper } from "./commandhelper";
+
+/**
+ * This command resolves conflicts based on given auto resolve type
+ *
+ * tf resolve [itemspec]
+ * [/auto:(AutoMerge|TakeTheirs|KeepYours|OverwriteLocal|DeleteConflict|KeepYoursRenameTheirs)]
+ * [/preview] [(/overridetype:overridetype | /converttotype:converttype] [/recursive] [/newname:path] [/noprompt] [/login:username, [password]]
+ */
+export class ResolveConflicts implements ITfvcCommand {
+ private _serverContext: TeamServerContext;
+ private _itemPaths: string[];
+ private _autoResolveType: AutoResolveType;
+
+ public constructor(serverContext: TeamServerContext, itemPaths: string[], autoResolveType: AutoResolveType) {
+ this._serverContext = serverContext;
+ CommandHelper.RequireStringArrayArgument(itemPaths, "itemPaths");
+ CommandHelper.RequireArgument(autoResolveType, "autoResolveType");
+ this._itemPaths = itemPaths;
+ this._autoResolveType = autoResolveType;
+ }
+
+ public GetArguments(): IArgumentProvider {
+ const builder: ArgumentBuilder = new ArgumentBuilder("resolve", this._serverContext)
+ .AddAll(this._itemPaths)
+ .AddSwitchWithValue("auto", AutoResolveType[this._autoResolveType], false);
+ return builder;
+ }
+
+ public GetOptions(): any {
+ return {};
+ }
+
+ /**
+ * Outputs the resolved conflicts in the following format:
+ *
+ * Resolved /Users/leantk/tfvc-tfs/tfsTest_01/TestAdd.txt as KeepYours
+ * Resolved /Users/leantk/tfvc-tfs/tfsTest_01/addFold/testHere2 as KeepYours
+ */
+ public async ParseOutput(executionResult: IExecutionResult): Promise {
+ CommandHelper.ProcessErrors(this.GetArguments().GetCommand(), executionResult);
+
+ let conflicts: IConflict[] = [];
+ const lines: string[] = CommandHelper.SplitIntoLines(executionResult.stdout, true, true);
+ for (let i: number = 0; i < lines.length; i++) {
+ const line: string = lines[i];
+ const startIndex: number = line.indexOf("Resolved ");
+ const endIndex: number = line.lastIndexOf(" as ");
+ if (startIndex >= 0 && endIndex > startIndex) {
+ conflicts.push({
+ localPath: line.slice(startIndex + "Resolved ".length, endIndex),
+ type: ConflictType.RESOLVED
+ });
+ }
+ }
+
+ return conflicts;
+ }
+}
diff --git a/src/tfvc/interfaces.ts b/src/tfvc/interfaces.ts
index 5e8e2ff3cd..1bdc764e59 100644
--- a/src/tfvc/interfaces.ts
+++ b/src/tfvc/interfaces.ts
@@ -89,6 +89,15 @@ export interface IConflict {
type: ConflictType;
}
+export enum AutoResolveType {
+ AutoMerge,
+ TakeTheirs,
+ KeepYours,
+ OverwriteLocal,
+ DeleteConflict,
+ KeepYoursRenameTheirs
+}
+
export interface IExecutionResult {
exitCode: number;
stdout: string;
diff --git a/src/tfvc/repository.ts b/src/tfvc/repository.ts
index ab17175f62..659d19e218 100644
--- a/src/tfvc/repository.ts
+++ b/src/tfvc/repository.ts
@@ -8,7 +8,7 @@ import { TeamServerContext} from "../contexts/servercontext";
import { Logger } from "../helpers/logger";
import { ITfvcCommand, IExecutionResult } from "./interfaces";
import { Tfvc } from "./tfvc";
-import { IArgumentProvider, IConflict, IItemInfo, IPendingChange, ISyncResults, IWorkspace } from "./interfaces";
+import { AutoResolveType, IArgumentProvider, IConflict, IItemInfo, IPendingChange, ISyncResults, IWorkspace } from "./interfaces";
import { Add } from "./commands/add";
import { Checkin } from "./commands/checkin";
import { FindConflicts } from "./commands/findconflicts";
@@ -16,6 +16,7 @@ import { FindWorkspace } from "./commands/findworkspace";
import { GetInfo } from "./commands/getinfo";
import { GetFileContent } from "./commands/getfilecontent";
import { GetVersion } from "./commands/getversion";
+import { ResolveConflicts } from "./commands/resolveconflicts";
import { Status } from "./commands/status";
import { Sync } from "./commands/sync";
import { Undo } from "./commands/undo";
@@ -96,6 +97,12 @@ export class Repository {
new Status(this._serverContext, ignoreFiles === undefined ? true : ignoreFiles));
}
+ public async ResolveConflicts(itemPaths: string[], autoResolveType: AutoResolveType): Promise {
+ Logger.LogDebug(`TFVC Repository.ResolveConflicts`);
+ return this.RunCommand(
+ new ResolveConflicts(this._serverContext, itemPaths, autoResolveType));
+ }
+
public async Sync(itemPaths: string[], recursive: boolean): Promise {
Logger.LogDebug(`TFVC Repository.Sync`);
return this.RunCommand(
diff --git a/src/tfvc/tfvc-extension.ts b/src/tfvc/tfvc-extension.ts
index 4237c933bd..6d31f72865 100644
--- a/src/tfvc/tfvc-extension.ts
+++ b/src/tfvc/tfvc-extension.ts
@@ -19,7 +19,7 @@ import { TfvcSCMProvider } from "./tfvcscmprovider";
import { TfvcErrorCodes } from "./tfvcerror";
import { Repository } from "./repository";
import { UIHelper } from "./uihelper";
-import { ICheckinInfo, IItemInfo, IPendingChange, ISyncResults } from "./interfaces";
+import { AutoResolveType, ICheckinInfo, IItemInfo, IPendingChange, ISyncResults } from "./interfaces";
import { TfvcOutput } from "./tfvcoutput";
export class TfvcExtension {
@@ -134,6 +134,23 @@ export class TfvcExtension {
}
}
+ public async TfvcResolve(uri: Uri, autoResolveType: AutoResolveType): Promise {
+ this.displayErrors(async () => {
+ if (uri) {
+ let localPath: string = TfvcSCMProvider.GetPathFromUri(uri);
+ const resolveTypeString: string = UIHelper.GetDisplayTextForAutoResolveType(autoResolveType);
+ const basename: string = path.basename(localPath);
+ const message: string = `Are you sure you want to resolve changes in ${basename} as ${resolveTypeString}?`;
+ if (await UIHelper.PromptForConfirmation(message, resolveTypeString)) {
+ await this._repo.ResolveConflicts([localPath], autoResolveType);
+ TfvcSCMProvider.Refresh();
+ }
+ } else {
+ this._manager.DisplayWarningMessage(Strings.CommandRequiresFileContext);
+ }
+ });
+ }
+
public async TfvcShowOutput(): Promise {
TfvcOutput.Show();
}
@@ -202,14 +219,10 @@ export class TfvcExtension {
if (pathToUndo) {
const basename: string = path.basename(pathToUndo);
const message: string = `Are you sure you want to undo changes in ${basename}?`;
- //TODO: use Modal api once vscode.d.ts exposes it (currently proposed)
- const pick: string = await window.showWarningMessage(message, /*{ modal: true },*/ Strings.UndoChanges);
- if (pick !== Strings.UndoChanges) {
- return;
+ if (await UIHelper.PromptForConfirmation(message, Strings.UndoChanges)) {
+ this._manager.Telemetry.SendEvent(TfvcTelemetryEvents.Undo);
+ await this._repo.Undo([pathToUndo]);
}
-
- this._manager.Telemetry.SendEvent(TfvcTelemetryEvents.Undo);
- await this._repo.Undo([pathToUndo]);
}
} catch (err) {
this._manager.DisplayErrorMessage(err.message);
@@ -261,6 +274,19 @@ export class TfvcExtension {
}
}
+ private async displayErrors(funcToTry: () => Promise): Promise {
+ if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) {
+ this._manager.DisplayErrorMessage();
+ return;
+ }
+
+ try {
+ await funcToTry();
+ } catch (err) {
+ this._manager.DisplayErrorMessage(err.message);
+ }
+ }
+
public async InitializeClients(repoType: RepositoryType): Promise {
//We only need to initialize for Tfvc repositories
if (repoType !== RepositoryType.TFVC) {
diff --git a/src/tfvc/uihelper.ts b/src/tfvc/uihelper.ts
index 4979d9326c..49a80cf505 100644
--- a/src/tfvc/uihelper.ts
+++ b/src/tfvc/uihelper.ts
@@ -6,7 +6,7 @@
import { QuickPickItem, window, workspace } from "vscode";
import { Strings } from "../helpers/strings";
-import { IPendingChange, ISyncResults, ISyncItemResult, SyncType } from "./interfaces";
+import { AutoResolveType, IPendingChange, ISyncResults, ISyncItemResult, SyncType } from "./interfaces";
import { TfvcOutput } from "./tfvcoutput";
var path = require("path");
@@ -106,6 +106,18 @@ export class UIHelper {
}
}
+ public static GetDisplayTextForAutoResolveType(type: AutoResolveType): string {
+ switch (type) {
+ case AutoResolveType.AutoMerge: return Strings.AutoResolveTypeAutoMerge;
+ case AutoResolveType.DeleteConflict: return Strings.AutoResolveTypeDeleteConflict;
+ case AutoResolveType.KeepYours: return Strings.AutoResolveTypeKeepYours;
+ case AutoResolveType.KeepYoursRenameTheirs: return Strings.AutoResolveTypeKeepYoursRenameTheirs;
+ case AutoResolveType.OverwriteLocal: return Strings.AutoResolveTypeOverwriteLocal;
+ case AutoResolveType.TakeTheirs: return Strings.AutoResolveTypeTakeTheirs;
+ default: return Strings.AutoResolveTypeAutoMerge;
+ }
+ }
+
public static GetFileName(change: IPendingChange) {
if (change && change.localItem) {
var filename = path.parse(change.localItem).base;
@@ -122,4 +134,11 @@ export class UIHelper {
return change.localItem;
}
+
+ public static async PromptForConfirmation(message: string, okButtonText?: string): Promise {
+ okButtonText = okButtonText ? okButtonText : "OK";
+ //TODO: use Modal api once vscode.d.ts exposes it (currently proposed)
+ const pick: string = await window.showWarningMessage(message, /*{ modal: true },*/ okButtonText);
+ return pick === okButtonText;
+ }
}
diff --git a/test/tfvc/commands/resolveconflicts.test.ts b/test/tfvc/commands/resolveconflicts.test.ts
new file mode 100644
index 0000000000..83cc3704e1
--- /dev/null
+++ b/test/tfvc/commands/resolveconflicts.test.ts
@@ -0,0 +1,129 @@
+/*---------------------------------------------------------------------------------------------
+* Copyright (c) Microsoft Corporation. All rights reserved.
+* Licensed under the MIT License. See License.txt in the project root for license information.
+*--------------------------------------------------------------------------------------------*/
+"use strict";
+
+import { assert } from "chai";
+import { Strings } from "../../../src/helpers/strings";
+import { ResolveConflicts } from "../../../src/tfvc/commands/resolveconflicts";
+import { TfvcError } from "../../../src/tfvc/tfvcerror";
+import { AutoResolveType, IExecutionResult, IConflict } from "../../../src/tfvc/interfaces";
+import { ConflictType } from "../../../src/tfvc/scm/status";
+import { TeamServerContext } from "../../../src/contexts/servercontext";
+import { CredentialInfo } from "../../../src/info/credentialinfo";
+import { RepositoryInfo } from "../../../src/info/repositoryinfo";
+
+describe("Tfvc-ResolveConflictsCommand", function() {
+ let serverUrl: string = "http://server:8080/tfs";
+ let repoUrl: string = "http://server:8080/tfs/collection1/_git/repo1";
+ let collectionUrl: string = "http://server:8080/tfs/collection1";
+ let user: string = "user1";
+ let pass: string = "pass1";
+ let context: TeamServerContext;
+
+ beforeEach(function() {
+ context = new TeamServerContext(repoUrl);
+ context.CredentialInfo = new CredentialInfo(user, pass);
+ context.RepoInfo = new RepositoryInfo({
+ serverUrl: serverUrl,
+ collection: {
+ name: "collection1",
+ id: ""
+ },
+ repository: {
+ remoteUrl: repoUrl,
+ id: "",
+ name: "",
+ project: {
+ name: "project1"
+ }
+ }
+ });
+ });
+
+ it("should verify constructor", function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ new ResolveConflicts(undefined, localPaths, AutoResolveType.KeepYours);
+ });
+
+ it("should verify constructor with context", function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ new ResolveConflicts(context, localPaths, AutoResolveType.KeepYours);
+ });
+
+ it("should verify constructor - undefined args", function() {
+ assert.throws(() => new ResolveConflicts(undefined, undefined, undefined), TfvcError, /Argument is required/);
+ });
+
+ it("should verify arguments", function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ let cmd: ResolveConflicts = new ResolveConflicts(undefined, localPaths, AutoResolveType.KeepYours);
+
+ assert.equal(cmd.GetArguments().GetArgumentsForDisplay(), "resolve -noprompt " + localPaths[0] + " -auto:KeepYours");
+ });
+
+ it("should verify arguments with context", function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ let cmd: ResolveConflicts = new ResolveConflicts(context, localPaths, AutoResolveType.KeepYours);
+
+ assert.equal(cmd.GetArguments().GetArgumentsForDisplay(), "resolve -noprompt -collection:" + collectionUrl + " ******** " + localPaths[0] + " -auto:KeepYours");
+ });
+
+ it("should verify arguments with TakeTheirs", function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ let cmd: ResolveConflicts = new ResolveConflicts(context, localPaths, AutoResolveType.TakeTheirs);
+
+ assert.equal(cmd.GetArguments().GetArgumentsForDisplay(), "resolve -noprompt -collection:" + collectionUrl + " ******** " + localPaths[0] + " -auto:TakeTheirs");
+ });
+
+ it("should verify parse output - no output", async function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ let cmd: ResolveConflicts = new ResolveConflicts(undefined, localPaths, AutoResolveType.KeepYours);
+ let executionResult: IExecutionResult = {
+ exitCode: 0,
+ stdout: undefined,
+ stderr: undefined
+ };
+
+ let results: IConflict[] = await cmd.ParseOutput(executionResult);
+ assert.equal(results.length, 0);
+ });
+
+ it("should verify parse output - no errors", async function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt", "/usr/alias/repo1/file2.txt"];
+ let cmd: ResolveConflicts = new ResolveConflicts(undefined, localPaths, AutoResolveType.KeepYours);
+ let executionResult: IExecutionResult = {
+ exitCode: 0,
+ stdout: "Resolved /usr/alias/repo1/file.txt as KeepYours\n" +
+ "Resolved /usr/alias/repo1/file2.txt as KeepYours",
+ stderr: undefined
+ };
+
+ let results: IConflict[] = await cmd.ParseOutput(executionResult);
+ assert.equal(results.length, 2);
+ assert.equal(results[0].localPath, "/usr/alias/repo1/file.txt");
+ assert.equal(results[0].type, ConflictType.RESOLVED);
+ assert.equal(results[1].localPath, "/usr/alias/repo1/file2.txt");
+ assert.equal(results[1].type, ConflictType.RESOLVED);
+ });
+
+ it("should verify parse output - errors - exit code 100", async function() {
+ let localPaths: string[] = ["/usr/alias/repo1/file.txt"];
+ let cmd: ResolveConflicts = new ResolveConflicts(undefined, localPaths, AutoResolveType.KeepYours);
+ let executionResult: IExecutionResult = {
+ exitCode: 100,
+ stdout: "Something bad this way comes.",
+ stderr: undefined
+ };
+
+ try {
+ await cmd.ParseOutput(executionResult);
+ } catch (err) {
+ assert.equal(err.exitCode, 100);
+ assert.equal(err.tfvcCommand, "resolve");
+ assert.equal(err.message.indexOf(Strings.TfExecFailedError), 0);
+ assert.equal(err.stdout.indexOf("Something bad this way comes."), 0);
+ }
+ });
+});