From 4dfe134df0008deb4276760ddb5cc399e335fd06 Mon Sep 17 00:00:00 2001 From: Ryan Luker Date: Sun, 23 Apr 2017 11:36:45 -0700 Subject: [PATCH] Add visible editor watch and cleanup dispose / tests (#50) * bump vscode engine to latest version * remove config metrics and use env var * update docs and package * add visible editor feature and rework tests * increment extension version and add vscodeVersion * add changelog and increment package version --- CHANGELOG.md | 7 +++++ README.md | 4 ++- package.json | 33 +++++++++++++++++++++--- src/config.ts | 8 ------ src/extension.ts | 5 ++++ src/gutters.ts | 60 ++++++++++++++++++++----------------------- src/reporter.ts | 10 +++----- test/gutters.test.ts | 22 ---------------- test/reporter.test.ts | 21 +++++++++++++++ 9 files changed, 97 insertions(+), 73 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c3d6e6..c1d21ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +### 0.5.0 +[Github Milestone](https://github.com/ryanluker/vscode-coverage-gutters/milestone/5?closed=1) +- added file watch and render feature +- added metrics for vscodeVersion +- use environment variables for ga tracking id +- cleanup tests + ### 0.4.0 [Github Milestone](https://github.com/ryanluker/vscode-coverage-gutters/milestone/4?closed=1) - added keybindings and shortcuts diff --git a/README.md b/README.md index e723c25..ef1c932 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ - colour compatibility with light and dark themes ## Requirements -- vscode 1.9.0 and up +- vscode 1.11.x and up - macos, linux or windows ## Extension Settings @@ -42,9 +42,11 @@ |`coverage-gutters.showGutterCoverage`|Show or hide the gutter coverage |`coverage-gutters.customizable.menus-editor-context-displayCoverage-enabled`|Setting this to false will remove the command from the editor context menu and vice versa |`coverage-gutters.customizable.menus-editor-context-watchLcovFile-enabled`|Setting this to false will remove the command from the editor context menu and vice versa +|`coverage-gutters.customizable.menus-editor-context-watchVisibleEditors-enabled`|Setting this to false will remove the command from the editor context menu and vice versa |`coverage-gutters.customizable.menus-editor-context-removeCoverage-enabled`|Setting this to false will remove the command from the editor context menu and vice versa |`coverage-gutters.customizable.keybindings-displayCoverage-enabled`|Setting this to false will remove the shortcut and vice versa |`coverage-gutters.customizable.keybindings-watchLcovFile-enabled`|Setting this to false will remove the shortcut and vice versa +|`coverage-gutters.customizable.keybindings-watchVisibleEditors-enabled`|Setting this to false will remove the shortcut and vice versa |`coverage-gutters.customizable.keybindings-removeCoverage-enabled`|Setting this to false will remove the shortcut and vice versa Some examples for the highlight colour are as follows: diff --git a/package.json b/package.json index 1d8e1f3..44d8959 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-coverage-gutters", "displayName": "Coverage Gutters", "description": "Display test coverage generated by lcov - works with many languages", - "version": "0.4.0", + "version": "0.5.0", "license": "MIT", "repository": { "type": "git", @@ -16,7 +16,7 @@ "bugs": "https://github.com/ryanluker/vscode-coverage-gutters/issues", "publisher": "ryanluker", "engines": { - "vscode": "^1.9.0" + "vscode": "^1.11.x" }, "categories": [ "Other" @@ -128,6 +128,11 @@ "default": true, "description": "enable or disable the watchLcovFile command in the editor/context menu" }, + "coverage-gutters.customizable.menus-editor-context-watchVisibleEditors-enabled": { + "type": "boolean", + "default": true, + "description": "enable or disable the watchVisibleEditors command in the editor/context menu" + }, "coverage-gutters.customizable.menus-editor-context-removeCoverage-enabled": { "type": "boolean", "default": true, @@ -143,6 +148,11 @@ "default": true, "description": "enable or disable the keybinding shortcut for watching the lcov file" }, + "coverage-gutters.customizable.keybindings-watchVisibleEditors-enabled": { + "type": "boolean", + "default": true, + "description": "enable or disable the keybinding shortcut for watching visible editors" + }, "coverage-gutters.customizable.keybindings-removeCoverage-enabled": { "type": "boolean", "default": true, @@ -159,6 +169,10 @@ "command": "extension.watchLcovFile", "title": "Coverage Gutters: Watch Lcov and Render Changes" }, + { + "command": "extension.watchVisibleEditors", + "title": "Coverage Gutters: Watch Visible Editors and Render Coverage" + }, { "command": "extension.removeCoverage", "title": "Coverage Gutters: Remove File Coverage" @@ -178,9 +192,15 @@ "when": "config.coverage-gutters.customizable.keybindings-watchLcovFile-enabled" }, { - "command": "extension.removeCoverage", + "command": "extension.watchVisibleEditors", "key": "ctrl+shift+9", "mac": "shift+cmd+9", + "when": "config.coverage-gutters.customizable.keybindings-watchVisibleEditors-enabled" + }, + { + "command": "extension.removeCoverage", + "key": "ctrl+shift+0", + "mac": "shift+cmd+0", "when": "config.coverage-gutters.customizable.keybindings-removeCoverage-enabled" } ], @@ -196,10 +216,15 @@ "command": "extension.watchLcovFile", "group": "Coverage-Gutters@2" }, + { + "when": "config.coverage-gutters.customizable.menus-editor-context-watchVisibleEditors-enabled", + "command": "extension.watchVisibleEditors", + "group": "Coverage-Gutters@3" + }, { "when": "config.coverage-gutters.customizable.menus-editor-context-removeCoverage-enabled", "command": "extension.removeCoverage", - "group": "Coverage-Gutters@3" + "group": "Coverage-Gutters@4" } ] } diff --git a/src/config.ts b/src/config.ts index 664eefb..8379e58 100644 --- a/src/config.ts +++ b/src/config.ts @@ -45,7 +45,6 @@ export class Config { public setup(): IConfigStore { const rootCustomConfig = this.vscode.getConfiguration("coverage-gutters.customizable"); - this.sendConfigMetrics(rootCustomConfig, "customConfig"); // Customizable UI configurations const configsCustom = Object.keys(rootCustomConfig); @@ -57,7 +56,6 @@ export class Config { } const rootConfig = this.vscode.getConfiguration("coverage-gutters"); - this.sendConfigMetrics(rootConfig, "config"); // Basic configurations this.lcovFileName = rootConfig.get("lcovname") as string; @@ -133,10 +131,4 @@ export class Config { return this.get(); } - - private sendConfigMetrics(config: WorkspaceConfiguration, category: string) { - Object.keys(config).forEach((configElement) => { - this.reporter.sendEvent(category, configElement, config.get(configElement) as string); - }); - } } diff --git a/src/extension.ts b/src/extension.ts index f5225f1..ddece26 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -17,6 +17,10 @@ export function activate(context: vscode.ExtensionContext) { gutters.watchLcovFile(); }); + const watchVisibleEditors = vscode.commands.registerCommand("extension.watchVisibleEditors", () => { + gutters.watchVisibleEditors(); + }); + const remove = vscode.commands.registerCommand("extension.removeCoverage", () => { gutters.removeCoverageForActiveFile(); }); @@ -24,5 +28,6 @@ export function activate(context: vscode.ExtensionContext) { context.subscriptions.push(remove); context.subscriptions.push(display); context.subscriptions.push(watchLcovFile); + context.subscriptions.push(watchVisibleEditors); context.subscriptions.push(gutters); } diff --git a/src/gutters.ts b/src/gutters.ts index 85c0957..8c06343 100644 --- a/src/gutters.ts +++ b/src/gutters.ts @@ -2,6 +2,7 @@ import { ExtensionContext, FileSystemWatcher, TextEditor, + version, window, } from "vscode"; @@ -20,24 +21,22 @@ const parseImpl = new LcovParse(); export class Gutters { private configStore: IConfigStore; - private fileWatcher: FileSystemWatcher; + private lcovWatcher: FileSystemWatcher; private lcov: Lcov; private indicators: Indicators; private reporter: Reporter; - private textEditors: TextEditor[]; constructor(context: ExtensionContext, reporter: Reporter) { this.configStore = new Config(vscodeImpl, context, reporter).setup(); this.lcov = new Lcov(this.configStore, vscodeImpl, fsImpl); this.indicators = new Indicators(parseImpl, vscodeImpl, this.configStore); this.reporter = reporter; - this.textEditors = []; this.reporter.sendEvent("user", "start"); + this.reporter.sendEvent("user", "vscodeVersion", version); } public async displayCoverageForActiveFile() { const textEditor = window.activeTextEditor; - this.addTextEditorToCache(textEditor); try { const lcovPath = await this.lcov.find(); await this.loadAndRenderCoverage(textEditor, lcovPath); @@ -51,19 +50,14 @@ export class Gutters { * Watch the lcov file and iterate over textEditors when changes occur */ public async watchLcovFile() { - if (this.fileWatcher) { return; } + if (this.lcovWatcher) { return; } try { const lcovPath = await this.lcov.find(); - this.fileWatcher = vscodeImpl.watchFile(lcovPath); - this.fileWatcher.onDidChange(async (event) => { - this.textEditors.forEach(async (editor) => { - if (!editor.document) { - // editor can no longer display coverage, remove from cache - this.removeTextEditorFromCache(editor); - } else { - this.loadAndRenderCoverage(editor, lcovPath); - } + this.lcovWatcher = vscodeImpl.watchFile(lcovPath); + this.lcovWatcher.onDidChange(async (event) => { + window.visibleTextEditors.forEach(async (editor) => { + await this.loadAndRenderCoverage(editor, lcovPath); }); }); this.reporter.sendEvent("user", "watch-lcov"); @@ -72,39 +66,40 @@ export class Gutters { } } + /** + * Watch the visible editors and render coverage when changes occur + */ + public async watchVisibleEditors() { + try { + const lcovPath = await this.lcov.find(); + window.onDidChangeVisibleTextEditors(async (event) => { + window.visibleTextEditors.forEach(async (editor) => { + await this.loadAndRenderCoverage(editor, lcovPath); + }); + }); + this.reporter.sendEvent("user", "watch-editors"); + } catch (error) { + this.handleError(error); + } + } + public removeCoverageForActiveFile() { const activeEditor = window.activeTextEditor; - this.removeTextEditorFromCache(activeEditor); this.removeDecorationsForTextEditor(activeEditor); this.reporter.sendEvent("user", "remove-coverage"); } public dispose() { - this.fileWatcher.dispose(); - this.textEditors.forEach(this.removeDecorationsForTextEditor); + this.lcovWatcher.dispose(); this.reporter.sendEvent("cleanup", "dispose"); } - public getTextEditors(): TextEditor[] { - return this.textEditors; - } - private handleError(error: Error) { const message = error.message ? error.message : error; - window.showErrorMessage(message.toString()); + window.showWarningMessage(message.toString()); this.reporter.sendEvent("error", message.toString()); } - private addTextEditorToCache(editor: TextEditor) { - // keep textEditors a unique array by removing existing editors - this.textEditors = this.textEditors.filter((cache) => cache !== editor); - this.textEditors.push(editor); - } - - private removeTextEditorFromCache(editor: TextEditor) { - this.textEditors = this.textEditors.filter((cache) => cache !== editor); - } - private removeDecorationsForTextEditor(editor: TextEditor) { if (!editor) { return; } editor.setDecorations(this.configStore.fullCoverageDecorationType, []); @@ -117,5 +112,6 @@ export class Gutters { const file = textEditor.document.fileName; const coveredLines = await this.indicators.extract(lcovFile, file); await this.indicators.renderToTextEditor(coveredLines, textEditor); + this.reporter.sendEvent("user", "loadAndRenderCoverage"); } } diff --git a/src/reporter.ts b/src/reporter.ts index 416dd9c..857950e 100644 --- a/src/reporter.ts +++ b/src/reporter.ts @@ -1,18 +1,17 @@ -import {platform} from "os"; import {Request} from "./wrappers/request"; import {Uuid} from "./wrappers/uuid"; -const PLATFORM = platform(); -const GA_TRACKING_ID = ""; // add before a release; const EXT_NAME = "vscode-coverage-gutters"; -const EXT_VERSION = "0.4.0"; +const EXT_VERSION = "0.5.0"; export class Reporter { private readonly cid: string; private readonly enableMetrics: boolean; + private readonly GA_TRACKING_ID: string; private readonly request: Request; constructor(request: Request, uuid: Uuid, enableMetrics: boolean) { + this.GA_TRACKING_ID = process.env.GA_TRACKING_ID || ""; this.request = request; this.cid = uuid.get(); this.enableMetrics = enableMetrics; @@ -34,8 +33,7 @@ export class Reporter { el: label, ev: value, t: "event", - tid: GA_TRACKING_ID, - ua: PLATFORM, + tid: this.GA_TRACKING_ID, v: "1", }; diff --git a/test/gutters.test.ts b/test/gutters.test.ts index 66f7ba7..ac95577 100644 --- a/test/gutters.test.ts +++ b/test/gutters.test.ts @@ -20,31 +20,9 @@ suite("Gutters Tests", function() { } as any; const gutters = new Gutters(ctx, reporter); - assert.equal(gutters.getTextEditors().length, 0); return done(); } catch (e) { return done(e); } }); - - test("Should remove the activeEditor from the textEditors array", async function() { - this.timeout(12000); - const ctx: vscode.ExtensionContext = { - asAbsolutePath() { - return "test"; - }, - subscriptions: [], - } as any; - const reporter: Reporter = { - sendEvent() { - return; - }, - } as any; - - const gutters = new Gutters(ctx, reporter); - await gutters.displayCoverageForActiveFile(); - assert.equal(gutters.getTextEditors().length, 1); - gutters.removeCoverageForActiveFile(); - assert.equal(gutters.getTextEditors().length, 0); - }); }); diff --git a/test/reporter.test.ts b/test/reporter.test.ts index 20d87ab..759692e 100644 --- a/test/reporter.test.ts +++ b/test/reporter.test.ts @@ -58,4 +58,25 @@ suite("Reporter Tests", function() { const reporter = new Reporter(fakeRequest, fakeUuid, true); reporter.sendEvent("test", "action"); }); + + test("GA tracking id should be set by env variable", function() { + process.env.GA_TRACKING_ID = "123"; + + const fakeRequest = { + post(uri: string, options?: IOptions) { + // tslint:disable-next-line:no-string-literal + assert.equal(options.form["tid"], "123"); + return; + }, + }; + + const fakeUuid = { + get() { + return "fakeuuidhere"; + }, + }; + + const reporter = new Reporter(fakeRequest, fakeUuid, true); + reporter.sendEvent("test", "action"); + }); });