Skip to content

Commit

Permalink
Metrics and config cleanup (#44)
Browse files Browse the repository at this point in the history
* update readme to have useful link for open bugs

* add request for metrics

* update typescript version

* cleanup and add metrics component

* cleanup tslint

* cleanup interfaces

* add metrics and config integration

* increment versions

* use DI instead

* add tests cleanup stricts

* fix lintings

* add platform
  • Loading branch information
ryanluker committed Apr 9, 2017
1 parent 6e6953c commit bebcf3b
Show file tree
Hide file tree
Showing 15 changed files with 432 additions and 290 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Some examples for the highlight colour are as follows:
<a>https://developer.mozilla.org/en/docs/Web/CSS/background-color#Syntax</a>

## Known Issues
- can only reliably handle one lcov file per workspace [#35](https://github.com/ryanluker/vscode-coverage-gutters/issues/35)
### [Open Bugs](https://github.com/ryanluker/vscode-coverage-gutters/issues?q=is%3Aopen+is%3Aissue+label%3Abug)

## Release Notes
### [Changelog](https://github.com/ryanluker/vscode-coverage-gutters/releases)
Expand Down
450 changes: 227 additions & 223 deletions package.json

Large diffs are not rendered by default.

35 changes: 22 additions & 13 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,37 @@ import {
ExtensionContext,
OverviewRulerLane,
TextEditorDecorationType,
WorkspaceConfiguration,
} from "vscode";
import {Reporter} from "./reporter";
import {InterfaceVscode} from "./wrappers/vscode";

export type ConfigStore = {
export interface IConfigStore {
lcovFileName: string;
fullCoverageDecorationType: TextEditorDecorationType;
partialCoverageDecorationType: TextEditorDecorationType;
noCoverageDecorationType: TextEditorDecorationType;
altSfCompare: boolean;
};

export interface InterfaceConfig {
get(): ConfigStore;
setup(): ConfigStore;
}

export class Config implements InterfaceConfig {
export class Config {
private vscode: InterfaceVscode;
private context: ExtensionContext;
private reporter: Reporter;

private lcovFileName: string;
private fullCoverageDecorationType: TextEditorDecorationType;
private partialCoverageDecorationType: TextEditorDecorationType;
private noCoverageDecorationType: TextEditorDecorationType;
private altSfCompare: boolean;

constructor(vscode: InterfaceVscode, context: ExtensionContext) {
constructor(vscode: InterfaceVscode, context: ExtensionContext, reporter: Reporter) {
this.vscode = vscode;
this.context = context;
this.reporter = reporter;
}

public get(): ConfigStore {
public get(): IConfigStore {
return {
altSfCompare: this.altSfCompare,
fullCoverageDecorationType: this.fullCoverageDecorationType,
Expand All @@ -44,19 +43,23 @@ export class Config implements InterfaceConfig {
};
}

public setup(): ConfigStore {
// Customizable UI configurations
public setup(): IConfigStore {
const rootCustomConfig = this.vscode.getConfiguration("coverage-gutters.customizable");
this.sendConfigMetrics(rootCustomConfig, "customConfig");

// Customizable UI configurations
const configsCustom = Object.keys(rootCustomConfig);
for (let element of configsCustom) {
for (const element of configsCustom) {
this.vscode.executeCommand(
"setContext",
"config.coverage-gutters.customizable." + element,
rootCustomConfig.get(element));
}

// Basic configurations
const rootConfig = this.vscode.getConfiguration("coverage-gutters");
this.sendConfigMetrics(rootConfig, "config");

// Basic configurations
this.lcovFileName = rootConfig.get("lcovname") as string;
this.altSfCompare = rootConfig.get("altSfCompare") as boolean;

Expand Down Expand Up @@ -130,4 +133,10 @@ export class Config implements InterfaceConfig {

return this.get();
}

private sendConfigMetrics(config: WorkspaceConfiguration, category: string) {
Object.keys(config).forEach((configElement) => {
this.reporter.sendEvent(category, configElement, config.get(configElement) as string);
});
}
}
13 changes: 9 additions & 4 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import * as vscode from "vscode";
import {Gutters} from "./gutters";
import {Reporter} from "./reporter";
import {Request} from "./wrappers/request";
import {Uuid} from "./wrappers/uuid";

export function activate(context: vscode.ExtensionContext) {
let gutters = new Gutters(context);
const enableMetrics = vscode.workspace.getConfiguration("telemetry").get("enableTelemetry") as boolean;
const reporter = new Reporter(new Request(), new Uuid(), enableMetrics);
const gutters = new Gutters(context, reporter);

let display = vscode.commands.registerCommand("extension.displayCoverage", () => {
const display = vscode.commands.registerCommand("extension.displayCoverage", () => {
gutters.displayCoverageForActiveFile();
});

let watchLcovFile = vscode.commands.registerCommand("extension.watchLcovFile", () => {
const watchLcovFile = vscode.commands.registerCommand("extension.watchLcovFile", () => {
gutters.watchLcovFile();
});

let remove = vscode.commands.registerCommand("extension.removeCoverage", () => {
const remove = vscode.commands.registerCommand("extension.removeCoverage", () => {
gutters.removeCoverageForActiveFile();
});

Expand Down
26 changes: 18 additions & 8 deletions src/gutters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,30 +4,35 @@ import {
TextEditor,
window,
} from "vscode";

import {Fs} from "./wrappers/fs";
import {LcovParse} from "./wrappers/lcov-parse";
import {Vscode} from "./wrappers/vscode";

import {Config, ConfigStore} from "./config";
import {Indicators, InterfaceIndicators} from "./indicators";
import {InterfaceLcov, Lcov} from "./lcov";
import {Config, IConfigStore} from "./config";
import {Indicators} from "./indicators";
import {Lcov} from "./lcov";
import {Reporter} from "./reporter";

const vscodeImpl = new Vscode();
const fsImpl = new Fs();
const parseImpl = new LcovParse();

export class Gutters {
private configStore: ConfigStore;
private configStore: IConfigStore;
private fileWatcher: FileSystemWatcher;
private lcov: InterfaceLcov;
private indicators: InterfaceIndicators;
private lcov: Lcov;
private indicators: Indicators;
private reporter: Reporter;
private textEditors: TextEditor[];

constructor(context: ExtensionContext) {
this.configStore = new Config(vscodeImpl, context).setup();
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");
}

public async displayCoverageForActiveFile() {
Expand All @@ -36,6 +41,7 @@ export class Gutters {
try {
const lcovPath = await this.lcov.find();
await this.loadAndRenderCoverage(textEditor, lcovPath);
this.reporter.sendEvent("user", "display-coverage");
} catch (error) {
this.handleError(error);
}
Expand All @@ -60,6 +66,7 @@ export class Gutters {
}
});
});
this.reporter.sendEvent("user", "watch-lcov");
} catch (error) {
this.handleError(error);
}
Expand All @@ -69,11 +76,13 @@ export class Gutters {
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.reporter.sendEvent("cleanup", "dispose");
}

public getTextEditors(): TextEditor[] {
Expand All @@ -83,6 +92,7 @@ export class Gutters {
private handleError(error: Error) {
const message = error.message ? error.message : error;
window.showErrorMessage(message.toString());
this.reporter.sendEvent("error", message.toString());
}

private addTextEditorToCache(editor: TextEditor) {
Expand Down
25 changes: 10 additions & 15 deletions src/indicators.ts
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import {ConfigStore} from "./config";
import {IConfigStore} from "./config";
import {InterfaceLcovParse} from "./wrappers/lcov-parse";
import {InterfaceVscode} from "./wrappers/vscode";

import {LcovSection} from "lcov-parse";
import {Range, TextEditor} from "vscode";

export interface InterfaceIndicators {
renderToTextEditor(lines: LcovSection, textEditor: TextEditor): Promise<string>;
extract(lcovFile: string, file: string): Promise<LcovSection>;
}

export type CoverageLines = {
export interface ICoverageLines {
full: Range[];
partial: Range[];
none: Range[];
};
}

export class Indicators implements InterfaceIndicators {
export class Indicators {
private parse: InterfaceLcovParse;
private vscode: InterfaceVscode;
private configStore: ConfigStore;
private configStore: IConfigStore;

constructor(
parse: InterfaceLcovParse,
vscode: InterfaceVscode,
configStore: ConfigStore,
configStore: IConfigStore,
) {
this.parse = parse;
this.vscode = vscode;
Expand All @@ -33,7 +28,7 @@ export class Indicators implements InterfaceIndicators {

public renderToTextEditor(section: LcovSection, textEditor: TextEditor): Promise<string> {
return new Promise<string>((resolve, reject) => {
let coverageLines: CoverageLines = {
const coverageLines: ICoverageLines = {
full: [],
none: [],
partial: [],
Expand All @@ -50,7 +45,7 @@ export class Indicators implements InterfaceIndicators {
return new Promise<LcovSection>((resolve, reject) => {
this.parse.source(lcovFile, (err, data) => {
if (err) { return reject(err); }
let section = data.find((lcovSection) => {
const section = data.find((lcovSection) => {
return this.compareFilePaths(lcovSection.file, file);
});

Expand All @@ -60,7 +55,7 @@ export class Indicators implements InterfaceIndicators {
});
}

private setDecorationsForEditor(editor: TextEditor, coverage: CoverageLines) {
private setDecorationsForEditor(editor: TextEditor, coverage: ICoverageLines) {
// remove coverage first to prevent graphical conflicts
editor.setDecorations(this.configStore.fullCoverageDecorationType, []);
editor.setDecorations(this.configStore.noCoverageDecorationType, []);
Expand All @@ -71,7 +66,7 @@ export class Indicators implements InterfaceIndicators {
editor.setDecorations(this.configStore.partialCoverageDecorationType, coverage.partial);
}

private filterCoverage(section: LcovSection, coverageLines: CoverageLines): CoverageLines {
private filterCoverage(section: LcovSection, coverageLines: ICoverageLines): ICoverageLines {
section.lines.details.forEach((detail) => {
const lineRange = new Range(detail.line - 1, 0, detail.line - 1, 0);
if (detail.hit > 0) {
Expand Down
13 changes: 4 additions & 9 deletions src/lcov.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import {ConfigStore} from "./config";
import {IConfigStore} from "./config";
import {InterfaceFs} from "./wrappers/fs";
import {InterfaceVscode} from "./wrappers/vscode";

export interface InterfaceLcov {
find(): Promise<string>;
load(lcovPath: string): Promise<string>;
}

export class Lcov implements InterfaceLcov {
private configStore: ConfigStore;
export class Lcov {
private configStore: IConfigStore;
private vscode: InterfaceVscode;
private fs: InterfaceFs;

constructor(
configStore: ConfigStore,
configStore: IConfigStore,
vscode: InterfaceVscode,
fs: InterfaceFs,
) {
Expand Down
44 changes: 44 additions & 0 deletions src/reporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
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";

export class Reporter {
private readonly cid: string;
private readonly enableMetrics: boolean;
private readonly request: Request;

constructor(request: Request, uuid: Uuid, enableMetrics: boolean) {
this.request = request;
this.cid = uuid.get();
this.enableMetrics = enableMetrics;
}

public sendEvent(
category: string,
action: string,
label?: string,
value?: number,
) {
if (!this.enableMetrics) { return; }
const data = {
an: EXT_NAME,
av: EXT_VERSION,
cid: this.cid,
ea: action,
ec: category,
el: label,
ev: value,
t: "event",
tid: GA_TRACKING_ID,
ua: PLATFORM,
v: "1",
};

return this.request.post("https://www.google-analytics.com/collect", { form: data });
}
}
10 changes: 10 additions & 0 deletions src/wrappers/request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {post} from "request";

export interface IOptions { form?: object; }

export class Request {
public post(uri: string, options?: IOptions): void {
post(uri, options);
return;
}
}
7 changes: 7 additions & 0 deletions src/wrappers/uuid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {v4} from "uuid";

export class Uuid {
public get(): string {
return v4();
}
}
3 changes: 0 additions & 3 deletions test/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
"use strict";

import * as assert from "assert";

import * as vscode from "vscode";
import {Config} from "../src/config";

Expand Down
Loading

0 comments on commit bebcf3b

Please sign in to comment.