Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
Add checks for non-ENU tf(.exe) (#158)
Browse files Browse the repository at this point in the history
* Remove optional settings

* Add return type for CheckVersion

* Check for non-ENU tf(.exe)

* Add support for Spanish, French and German

These are 3 of the supported tf (VS) languages and are all a bit different from each other.

* Ensure initialize and reinitialize only occur for TFVC
  • Loading branch information
Jeff Young authored Mar 21, 2017
1 parent 16fe713 commit 435bf91
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 14 deletions.
4 changes: 2 additions & 2 deletions src/contexts/repocontextfactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@ export class RepositoryContextFactory {
//Check for Git next since it should be faster to determine and this code will
//be called on Reinitialize (when config changes, for example)
repoContext = new GitContext(path);
initialized = await repoContext.Initialize(settings);
initialized = await repoContext.Initialize();
if (!repoContext || repoContext.IsTeamFoundation === false || !initialized) {
//Check if we have a TFVC repository
repoContext = new TfvcContext(path);
initialized = await repoContext.Initialize(settings);
initialized = await repoContext.Initialize();
if (!initialized) {
return undefined;
}
Expand Down
3 changes: 3 additions & 0 deletions src/contexts/tfvccontext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export class TfvcContext implements IRepositoryContext {
public async Initialize(): Promise<boolean> {
Logger.LogDebug(`Looking for TFVC repository at ${this._tfvcFolder}`);
this._repo = TfCommandLineRunner.CreateRepository(undefined, this._tfvcFolder);
//Ensure we have an appropriate ENU version of tf executable
//The call will throw if we have tf configured properly but it isn't ENU
await this._repo.CheckVersion();
this._tfvcWorkspace = await this._repo.FindWorkspace(this._tfvcFolder);
this._tfvcRemoteUrl = this._tfvcWorkspace.server;
this._isTeamServicesUrl = RepoUtils.IsTeamFoundationServicesRepo(this._tfvcRemoteUrl);
Expand Down
23 changes: 13 additions & 10 deletions src/extensionmanager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,16 @@ export class ExtensionManager implements Disposable {
}
}
}

// Now that everything else is ready, create the SCM provider
if (this._repoContext.Type === RepositoryType.TFVC) {
if (!this._scmProvider) {
this._scmProvider = new TfvcSCMProvider(this);
await this._scmProvider.Initialize();
} else {
await this._scmProvider.Reinitialize();
}
}
}).fail((err) => {
this.setErrorStatus(Utils.GetMessageForStatusCode(err, err.message), (err.statusCode === 401 ? CommandNames.Signin : undefined), false);
//If we can't get a requestHandler, report the error via the feedbackclient
Expand All @@ -283,15 +293,6 @@ export class ExtensionManager implements Disposable {
Telemetry.SendException(err);
});
}

// Now that everything else is ready, create the SCM provider
if (!this._scmProvider) {
this._scmProvider = new TfvcSCMProvider(this);
await this._scmProvider.Initialize();
} else {
await this._scmProvider.Reinitialize();
}

} catch (err) {
Logger.LogError(err.message);
//For now, don't report these errors via the _feedbackClient
Expand All @@ -317,7 +318,8 @@ export class ExtensionManager implements Disposable {
//Determines which Tfvc errors to display in the status bar ui
private shouldDisplayTfvcError(errorCode: string): boolean {
if (TfvcErrorCodes.TfvcMinVersionWarning === errorCode ||
TfvcErrorCodes.TfvcNotFound === errorCode) {
TfvcErrorCodes.TfvcNotFound === errorCode ||
TfvcErrorCodes.NotAnEnuTfCommandLine === errorCode) {
return true;
}
return false;
Expand Down Expand Up @@ -383,6 +385,7 @@ export class ExtensionManager implements Disposable {
private setErrorStatus(message: string, commandOnClick?: string, showRetryMessage?: boolean) {
this._errorMessage = message;
if (this._teamServicesStatusBarItem !== undefined) {
//TODO: Should the default command be to do nothing? Or perhaps to display the message?
this._teamServicesStatusBarItem.command = commandOnClick === undefined ? CommandNames.Reinitialize : commandOnClick;
this._teamServicesStatusBarItem.text = "Team " + `$(icon octicon-stop)`;
let message: string = this._errorMessage + (showRetryMessage !== undefined && showRetryMessage === true ? " " + Strings.ClickToRetryConnection : "") ;
Expand Down
1 change: 1 addition & 0 deletions src/helpers/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export class Strings {
static ChooseItemQuickPickPlaceHolder: string = "Choose a file to open it.";
static NotAGitRepository: string = "The open folder is not a Git repository. Please check the folder location and try again.";
static NotATfvcRepository: string = "The open folder is not a TFVC repository. Please check the folder location and try again.";
static NotAnEnuTfCommandLine: string = "It appears you have configured a non-English version of the TF executable. Please ensure an English version is properly configured.";
static TokenNotAllScopes: string = "The personal access token provided does not have All Scopes. All Scopes is required for TFVC support.";
static TfvcLocationMissingError: string = "The path to the TFVC command line was not found in the user settings. Please set this value (tfvc.location) and try again.";
static TfMissingError: string = "Unable to find the TF executable at the expected location. Please verify the installation and location of TF. Expected path: ";
Expand Down
10 changes: 10 additions & 0 deletions src/tfvc/commands/findworkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,16 @@ export class FindWorkspace implements ITfvcCommand<IWorkspace> {
tfvcErrorCode: TfvcErrorCodes.NotATfvcRepository
});
}
//If there are mappings but no workspace name, the term 'workspace' couldn't be parsed. According to Bing
//translate, other than Klingon, no other supported language translates 'workspace' as 'workspace'.
//So if we determine there are mappings but can't get the workspace name, we assume it's a non-ENU
//tf executable. One example of this is German.
if (mappings.length > 0 && !workspaceName) {
throw new TfvcError( {
message: Strings.NotAnEnuTfCommandLine,
tfvcErrorCode: TfvcErrorCodes.NotAnEnuTfCommandLine
});
}

const workspace: IWorkspace = {
name: workspaceName,
Expand Down
22 changes: 21 additions & 1 deletion src/tfvc/commands/getversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import { IArgumentProvider, IExecutionResult, ITfvcCommand } from "../interfaces";
import { ArgumentBuilder } from "./argumentbuilder";
import { CommandHelper } from "./commandhelper";
import { TfvcError, TfvcErrorCodes } from "../tfvcerror";
import { Strings } from "../../helpers/strings";

/**
* This command calls the command line doing a simple call to get the help for the add command.
Expand Down Expand Up @@ -48,7 +50,25 @@ export class GetVersion implements ITfvcCommand<string> {
const lines: string[] = CommandHelper.SplitIntoLines(executionResult.stdout);
// Find just the version number and return it. Ex. Microsoft (R) TF - Team Foundation Version Control Tool, Version 14.102.25619.0
if (lines && lines.length > 0) {
let value: string = lines[0].replace(expression, "$2");
let value: string = lines[0].replace(expression, "$2"); //Example: 14.111.1.201612142018
//Spanish tf.exe example: "Microsoft (R) TF - Herramienta Control de versiones de Team Foundation, versi�n 14.102.25619.0"
//value = "Microsoft (R) TF - Herramienta Control de versiones de Team Foundation, versi�n 14.102.25619.0"
//French tf.exe example: "Microsoft (R) TF�- Outil Team Foundation Version Control, version�14.102.25619.0"
//value = ""
//German tf.exe example: "Microsoft (R) TF - Team Foundation-Versionskontrolltool, Version 14.102.25619.0"
//value = "14.102.25619.0"
//Check to see if we have either less or more than the version string. Less is the French case (and the like). More is
//the Spanish case (and the like). If we do, we assume that we are using a non-ENU tf executable. So if we get here,
//we were able to run tf but we might not have gotten the version fron an ENU tf. So even if we did get a version string,
//we will still need to check later if this version is from a non-ENU SKU.
let items: string[] = value.split(" ");
if (!value || items.length > 1) {
//This error is an early-out in the cases of Spanish and French (which translate version). German will continue normally.
throw new TfvcError({
message: Strings.NotAnEnuTfCommandLine,
tfvcErrorCode: TfvcErrorCodes.NotAnEnuTfCommandLine
});
}
return value;
} else {
return "";
Expand Down
2 changes: 1 addition & 1 deletion src/tfvc/tfcommandlinerunner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class TfCommandLineRunner {
* This method checks the version of the CLC against the minimum version that we expect.
* It throws an error if the version does not meet or exceed the minimum.
*/
public static CheckVersion(tfvc: ITfCommandLine, version: string) {
public static CheckVersion(tfvc: ITfCommandLine, version: string): void {
if (!version) {
// If the version isn't set just return
Logger.LogDebug(`TFVC CheckVersion called without a version.`);
Expand Down
1 change: 1 addition & 0 deletions src/tfvc/tfvcerror.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class TfvcErrorCodes {
public static get MissingArgument(): string { return "MissingArgument"; }
public static get AuthenticationFailed(): string { return "AuthenticationFailed"; }
public static get NotATfvcRepository(): string { return "NotATfvcRepository"; }
public static get NotAnEnuTfCommandLine(): string { return "NotAnEnuTfCommandLine"; }
public static get TfvcLocationMissing(): string { return "TfvcLocationMissing"; }
public static get TfvcNotFound(): string { return "TfvcNotFound"; }
public static get TfvcMinVersionWarning(): string { return "TfvcMinVersionWarning"; }
Expand Down
40 changes: 40 additions & 0 deletions test/tfvc/commands/findworkspace.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,26 @@ describe("Tfvc-FindWorkspaceCommand", function() {
assert.equal(workspace.mappings.length, 1);
});

it("should verify parse output - German - no 'workspace' and 'collection'", async function() {
let localPath: string = "/path/to/workspace";
let cmd: FindWorkspace = new FindWorkspace(localPath);
let executionResult: IExecutionResult = {
exitCode: 0,
stdout: "=====================================================================================================================================================\n" +
"Arbeitsbereich: DESKTOP-KI56MCL (Jeff Young (TFS))\n" +
"Sammlung : http://java-tfs2015:8081/tfs/defaultcollection\n" +
"$/project1: /path",
stderr: undefined
};

try {
await cmd.ParseOutput(executionResult);
} catch (err) {
assert.isTrue(err.message.startsWith(Strings.NotAnEnuTfCommandLine));
assert.equal(err.tfvcErrorCode, TfvcErrorCodes.NotAnEnuTfCommandLine);
}
});

it("should verify parse output - not a tf workspace", async function() {
let localPath: string = "/path/to/workspace";
let cmd: FindWorkspace = new FindWorkspace(localPath);
Expand Down Expand Up @@ -177,6 +197,26 @@ describe("Tfvc-FindWorkspaceCommand", function() {
assert.equal(workspace.mappings.length, 1);
});

it("should verify parse EXE output - German - no 'workspace' and 'collection'", async function() {
let localPath: string = "/path/to/workspace";
let cmd: FindWorkspace = new FindWorkspace(localPath);
let executionResult: IExecutionResult = {
exitCode: 0,
stdout: "=====================================================================================================================================================\n" +
"Arbeitsbereich: DESKTOP-KI56MCL (Jeff Young (TFS))\n" +
"Sammlung : http://java-tfs2015:8081/tfs/defaultcollection\n" +
"$/project1: /path",
stderr: undefined
};

try {
await cmd.ParseExeOutput(executionResult);
} catch (err) {
assert.isTrue(err.message.startsWith(Strings.NotAnEnuTfCommandLine));
assert.equal(err.tfvcErrorCode, TfvcErrorCodes.NotAnEnuTfCommandLine);
}
});

it("should verify parse EXE output - not a tf workspace", async function() {
let localPath: string = "/path/to/workspace";
let cmd: FindWorkspace = new FindWorkspace(localPath);
Expand Down
44 changes: 44 additions & 0 deletions test/tfvc/commands/getversion.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import { assert } from "chai";
import { GetVersion } from "../../../src/tfvc/commands/getversion";
import { IExecutionResult } from "../../../src/tfvc/interfaces";
import { TfvcErrorCodes } from "../../../src/tfvc/tfvcerror";
import { Strings } from "../../../src/helpers/strings";

describe("Tfvc-GetVersionCommand", function() {
Expand Down Expand Up @@ -115,4 +116,47 @@ describe("Tfvc-GetVersionCommand", function() {
}
});

it("should verify parse EXE output - Spanish version", async function() {
let cmd: GetVersion = new GetVersion();
let executionResult: IExecutionResult = {
exitCode: 0,
stdout: "Microsoft (R) TF - Herramienta Control de versiones de Team Foundation, versi�n 14.102.25619.0",
stderr: undefined
};

try {
await cmd.ParseExeOutput(executionResult);
} catch (err) {
assert.equal(err.tfvcErrorCode, TfvcErrorCodes.NotAnEnuTfCommandLine);
assert.isTrue(err.message.startsWith(Strings.NotAnEnuTfCommandLine));
}
});

it("should verify parse EXE output - French version", async function() {
let cmd: GetVersion = new GetVersion();
let executionResult: IExecutionResult = {
exitCode: 0,
stdout: "Microsoft (R) TF�- Outil Team Foundation Version Control, version�14.102.25619.0",
stderr: undefined
};

try {
await cmd.ParseExeOutput(executionResult);
} catch (err) {
assert.equal(err.tfvcErrorCode, TfvcErrorCodes.NotAnEnuTfCommandLine);
assert.isTrue(err.message.startsWith(Strings.NotAnEnuTfCommandLine));
}
});

it("should verify parse EXE output - German version", async function() {
let cmd: GetVersion = new GetVersion();
let executionResult: IExecutionResult = {
exitCode: 0,
stdout: "Microsoft (R) TF - Team Foundation-Versionskontrolltool, Version 14.102.25619.0",
stderr: undefined
};

let version: string = await cmd.ParseExeOutput(executionResult);
assert.equal(version, "14.102.25619.0");
});
});

0 comments on commit 435bf91

Please sign in to comment.