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

Status cmd is working - still have a few TODOs #68

Merged
merged 2 commits into from
Jan 28, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
"underscore": "^1.8.3",
"url": "^0.11.0",
"vso-node-api": "^5.1.1",
"winston": "^2.1.1"
"winston": "^2.1.1",
"xml2js": "^0.4.17"
}
}
5 changes: 4 additions & 1 deletion src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@
import { commands, ExtensionContext } from "vscode";
import { CommandNames, TfvcCommandNames } from "./helpers/constants";
import { TeamExtension } from "./team-extension";
import { TfvcExtension } from "./tfvc/tfvc-extension";

var teamExtension: TeamExtension;
var tfvcExtension: TfvcExtension;

export function activate(context: ExtensionContext) {
teamExtension = new TeamExtension();
tfvcExtension = new TfvcExtension();

context.subscriptions.push(commands.registerCommand(CommandNames.GetPullRequests, () => teamExtension.GetMyPullRequests()));
context.subscriptions.push(commands.registerCommand(CommandNames.Login, () => teamExtension.Login()));
Expand All @@ -33,5 +36,5 @@ export function activate(context: ExtensionContext) {
context.subscriptions.push(commands.registerCommand(CommandNames.Reinitialize, () => teamExtension.Reinitialize()));

// TFVC Commands
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Status, () => teamExtension.TfvcStatus()));
context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Status, () => tfvcExtension.TfvcStatus()));
}
27 changes: 0 additions & 27 deletions src/team-extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,6 @@ import { GitClient } from "./clients/gitclient";
import { WitClient } from "./clients/witclient";
import { RepositoryInfo } from "./info/repositoryinfo";
import { UserInfo } from "./info/userinfo";
import { Tfvc } from "./tfvc/tfvc";
import { Repository } from "./tfvc/repository";
import { IWorkspace } from "./tfvc/interfaces";

var os = require("os");
var path = require("path");
Expand Down Expand Up @@ -297,30 +294,6 @@ export class TeamExtension {
}
}

/********* TFVC Commands - START *************/

//Run the TF status command and display the results
public async TfvcStatus(): Promise<void> {
if (this.ensureInitialized()) {
if (!workspace || !workspace.rootPath) {
return;
}

try {
const tfvc: Tfvc = new Tfvc();
const repo: Repository = tfvc.Open(workspace.rootPath);
const tfvcWorkspace: IWorkspace = await repo.FindWorkspace(workspace.rootPath);
VsCodeUtils.ShowWarningMessage(tfvcWorkspace.name + " | " + tfvcWorkspace.server);
} catch (err) {
VsCodeUtils.ShowErrorMessage(err);
}
} else {
VsCodeUtils.ShowErrorMessage(this._errorMessage);
}
}

/********* TFVC Commands - END *************/

