Skip to content
This repository has been archived by the owner on Dec 15, 2022. It is now read-only.

Commit

Permalink
Merge 348ec0d into 715f040
Browse files Browse the repository at this point in the history
  • Loading branch information
Tilde Ann Thurium committed Jul 6, 2018
2 parents 715f040 + 348ec0d commit 601cfcb
Show file tree
Hide file tree
Showing 14 changed files with 378 additions and 2 deletions.
3 changes: 3 additions & 0 deletions lib/containers/remote-container.js
Expand Up @@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import {QueryRenderer, graphql} from 'react-relay';

import {incrementCounter} from '../reporter-proxy';
import {autobind} from '../helpers';
import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types';
import RelayNetworkLayerManager from '../relay-network-layer-manager';
Expand Down Expand Up @@ -132,10 +133,12 @@ export default class RemoteContainer extends React.Component {
}

handleLogin(token) {
incrementCounter('github-login');
this.props.loginModel.setToken(this.props.host, token);
}

handleLogout() {
incrementCounter('github-logout');
this.props.loginModel.removeToken(this.props.host);
}
}
8 changes: 7 additions & 1 deletion lib/controllers/remote-controller.js
Expand Up @@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import {shell} from 'electron';

import {autobind} from '../helpers';
import {incrementCounter} from '../reporter-proxy';
import {RemotePropType, BranchSetPropType, OperationStateObserverPropType} from '../prop-types';
import IssueishSearchesController from './issueish-searches-controller';

Expand Down Expand Up @@ -71,7 +72,12 @@ export default class RemoteController extends React.Component {

return new Promise((resolve, reject) => {
shell.openExternal(createPrUrl, {}, err => {
if (err) { reject(err); } else { resolve(); }
if (err) {
reject(err);
} else {
incrementCounter('create-pull-request');
resolve();
}
});
});
}
Expand Down
3 changes: 3 additions & 0 deletions lib/controllers/root-controller.js
Expand Up @@ -25,6 +25,7 @@ import Conflict from '../models/conflicts/conflict';
import Switchboard from '../switchboard';
import {destroyFilePatchPaneItems, destroyEmptyFilePatchPaneItems, autobind} from '../helpers';
import {GitError} from '../git-shell-out-strategy';
import {incrementCounter} from '../reporter-proxy';

