+
Skip to content
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
19 changes: 0 additions & 19 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,6 @@ jobs:
- checkout
- node/install-packages
- run: npm test
publish:
executor:
name: node
steps:
- browser-tools/install-browser-tools
- node/install-npm
- checkout
- node/install-packages
- run:
name: "Deploy plugin to marketplace"
command: npm run deploy

workflows:
test-publish:
Expand All @@ -38,11 +27,3 @@ workflows:
filters:
tags:
only: /.*/
- publish:
requires:
- test
filters:
tags:
only: /^\d+\.\d+\.\d+$/
branches:
ignore: /.*/
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
# Change Log

## 1.2.0 - 7 December 2021

### Added
- Telemetry, including for errors like if there are no jobs. [#55](https://github.com/getlocalci/local-ci/pull/55/)

### Fixed
- Fix cannot stat error in `tmp/`. [#54](https://github.com/getlocalci/local-ci/pull/54)

## 1.1.0 - 6 December 2021

### Added
- Telemetry for activating, running a job, and no jobs, opt out with `"telemetry.enableTelemetry": false`. [#50](https://github.com/getlocalci/local-ci/pull/50/)
- Telemetry for activating, running a job, and no jobs, opt out with `"telemetry.telemetryLevel": "off"`. [#50](https://github.com/getlocalci/local-ci/pull/50/)

## 1.0.2 - 5 December 2021

Expand Down
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[![2 day free preview](https://img.shields.io/badge/trial-2%20day-orange)](https://getlocalci.com/pricing)
[![Buy license key](https://img.shields.io/badge/%24-paid-orange)](https://getlocalci.com/pricing)
[![2 day free preview](https://img.shields.io/badge/trial-2%20day-orange)](https://getlocalci.com/pricing/?utm_medium=extension&utm_source=readme)
[![Buy license key](https://img.shields.io/badge/%24-paid-orange)](https://getlocalci.com/pricing/?utm_medium=extension&utm_source=readme)
[![Platform: macOS](https://img.shields.io/badge/platform-macOS-yellow)](https://en.wikipedia.org/wiki/MacOS)
[![Requires CircleCI®](https://img.shields.io/badge/requires-CirlcleCI%C2%AE-yellow)](https://circleci.com)

Expand Down Expand Up @@ -37,7 +37,7 @@ CircleCI® is a registered trademark of Circle Internet Services, Inc.

## License

Local CI requires a [license](https://getlocalci.com/pricing/) for $70 per month.
Local CI requires a [license](https://getlocalci.com/pricing/?utm_medium=extension&utm_source=readme) for $70 per month.

But first you'll get a free 2-day preview, no sign-up or credit card needed.

Expand All @@ -55,15 +55,11 @@ If there's more than one `.circleci/config.yml` file, click the gear icon to sel

## Privacy

You can opt out of telemetry by adding this to your VS Code `settings.json`:
You can opt out of all telemetry by adding this to your VS Code `settings.json`:

`"telemetry.enableTelemetry": false`
`"telemetry.telemetryLevel": "off"`

If you haven't opted out, this will send the following events via [VS Code telemetry](https://code.visualstudio.com/docs/getstarted/telemetry):

* This extension is activated
* There are no jobs found, like if there's no `.circleci/config.yml` file
* A CircleCI® job is run (but it sends no data about the job, not even the name)
If you haven't opted out, here are the [telemetry events](https://github.com/getlocalci/local-ci/search?q=reporter.send) sent via [VS Code telemetry](https://code.visualstudio.com/docs/getstarted/telemetry).

If you haven't entered a license key, like during the free preview, this extension has no interaction with Local CI's site.

Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "local-ci",
"displayName": "Local CI",
"description": "Debug CircleCI® workflows locally, with Bash access during and after. Free preview, then paid.",
"version": "1.1.0",
"version": "1.2.0",
"publisher": "LocalCI",
"contributors": [
"Ryan Kienstra"
Expand Down Expand Up @@ -223,12 +223,12 @@
"badges": [
{
"url": "https://img.shields.io/badge/trial-2%20day-orange",
"href": "https://getlocalci.com/pricing",
"href": "https://getlocalci.com/pricing/?utm_medium=extension&utm_source=badge",
"description": "2 day free preview"
},
{
"url": "https://img.shields.io/badge/%24-paid-orange",
"href": "https://getlocalci.com/pricing",
"href": "https://getlocalci.com/pricing/?utm_medium=extension&utm_source=badge",
"description": "Buy license key"
},
{
Expand Down
29 changes: 27 additions & 2 deletions src/classes/JobProvider.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as fs from 'fs';
import * as vscode from 'vscode';
import TelemetryReporter from 'vscode-extension-telemetry';
import Command from './Command';
import Job from './Job';
import Warning from './Warning';
Expand Down Expand Up @@ -32,7 +33,10 @@ export default class JobProvider
private runningJob: string | undefined;
private suppressMessage: boolean | undefined;

constructor(private readonly context: vscode.ExtensionContext) {}
constructor(
private readonly context: vscode.ExtensionContext,
private readonly reporter: TelemetryReporter
) {}

refresh(job?: Job, suppressMessage?: boolean): void {
this.suppressMessage = suppressMessage;
Expand All @@ -46,6 +50,8 @@ export default class JobProvider
async getChildren(): Promise<vscode.TreeItem[]> {
const configFilePath = await getConfigFilePath(this.context);
if (!configFilePath || !fs.existsSync(configFilePath)) {
this.reporter.sendTelemetryErrorEvent('configFilePath');

return [
new Warning('Error: No jobs found'),
(await getAllConfigFilePaths(this.context)).length
Expand All @@ -70,6 +76,8 @@ export default class JobProvider
}`
);
}

this.reporter.sendTelemetryErrorEvent('writeProcessFile');
}

const shouldEnableExtension =
Expand All @@ -87,10 +95,27 @@ export default class JobProvider
new vscode.TreeItem(processError),
new Command('Try Again', `${JOB_TREE_VIEW_ID}.refresh`),
]
: await getJobs(this.context, processedConfig, this.runningJob);
: await getJobs(
this.context,
processedConfig,
this.reporter,
this.runningJob
);
this.runningJob = undefined;
}

if (processError) {
this.reporter.sendTelemetryErrorEvent('processError');
}

if (!dockerRunning) {
this.reporter.sendTelemetryErrorEvent('dockerNotRunning');
}

if (!this.jobs.length) {
this.reporter.sendTelemetryErrorEvent('noJobsFound');
}

return shouldEnableExtension
? dockerRunning
? this.jobs
Expand Down
5 changes: 3 additions & 2 deletions src/constants/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const EXTENSION_VERSION = '1.1.0';
export const EXTENSION_VERSION = '1.2.0';
export const EXTENSION_ID = 'LocalCI.local-ci';
export const COMMITTED_IMAGE_NAMESPACE = 'local-ci';
export const SELECTED_CONFIG_PATH = 'local-ci.config.path';
Expand Down Expand Up @@ -34,7 +34,8 @@ export const GET_PICARD_CONTAINER_FUNCTION = `get_picard_container() {
fi
done
}`;
export const GET_LICENSE_KEY_URL = 'https://getlocalci.com/pricing';
export const GET_LICENSE_KEY_URL =
'https://getlocalci.com/pricing/?utm_medium=extension&utm_source=ui';
export const HELP_URL = 'https://github.com/getlocalci/local-ci/discussions';
export const JOB_TREE_VIEW_ID = 'localCiJobs';
export const LICENSE_ITEM_ID = 43;
Expand Down
48 changes: 39 additions & 9 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,37 @@ import runJob from './utils/runJob';
import showLicenseInput from './utils/showLicenseInput';
import writeProcessFile from './utils/writeProcessFile';

const reporter = new TelemetryReporter(
EXTENSION_ID,
EXTENSION_VERSION,
TELEMETRY_KEY
);

export function activate(context: vscode.ExtensionContext): void {
if (!context.globalState.get(TRIAL_STARTED_TIMESTAMP)) {
context.globalState.update(TRIAL_STARTED_TIMESTAMP, new Date().getTime());
reporter.sendTelemetryEvent('firstActivation');

const getStartedText = 'Get started debugging faster';
vscode.window
.showInformationMessage(
'Thanks for installing Local CI!',
{ detail: 'Getting started with Local CI' },
getStartedText
)
.then((clicked) => {
if (clicked === getStartedText) {
vscode.commands.executeCommand(
'workbench.action.openWalkthrough',
'LocalCI.local-ci#welcomeLocalCi'
);
reporter.sendTelemetryEvent('click.getStarted');
}
});
}
const jobProvider = new JobProvider(context);
const reporter = new TelemetryReporter(
EXTENSION_ID,
EXTENSION_VERSION,
TELEMETRY_KEY
);

const jobProvider = new JobProvider(context, reporter);
reporter.sendTelemetryEvent('activate');
const reportRunJob = () => reporter.sendTelemetryEvent('runJob');

vscode.window.registerTreeDataProvider(JOB_TREE_VIEW_ID, jobProvider);
context.subscriptions.push(
Expand All @@ -57,6 +76,7 @@ export function activate(context: vscode.ExtensionContext): void {
vscode.env.openExternal(vscode.Uri.parse(HELP_URL))
),
vscode.commands.registerCommand(`${JOB_TREE_VIEW_ID}.exitAllJobs`, () => {
reporter.sendTelemetryEvent('exitAllJobs');
jobProvider.refresh();

const confirmText = 'Yes';
Expand All @@ -83,6 +103,7 @@ export function activate(context: vscode.ExtensionContext): void {
vscode.commands.registerCommand(
`${JOB_TREE_VIEW_ID}.selectRepo`,
async () => {
reporter.sendTelemetryEvent('selectRepo');
const quickPick = vscode.window.createQuickPick();
const configFilePaths = await getAllConfigFilePaths(context);
quickPick.title = 'Repo to run CI on';
Expand Down Expand Up @@ -143,7 +164,8 @@ export function activate(context: vscode.ExtensionContext): void {
jobProvider.refresh(job);
}

runJob(context, jobName, reportRunJob);
reporter.sendTelemetryEvent('runJob');
runJob(context, jobName);
}
),
vscode.commands.registerCommand(EXIT_JOB_COMMAND, (job: Job) => {
Expand All @@ -157,11 +179,14 @@ export function activate(context: vscode.ExtensionContext): void {
jobProvider.refresh(job);
const jobName = job.getJobName();
disposeTerminalsForJob(jobName);
runJob(context, jobName, reportRunJob);

reporter.sendTelemetryEvent('rerunJob');
runJob(context, jobName);
}),
vscode.commands.registerCommand(
'local-ci.debug.repo',
(clickedFile: vscode.Uri) => {
reporter.sendTelemetryEvent('click.debugRepo');
if (clickedFile.fsPath) {
context.globalState
.update(SELECTED_CONFIG_PATH, clickedFile.fsPath)
Expand All @@ -175,6 +200,7 @@ export function activate(context: vscode.ExtensionContext): void {
}
),
vscode.commands.registerCommand('local-ci.runWalkthroughJob', async () => {
reporter.sendTelemetryEvent('runWalkthroughJob');
const configFilePath = await getConfigFilePath(context);
let processedConfig;
try {
Expand Down Expand Up @@ -271,3 +297,7 @@ export function activate(context: vscode.ExtensionContext): void {
},
});
}

export function deactivate(): void {
reporter.sendTelemetryEvent('deactivate');
}
19 changes: 17 additions & 2 deletions src/test/suite/utils/getJobs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as vscode from 'vscode';
import * as yaml from 'js-yaml';
import { Substitute } from '@fluffy-spoon/substitute';
import getJobs from '../../../utils/getJobs';
import TelemetryReporter from 'vscode-extension-telemetry';

mocha.afterEach(() => {
sinon.restore();
Expand Down Expand Up @@ -35,7 +36,14 @@ suite('getJobs', () => {
});

assert.strictEqual(
(await getJobs(getMockContext(), 'example-path')).length,
(
await getJobs(
getMockContext(),
'example-path',
Substitute.for<TelemetryReporter>(),
'build'
)
).length,
1
);
});
Expand All @@ -61,7 +69,14 @@ suite('getJobs', () => {
});

assert.strictEqual(
(await getJobs(getMockContext(), 'example-path')).length,
(
await getJobs(
getMockContext(),
'example-path',
Substitute.for<TelemetryReporter>(),
'build'
)
).length,
3
);
});
Expand Down
8 changes: 2 additions & 6 deletions src/utils/getJobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import Command from '../classes/Command';
import getAllConfigFilePaths from './getAllConfigFilePaths';
import getConfig from './getConfig';
import isWindows from './isWindows';
import { EXTENSION_ID, EXTENSION_VERSION, TELEMETRY_KEY } from '../constants';

export default async function getJobs(
context: vscode.ExtensionContext,
processedConfig: string,
reporter: TelemetryReporter,
runningJob?: string
): Promise<vscode.TreeItem[]> {
if (isWindows()) {
Expand Down Expand Up @@ -41,11 +41,7 @@ export default async function getJobs(
: [];

if (!jobs.length) {
new TelemetryReporter(
EXTENSION_ID,
EXTENSION_VERSION,
TELEMETRY_KEY
).sendTelemetryEvent('noJobs');
reporter.sendTelemetryEvent('noJobs');
}

return jobs.length
Expand Down
4 changes: 1 addition & 3 deletions src/utils/runJob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ import uncommittedWarning from './uncommittedWarning';

export default async function runJob(
context: vscode.ExtensionContext,
jobName: string,
reportRunJob: () => void
jobName: string
): Promise<void> {
const configFilePath = await getConfigFilePath(context);
const repoPath = path.dirname(path.dirname(configFilePath));
Expand All @@ -42,7 +41,6 @@ export default async function runJob(
cwd: repoPath,
});
terminal.show();
reportRunJob();

const processFilePath = getProcessFilePath(configFilePath);
const parsedProcessFile = getConfigFromPath(processFilePath);
Expand Down
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载