private displayNoCredentialsMessage(): void {
let error: string = Strings.NoTeamServerCredentialsRunLogin;
let displayError: string = Strings.NoTeamServerCredentialsRunLogin;
Expand Down
45 changes: 45 additions & 0 deletions src/tfvc/commands/commandhelper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*---------------------------------------------------------------------------------------------
* 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 { parseString } from "xml2js";

export class CommandHelper {
public static async ParseXml(xml: string): Promise<any> {
return new Promise<any>((resolve, reject) => {
parseString(
xml,
{
tagNameProcessors: [CommandHelper.normalizeName],
attrNameProcessors: [CommandHelper.normalizeName]
},
(err, result) => {
if (err) {
reject(err);
} else {
resolve(result);
}
});
});
}

public static TrimToXml(xml: string): string {
if (xml) {
const start: number = xml.indexOf("<?xml");
const end: number = xml.lastIndexOf(">");
if (start >= 0 && end > start) {
return xml.slice(start, end + 1);
}
}
return xml;
}

private static normalizeName(name: string): string {
if (name) {
return name.replace(/\-/g, "").toLowerCase();
}
return name;
}
}
2 changes: 1 addition & 1 deletion src/tfvc/commands/findworkspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export class FindWorkspace implements ITfvcCommand<IWorkspace> {
* Collection: http://java-tfs2015:8081/tfs/
* $/tfsTest_01: D:\tmp\test
*/
public ParseOutput(executionResult: IExecutionResult): IWorkspace {
public async ParseOutput(executionResult: IExecutionResult): Promise<IWorkspace> {
const stdout = executionResult.stdout;

// Find the workspace name and collectionUrl
Expand Down
2 changes: 1 addition & 1 deletion src/tfvc/commands/getversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export class GetVersion implements ITfvcCommand<string> {
return {};
}

public ParseOutput(executionResult: IExecutionResult): string {
public async ParseOutput(executionResult: IExecutionResult): Promise<string> {
const stdout = executionResult.stdout;
// Find just the version number and return it. Ex. Team Explorer Everywhere Command Line Client (Version 14.0.3.201603291047)
return stdout.replace(/(.*\(version )([\.\d]*)(\).*)/i, "$2");
Expand Down
106 changes: 106 additions & 0 deletions src/tfvc/commands/status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*---------------------------------------------------------------------------------------------
* 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 { IExecutionResult, ITfvcCommand, IPendingChange } from "../interfaces";
import { ArgumentBuilder } from "./argumentbuilder";
import { CommandHelper } from "./commandhelper";

var fs = require("fs");

/**
* This command returns the status of the workspace as a list of pending changes.
* NOTE: Currently this command does not support all of the options of the command line
* <p/>
* status [/workspace:<value>] [/shelveset:<value>] [/format:brief|detailed|xml] [/recursive] [/user:<value>] [/nodetect] [<itemSpec>...]
*/
export class Status implements ITfvcCommand<IPendingChange[]> {
private _localPaths: string[];
private _ignoreFolers: boolean;

public constructor(ignoreFolders: boolean, localPaths?: string[]) {
this._ignoreFolers = ignoreFolders;
this._localPaths = localPaths;
}

//TODO need to pass in context here as an optional parameter
public GetArguments(): string[] {
const builder: ArgumentBuilder = new ArgumentBuilder("status")
.AddSwitchWithValue("format", "xml", false)
.AddSwitch("recursive");

if (this._localPaths && this._localPaths.length > 0) {
for (let i = 0; i < this._localPaths.length; i++) {
builder.Add(this._localPaths[i]);
}
}

return builder.Build();
}

public GetOptions(): any {
return {};
}

/**
* Parses the output of the status command when formatted as xml.
* SAMPLE
* <?xml version="1.0" encoding="utf-8"?>
* <status>
* <pending-changes/>
* <candidate-pending-changes>
* <pending-change server-item="$/tfsTest_01/test.txt" version="0" owner="jason" date="2016-07-13T12:36:51.060-0400" lock="none" change-type="add" workspace="MyNewWorkspace2" computer="JPRICKET-DEV2" local-item="D:\tmp\test\test.txt"/>
* </candidate-pending-changes>
* </status>
*/
public async ParseOutput(executionResult: IExecutionResult): Promise<IPendingChange[]> {
let changes: IPendingChange[] = [];
const xml: string = CommandHelper.TrimToXml(executionResult.stdout);
// Parse the xml using xml2js
const json: any = await CommandHelper.ParseXml(xml);
if (json && json.status) {
// get all the pending changes first
const pending: any = json.status.pendingchanges[0].pendingchange;
for (let i = 0; i < pending.length; i++) {
this.add(changes, this.convert(pending[i].$, false), this._ignoreFolers);
}
// next, get all the candidate pending changes
const candidate: any = json.status.candidatependingchanges[0].pendingchange;
for (let i = 0; i < candidate.length; i++) {
this.add(changes, this.convert(candidate[i].$, false), this._ignoreFolers);
}
}
return changes;
}

private add(changes: IPendingChange[], newChange: IPendingChange, ignoreFolders: boolean) {
if (ignoreFolders) {
// check to see if the local item is a file or folder
const f: string = newChange.localItem;
const stats: any = fs.lstatSync(f);
if (stats.isDirectory()) {
// It's a directory/folder and we don't want those
return;
}
}
changes.push(newChange);
}

private convert(jsonChange: any, isCandidate: boolean): IPendingChange {
// TODO check to make sure jsonChange is valid
return {
changeType: jsonChange.changetype,
computer: jsonChange.computer,
date: jsonChange.date,
localItem: jsonChange.localitem,
lock: jsonChange.lock,
owner: jsonChange.owner,
serverItem: jsonChange.serveritem,
version: jsonChange.version,
workspace: jsonChange.workspace,
isCandidate: isCandidate
};
}
}
18 changes: 12 additions & 6 deletions src/tfvc/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,17 @@ export interface IWorkspace {
//List<Mapping> mappings;
}

export interface IFileStatus {
x: string;
y: string;
path: string;
rename?: string;
export interface IPendingChange {
changeType: string;
computer: string;
date: string;
localItem: string;
lock: string;
owner: string;
serverItem: string;
version: string;
workspace: string;
isCandidate: boolean;
}

export interface IExecutionResult {
Expand All @@ -45,5 +51,5 @@ export interface ITfvcErrorData {
export interface ITfvcCommand<T> {
GetArguments(): string[];
GetOptions(): any;
ParseOutput(executionResult: IExecutionResult): T;
ParseOutput(executionResult: IExecutionResult): Promise<T>;
}
14 changes: 12 additions & 2 deletions src/tfvc/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@

import { ITfvcCommand, IExecutionResult } from "./interfaces";
import { Tfvc } from "./tfvc";
import { IWorkspace } from "./interfaces";
import { IWorkspace, IPendingChange } from "./interfaces";
import { GetVersion } from "./commands/getversion";
import { FindWorkspace } from "./commands/findworkspace";
import { Status } from "./commands/status";

var _ = require("underscore");

/**
* The Repository class allows you to perform TFVC commands on the workspace represented
* by the repositoryRootFolder.
*/
export class Repository {

public constructor(
Expand All @@ -33,14 +38,19 @@ export class Repository {
new FindWorkspace(localPath));
}

public async GetStatus(ignoreFiles?: boolean): Promise<IPendingChange[]> {
return this.RunCommand<IPendingChange[]>(
new Status(ignoreFiles === undefined ? true : ignoreFiles));
}

public async Version(): Promise<string> {
return this.RunCommand<string>(
new GetVersion());
}

public async RunCommand<T>(cmd: ITfvcCommand<T>): Promise<T> {
const result = await this.exec(cmd.GetArguments(), cmd.GetOptions());
return cmd.ParseOutput(result);
return await cmd.ParseOutput(result);
}

private async exec(args: string[], options: any = {}): Promise<IExecutionResult> {
Expand Down
38 changes: 38 additions & 0 deletions src/tfvc/tfvc-extension.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* 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 { window, workspace } from "vscode";
import { VsCodeUtils } from "../helpers/vscodeutils";
import { Tfvc } from "./tfvc";
import { Repository } from "./repository";
import { UIHelper } from "./uihelper";
import { IPendingChange } from "./interfaces";

export class TfvcExtension {
/**
* This command runs a status command on the VSCode workspace folder and
* displays the results to the user. Selecting one of the files in the list will
* open the file in the editor.
*/
public async TfvcStatus(): Promise<void> {
// TODO cache the tfvc/repository instances for all commands
// TODO hook into reinitialize logic like TeamExtension
if (!workspace || !workspace.rootPath) {
return;
}

try {
const tfvc: Tfvc = new Tfvc();
const repo: Repository = tfvc.Open(workspace.rootPath);
const chosenItem: IPendingChange = await UIHelper.ChoosePendingChange(await repo.GetStatus());
if (chosenItem) {
window.showTextDocument(await workspace.openTextDocument(chosenItem.localItem));
}
} catch (err) {
VsCodeUtils.ShowErrorMessage(err);
}
}
}
4 changes: 3 additions & 1 deletion src/tfvc/tfvc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ export class Tfvc {
tfvcErrorCode: TfvcErrorCodes.TfvcNotFound
});
}
//TODO check the version of TFVC command line
}
//TODO check to make sure that the file exists in that location
//TODO check the version of TFVC command line

}

public Open(repositoryRootFolder: string, env: any = {}): Repository {
Expand Down
Loading