Skip to content

Commit e74f22e

Browse files
committed
WIP implement regex match of params with Sentry extension settings, update package.json to add testing
1 parent 9225940 commit e74f22e

File tree

6 files changed

+1094
-119
lines changed

6 files changed

+1094
-119
lines changed

mocha.opts

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
--recursive
2+
--watch-extensions ts
3+
--timeout 200
4+
src/**/*.test.ts

package.json

+14-5
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
"configuration": {
2626
"title": "Sentry extension settings",
2727
"properties": {
28-
"sentryOrganization": {
28+
"sentry.organization": {
2929
"description": "Name of the Sentry organization",
3030
"type": "string",
3131
"default": ""
3232
},
33-
"sentryProjects": {
33+
"sentry.projects": {
3434
"type": "array",
3535
"items": {
3636
"name": { "type" : "string" },
@@ -79,13 +79,15 @@
7979
"url": "https://github.com/sourcegraph/sourcegraph-sentry.git"
8080
},
8181
"license": "Apache-2.0",
82-
"main": "dist/sourcegraph-sentry.js",
82+
"main": "dist/extension.js",
8383
"scripts": {
8484
"tslint": "tslint -p tsconfig.json './src/**/*.ts'",
8585
"typecheck": "tsc -p tsconfig.json",
86-
"build": "parcel build --out-file dist/sourcegraph-sentry.js src/sourcegraph-sentry.ts",
86+
"test": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' mocha --require ts-node/register --require source-map-support/register --opts mocha.opts",
87+
"cover": "TS_NODE_COMPILER_OPTIONS='{\"module\":\"commonjs\"}' nyc --require ts-node/register --require source-map-support/register --all mocha --opts mocha.opts --timeout 10000",
88+
"build": "parcel build --out-file dist/extension.js src/extension.ts",
8789
"symlink-package": "mkdirp dist && lnfs ./package.json ./dist/package.json",
88-
"serve": "npm run symlink-package && parcel serve --no-hmr --out-file dist/sourcegraph-sentry.js src/sourcegraph-sentry.ts",
90+
"serve": "npm run symlink-package && parcel serve --no-hmr --out-file dist/extension.js src/extension.ts",
8991
"watch:typecheck": "tsc -p tsconfig.json -w",
9092
"watch:build": "tsc -p tsconfig.dist.json -w",
9193
"sourcegraph:prepublish": "npm run build"
@@ -100,11 +102,18 @@
100102
"@sourcegraph/prettierrc": "^2.2.0",
101103
"@sourcegraph/tsconfig": "^4.0.0",
102104
"@sourcegraph/tslint-config": "^12.3.1",
105+
"@types/expect": "^1.20.4",
106+
"@types/mocha": "^5.2.6",
107+
"expect": "^24.4.0",
103108
"lnfs-cli": "^2.1.0",
104109
"mkdirp": "^0.5.1",
110+
"mocha": "^6.0.2",
111+
"nyc": "^13.3.0",
105112
"parcel-bundler": "^1.12.0",
106113
"rxjs": "^6.4.0",
114+
"source-map-support": "^0.5.11",
107115
"sourcegraph": "^23.0.0",
116+
"ts-node": "^8.0.3",
108117
"tslint": "^5.13.1",
109118
"typescript": "^3.3.3333"
110119
}

src/extension.ts

+119
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
import { from } from 'rxjs'
2+
import { filter, switchMap } from 'rxjs/operators'
3+
import * as sourcegraph from 'sourcegraph'
4+
import { resolveSettings, Settings } from './settings'
5+
6+
interface Params {
7+
repo: string | null
8+
file: string | null
9+
folder: string | null
10+
}
11+
12+
// TODO: Receive code matching patterns from the Sentry extension settings
13+
const CODE_PATTERNS = [
14+
/throw new Error+\([\'\"]([^\'\"]+)[\'\"]\)/gi,
15+
/console\.[^\'\"\`]+\([\'\"\`]([^\'\"\`]+)[\'\"\`]\)/gi,
16+
/log\.[^\'\"]+\([\'\"]([^\'\"]+)[\'\"]\)/gi,
17+
]
18+
19+
const DECORATION_TYPE = sourcegraph.app.createDecorationType()
20+
const SETTINGSCONFIG = resolveSettings(sourcegraph.configuration.get<Settings>().value)
21+
22+
function decorateEditor(editor: sourcegraph.CodeEditor, sentryProjects: Settings['sentry.projects']): void {
23+
const decorations: sourcegraph.TextDocumentDecoration[] = []
24+
for (const [i, line] of editor.document.text!.split('\n').entries()) {
25+
let m: RegExpExecArray | null
26+
for (const pattern of CODE_PATTERNS) {
27+
do {
28+
m = pattern.exec(line)
29+
if (m) {
30+
decorations.push({
31+
range: new sourcegraph.Range(i, 0, i, 0),
32+
isWholeLine: true,
33+
after: {
34+
backgroundColor: '#e03e2f',
35+
color: 'rgba(255, 255, 255, 0.8)',
36+
contentText: ' View logs in Sentry » ',
37+
linkURL: buildUrl(m[1]).toString(),
38+
},
39+
})
40+
}
41+
} while (m)
42+
pattern.lastIndex = 0 // reset
43+
}
44+
}
45+
editor.setDecorations(DECORATION_TYPE, decorations)
46+
}
47+
48+
export function activate(context: sourcegraph.ExtensionContext): void {
49+
sourcegraph.workspace.onDidOpenTextDocument.subscribe(textDocument => {
50+
const params: Params = getParamsFromUriPath(textDocument.uri)
51+
const sentryProjects = SETTINGSCONFIG['sentry.projects']
52+
53+
if (sourcegraph.app.activeWindowChanges && sentryProjects && isSentryEnabled(params, sentryProjects)) {
54+
const activeEditor = from(sourcegraph.app.activeWindowChanges).pipe(
55+
filter((window): window is sourcegraph.Window => window !== undefined),
56+
switchMap(window => window.activeViewComponentChanges),
57+
filter((editor): editor is sourcegraph.CodeEditor => editor !== undefined)
58+
)
59+
// When the active editor changes, publish new decorations.
60+
context.subscriptions.add(
61+
activeEditor.subscribe(editor => {
62+
decorateEditor(editor, sentryProjects)
63+
})
64+
)
65+
}
66+
})
67+
}
68+
69+
/**
70+
* Extract Sentry params from Document URI necessary to
71+
* build URL to the Sentry issues stream page, if the current
72+
* Document sends log events to Sentry.
73+
*
74+
* TODO: Implement regex match of params with Sentry extension settings.
75+
*/
76+
export function getParamsFromUriPath(textDocument: string): Params {
77+
const repoPattern = /github\.com\/([^\?\#]+)/gi
78+
const filePattern = /#([^\?\#\/]+)\/.*\.tsx?$/gi
79+
const repoM = repoPattern.exec(textDocument)
80+
const fileM = filePattern.exec(textDocument)
81+
return {
82+
repo: repoM![1],
83+
file: fileM![0],
84+
folder: fileM![1],
85+
}
86+
}
87+
88+
/**
89+
* Verify if the params from the document URI match with the repo and file formats specified
90+
* in the Sentry extension settings, we know the document is enabled to send logs
91+
* to Sentry.
92+
* @param params params extracted from the document's URI
93+
* @param projects Sentry extension projects configurations
94+
*/
95+
function isSentryEnabled(params: Params, projects: Settings['sentry.projects']): boolean {
96+
// Check if repo matches the repo specified under the Sentry extension configuration
97+
const doesRepoMatch: boolean = !!projects!.find(p => !!new RegExp(p.patternProperties.repoMatch).exec(params.repo!))
98+
99+
// Check if document matches the file format specified under the Sentry extension configuration
100+
const doesFileMatch: boolean = !!projects!.find(p => !!new RegExp(p.patternProperties.fileMatch).exec(params.file!))
101+
102+
if (doesRepoMatch && doesFileMatch) {
103+
return true
104+
}
105+
return false
106+
}
107+
108+
// TODO receive projectId from enabled Sentry project
109+
function buildUrl(errorQuery: string): URL {
110+
const url = new URL(
111+
'https://sentry.io/organizations/' +
112+
SETTINGSCONFIG['sentry.organization'] +
113+
'/issues/?project=1334031&query=is%3Aunresolved+' +
114+
errorQuery.split(' ').join('+') +
115+
'&statsPeriod=14d'
116+
)
117+
return url
118+
}
119+
// Sourcegraph extension documentation: https://docs.sourcegraph.com/extensions/authoring

src/settings.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,22 @@
66
*/
77
export interface Settings {
88
['sentry.organization']?: string
9-
['sentry.projects']?: []
9+
['sentry.projects']?: [
10+
{
11+
name: string
12+
projectId: string
13+
patternProperties: {
14+
repoMatch: RegExp
15+
fileMatch: RegExp
16+
lineMatch: RegExp
17+
}
18+
additionalProperties: {
19+
contentText: string
20+
hoverMessage: string
21+
query: string
22+
}
23+
}
24+
]
1025
}
1126

1227
/** Returns a copy of the extension settings with values normalized and defaults applied. */

src/sourcegraph-sentry.ts

-86
This file was deleted.

0 commit comments

Comments
 (0)