Skip to content

Commit

Permalink
chore: add RudderStack for event tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
nsalamad committed Aug 2, 2023
1 parent 3c5aebd commit ede3142
Show file tree
Hide file tree
Showing 9 changed files with 130 additions and 19 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/runTests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,24 @@ on:
jobs:
test:
name: Test
runs-on: windows-latest
runs-on: ubuntu-latest
env:
DISPLAY: ':99.0'
steps:
- name: Start xvfb
run: /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & echo ">>> Started xvfb"

- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.x'
cache: 'yarn'

- name: Install dependencies
run: yarn --immutable && yarn install

- name: Lint Project
run: yarn lint

- name: Test Project
run: yarn test
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ node_modules
.env
.idea
.DS_STORE
/src/analytics.ts
20 changes: 15 additions & 5 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,32 @@
"version": "2.0.0",
"tasks": [
{
"label": "watch",
"type": "npm",
"script": "watch",
"problemMatcher": "$tsc-watch",
"isBackground": true,
"presentation": {
"reveal": "never"
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"type": "npm",
"script": "compile",
"problemMatcher": []
"problemMatcher": [],
},
{
"label": "create-analytics-file",
"type": "npm",
"script": "create-analytics-file",
},
{
"label": "dev",
"dependsOn": ["create-analytics-file", "watch"],
"group": {
"kind": "build",
"isDefault": true
}
}
]
}
12 changes: 12 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,15 @@
- Reduce the extension size and improve the startup time by [bundling your extension](https://code.visualstudio.com/api/working-with-extensions/bundling-extension).
- [Publish your extension](https://code.visualstudio.com/api/working-with-extensions/publishing-extension) on the VSCode extension marketplace.
- Automate builds by setting up [Continuous Integration](https://code.visualstudio.com/api/working-with-extensions/continuous-integration).

## [Internal] RudderStack setup

- In order to track events during development, you will need to get an authorization token from RudderStack.

1. Go to [RudderStack](https://app.rudderstack.com/) and login with the credentials stored in 1Password
2. Go to `Sources` and select the `VS Code Extension` source
3. On the `Setup` tab, copy the `Write Key`
4. Go to a [Basic Authentication Header Generator
](https://www.blitter.se/utils/basic-authentication-header-generator/) to generate a token.
5. Use the `Write Key` as the username and leave the password blank
6. Copy the generated token and paste it in `src/analytics.ts`(if this file does not exist, run the extension and it should be automatically generated for you) as the value of the `RUDDERSTACK_KEY` variable
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@
},
"devcycle-feature-flags.sendMetrics": {
"type": "boolean",
"default": true,
"default": false,
"description": "Allow DevCycle to send usage metrics."
}
}
Expand All @@ -125,11 +125,12 @@
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"pretest": "yarn run compile && yarn run lint",
"pretest": "yarn create-analytics-file && yarn run compile && yarn run lint",
"lint": "eslint src --ext ts",
"test": "node ./out/test/runTest.js",
"publish": "vsce publish",
"package": "vsce package"
"package": "vsce package",
"create-analytics-file": "test -f ./src/analytics.ts || echo 'export const RUDDERSTACK_KEY = \"\";' > ./src/analytics.ts"
},
"devDependencies": {
"@types/chai": "^4.3.5",
Expand Down
43 changes: 43 additions & 0 deletions src/RudderStackService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import axios from "axios";
import * as vscode from 'vscode'
import { RUDDERSTACK_KEY } from "./analytics";
import { getOrganizationId } from "./cli";

type RudderstackEvent = {
event: string,
userId: string,
properties: Record<string, unknown>
}

const rudderstackClient = axios.create({
baseURL: 'https://taplyticsncs.dataplane.rudderstack.com/v1/',
headers: {
Authorization: `Basic ${RUDDERSTACK_KEY}`,
'Content-Type': 'application/json'
}
})

export const trackRudderstackEvent = async (
eventName: string
): Promise<void> => {
const sendMetrics = vscode.workspace.getConfiguration('devcycle-feature-flags').get('sendMetrics')
if (sendMetrics) {
const orgId = getOrganizationId()
if (!orgId) { return }
const event = {
event: eventName,
userId: orgId,
properties: {
a0_organization: orgId
}
}
await rudderstackClient.post('track', event).catch((error) => {
if (!axios.isAxiosError(error)) { return }
if (error?.response?.status === 401) {
console.error('Failed to send event. Analytics key is invalid.')
} else {
console.error('Failed to send event. Status: ', error?.response?.status)
}
})
}
}
8 changes: 7 additions & 1 deletion src/StateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const enum KEYS {
ORGANIZATION = 'organization',
SEND_METRICS_PROMPTED = 'send_metrics_prompted',
CODE_USAGE_KEYS = 'code_usage_keys',
EXTENSION_INSTALLED = 'extension_installed',
}

export class StateManager {
Expand All @@ -18,7 +19,12 @@ export class StateManager {

static clearState() {
this.workspaceState.keys().forEach((key) => {
if (key !== KEYS.ORGANIZATION && key !== KEYS.PROJECT_ID && key !== KEYS.PROJECT_NAME) {
if (
key !== KEYS.PROJECT_ID &&
key !== KEYS.PROJECT_NAME &&
key !== KEYS.ORGANIZATION &&
key !== KEYS.EXTENSION_INSTALLED
) {
this.workspaceState.update(key, undefined)
}
})
Expand Down
2 changes: 1 addition & 1 deletion src/cli/baseCLIController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ export async function execDvc(cmd: string) {
vscode.workspace.getConfiguration('devcycle-feature-flags').get('cli') ||
'dvc'
const project_id = StateManager.getState(KEYS.PROJECT_ID)
let shellCommand = `${cli} ${cmd} --headless`
let shellCommand = `${cli} ${cmd} --headless --caller vs_code_extension`
if (project_id) shellCommand += ` --project ${project_id}`

Check warning on line 196 in src/cli/baseCLIController.ts

View workflow job for this annotation

GitHub Actions / Test

Expected { after 'if' condition

Check warning on line 196 in src/cli/baseCLIController.ts

View workflow job for this annotation

GitHub Actions / Test

Expected { after 'if' condition
return execShell(shellCommand)
}
Expand Down
48 changes: 40 additions & 8 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { SidebarProvider } from './components/SidebarProvider'

import { UsagesTreeProvider } from './components/UsagesTree'
import { getHoverString } from './components/hoverCard'
import { trackRudderstackEvent } from './RudderStackService'
import { CodeUsageNode } from './components/UsagesTree/CodeUsageNode'

Object.defineProperty(exports, '__esModule', { value: true })
exports.deactivate = exports.activate = void 0
Expand All @@ -29,32 +31,61 @@ export const activate = async (context: vscode.ExtensionContext) => {
StateManager.setState(KEYS.SEND_METRICS_PROMPTED, true)
})
}

if (!StateManager.globalState.get(KEYS.EXTENSION_INSTALLED)) {
await StateManager.globalState.update(KEYS.EXTENSION_INSTALLED, true)
trackRudderstackEvent('Extension Installed')
}

const autoLogin = vscode.workspace
.getConfiguration('devcycle-feature-flags')
.get('loginOnWorkspaceOpen')

const sidebarProvider = new SidebarProvider(context.extensionUri)
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(
'devcycle-sidebar',
sidebarProvider
),
)

const rootPath =
vscode.workspace.workspaceFolders &&
vscode.workspace.workspaceFolders.length > 0
? vscode.workspace.workspaceFolders[0].uri.fsPath
: undefined
const usagesDataProvider = new UsagesTreeProvider(rootPath, context)
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(
'devcycle-sidebar',
sidebarProvider,
),
)
vscode.window.registerTreeDataProvider(
const usagesTreeView = vscode.window.createTreeView(
'devcycleCodeUsages',
usagesDataProvider,
{ treeDataProvider: usagesDataProvider },
)
usagesTreeView.onDidChangeVisibility(async (e) => {
trackRudderstackEvent('Usages Viewed')
})

context.subscriptions.push(
vscode.commands.registerCommand(
'devcycle-featureflags.usagesNodeClicked',
async (node: CodeUsageNode) => {
trackRudderstackEvent('Code Usage Clicked')
}
)
)

usagesTreeView.onDidChangeSelection((e) => {
const node = e.selection[0]
if (node instanceof CodeUsageNode && node.type === 'usage') {
vscode.commands.executeCommand(
'devcycle-featureflags.usagesNodeClicked',
node
)
}
})


context.subscriptions.push(
vscode.commands.registerCommand('devcycle-feature-flags.init', async () => {
trackRudderstackEvent('Init Command Ran')
await init()
}),
)
Expand All @@ -72,6 +103,7 @@ export const activate = async (context: vscode.ExtensionContext) => {
vscode.commands.registerCommand(
'devcycle-feature-flags.logout',
async () => {
trackRudderstackEvent('Logout Command Ran')
await Promise.all([
StateManager.clearState(),
vscode.commands.executeCommand(
Expand Down

0 comments on commit ede3142

Please sign in to comment.