export default class RootController extends React.Component {
static propTypes = {
Expand Down Expand Up @@ -788,10 +789,12 @@ class TabTracker {
}

reveal() {
incrementCounter(`${this.name}-tab-open`);
return this.getWorkspace().open(this.uri, {searchAllPanes: true, activateItem: true, activatePane: true});
}

hide() {
incrementCounter(`${this.name}-tab-close`);
return this.getWorkspace().hide(this.uri);
}

Expand Down
9 changes: 9 additions & 0 deletions lib/git-shell-out-strategy.js
Expand Up @@ -13,6 +13,7 @@ import {parse as parseStatus} from 'what-the-status';
import GitPromptServer from './git-prompt-server';
import GitTempDir from './git-temp-dir';
import AsyncQueue from './async-queue';
import {incrementCounter} from './reporter-proxy';
import {
getDugitePath, getSharedModulePath, getAtomHelperPath,
extractCoAuthorsAndRawCommitMessage, fileExists, isFileExecutable, isFileSymlink, isBinary,
Expand Down Expand Up @@ -42,6 +43,9 @@ export class LargeRepoError extends Error {
}
}

// ignored for the purposes of usage metrics tracking because they're noisy
const IGNORED_GIT_COMMANDS = ['cat-file', 'config', 'diff', 'for-each-ref', 'log', 'rev-parse', 'status'];

const DISABLE_COLOR_FLAGS = [
'branch', 'diff', 'showBranch', 'status', 'ui',
].reduce((acc, type) => {
Expand Down Expand Up @@ -89,6 +93,7 @@ export default class GitShellOutStrategy {
async exec(args, options = GitShellOutStrategy.defaultExecArgs) {
/* eslint-disable no-console,no-control-regex */
const {stdin, useGitPromptServer, useGpgWrapper, useGpgAtomPrompt, writeOperation} = options;
const commandName = args[0];
const subscriptions = new CompositeDisposable();
const diagnosticsEnabled = process.env.ATOM_GITHUB_GIT_DIAGNOSTICS || atom.config.get('github.gitDiagnostics');

Expand Down Expand Up @@ -311,6 +316,10 @@ export default class GitShellOutStrategy {
err.command = formattedArgs;
reject(err);
}

if (!IGNORED_GIT_COMMANDS.includes(commandName)) {
incrementCounter(commandName);
}
resolve(stdout);
});
}, {parallel: !writeOperation});
Expand Down
5 changes: 5 additions & 0 deletions lib/github-package.js
Expand Up @@ -22,6 +22,7 @@ import ContextMenuInterceptor from './context-menu-interceptor';
import AsyncQueue from './async-queue';
import WorkerManager from './worker-manager';
import getRepoPipelineManager from './get-repo-pipeline-manager';
import {reporterProxy} from './reporter-proxy';

const defaultState = {
newProject: true,
Expand Down Expand Up @@ -313,6 +314,10 @@ export default class GithubPackage {
this.rerender();
}

consumeReporter(reporter) {
reporterProxy.setReporter(reporter);
}

createGitTimingsView() {
return StubItem.create('git-timings-view', {
title: 'GitHub Package Timings View',
Expand Down
82 changes: 82 additions & 0 deletions lib/reporter-proxy.js
@@ -0,0 +1,82 @@
const pjson = require('../package.json');

export const FIVE_MINUTES_IN_MILLISECONDS = 1000 * 60 * 5;

// this class allows us to call reporter methods
// before the reporter is actually loaded, since we don't want to
// assume that the metrics package will load before the GitHub package.
class ReporterProxy {
constructor() {
this.reporter = null;
this.events = [];
this.timings = [];
this.counters = [];
this.gitHubPackageVersion = pjson.version;

// if for some reason a user disables the metrics package, we don't want to
// just keep accumulating events in memory until the heat death of the universe.
// Use a no-op class, clear all queues, move on with our lives.
setTimeout(FIVE_MINUTES_IN_MILLISECONDS, () => {
if (this.reporter === null) {
this.setReporter(new FakeReporter());
this.events = [];
this.timings = [];
this.counters = [];
}
});
}

// function that is called after the reporter is actually loaded, to
// set the reporter and send any data that have accumulated while it was loading.
setReporter(reporter) {
this.reporter = reporter;

this.events.forEach(customEvent => {
this.reporter.addCustomEvent(customEvent.eventType, customEvent.event);
});

this.timings.forEach(timing => {
this.reporter.addTiming(timing.eventType, timing.durationInMilliseconds, timing.metadata);
});

this.counters.forEach(counterName => {
this.reporter.incrementCounter(counterName);
});
}
}

export const reporterProxy = new ReporterProxy();

export class FakeReporter {
addCustomEvent() {}

addTiming() {}

incrementCounter() {}
}

export function incrementCounter(counterName) {
if (reporterProxy.reporter) {
reporterProxy.reporter.incrementCounter(counterName);
} else {
reporterProxy.counters.push(counterName);
}
}

export function addTiming(eventType, durationInMilliseconds, metadata = {}) {
metadata.gitHubPackageVersion = reporterProxy.gitHubPackageVersion;
if (reporterProxy.reporter) {
reporterProxy.reporter.addTiming(eventType, durationInMilliseconds, metadata);
} else {
reporterProxy.timings.push({eventType, durationInMilliseconds, metadata});
}
}

export function addEvent(eventType, event) {
event.gitHubPackageVersion = reporterProxy.gitHubPackageVersion;
if (reporterProxy.reporter) {
reporterProxy.reporter.addCustomEvent(eventType, event);
} else {
reporterProxy.events.push({eventType, event});
}
}
5 changes: 5 additions & 0 deletions lib/views/commit-view.js
Expand Up @@ -13,6 +13,7 @@ import Author from '../models/author';
import ObserveModel from './observe-model';
import {LINE_ENDING_REGEX, autobind} from '../helpers';
import {AuthorPropType, UserStorePropType} from '../prop-types';
import {incrementCounter} from '../reporter-proxy';

const TOOLTIP_DELAY = 200;

Expand Down Expand Up @@ -384,10 +385,12 @@ export default class CommitView extends React.Component {
showCoAuthorInput: !this.state.showCoAuthorInput,
}, () => {
if (this.state.showCoAuthorInput) {
incrementCounter('show-co-author-input');
this.refCoAuthorSelect.map(c => c.focus());
} else {
// if input is closed, remove all co-authors
this.props.updateSelectedCoAuthors([]);
incrementCounter('hide-co-author-input');
}
});
}
Expand Down Expand Up @@ -426,6 +429,7 @@ export default class CommitView extends React.Component {
}

amendLastCommit() {
incrementCounter('amend');
this.commit(null, true);
}

Expand Down Expand Up @@ -535,6 +539,7 @@ export default class CommitView extends React.Component {
}

onSelectedCoAuthorsChanged(selectedCoAuthors) {
incrementCounter('selected-co-authors-changed');
const newAuthor = selectedCoAuthors.find(author => author.isNew());

if (newAuthor) {
Expand Down
5 changes: 5 additions & 0 deletions package.json
Expand Up @@ -97,6 +97,11 @@
"versions": {
"^1.0.0": "consumeStatusBar"
}
},
"metrics-reporter": {
"versions": {
"^1.1.0": "consumeReporter"
}
}
},
"configSchema": {
Expand Down
23 changes: 23 additions & 0 deletions test/containers/remote-container.test.js
@@ -1,6 +1,7 @@
import React from 'react';
import {mount} from 'enzyme';

import * as reporterProxy from '../../lib/reporter-proxy';
import {createRepositoryResult} from '../fixtures/factories/repository-result';
import Remote from '../../lib/models/remote';
import Branch, {nullBranch} from '../../lib/models/branch';
Expand Down Expand Up @@ -131,6 +132,28 @@ describe('RemoteContainer', function() {
assert.strictEqual(qev.prop('error'), e);
});

it('increments a counter on login', function() {
const token = '1234';
sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES);
const incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter');

const wrapper = mount(buildApp());
wrapper.instance().handleLogin(token);
assert.isTrue(incrementCounterStub.calledOnceWith('github-login'));
});

it('increments a counter on logout', function() {
const token = '1234';
sinon.stub(model, 'getScopes').resolves(GithubLoginModel.REQUIRED_SCOPES);

const wrapper = mount(buildApp());
wrapper.instance().handleLogin(token);

const incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter');
wrapper.instance().handleLogout();
assert.isTrue(incrementCounterStub.calledOnceWith('github-logout'));
});

it('renders the controller once results have arrived', async function() {
const {resolve} = expectRepositoryQuery();
expectEmptyIssueishQuery();
Expand Down
25 changes: 25 additions & 0 deletions test/controllers/remote-controller.test.js
@@ -1,11 +1,13 @@
import React from 'react';
import {shallow} from 'enzyme';
import {shell} from 'electron';

import BranchSet from '../../lib/models/branch-set';
import Branch, {nullBranch} from '../../lib/models/branch';
import Remote from '../../lib/models/remote';
import {nullOperationStateObserver} from '../../lib/models/operation-state-observer';
import RemoteController from '../../lib/controllers/remote-controller';
import * as reporterProxy from '../../lib/reporter-proxy';

describe('RemoteController', function() {
let atomEnv, remote, branchSet, currentBranch;
Expand Down Expand Up @@ -49,6 +51,29 @@ describe('RemoteController', function() {
);
}

it('increments a counter when onCreatePr is called', async function() {
const wrapper = shallow(createApp());
sinon.stub(shell, 'openExternal').callsArg(2);
sinon.stub(reporterProxy, 'incrementCounter');

await wrapper.instance().onCreatePr();
assert.equal(reporterProxy.incrementCounter.callCount, 1);
assert.deepEqual(reporterProxy.incrementCounter.lastCall.args, ['create-pull-request']);
});

it('handles error when onCreatePr fails', async function() {
const wrapper = shallow(createApp());
sinon.stub(shell, 'openExternal').callsArgWith(2, new Error('oh noes'));
sinon.stub(reporterProxy, 'incrementCounter');

try {
await wrapper.instance().onCreatePr();
} catch (err) {
assert.equal(err.message, 'oh noes');
}
assert.equal(reporterProxy.incrementCounter.callCount, 0);
});

it('renders issueish searches', function() {
const wrapper = shallow(createApp());

Expand Down
17 changes: 17 additions & 0 deletions test/controllers/root-controller.test.js
Expand Up @@ -11,6 +11,7 @@ import Repository from '../../lib/models/repository';
import GitTabItem from '../../lib/items/git-tab-item';
import GithubTabController from '../../lib/controllers/github-tab-controller';
import ResolutionProgress from '../../lib/models/conflicts/resolution-progress';
import * as reporterProxy from '../../lib/reporter-proxy';

import RootController from '../../lib/controllers/root-controller';

Expand Down Expand Up @@ -120,6 +121,14 @@ describe('RootController', function() {
{searchAllPanes: true, activateItem: true, activatePane: true},
]);
});
it('increments counter with correct name', function() {
sinon.stub(workspace, 'open');
const incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter');

tabTracker.reveal();
assert.equal(incrementCounterStub.callCount, 1);
assert.deepEqual(incrementCounterStub.lastCall.args, [`${tabName}-tab-open`]);
});
});

describe('hide', function() {
Expand All @@ -132,6 +141,14 @@ describe('RootController', function() {
`atom-github://dock-item/${tabName}`,
]);
});
it('increments counter with correct name', function() {
sinon.stub(workspace, 'hide');
const incrementCounterStub = sinon.stub(reporterProxy, 'incrementCounter');

tabTracker.hide();
assert.equal(incrementCounterStub.callCount, 1);
assert.deepEqual(incrementCounterStub.lastCall.args, [`${tabName}-tab-close`]);
});
});

describe('toggle()', function() {
Expand Down

0 comments on commit 601cfcb

Please sign in to comment.