From 0daa4e59e1991a96a1a95380412a8c1c00f123ee Mon Sep 17 00:00:00 2001 From: Jason Prickett Date: Wed, 15 Feb 2017 15:20:33 -0500 Subject: [PATCH 1/3] A little refactoring to lessen the code --- src/tfvc/tfvc-extension.ts | 113 ++++++++++--------------------------- 1 file changed, 29 insertions(+), 84 deletions(-) diff --git a/src/tfvc/tfvc-extension.ts b/src/tfvc/tfvc-extension.ts index 9457e6a5b1..2ef959c9d4 100644 --- a/src/tfvc/tfvc-extension.ts +++ b/src/tfvc/tfvc-extension.ts @@ -33,12 +33,7 @@ export class TfvcExtension { } public async TfvcCheckin(): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { // get the checkin info from the SCM viewlet const checkinInfo: ICheckinInfo = TfvcSCMProvider.GetCheckinInfo(); if (!checkinInfo) { @@ -51,88 +46,59 @@ export class TfvcExtension { await this._repo.Checkin(checkinInfo.files, checkinInfo.comment, checkinInfo.workItemIds); TfvcOutput.AppendLine("Changeset " + changeset + " checked in."); TfvcSCMProvider.ClearCheckinMessage(); - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } public async TfvcExclude(uri?: Uri): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - + this.displayErrors(async () => { if (uri) { //Keep an in-memory list of items that were explicitly excluded. The list is not persisted at this time. await TfvcSCMProvider.Exclude(TfvcSCMProvider.GetPathFromUri(uri)); } + }); } public async TfvcInclude(uri?: Uri): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } + this.displayErrors(async () => { + if (uri) { + let resource: Resource = TfvcSCMProvider.ResolveTfvcResource(uri); + let path: string = TfvcSCMProvider.GetPathFromUri(uri); - if (uri) { - let resource: Resource = TfvcSCMProvider.ResolveTfvcResource(uri); - let path: string = TfvcSCMProvider.GetPathFromUri(uri); + //At this point, an unversioned file could be a candidate file, so call Add. Once it is added, it should be a Pending change. + if (!resource.IsVersioned) { + await this._repo.Add([path]); + //Don't return after adding, we may still need to unexclude it (it may have been excluded previously) + } - //At this point, an unversioned file could be a candidate file, so call Add. Once it is added, it should be a Pending change. - if (!resource.IsVersioned) { - await this._repo.Add([path]); - //Don't return after adding, we may still need to unexclude it (it may have been excluded previously) + //Otherwise, ensure its not in the explicitly excluded list (if it's already there) + //Unexclude doesn't explicitly INclude. It defers to the status of the individual item. + await TfvcSCMProvider.Unexclude(path); } - - //Otherwise, ensure its not in the explicitly excluded list (if it's already there) - //Unexclude doesn't explicitly INclude. It defers to the status of the individual item. - await TfvcSCMProvider.Unexclude(path); - } + }); } public async TfvcOpenDiff(uri?: Uri): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { if (uri) { let resource: Resource = TfvcSCMProvider.ResolveTfvcResource(uri); TfvcSCMProvider.OpenDiff(resource); } - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } public async TfvcOpenFile(uri?: Uri): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { if (uri) { let path: string = TfvcSCMProvider.GetPathFromUri(uri); await window.showTextDocument(await workspace.openTextDocument(path)); } - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } public async TfvcRefresh(): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { TfvcSCMProvider.Refresh(); - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } public async TfvcResolve(uri: Uri, autoResolveType: AutoResolveType): Promise { @@ -162,20 +128,13 @@ export class TfvcExtension { * open the file in the editor. */ public async TfvcStatus(): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { Telemetry.SendEvent(TfvcTelemetryEvents.Status); const chosenItem: IPendingChange = await UIHelper.ChoosePendingChange(await this._repo.GetStatus()); if (chosenItem) { window.showTextDocument(await workspace.openTextDocument(chosenItem.localItem)); } - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } /** @@ -183,18 +142,11 @@ export class TfvcExtension { * displays the results to the user. */ public async TfvcSync(): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { Telemetry.SendEvent(TfvcTelemetryEvents.Sync); const results: ISyncResults = await this._repo.Sync([this._repo.Path], true); await UIHelper.ShowSyncResults(results, results.hasConflicts || results.hasErrors, true); - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } /** @@ -203,12 +155,7 @@ export class TfvcExtension { * file system watcher will update the UI soon thereafter. No results are displayed to the user. */ public async TfvcUndo(uri?: Uri): Promise { - if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { - this._manager.DisplayErrorMessage(); - return; - } - - try { + this.displayErrors(async () => { //When calling from UI, we have the uri of the resource from which the command was invoked let pathToUndo: string = TfvcSCMProvider.GetPathFromUri(uri); if (!pathToUndo) { @@ -225,9 +172,7 @@ export class TfvcExtension { await this._repo.Undo([pathToUndo]); } } - } catch (err) { - this._manager.DisplayErrorMessage(err.message); - } + }); } /** From 41f660e8eace99af3fb30ec60f1f8d205b3db162 Mon Sep 17 00:00:00 2001 From: Jason Prickett Date: Wed, 15 Feb 2017 15:27:19 -0500 Subject: [PATCH 2/3] More refactoring to remove TFVC in method names --- src/extension.ts | 24 ++++++++++++------------ src/team-extension.ts | 2 +- src/tfvc/repository.ts | 12 ++++++------ src/tfvc/tfvc-extension.ts | 24 ++++++++++++------------ 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index f2457d3c1d..70e8be9430 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -45,30 +45,30 @@ export async function activate(context: ExtensionContext) { context.subscriptions.push(commands.registerCommand(CommandNames.Reinitialize, () => _extensionManager.Reinitialize())); // TFVC Commands - context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Status, () => _extensionManager.Tfvc.TfvcStatus())); + context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Status, () => _extensionManager.Tfvc.Status())); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Undo, (...args) => { - _extensionManager.Tfvc.TfvcUndo(args ? args[0] : undefined); + _extensionManager.Tfvc.Undo(args ? args[0] : undefined); })); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Exclude, (...args) => { - _extensionManager.Tfvc.TfvcExclude(args ? args[0] : undefined); + _extensionManager.Tfvc.Exclude(args ? args[0] : undefined); })); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Include, (...args) => { - _extensionManager.Tfvc.TfvcInclude(args ? args[0] : undefined); + _extensionManager.Tfvc.Include(args ? args[0] : undefined); })); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.OpenDiff, (...args) => { - _extensionManager.Tfvc.TfvcOpenDiff(args ? args[0] : undefined); + _extensionManager.Tfvc.OpenDiff(args ? args[0] : undefined); })); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.OpenFile, (...args) => { - _extensionManager.Tfvc.TfvcOpenFile(args ? args[0] : undefined); + _extensionManager.Tfvc.OpenFile(args ? args[0] : undefined); })); - 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.Refresh, () => _extensionManager.Tfvc.Refresh())); + context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ShowOutput, () => _extensionManager.Tfvc.ShowOutput())); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ResolveKeepYours, (...args) => { - _extensionManager.Tfvc.TfvcResolve(args ? args[0] : undefined, AutoResolveType.KeepYours); + _extensionManager.Tfvc.Resolve(args ? args[0] : undefined, AutoResolveType.KeepYours); })); context.subscriptions.push(commands.registerCommand(TfvcCommandNames.ResolveTakeTheirs, (...args) => { - _extensionManager.Tfvc.TfvcResolve(args ? args[0] : undefined, AutoResolveType.TakeTheirs); + _extensionManager.Tfvc.Resolve(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())); + context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Checkin, () => _extensionManager.Tfvc.Checkin())); + context.subscriptions.push(commands.registerCommand(TfvcCommandNames.Sync, () => _extensionManager.Tfvc.Sync())); } diff --git a/src/team-extension.ts b/src/team-extension.ts index a6f98073ae..9817a28b1a 100644 --- a/src/team-extension.ts +++ b/src/team-extension.ts @@ -146,7 +146,7 @@ export class TeamExtension { if (this._manager.RepoContext.Type === RepositoryType.GIT && this._gitClient) { this._gitClient.OpenFileHistory(this._manager.RepoContext); } else if (this._manager.RepoContext.Type === RepositoryType.TFVC) { - this._manager.Tfvc.TfvcViewHistory(); + this._manager.Tfvc.ViewHistory(); } else { this._manager.DisplayErrorMessage(Strings.NoRepoInformation); } diff --git a/src/tfvc/repository.ts b/src/tfvc/repository.ts index 659d19e218..a72ad888be 100644 --- a/src/tfvc/repository.ts +++ b/src/tfvc/repository.ts @@ -55,18 +55,18 @@ export class Repository { return this._repositoryRootFolder; } - public async Checkin(files: string[], comment: string, workItemIds: number[]): Promise { - Logger.LogDebug(`TFVC Repository.Checkin`); - return this.RunCommand( - new Checkin(this._serverContext, files, comment, workItemIds)); - } - public async Add(itemPaths: string[]): Promise { Logger.LogDebug(`TFVC Repository.Add`); return this.RunCommand( new Add(this._serverContext, itemPaths)); } + public async Checkin(files: string[], comment: string, workItemIds: number[]): Promise { + Logger.LogDebug(`TFVC Repository.Checkin`); + return this.RunCommand( + new Checkin(this._serverContext, files, comment, workItemIds)); + } + public async FindConflicts(itemPath?: string): Promise { Logger.LogDebug(`TFVC Repository.FindConflicts`); return this.RunCommand( diff --git a/src/tfvc/tfvc-extension.ts b/src/tfvc/tfvc-extension.ts index 2ef959c9d4..83f59a1d5a 100644 --- a/src/tfvc/tfvc-extension.ts +++ b/src/tfvc/tfvc-extension.ts @@ -32,7 +32,7 @@ export class TfvcExtension { this._manager = manager; } - public async TfvcCheckin(): Promise { + public async Checkin(): Promise { this.displayErrors(async () => { // get the checkin info from the SCM viewlet const checkinInfo: ICheckinInfo = TfvcSCMProvider.GetCheckinInfo(); @@ -49,7 +49,7 @@ export class TfvcExtension { }); } - public async TfvcExclude(uri?: Uri): Promise { + public async Exclude(uri?: Uri): Promise { this.displayErrors(async () => { if (uri) { //Keep an in-memory list of items that were explicitly excluded. The list is not persisted at this time. @@ -58,7 +58,7 @@ export class TfvcExtension { }); } - public async TfvcInclude(uri?: Uri): Promise { + public async Include(uri?: Uri): Promise { this.displayErrors(async () => { if (uri) { let resource: Resource = TfvcSCMProvider.ResolveTfvcResource(uri); @@ -77,7 +77,7 @@ export class TfvcExtension { }); } - public async TfvcOpenDiff(uri?: Uri): Promise { + public async OpenDiff(uri?: Uri): Promise { this.displayErrors(async () => { if (uri) { let resource: Resource = TfvcSCMProvider.ResolveTfvcResource(uri); @@ -86,7 +86,7 @@ export class TfvcExtension { }); } - public async TfvcOpenFile(uri?: Uri): Promise { + public async OpenFile(uri?: Uri): Promise { this.displayErrors(async () => { if (uri) { let path: string = TfvcSCMProvider.GetPathFromUri(uri); @@ -95,13 +95,13 @@ export class TfvcExtension { }); } - public async TfvcRefresh(): Promise { + public async Refresh(): Promise { this.displayErrors(async () => { TfvcSCMProvider.Refresh(); }); } - public async TfvcResolve(uri: Uri, autoResolveType: AutoResolveType): Promise { + public async Resolve(uri: Uri, autoResolveType: AutoResolveType): Promise { this.displayErrors(async () => { if (uri) { let localPath: string = TfvcSCMProvider.GetPathFromUri(uri); @@ -118,7 +118,7 @@ export class TfvcExtension { }); } - public async TfvcShowOutput(): Promise { + public async ShowOutput(): Promise { TfvcOutput.Show(); } @@ -127,7 +127,7 @@ export class TfvcExtension { * 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 { + public async Status(): Promise { this.displayErrors(async () => { Telemetry.SendEvent(TfvcTelemetryEvents.Status); const chosenItem: IPendingChange = await UIHelper.ChoosePendingChange(await this._repo.GetStatus()); @@ -141,7 +141,7 @@ export class TfvcExtension { * This command runs a 'tf get' command on the VSCode workspace folder and * displays the results to the user. */ - public async TfvcSync(): Promise { + public async Sync(): Promise { this.displayErrors(async () => { Telemetry.SendEvent(TfvcTelemetryEvents.Sync); const results: ISyncResults = await this._repo.Sync([this._repo.Path], true); @@ -154,7 +154,7 @@ export class TfvcExtension { * editor. If the undo command applies to the file, the pending changes will be undone. The * file system watcher will update the UI soon thereafter. No results are displayed to the user. */ - public async TfvcUndo(uri?: Uri): Promise { + public async Undo(uri?: Uri): Promise { this.displayErrors(async () => { //When calling from UI, we have the uri of the resource from which the command was invoked let pathToUndo: string = TfvcSCMProvider.GetPathFromUri(uri); @@ -179,7 +179,7 @@ export class TfvcExtension { * This command runs the info command on the passed in itemPath and * opens a web browser to the appropriate history page. */ - public async TfvcViewHistory(): Promise { + public async ViewHistory(): Promise { if (!this._manager.EnsureInitialized(RepositoryType.TFVC)) { this._manager.DisplayErrorMessage(); return; From 8d06fa5860e722343878bfebc14eba8771ec60e7 Mon Sep 17 00:00:00 2001 From: Jason Prickett Date: Wed, 15 Feb 2017 16:01:15 -0500 Subject: [PATCH 3/3] Parsing work item ids out of message for associate --- src/tfvc/tfvcscmprovider.ts | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/tfvc/tfvcscmprovider.ts b/src/tfvc/tfvcscmprovider.ts index e9d6842a43..2b5d7af321 100644 --- a/src/tfvc/tfvcscmprovider.ts +++ b/src/tfvc/tfvcscmprovider.ts @@ -50,7 +50,7 @@ export class TfvcSCMProvider implements SCMProvider { try { const files: string[] = []; const commitMessage: string = scm.inputBox.value; - const workItemIds: number[] = []; + const workItemIds: number[] = TfvcSCMProvider.getWorkItemIdsFromMessage(commitMessage); const resources: Resource[] = tfvcProvider._model.IncludedGroup.resources; if (!resources || resources.length === 0) { @@ -72,6 +72,26 @@ export class TfvcSCMProvider implements SCMProvider { } } + private static getWorkItemIdsFromMessage(message: string) { + let ids: number[] = []; + try { + // Find all the work item mentions in the string. + // This returns an array like: ["#1", "#12", "#33"] + const matches: string[] = message ? message.match(/#(\d+)/gm) : []; + if (matches) { + for (let i: number = 0; i < matches.length; i++) { + const id: number = parseInt(matches[i].slice(1)); + if (!isNaN(id)) { + ids.push(id); + } + } + } + } catch (err) { + Logger.LogDebug("Failed to get all workitems from message: " + message); + } + return ids; + } + public static async Exclude(path: string): Promise { const tfvcProvider: TfvcSCMProvider = TfvcSCMProvider.GetProviderInstance();