From 4b36175470caf7de643f1c24b9f9139818cd11de Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Tue, 23 Apr 2019 16:56:02 -0700 Subject: [PATCH 01/38] add more tests, extend the mock API to test activate --- src/test/extension.test.ts | 80 +++++++++++++++++++++++++++++++++++--- src/test/stubs.ts | 10 +++++ 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index b688d63e..4d9da36e 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -6,12 +6,16 @@ const sourcegraph = createMockSourcegraphAPI() // For modules importing Range/Location/URI/etc mock('sourcegraph', sourcegraph) -import { decorateEditor, decorateLine, getDecorations } from '../extension' +import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' describe('extension', () => { it('works', () => void 0) }) +describe('check for extension activation', () => { + it('activate extension', () => expect(activate(sourcegraph.ExtensionContext)).toEqual(void 0)) +}) + const data = [ { goal: 'render complete Sentry link', @@ -41,6 +45,14 @@ const data = [ missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, }, + { + goal: + 'match line based on common pattern, render warning link hinting to add projectId and render link to general issues page', + index: 1, + match: '', + missingConfigData: ['repoMatch', 'fileMatch'], + sentryProjectId: undefined, + }, ] const decorationsList = [ @@ -92,6 +104,17 @@ const decorationsList = [ linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', }, }, + { + range: new sourcegraph.Range(1, 0, 1, 0), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, ] describe('decorate line', () => { @@ -144,13 +167,29 @@ const decorationsData = [ { goal: 'receive no decoration due to no line matches', documentUri: - 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/file_info.php', + 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/empty.ts', documentText: `export const resolveDiffFileInfo = (codeView: HTMLElement): Observable => of(codeView).pipe( map(({ codeView, ...rest }) => { const { headFilePath, baseFilePath } = getDeltaFileName(codeView) }),`, }, + { + goal: 'receive no decoration due to empty textdocument', + documentUri: + 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/file_info.php', + documentText: ``, + }, + { + goal: 'receive one decoration on GitLab', + documentUri: + 'git://gitlab.com/sourcegraph/sourcegraph?92a448bdda22fea9a422f37cf83d99edeaa7fe4c#client/browser/src/e2e/chrome.e2e.test.ts', + documentText: `if (!headFilePath) { + throw new Error('cannot determine file path') + } + return { ...rest, codeView, headFilePath, baseFilePath } + }),`, + }, ] const expectedDecorations = [ @@ -200,6 +239,23 @@ const expectedDecorations = [ [], // receive no decoration due to no line matches [], + // receive no decoration due to no textdocument + [], + // receive on decoration from GitLab + [ + { + range: new sourcegraph.Range(1, 0, 1, 0), + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, + ], ] describe('get Decorations', () => { @@ -235,14 +291,28 @@ const languageCode = [ logger.debug("failed to build URL"); err.printStackTrace();`, }, + { + lang: 'C++', + code: ` { + log_error("Exception occurred!"); + throw; + }`, + }, ] describe('decorate Editor', () => { projects[0].patternProperties.lineMatches = [] for (const [i, codeExample] of languageCode.entries()) { - it('check common pattern matching for ' + languageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([decorationsList[3]]) - ) + if (i < 4) { + it('check common pattern matching for ' + languageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual([decorationsList[3]]) + ) + } else { + console.log(languageCode[i].lang) + it('should not render due to unsupported language ' + languageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual([]) + ) + } } // set lineMatches back to original state for the other tests projects[0].patternProperties.lineMatches = [ diff --git a/src/test/stubs.ts b/src/test/stubs.ts index 91c90565..06d32ad0 100644 --- a/src/test/stubs.ts +++ b/src/test/stubs.ts @@ -16,6 +16,10 @@ class Range { class Location { constructor(public uri: URI, public range: Range) {} } +export interface Unsubscribable { + unsubscribe(): void +} + /** * Creates an object that (mostly) implements the Sourcegraph API, * with all methods being Sinon spys and all Subscribables being Subjects. @@ -40,9 +44,15 @@ export const createMockSourcegraphAPI = () => ({ projects, }, }), + subscribe: (next: () => void) => void 0, }, search: {}, commands: {}, + ExtensionContext: { + subscriptions: { + add: () => createMockSourcegraphAPI().configuration.subscribe(() => void 0), + }, + }, }) export let projects: SentryProject[] = [ From 90bed81cec7e5b098b868c324939d49d7df56f2b Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Fri, 26 Apr 2019 17:50:15 +0000 Subject: [PATCH 02/38] Update dependency @sourcegraph/tslint-config to ^13.1.0 --- package-lock.json | 31 ++++++++++++++++++++----------- package.json | 2 +- yarn.lock | 24 +++++++++++++++--------- 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/package-lock.json b/package-lock.json index 424e2d18..2c001904 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "sourcegraph-sentry", + "name": "sentry", "version": "0.0.0-DEVELOPMENT", "lockfileVersion": 1, "requires": true, @@ -1036,12 +1036,12 @@ "dev": true }, "@sourcegraph/tslint-config": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@sourcegraph/tslint-config/-/tslint-config-13.0.0.tgz", - "integrity": "sha512-kDWngKXc7Qu8rdtsUP1pics0vOIx37e1ygjyrxMfhav722dhByxYowK3AxcbyECyaKEYt0wCp+bCqeVQX+XksQ==", + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@sourcegraph/tslint-config/-/tslint-config-13.1.0.tgz", + "integrity": "sha512-t4kkv7/q5+eG17LkFtNzT39dCOrokmugqsyFrVk0c8I+bH9R4lvFAgrMK6sOIaLQS0rYzPxECmgll5B5lY2haw==", "dev": true, "requires": { - "rxjs-tslint-rules": "^4.19.1", + "rxjs-tslint-rules": "^4.23.0", "tslint-config-prettier": "^1.18.0", "tslint-react": "^4.0.0" } @@ -7799,9 +7799,9 @@ "dev": true }, "prettier": { - "version": "1.16.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.4.tgz", - "integrity": "sha512-ZzWuos7TI5CKUeQAtFd6Zhm2s6EpAD/ZLApIhsF9pRvRtM1RFo61dM/4MSRUA0SuLugA/zgrZD8m0BaY46Og7g==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.17.0.tgz", + "integrity": "sha512-sXe5lSt2WQlCbydGETgfm1YBShgOX4HxQkFPvbxkcwgDvGDeqVau8h+12+lmSVlP3rHPz0oavfddSZg/q+Szjw==", "dev": true }, "pretty-format": { @@ -8271,17 +8271,26 @@ } }, "rxjs-tslint-rules": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/rxjs-tslint-rules/-/rxjs-tslint-rules-4.19.1.tgz", - "integrity": "sha512-TwosfLg5HgG6vSq6uHM49cUMJxX6ZfF8Cd4/r7TPc/h4hV2vm675T7zwO49MD2YxNpQbge4Xi8EOzn8XvJwYAA==", + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/rxjs-tslint-rules/-/rxjs-tslint-rules-4.23.0.tgz", + "integrity": "sha512-8lUa9tszIT3cZjGWMGh3lYMheQJO5RxuxCn7c3rhX7IiOGAq7BX6Fu2mP/0aUC9KzmxxP47FMDULFlZnrR4Oiw==", "dev": true, "requires": { "@phenomnomnominal/tsquery": "^3.0.0", "decamelize": "^3.0.0", "resolve": "^1.4.0", + "semver": "^6.0.0", "tslib": "^1.8.0", "tsutils": "^3.0.0", "tsutils-etc": "^1.1.0" + }, + "dependencies": { + "semver": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz", + "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ==", + "dev": true + } } }, "safe-buffer": { diff --git a/package.json b/package.json index acf75ccd..93d13b9c 100644 --- a/package.json +++ b/package.json @@ -177,7 +177,7 @@ "devDependencies": { "@sourcegraph/prettierrc": "^2.2.0", "@sourcegraph/tsconfig": "^4.0.0", - "@sourcegraph/tslint-config": "^13.0.0", + "@sourcegraph/tslint-config": "^13.1.0", "@types/expect": "1.20.4", "@types/lodash": "4.14.123", "@types/mocha": "5.2.6", diff --git a/yarn.lock b/yarn.lock index de5edfcc..33476308 100644 --- a/yarn.lock +++ b/yarn.lock @@ -791,12 +791,12 @@ resolved "https://registry.yarnpkg.com/@sourcegraph/tsconfig/-/tsconfig-4.0.0.tgz#dd2a406f90760bb789fd89fde4bd0a8d681f2767" integrity sha512-jxrhKbek4yu1HUDpUhqR9hAGFiUgaJ9NIM+c8JEkAnvpW67ab1AUFWb82aSVfZWX1UVqfR84AMr7xP3E8LlL+A== -"@sourcegraph/tslint-config@^13.0.0": - version "13.0.0" - resolved "https://registry.yarnpkg.com/@sourcegraph/tslint-config/-/tslint-config-13.0.0.tgz#f75d2ea51972c9f8cab233de98824b954457729b" - integrity sha512-kDWngKXc7Qu8rdtsUP1pics0vOIx37e1ygjyrxMfhav722dhByxYowK3AxcbyECyaKEYt0wCp+bCqeVQX+XksQ== +"@sourcegraph/tslint-config@^13.1.0": + version "13.1.0" + resolved "https://registry.yarnpkg.com/@sourcegraph/tslint-config/-/tslint-config-13.1.0.tgz#8053ea96bf58fcb0a9e120b129fb3e5aa03548cb" + integrity sha512-t4kkv7/q5+eG17LkFtNzT39dCOrokmugqsyFrVk0c8I+bH9R4lvFAgrMK6sOIaLQS0rYzPxECmgll5B5lY2haw== dependencies: - rxjs-tslint-rules "^4.19.1" + rxjs-tslint-rules "^4.23.0" tslint-config-prettier "^1.18.0" tslint-react "^4.0.0" @@ -5462,14 +5462,15 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" -rxjs-tslint-rules@^4.19.1: - version "4.19.1" - resolved "https://registry.yarnpkg.com/rxjs-tslint-rules/-/rxjs-tslint-rules-4.19.1.tgz#e5328cface0a0d0b52f2601082fa1ffd617f7869" - integrity sha512-TwosfLg5HgG6vSq6uHM49cUMJxX6ZfF8Cd4/r7TPc/h4hV2vm675T7zwO49MD2YxNpQbge4Xi8EOzn8XvJwYAA== +rxjs-tslint-rules@^4.23.0: + version "4.23.0" + resolved "https://registry.yarnpkg.com/rxjs-tslint-rules/-/rxjs-tslint-rules-4.23.0.tgz#e1aee3c1cd1e08ec013fe43f7008c60ce936c29f" + integrity sha512-8lUa9tszIT3cZjGWMGh3lYMheQJO5RxuxCn7c3rhX7IiOGAq7BX6Fu2mP/0aUC9KzmxxP47FMDULFlZnrR4Oiw== dependencies: "@phenomnomnominal/tsquery" "^3.0.0" decamelize "^3.0.0" resolve "^1.4.0" + semver "^6.0.0" tslib "^1.8.0" tsutils "^3.0.0" tsutils-etc "^1.1.0" @@ -5515,6 +5516,11 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" + integrity sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ== + send@0.16.2: version "0.16.2" resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1" From 4d26f4db2c64956b7975fd34a0077d90445903d2 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Fri, 26 Apr 2019 11:35:08 -0700 Subject: [PATCH 03/38] WIP: refactor to use extension api stubs --- package.json | 16 +- src/extension.ts | 10 +- src/test/extension.test.ts | 350 +++++++++++++++++++++---------------- src/test/handler.test.ts | 13 +- src/test/stubs.ts | 107 ------------ yarn.lock | 41 +++++ 6 files changed, 266 insertions(+), 271 deletions(-) delete mode 100644 src/test/stubs.ts diff --git a/package.json b/package.json index acf75ccd..7b20d9b0 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "alt": "sentry.link.fileList", "when": "resource && !config.sentry.hideSentryButton" } - ], "commandPalette": [ { @@ -89,22 +88,22 @@ "repoMatches": { "type": "array", "items": { - "type": "string" - }, + "type": "string" + }, "description": "Regex to match repos associated to this Sentry project, e.g. github\\.com/sourcegraph/sourcegraph" }, "fileMatches": { "type": "array", "items": { - "type": "string" - }, + "type": "string" + }, "description": "Regex to match files associated with this project, e.g. (web|shared)/.*\\.tsx?$" }, "lineMatches": { "type": "array", "items": { - "type": "string" - }, + "type": "string" + }, "description": "Regex to match lines associated with this project, e.g. throw new Error\\([\"']([^'\"]+)[\"']\\)" } }, @@ -200,5 +199,8 @@ "ts-node": "^8.0.3", "tslint": "^5.15.0", "typescript": "^3.4.2" + }, + "dependencies": { + "@sourcegraph/extension-api-stubs": "^0.1.0" } } diff --git a/src/extension.ts b/src/extension.ts index e8b12c84..e25314db 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,8 +18,6 @@ interface Params { file: string | null } -const SENTRYORGANIZATION = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] - /** * Common error log patterns to use in case no line matching regexes * are set in the sentry extension settings. @@ -170,7 +168,8 @@ export function decorateLine( missingConfigData: string[], sentryProjectId?: string ): sourcegraph.TextDocumentDecoration { - const lineDecorationText = createDecoration(missingConfigData, SENTRYORGANIZATION, sentryProjectId) + const sentryOrg = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] + const lineDecorationText = createDecoration(missingConfigData, sentryOrg, sentryProjectId) const decoration: sourcegraph.TextDocumentDecoration = { range: new sourcegraph.Range(index, 0, index, 0), isWholeLine: true, @@ -181,7 +180,7 @@ export function decorateLine( hoverMessage: lineDecorationText.hover, // TODO: If !SENTRYORGANIZATION is missing in config, link to $USER/settings and hint // user to fill it out. - linkURL: !SENTRYORGANIZATION + linkURL: !sentryOrg ? '' : sentryProjectId ? buildUrl(match, sentryProjectId).toString() @@ -199,9 +198,10 @@ export function decorateLine( */ // TODO: Use URLSearchParams instead of encodeURIComponent function buildUrl(errorQuery: string, sentryProjectId?: string): URL { + const sentryOrg = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] const url = new URL( 'https://sentry.io/organizations/' + - encodeURIComponent(SENTRYORGANIZATION!) + + encodeURIComponent(sentryOrg!) + '/issues/' + (sentryProjectId ? '?project=' + diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 4d9da36e..3c4cd871 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -1,21 +1,65 @@ +import { createStubExtensionContext, createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' +import { uniqueId } from 'lodash' import mock from 'mock-require' -import { createMockSourcegraphAPI, projects } from './stubs' - -const sourcegraph = createMockSourcegraphAPI() -// For modules importing Range/Location/URI/etc -mock('sourcegraph', sourcegraph) import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' +import { SentryProject } from '../settings' + +export const sourcegraph = createStubSourcegraphAPI() +// For modules importing Range/Location/Position/URI/etc +mock('sourcegraph', sourcegraph) describe('extension', () => { it('works', () => void 0) }) describe('check for extension activation', () => { - it('activate extension', () => expect(activate(sourcegraph.ExtensionContext)).toEqual(void 0)) + const context = createStubExtensionContext() + it('activate extension', () => expect(activate(context)).toEqual(void 0)) }) +export let projects: SentryProject[] = [ + { + name: 'Webapp typescript errors', + projectId: '1334031', + patternProperties: { + repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], + fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + lineMatches: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + }, + additionalProperties: { + contentText: 'View sourcegraph/sourcegraph_dot_com errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + }, + + { + name: 'Dev env errors', + projectId: '213332', + patternProperties: { + repoMatches: [/dev-repo/], + fileMatches: [/(dev)\/.*\\.go?/], + lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + }, + additionalProperties: { + contentText: 'View sourcegraph/dev-repo errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + }, +] + +sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' +sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') +sourcegraph.configuration.get().update('sentry.projects', projects) +sourcegraph.app.createDecorationType = () => ({ key: uniqueId('decorationType') }) + const data = [ { goal: 'render complete Sentry link', @@ -23,6 +67,18 @@ const data = [ match: 'cannot determine file path', missingConfigData: [], sentryProjectId: '134412', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, }, { goal: 'warn about incomplete config with missing repoMatch', @@ -30,6 +86,19 @@ const data = [ match: 'cannot determine file path', missingConfigData: ['repoMatch'], sentryProjectId: '134412', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: + ' Please fill out the following configurations in your Sentry extension settings: repoMatch', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, }, { goal: 'warn about incomplete config with missing repoMatch and fileMatch patterns', @@ -37,6 +106,19 @@ const data = [ match: 'cannot determine file path', missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: '134412', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: + ' Please fill out the following configurations in your Sentry extension settings: repoMatch, fileMatch', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, }, { goal: 'render warning link hinting to add projectId and render link to general issues page', @@ -44,6 +126,17 @@ const data = [ match: 'cannot determine file path', missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, }, { goal: @@ -52,76 +145,25 @@ const data = [ match: '', missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, - }, -] - -const decorationsList = [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Please fill out the following configurations in your Sentry extension settings: repoMatch', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: - ' Please fill out the following configurations in your Sentry extension settings: repoMatch, fileMatch', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', - linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', - linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, }, }, ] describe('decorate line', () => { - for (const [i, deco] of data.entries()) { + for (const [, deco] of data.entries()) { it('decorates the line with the following goal: ' + deco.goal, () => expect(decorateLine(deco.index, deco.match, deco.missingConfigData, deco.sentryProjectId)).toEqual( - decorationsList[i] + deco.expected ) ) } @@ -142,6 +184,32 @@ const decorationsData = [ if (!diffResolvedRev) { throw new Error('cannot determine delta info') },`, + expected: [ + { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, + { + range: new sourcegraph.Range(new sourcegraph.Position(8, 0), new sourcegraph.Position(8, 0)), + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20delta%20info&statsPeriod=14d', + }, + }, + ], }, { goal: 'receive one decoration', @@ -152,6 +220,21 @@ const decorationsData = [ } return { ...rest, codeView, headFilePath, baseFilePath } }),`, + // receive one decoration + expected: [ + { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, + ], }, { goal: 'receive no decoration due to file format mismatch', @@ -163,6 +246,7 @@ const decorationsData = [ return { ...rest, codeView, headFilePath, baseFilePath } }),`, + expected: [], }, { goal: 'receive no decoration due to no line matches', @@ -173,12 +257,14 @@ of(codeView).pipe( map(({ codeView, ...rest }) => { const { headFilePath, baseFilePath } = getDeltaFileName(codeView) }),`, + expected: [], }, { goal: 'receive no decoration due to empty textdocument', documentUri: 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/file_info.php', documentText: ``, + expected: [], }, { goal: 'receive one decoration on GitLab', @@ -189,85 +275,36 @@ of(codeView).pipe( } return { ...rest, codeView, headFilePath, baseFilePath } }),`, - }, -] - -const expectedDecorations = [ - // receive two decorations - [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + expected: [ + { + range: { + start: { line: 1, character: 0 }, + end: { line: 1, character: 0 }, + }, + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, }, - }, - { - range: new sourcegraph.Range(8, 0, 8, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20delta%20info&statsPeriod=14d', - }, - }, - ], - // receive one decoration - [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - ], - // receive no decoration due to file format mismatch - [], - // receive no decoration due to no line matches - [], - // receive no decoration due to no textdocument - [], - // receive on decoration from GitLab - [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - ], + ], + }, ] describe('get Decorations', () => { - for (const [i, deco] of decorationsData.entries()) { + for (const [, deco] of decorationsData.entries()) { it('fulfills the following goal:' + deco.goal, () => - expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(expectedDecorations[i]) + expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(deco.expected) ) } }) // make sure matching code is located on line 1 to ensure same start/end as decorationsList[3] -const languageCode = [ +const supportedLanguageCode = [ { lang: 'go', code: `// ErrInvalidToken is returned by DiscussionMailReplyTokens.Get when the token is invalid @@ -291,6 +328,9 @@ const languageCode = [ logger.debug("failed to build URL"); err.printStackTrace();`, }, +] + +const unsupportedLanguageCode = [ { lang: 'C++', code: ` { @@ -300,19 +340,31 @@ const languageCode = [ }, ] +const expectedLanguageTestOutcome = [ + { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, +] + describe('decorate Editor', () => { projects[0].patternProperties.lineMatches = [] - for (const [i, codeExample] of languageCode.entries()) { - if (i < 4) { - it('check common pattern matching for ' + languageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([decorationsList[3]]) - ) - } else { - console.log(languageCode[i].lang) - it('should not render due to unsupported language ' + languageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([]) - ) - } + for (const [i, codeExample] of supportedLanguageCode.entries()) { + it('check common pattern matching for ' + supportedLanguageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual(expectedLanguageTestOutcome) + ) + } + for (const [i, codeExample] of unsupportedLanguageCode.entries()) { + it('should not render due to unsupported language ' + unsupportedLanguageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual([]) + ) } // set lineMatches back to original state for the other tests projects[0].patternProperties.lineMatches = [ diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 609fc2e4..7695a95d 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -1,11 +1,18 @@ +import { createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' +import { uniqueId } from 'lodash' import mock from 'mock-require' -import { createMockSourcegraphAPI, projects } from './stubs' +import { projects } from './extension.test' -const sourcegraph = createMockSourcegraphAPI() -// For modules importing Range/Location/URI/etc +export const sourcegraph = createStubSourcegraphAPI() +// For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) +sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' +sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') +sourcegraph.configuration.get().update('sentry.projects', projects) +sourcegraph.app.createDecorationType = () => ({ key: uniqueId('decorationType') }) + import { checkMissingConfig, getParamsFromUriPath, matchSentryProject } from '../handler' import { SentryProject } from '../settings' diff --git a/src/test/stubs.ts b/src/test/stubs.ts deleted file mode 100644 index 06d32ad0..00000000 --- a/src/test/stubs.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { uniqueId } from 'lodash' -import * as sourcegraph from 'sourcegraph' -import { SentryProject } from '../settings' - -const URI = URL -type URI = URL - -class Range { - constructor( - public startLine: number, - public startCharacter: number, - public endLine: number, - public endCharacter: number - ) {} -} -class Location { - constructor(public uri: URI, public range: Range) {} -} -export interface Unsubscribable { - unsubscribe(): void -} - -/** - * Creates an object that (mostly) implements the Sourcegraph API, - * with all methods being Sinon spys and all Subscribables being Subjects. - */ -export const createMockSourcegraphAPI = () => ({ - internal: { - sourcegraphURL: 'https://sourcegraph.test', - }, - URI, - Range, - Location, - workspace: { - textDocuments: [] as sourcegraph.TextDocument[], - }, - app: { - createDecorationType: () => ({ key: uniqueId('decorationType') }), - }, - configuration: { - get: () => ({ - value: { - 'sentry.organization': 'sourcegraph', - projects, - }, - }), - subscribe: (next: () => void) => void 0, - }, - search: {}, - commands: {}, - ExtensionContext: { - subscriptions: { - add: () => createMockSourcegraphAPI().configuration.subscribe(() => void 0), - }, - }, -}) - -export let projects: SentryProject[] = [ - { - name: 'Webapp typescript errors', - projectId: '1334031', - patternProperties: { - repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], - fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], - lineMatches: [ - /throw new Error+\(['"]([^'"]+)['"]\)/, - /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, - /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], - }, - additionalProperties: { - contentText: 'View sourcegraph/sourcegraph_dot_com errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - }, - - { - name: 'Dev env errors', - projectId: '213332', - patternProperties: { - repoMatches: [/dev-repo/], - fileMatches: [/(dev)\/.*\\.go?/], - lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], - }, - additionalProperties: { - contentText: 'View sourcegraph/dev-repo errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - }, -] - -export const paramsWeb = { - repo: 'sourcegraph/sourcegraph', - file: '#web/src/storm/index.tsx', -} - -export const paramsDev = { - repo: 'sourcegraph/dev-repo', - file: '#dev/backend/main.go', -} - -export const paramsNone = { - repo: 'sourcegraph/test-repo', - file: '#dev/test/start.rb', -} diff --git a/yarn.lock b/yarn.lock index de5edfcc..4e0fa5f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -781,6 +781,17 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== +"@sourcegraph/extension-api-stubs@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-stubs/-/extension-api-stubs-0.1.0.tgz#34cab8c9a4ddd3db0d34b34d1cd740cbe7662f57" + integrity sha512-IyBk1Vae8rXDi2AM4w3hT+XwveALDZCAswQErc3mlXBIlrG1zm5sHdFum6EQgxL1eAFLj9yaSNdtNB1uTY2gGg== + dependencies: + "@types/sinon" "7.0.11" + rxjs "^6.5.1" + sinon "^7.3.2" + sourcegraph "^23.0.0" + vscode-languageserver-types "^3.14.0" + "@sourcegraph/prettierrc@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@sourcegraph/prettierrc/-/prettierrc-2.2.0.tgz#af4a6fcd465b0a39a07ffbd8f2d3414d01e603e8" @@ -3654,6 +3665,11 @@ lolex@^3.1.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-3.1.0.tgz#1a7feb2fefd75b3e3a7f79f0e110d9476e294434" integrity sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw== +lolex@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.0.1.tgz#4a99c2251579d693c6a083446dae0e5c3844d3fa" + integrity sha512-UHuOBZ5jjsKuzbB/gRNNW8Vg8f00Emgskdq2kvZxgBJCS0aqquAuXai/SkWORlKeZEiNQWZjFZOqIUcH9LqKCw== + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -5481,6 +5497,13 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" +rxjs@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.1.tgz#f7a005a9386361921b8524f38f54cbf80e5d08f4" + integrity sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg== + dependencies: + tslib "^1.9.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5642,6 +5665,19 @@ sinon@^7.3.1: nise "^1.4.10" supports-color "^5.5.0" +sinon@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28" + integrity sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA== + dependencies: + "@sinonjs/commons" "^1.4.0" + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/samsam" "^3.3.1" + diff "^3.5.0" + lolex "^4.0.1" + nise "^1.4.10" + supports-color "^5.5.0" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -6420,6 +6456,11 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +vscode-languageserver-types@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== + w3c-hr-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" From 3665af20bd90ac3488b70b4de494e2b19c1ad64f Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Mon, 29 Apr 2019 08:38:59 -0700 Subject: [PATCH 04/38] remove wip --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index acf75ccd..87c56437 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "activationEvents": [ "*" ], - "wip": true, + "wip": false, "categories": [ "External services" ], From 2afb581280dd604bdf90797ae70b0afc443ed243 Mon Sep 17 00:00:00 2001 From: Renovate Bot Date: Tue, 30 Apr 2019 12:55:17 +0000 Subject: [PATCH 05/38] Update dependency sourcegraph to ^23.0.1 --- package-lock.json | 6 +++--- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2c001904..dff649d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8649,9 +8649,9 @@ "dev": true }, "sourcegraph": { - "version": "23.0.0", - "resolved": "https://registry.npmjs.org/sourcegraph/-/sourcegraph-23.0.0.tgz", - "integrity": "sha512-hQALHrTt+AK5ZAqUAUNhxO7ClSv/xyTjMQPBb+hQykKJrMaHTk+CnJNHs7dRfXYKnbnZeisQRjaxKGX8UecU0Q==", + "version": "23.0.1", + "resolved": "https://registry.npmjs.org/sourcegraph/-/sourcegraph-23.0.1.tgz", + "integrity": "sha512-4We7zqhOagOVxNFdS6/xT/Crhb0Arw/9ytGBu8JuHfjo5yjMtcUYt22kZyu2TaPHXwyPW9muUi1eKSFA6Qg4lw==", "dev": true }, "spdx-correct": { diff --git a/package.json b/package.json index ce6f8612..2bc7a19d 100644 --- a/package.json +++ b/package.json @@ -196,7 +196,7 @@ "rxjs": "^6.4.0", "sinon": "^7.3.1", "source-map-support": "^0.5.12", - "sourcegraph": "^23.0.0", + "sourcegraph": "^23.0.1", "ts-node": "^8.0.3", "tslint": "^5.15.0", "typescript": "^3.4.2" diff --git a/yarn.lock b/yarn.lock index 33476308..6189ea55 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5717,10 +5717,10 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -sourcegraph@^23.0.0: - version "23.0.0" - resolved "https://registry.yarnpkg.com/sourcegraph/-/sourcegraph-23.0.0.tgz#1fb96015af3e84cc9cc2944823f04a7e952ed565" - integrity sha512-hQALHrTt+AK5ZAqUAUNhxO7ClSv/xyTjMQPBb+hQykKJrMaHTk+CnJNHs7dRfXYKnbnZeisQRjaxKGX8UecU0Q== +sourcegraph@^23.0.1: + version "23.0.1" + resolved "https://registry.yarnpkg.com/sourcegraph/-/sourcegraph-23.0.1.tgz#715fcf4129a6d94bc3bfd2740d9c706ae6357ffe" + integrity sha512-4We7zqhOagOVxNFdS6/xT/Crhb0Arw/9ytGBu8JuHfjo5yjMtcUYt22kZyu2TaPHXwyPW9muUi1eKSFA6Qg4lw== spawn-wrap@^1.4.2: version "1.4.2" From b28aeea31e194c3ee23236c2f931b7314151bd90 Mon Sep 17 00:00:00 2001 From: Felix Becker Date: Tue, 30 Apr 2019 19:50:27 +0200 Subject: [PATCH 06/38] Add CI badge (#17) --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d3316aef..0de11474 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,8 @@ -[![codecov](https://codecov.io/gh/sourcegraph/sentry/branch/master/graph/badge.svg)](https://codecov.io/gh/sourcegraph/sourcegraph-sentry) - # Sentry extension +[![build](https://travis-ci.org/sourcegraph/sentry.svg?branch=master)](https://travis-ci.org/sourcegraph/sentry) +[![codecov](https://codecov.io/gh/sourcegraph/sentry/branch/master/graph/badge.svg)](https://codecov.io/gh/sourcegraph/sourcegraph-sentry) + Sentry helps devs track, organize and break down errors more efficiently, facilitating their debug process. We want to make it more convenient for developers to access Sentry's error tracking tools directly from the code that is doing the error handling, code such as `throw new Error(QUERY)`, `console.log(QUERY)`, `console.error(QUERY)` etc.. The Sentry extension renders a `View logs in Sentry` next to error throwing statements, linking directly to the corresponding Sentry issues stream page. Links are rendered when viewing files on [Sourcegraph](https://sourcegraph.com), GitHub and GitLab. From dbbdb88a04b28219f2f34c1bcb2b01dccb55f299 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Tue, 23 Apr 2019 16:56:02 -0700 Subject: [PATCH 07/38] add more tests, extend the mock API to test activate --- src/test/extension.test.ts | 80 +++++++++++++++++++++++++++++++++++--- src/test/stubs.ts | 10 +++++ 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index b688d63e..4d9da36e 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -6,12 +6,16 @@ const sourcegraph = createMockSourcegraphAPI() // For modules importing Range/Location/URI/etc mock('sourcegraph', sourcegraph) -import { decorateEditor, decorateLine, getDecorations } from '../extension' +import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' describe('extension', () => { it('works', () => void 0) }) +describe('check for extension activation', () => { + it('activate extension', () => expect(activate(sourcegraph.ExtensionContext)).toEqual(void 0)) +}) + const data = [ { goal: 'render complete Sentry link', @@ -41,6 +45,14 @@ const data = [ missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, }, + { + goal: + 'match line based on common pattern, render warning link hinting to add projectId and render link to general issues page', + index: 1, + match: '', + missingConfigData: ['repoMatch', 'fileMatch'], + sentryProjectId: undefined, + }, ] const decorationsList = [ @@ -92,6 +104,17 @@ const decorationsList = [ linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', }, }, + { + range: new sourcegraph.Range(1, 0, 1, 0), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, ] describe('decorate line', () => { @@ -144,13 +167,29 @@ const decorationsData = [ { goal: 'receive no decoration due to no line matches', documentUri: - 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/file_info.php', + 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/empty.ts', documentText: `export const resolveDiffFileInfo = (codeView: HTMLElement): Observable => of(codeView).pipe( map(({ codeView, ...rest }) => { const { headFilePath, baseFilePath } = getDeltaFileName(codeView) }),`, }, + { + goal: 'receive no decoration due to empty textdocument', + documentUri: + 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/file_info.php', + documentText: ``, + }, + { + goal: 'receive one decoration on GitLab', + documentUri: + 'git://gitlab.com/sourcegraph/sourcegraph?92a448bdda22fea9a422f37cf83d99edeaa7fe4c#client/browser/src/e2e/chrome.e2e.test.ts', + documentText: `if (!headFilePath) { + throw new Error('cannot determine file path') + } + return { ...rest, codeView, headFilePath, baseFilePath } + }),`, + }, ] const expectedDecorations = [ @@ -200,6 +239,23 @@ const expectedDecorations = [ [], // receive no decoration due to no line matches [], + // receive no decoration due to no textdocument + [], + // receive on decoration from GitLab + [ + { + range: new sourcegraph.Range(1, 0, 1, 0), + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, + ], ] describe('get Decorations', () => { @@ -235,14 +291,28 @@ const languageCode = [ logger.debug("failed to build URL"); err.printStackTrace();`, }, + { + lang: 'C++', + code: ` { + log_error("Exception occurred!"); + throw; + }`, + }, ] describe('decorate Editor', () => { projects[0].patternProperties.lineMatches = [] for (const [i, codeExample] of languageCode.entries()) { - it('check common pattern matching for ' + languageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([decorationsList[3]]) - ) + if (i < 4) { + it('check common pattern matching for ' + languageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual([decorationsList[3]]) + ) + } else { + console.log(languageCode[i].lang) + it('should not render due to unsupported language ' + languageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual([]) + ) + } } // set lineMatches back to original state for the other tests projects[0].patternProperties.lineMatches = [ diff --git a/src/test/stubs.ts b/src/test/stubs.ts index 91c90565..06d32ad0 100644 --- a/src/test/stubs.ts +++ b/src/test/stubs.ts @@ -16,6 +16,10 @@ class Range { class Location { constructor(public uri: URI, public range: Range) {} } +export interface Unsubscribable { + unsubscribe(): void +} + /** * Creates an object that (mostly) implements the Sourcegraph API, * with all methods being Sinon spys and all Subscribables being Subjects. @@ -40,9 +44,15 @@ export const createMockSourcegraphAPI = () => ({ projects, }, }), + subscribe: (next: () => void) => void 0, }, search: {}, commands: {}, + ExtensionContext: { + subscriptions: { + add: () => createMockSourcegraphAPI().configuration.subscribe(() => void 0), + }, + }, }) export let projects: SentryProject[] = [ From 1a3dbc7e838febbf6454452351cf13fab01c1d3b Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Fri, 26 Apr 2019 11:35:08 -0700 Subject: [PATCH 08/38] WIP: refactor to use extension api stubs --- package.json | 16 +- src/extension.ts | 10 +- src/test/extension.test.ts | 350 +++++++++++++++++++++---------------- src/test/handler.test.ts | 13 +- src/test/stubs.ts | 107 ------------ yarn.lock | 41 +++++ 6 files changed, 266 insertions(+), 271 deletions(-) delete mode 100644 src/test/stubs.ts diff --git a/package.json b/package.json index 2bc7a19d..38790461 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,6 @@ "alt": "sentry.link.fileList", "when": "resource && !config.sentry.hideSentryButton" } - ], "commandPalette": [ { @@ -89,22 +88,22 @@ "repoMatches": { "type": "array", "items": { - "type": "string" - }, + "type": "string" + }, "description": "Regex to match repos associated to this Sentry project, e.g. github\\.com/sourcegraph/sourcegraph" }, "fileMatches": { "type": "array", "items": { - "type": "string" - }, + "type": "string" + }, "description": "Regex to match files associated with this project, e.g. (web|shared)/.*\\.tsx?$" }, "lineMatches": { "type": "array", "items": { - "type": "string" - }, + "type": "string" + }, "description": "Regex to match lines associated with this project, e.g. throw new Error\\([\"']([^'\"]+)[\"']\\)" } }, @@ -200,5 +199,8 @@ "ts-node": "^8.0.3", "tslint": "^5.15.0", "typescript": "^3.4.2" + }, + "dependencies": { + "@sourcegraph/extension-api-stubs": "^0.1.0" } } diff --git a/src/extension.ts b/src/extension.ts index e8b12c84..e25314db 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,8 +18,6 @@ interface Params { file: string | null } -const SENTRYORGANIZATION = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] - /** * Common error log patterns to use in case no line matching regexes * are set in the sentry extension settings. @@ -170,7 +168,8 @@ export function decorateLine( missingConfigData: string[], sentryProjectId?: string ): sourcegraph.TextDocumentDecoration { - const lineDecorationText = createDecoration(missingConfigData, SENTRYORGANIZATION, sentryProjectId) + const sentryOrg = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] + const lineDecorationText = createDecoration(missingConfigData, sentryOrg, sentryProjectId) const decoration: sourcegraph.TextDocumentDecoration = { range: new sourcegraph.Range(index, 0, index, 0), isWholeLine: true, @@ -181,7 +180,7 @@ export function decorateLine( hoverMessage: lineDecorationText.hover, // TODO: If !SENTRYORGANIZATION is missing in config, link to $USER/settings and hint // user to fill it out. - linkURL: !SENTRYORGANIZATION + linkURL: !sentryOrg ? '' : sentryProjectId ? buildUrl(match, sentryProjectId).toString() @@ -199,9 +198,10 @@ export function decorateLine( */ // TODO: Use URLSearchParams instead of encodeURIComponent function buildUrl(errorQuery: string, sentryProjectId?: string): URL { + const sentryOrg = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] const url = new URL( 'https://sentry.io/organizations/' + - encodeURIComponent(SENTRYORGANIZATION!) + + encodeURIComponent(sentryOrg!) + '/issues/' + (sentryProjectId ? '?project=' + diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 4d9da36e..3c4cd871 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -1,21 +1,65 @@ +import { createStubExtensionContext, createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' +import { uniqueId } from 'lodash' import mock from 'mock-require' -import { createMockSourcegraphAPI, projects } from './stubs' - -const sourcegraph = createMockSourcegraphAPI() -// For modules importing Range/Location/URI/etc -mock('sourcegraph', sourcegraph) import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' +import { SentryProject } from '../settings' + +export const sourcegraph = createStubSourcegraphAPI() +// For modules importing Range/Location/Position/URI/etc +mock('sourcegraph', sourcegraph) describe('extension', () => { it('works', () => void 0) }) describe('check for extension activation', () => { - it('activate extension', () => expect(activate(sourcegraph.ExtensionContext)).toEqual(void 0)) + const context = createStubExtensionContext() + it('activate extension', () => expect(activate(context)).toEqual(void 0)) }) +export let projects: SentryProject[] = [ + { + name: 'Webapp typescript errors', + projectId: '1334031', + patternProperties: { + repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], + fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + lineMatches: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + }, + additionalProperties: { + contentText: 'View sourcegraph/sourcegraph_dot_com errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + }, + + { + name: 'Dev env errors', + projectId: '213332', + patternProperties: { + repoMatches: [/dev-repo/], + fileMatches: [/(dev)\/.*\\.go?/], + lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + }, + additionalProperties: { + contentText: 'View sourcegraph/dev-repo errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + }, +] + +sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' +sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') +sourcegraph.configuration.get().update('sentry.projects', projects) +sourcegraph.app.createDecorationType = () => ({ key: uniqueId('decorationType') }) + const data = [ { goal: 'render complete Sentry link', @@ -23,6 +67,18 @@ const data = [ match: 'cannot determine file path', missingConfigData: [], sentryProjectId: '134412', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, }, { goal: 'warn about incomplete config with missing repoMatch', @@ -30,6 +86,19 @@ const data = [ match: 'cannot determine file path', missingConfigData: ['repoMatch'], sentryProjectId: '134412', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: + ' Please fill out the following configurations in your Sentry extension settings: repoMatch', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, }, { goal: 'warn about incomplete config with missing repoMatch and fileMatch patterns', @@ -37,6 +106,19 @@ const data = [ match: 'cannot determine file path', missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: '134412', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: + ' Please fill out the following configurations in your Sentry extension settings: repoMatch, fileMatch', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, }, { goal: 'render warning link hinting to add projectId and render link to general issues page', @@ -44,6 +126,17 @@ const data = [ match: 'cannot determine file path', missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, }, { goal: @@ -52,76 +145,25 @@ const data = [ match: '', missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, - }, -] - -const decorationsList = [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Please fill out the following configurations in your Sentry extension settings: repoMatch', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: - ' Please fill out the following configurations in your Sentry extension settings: repoMatch, fileMatch', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', - linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', - }, - }, - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', - linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + expected: { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, }, }, ] describe('decorate line', () => { - for (const [i, deco] of data.entries()) { + for (const [, deco] of data.entries()) { it('decorates the line with the following goal: ' + deco.goal, () => expect(decorateLine(deco.index, deco.match, deco.missingConfigData, deco.sentryProjectId)).toEqual( - decorationsList[i] + deco.expected ) ) } @@ -142,6 +184,32 @@ const decorationsData = [ if (!diffResolvedRev) { throw new Error('cannot determine delta info') },`, + expected: [ + { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, + { + range: new sourcegraph.Range(new sourcegraph.Position(8, 0), new sourcegraph.Position(8, 0)), + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20delta%20info&statsPeriod=14d', + }, + }, + ], }, { goal: 'receive one decoration', @@ -152,6 +220,21 @@ const decorationsData = [ } return { ...rest, codeView, headFilePath, baseFilePath } }),`, + // receive one decoration + expected: [ + { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, + }, + ], }, { goal: 'receive no decoration due to file format mismatch', @@ -163,6 +246,7 @@ const decorationsData = [ return { ...rest, codeView, headFilePath, baseFilePath } }),`, + expected: [], }, { goal: 'receive no decoration due to no line matches', @@ -173,12 +257,14 @@ of(codeView).pipe( map(({ codeView, ...rest }) => { const { headFilePath, baseFilePath } = getDeltaFileName(codeView) }),`, + expected: [], }, { goal: 'receive no decoration due to empty textdocument', documentUri: 'git://github.com/sourcegraph/sourcegraph?c436567c152bf40668c75815ed3ce62983af942d#client/browser/src/libs/github/file_info.php', documentText: ``, + expected: [], }, { goal: 'receive one decoration on GitLab', @@ -189,85 +275,36 @@ of(codeView).pipe( } return { ...rest, codeView, headFilePath, baseFilePath } }),`, - }, -] - -const expectedDecorations = [ - // receive two decorations - [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + expected: [ + { + range: { + start: { line: 1, character: 0 }, + end: { line: 1, character: 0 }, + }, + isWholeLine: true, + after: { + backgroundColor: '#e03e2f', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry » ', + hoverMessage: ' View logs in Sentry » ', + linkURL: + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + }, }, - }, - { - range: new sourcegraph.Range(8, 0, 8, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20delta%20info&statsPeriod=14d', - }, - }, - ], - // receive one decoration - [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - ], - // receive no decoration due to file format mismatch - [], - // receive no decoration due to no line matches - [], - // receive no decoration due to no textdocument - [], - // receive on decoration from GitLab - [ - { - range: new sourcegraph.Range(1, 0, 1, 0), - isWholeLine: true, - after: { - backgroundColor: '#e03e2f', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry » ', - hoverMessage: ' View logs in Sentry » ', - linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', - }, - }, - ], + ], + }, ] describe('get Decorations', () => { - for (const [i, deco] of decorationsData.entries()) { + for (const [, deco] of decorationsData.entries()) { it('fulfills the following goal:' + deco.goal, () => - expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(expectedDecorations[i]) + expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(deco.expected) ) } }) // make sure matching code is located on line 1 to ensure same start/end as decorationsList[3] -const languageCode = [ +const supportedLanguageCode = [ { lang: 'go', code: `// ErrInvalidToken is returned by DiscussionMailReplyTokens.Get when the token is invalid @@ -291,6 +328,9 @@ const languageCode = [ logger.debug("failed to build URL"); err.printStackTrace();`, }, +] + +const unsupportedLanguageCode = [ { lang: 'C++', code: ` { @@ -300,19 +340,31 @@ const languageCode = [ }, ] +const expectedLanguageTestOutcome = [ + { + range: { start: 1, end: 0 }, + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, +] + describe('decorate Editor', () => { projects[0].patternProperties.lineMatches = [] - for (const [i, codeExample] of languageCode.entries()) { - if (i < 4) { - it('check common pattern matching for ' + languageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([decorationsList[3]]) - ) - } else { - console.log(languageCode[i].lang) - it('should not render due to unsupported language ' + languageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([]) - ) - } + for (const [i, codeExample] of supportedLanguageCode.entries()) { + it('check common pattern matching for ' + supportedLanguageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual(expectedLanguageTestOutcome) + ) + } + for (const [i, codeExample] of unsupportedLanguageCode.entries()) { + it('should not render due to unsupported language ' + unsupportedLanguageCode[i].lang, () => + expect(decorateEditor([], codeExample.code)).toEqual([]) + ) } // set lineMatches back to original state for the other tests projects[0].patternProperties.lineMatches = [ diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 609fc2e4..7695a95d 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -1,11 +1,18 @@ +import { createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' +import { uniqueId } from 'lodash' import mock from 'mock-require' -import { createMockSourcegraphAPI, projects } from './stubs' +import { projects } from './extension.test' -const sourcegraph = createMockSourcegraphAPI() -// For modules importing Range/Location/URI/etc +export const sourcegraph = createStubSourcegraphAPI() +// For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) +sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' +sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') +sourcegraph.configuration.get().update('sentry.projects', projects) +sourcegraph.app.createDecorationType = () => ({ key: uniqueId('decorationType') }) + import { checkMissingConfig, getParamsFromUriPath, matchSentryProject } from '../handler' import { SentryProject } from '../settings' diff --git a/src/test/stubs.ts b/src/test/stubs.ts deleted file mode 100644 index 06d32ad0..00000000 --- a/src/test/stubs.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { uniqueId } from 'lodash' -import * as sourcegraph from 'sourcegraph' -import { SentryProject } from '../settings' - -const URI = URL -type URI = URL - -class Range { - constructor( - public startLine: number, - public startCharacter: number, - public endLine: number, - public endCharacter: number - ) {} -} -class Location { - constructor(public uri: URI, public range: Range) {} -} -export interface Unsubscribable { - unsubscribe(): void -} - -/** - * Creates an object that (mostly) implements the Sourcegraph API, - * with all methods being Sinon spys and all Subscribables being Subjects. - */ -export const createMockSourcegraphAPI = () => ({ - internal: { - sourcegraphURL: 'https://sourcegraph.test', - }, - URI, - Range, - Location, - workspace: { - textDocuments: [] as sourcegraph.TextDocument[], - }, - app: { - createDecorationType: () => ({ key: uniqueId('decorationType') }), - }, - configuration: { - get: () => ({ - value: { - 'sentry.organization': 'sourcegraph', - projects, - }, - }), - subscribe: (next: () => void) => void 0, - }, - search: {}, - commands: {}, - ExtensionContext: { - subscriptions: { - add: () => createMockSourcegraphAPI().configuration.subscribe(() => void 0), - }, - }, -}) - -export let projects: SentryProject[] = [ - { - name: 'Webapp typescript errors', - projectId: '1334031', - patternProperties: { - repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], - fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], - lineMatches: [ - /throw new Error+\(['"]([^'"]+)['"]\)/, - /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, - /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], - }, - additionalProperties: { - contentText: 'View sourcegraph/sourcegraph_dot_com errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - }, - - { - name: 'Dev env errors', - projectId: '213332', - patternProperties: { - repoMatches: [/dev-repo/], - fileMatches: [/(dev)\/.*\\.go?/], - lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], - }, - additionalProperties: { - contentText: 'View sourcegraph/dev-repo errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - }, -] - -export const paramsWeb = { - repo: 'sourcegraph/sourcegraph', - file: '#web/src/storm/index.tsx', -} - -export const paramsDev = { - repo: 'sourcegraph/dev-repo', - file: '#dev/backend/main.go', -} - -export const paramsNone = { - repo: 'sourcegraph/test-repo', - file: '#dev/test/start.rb', -} diff --git a/yarn.lock b/yarn.lock index 6189ea55..452c27f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -781,6 +781,17 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== +"@sourcegraph/extension-api-stubs@^0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-stubs/-/extension-api-stubs-0.1.0.tgz#34cab8c9a4ddd3db0d34b34d1cd740cbe7662f57" + integrity sha512-IyBk1Vae8rXDi2AM4w3hT+XwveALDZCAswQErc3mlXBIlrG1zm5sHdFum6EQgxL1eAFLj9yaSNdtNB1uTY2gGg== + dependencies: + "@types/sinon" "7.0.11" + rxjs "^6.5.1" + sinon "^7.3.2" + sourcegraph "^23.0.0" + vscode-languageserver-types "^3.14.0" + "@sourcegraph/prettierrc@^2.2.0": version "2.2.0" resolved "https://registry.yarnpkg.com/@sourcegraph/prettierrc/-/prettierrc-2.2.0.tgz#af4a6fcd465b0a39a07ffbd8f2d3414d01e603e8" @@ -3654,6 +3665,11 @@ lolex@^3.1.0: resolved "https://registry.yarnpkg.com/lolex/-/lolex-3.1.0.tgz#1a7feb2fefd75b3e3a7f79f0e110d9476e294434" integrity sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw== +lolex@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.0.1.tgz#4a99c2251579d693c6a083446dae0e5c3844d3fa" + integrity sha512-UHuOBZ5jjsKuzbB/gRNNW8Vg8f00Emgskdq2kvZxgBJCS0aqquAuXai/SkWORlKeZEiNQWZjFZOqIUcH9LqKCw== + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -5482,6 +5498,13 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" +rxjs@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.1.tgz#f7a005a9386361921b8524f38f54cbf80e5d08f4" + integrity sha512-y0j31WJc83wPu31vS1VlAFW5JGrnGC+j+TtGAa1fRQphy48+fDYiDmX8tjGloToEsMkxnouOg/1IzXGKkJnZMg== + dependencies: + tslib "^1.9.0" + safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" @@ -5648,6 +5671,19 @@ sinon@^7.3.1: nise "^1.4.10" supports-color "^5.5.0" +sinon@^7.3.2: + version "7.3.2" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28" + integrity sha512-thErC1z64BeyGiPvF8aoSg0LEnptSaWE7YhdWWbWXgelOyThent7uKOnnEh9zBxDbKixtr5dEko+ws1sZMuFMA== + dependencies: + "@sinonjs/commons" "^1.4.0" + "@sinonjs/formatio" "^3.2.1" + "@sinonjs/samsam" "^3.3.1" + diff "^3.5.0" + lolex "^4.0.1" + nise "^1.4.10" + supports-color "^5.5.0" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -6426,6 +6462,11 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" +vscode-languageserver-types@^3.14.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" + integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== + w3c-hr-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" From 07a36935ef44aa22171478339cce257a8ee56c8b Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Tue, 23 Apr 2019 16:56:02 -0700 Subject: [PATCH 09/38] add more tests, extend the mock API to test activate --- src/test/extension.test.ts | 13 +++-- src/test/stubs.ts | 107 +++++++++++++++++++++++++++++++++++++ 2 files changed, 117 insertions(+), 3 deletions(-) create mode 100644 src/test/stubs.ts diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 3c4cd871..3420b461 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -3,13 +3,13 @@ import expect from 'expect' import { uniqueId } from 'lodash' import mock from 'mock-require' -import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' -import { SentryProject } from '../settings' - export const sourcegraph = createStubSourcegraphAPI() // For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) +import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' +import { SentryProject } from '../settings' + describe('extension', () => { it('works', () => void 0) }) @@ -328,6 +328,13 @@ const supportedLanguageCode = [ logger.debug("failed to build URL"); err.printStackTrace();`, }, + { + lang: 'C++', + code: ` { + log_error("Exception occurred!"); + throw; + }`, + }, ] const unsupportedLanguageCode = [ diff --git a/src/test/stubs.ts b/src/test/stubs.ts new file mode 100644 index 00000000..06d32ad0 --- /dev/null +++ b/src/test/stubs.ts @@ -0,0 +1,107 @@ +import { uniqueId } from 'lodash' +import * as sourcegraph from 'sourcegraph' +import { SentryProject } from '../settings' + +const URI = URL +type URI = URL + +class Range { + constructor( + public startLine: number, + public startCharacter: number, + public endLine: number, + public endCharacter: number + ) {} +} +class Location { + constructor(public uri: URI, public range: Range) {} +} +export interface Unsubscribable { + unsubscribe(): void +} + +/** + * Creates an object that (mostly) implements the Sourcegraph API, + * with all methods being Sinon spys and all Subscribables being Subjects. + */ +export const createMockSourcegraphAPI = () => ({ + internal: { + sourcegraphURL: 'https://sourcegraph.test', + }, + URI, + Range, + Location, + workspace: { + textDocuments: [] as sourcegraph.TextDocument[], + }, + app: { + createDecorationType: () => ({ key: uniqueId('decorationType') }), + }, + configuration: { + get: () => ({ + value: { + 'sentry.organization': 'sourcegraph', + projects, + }, + }), + subscribe: (next: () => void) => void 0, + }, + search: {}, + commands: {}, + ExtensionContext: { + subscriptions: { + add: () => createMockSourcegraphAPI().configuration.subscribe(() => void 0), + }, + }, +}) + +export let projects: SentryProject[] = [ + { + name: 'Webapp typescript errors', + projectId: '1334031', + patternProperties: { + repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], + fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + lineMatches: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + }, + additionalProperties: { + contentText: 'View sourcegraph/sourcegraph_dot_com errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + }, + + { + name: 'Dev env errors', + projectId: '213332', + patternProperties: { + repoMatches: [/dev-repo/], + fileMatches: [/(dev)\/.*\\.go?/], + lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + }, + additionalProperties: { + contentText: 'View sourcegraph/dev-repo errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + }, +] + +export const paramsWeb = { + repo: 'sourcegraph/sourcegraph', + file: '#web/src/storm/index.tsx', +} + +export const paramsDev = { + repo: 'sourcegraph/dev-repo', + file: '#dev/backend/main.go', +} + +export const paramsNone = { + repo: 'sourcegraph/test-repo', + file: '#dev/test/start.rb', +} From f1a5fd0fd6b4b1aa1d97cc7b720902a12204e8fa Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Fri, 26 Apr 2019 11:35:08 -0700 Subject: [PATCH 10/38] WIP: refactor to use extension api stubs --- src/test/extension.test.ts | 7 --- src/test/stubs.ts | 107 ------------------------------------- 2 files changed, 114 deletions(-) delete mode 100644 src/test/stubs.ts diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 3420b461..c8309527 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -328,13 +328,6 @@ const supportedLanguageCode = [ logger.debug("failed to build URL"); err.printStackTrace();`, }, - { - lang: 'C++', - code: ` { - log_error("Exception occurred!"); - throw; - }`, - }, ] const unsupportedLanguageCode = [ diff --git a/src/test/stubs.ts b/src/test/stubs.ts deleted file mode 100644 index 06d32ad0..00000000 --- a/src/test/stubs.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { uniqueId } from 'lodash' -import * as sourcegraph from 'sourcegraph' -import { SentryProject } from '../settings' - -const URI = URL -type URI = URL - -class Range { - constructor( - public startLine: number, - public startCharacter: number, - public endLine: number, - public endCharacter: number - ) {} -} -class Location { - constructor(public uri: URI, public range: Range) {} -} -export interface Unsubscribable { - unsubscribe(): void -} - -/** - * Creates an object that (mostly) implements the Sourcegraph API, - * with all methods being Sinon spys and all Subscribables being Subjects. - */ -export const createMockSourcegraphAPI = () => ({ - internal: { - sourcegraphURL: 'https://sourcegraph.test', - }, - URI, - Range, - Location, - workspace: { - textDocuments: [] as sourcegraph.TextDocument[], - }, - app: { - createDecorationType: () => ({ key: uniqueId('decorationType') }), - }, - configuration: { - get: () => ({ - value: { - 'sentry.organization': 'sourcegraph', - projects, - }, - }), - subscribe: (next: () => void) => void 0, - }, - search: {}, - commands: {}, - ExtensionContext: { - subscriptions: { - add: () => createMockSourcegraphAPI().configuration.subscribe(() => void 0), - }, - }, -}) - -export let projects: SentryProject[] = [ - { - name: 'Webapp typescript errors', - projectId: '1334031', - patternProperties: { - repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], - fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], - lineMatches: [ - /throw new Error+\(['"]([^'"]+)['"]\)/, - /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, - /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], - }, - additionalProperties: { - contentText: 'View sourcegraph/sourcegraph_dot_com errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - }, - - { - name: 'Dev env errors', - projectId: '213332', - patternProperties: { - repoMatches: [/dev-repo/], - fileMatches: [/(dev)\/.*\\.go?/], - lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], - }, - additionalProperties: { - contentText: 'View sourcegraph/dev-repo errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - }, -] - -export const paramsWeb = { - repo: 'sourcegraph/sourcegraph', - file: '#web/src/storm/index.tsx', -} - -export const paramsDev = { - repo: 'sourcegraph/dev-repo', - file: '#dev/backend/main.go', -} - -export const paramsNone = { - repo: 'sourcegraph/test-repo', - file: '#dev/test/start.rb', -} From a40c7ca1737f33de1c6316ff293daeaa5b860d0e Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Tue, 30 Apr 2019 11:14:22 -0700 Subject: [PATCH 11/38] fix tests --- src/test/extension.test.ts | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index c8309527..3bfb7d45 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -1,6 +1,5 @@ import { createStubExtensionContext, createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' -import { uniqueId } from 'lodash' import mock from 'mock-require' export const sourcegraph = createStubSourcegraphAPI() @@ -55,11 +54,6 @@ export let projects: SentryProject[] = [ }, ] -sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' -sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') -sourcegraph.configuration.get().update('sentry.projects', projects) -sourcegraph.app.createDecorationType = () => ({ key: uniqueId('decorationType') }) - const data = [ { goal: 'render complete Sentry link', @@ -68,7 +62,7 @@ const data = [ missingConfigData: [], sentryProjectId: '134412', expected: { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#e03e2f', @@ -87,7 +81,7 @@ const data = [ missingConfigData: ['repoMatch'], sentryProjectId: '134412', expected: { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#f2736d', @@ -107,7 +101,7 @@ const data = [ missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: '134412', expected: { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#f2736d', @@ -127,7 +121,7 @@ const data = [ missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, expected: { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#f2736d', @@ -146,7 +140,7 @@ const data = [ missingConfigData: ['repoMatch', 'fileMatch'], sentryProjectId: undefined, expected: { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#f2736d', @@ -160,6 +154,9 @@ const data = [ ] describe('decorate line', () => { + sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' + sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + sourcegraph.configuration.get().update('sentry.projects', projects) for (const [, deco] of data.entries()) { it('decorates the line with the following goal: ' + deco.goal, () => expect(decorateLine(deco.index, deco.match, deco.missingConfigData, deco.sentryProjectId)).toEqual( @@ -223,7 +220,7 @@ const decorationsData = [ // receive one decoration expected: [ { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#e03e2f', @@ -277,10 +274,7 @@ of(codeView).pipe( }),`, expected: [ { - range: { - start: { line: 1, character: 0 }, - end: { line: 1, character: 0 }, - }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#e03e2f', @@ -296,6 +290,9 @@ of(codeView).pipe( ] describe('get Decorations', () => { + sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' + sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + sourcegraph.configuration.get().update('sentry.projects', projects) for (const [, deco] of decorationsData.entries()) { it('fulfills the following goal:' + deco.goal, () => expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(deco.expected) @@ -342,7 +339,7 @@ const unsupportedLanguageCode = [ const expectedLanguageTestOutcome = [ { - range: { start: 1, end: 0 }, + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, after: { backgroundColor: '#f2736d', @@ -355,6 +352,10 @@ const expectedLanguageTestOutcome = [ ] describe('decorate Editor', () => { + sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' + sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + sourcegraph.configuration.get().update('sentry.projects', projects) + projects[0].patternProperties.lineMatches = [] for (const [i, codeExample] of supportedLanguageCode.entries()) { it('check common pattern matching for ' + supportedLanguageCode[i].lang, () => From accbf416cad9f989a21a3eee1a4ce12b1aaec12f Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Tue, 30 Apr 2019 11:29:36 -0700 Subject: [PATCH 12/38] update extension stubs package and tests --- package.json | 2 +- src/test/extension.test.ts | 29 ++++++++++++----------------- yarn.lock | 29 ++++++++++++++++++----------- 3 files changed, 31 insertions(+), 29 deletions(-) diff --git a/package.json b/package.json index 38790461..0baf9a09 100644 --- a/package.json +++ b/package.json @@ -201,6 +201,6 @@ "typescript": "^3.4.2" }, "dependencies": { - "@sourcegraph/extension-api-stubs": "^0.1.0" + "@sourcegraph/extension-api-stubs": "^0.1.1" } } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 3bfb7d45..dcb733f9 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -9,10 +9,6 @@ mock('sourcegraph', sourcegraph) import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' import { SentryProject } from '../settings' -describe('extension', () => { - it('works', () => void 0) -}) - describe('check for extension activation', () => { const context = createStubExtensionContext() it('activate extension', () => expect(activate(context)).toEqual(void 0)) @@ -75,10 +71,10 @@ const data = [ }, }, { - goal: 'warn about incomplete config with missing repoMatch', + goal: 'warn about incomplete config with missing repoMatches', index: 1, match: 'cannot determine file path', - missingConfigData: ['repoMatch'], + missingConfigData: ['repoMatches'], sentryProjectId: '134412', expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -88,17 +84,17 @@ const data = [ color: 'rgba(255, 255, 255, 0.8)', contentText: ' View logs in Sentry (❕)» ', hoverMessage: - ' Please fill out the following configurations in your Sentry extension settings: repoMatch', + ' Please fill out the following configurations in your Sentry extension settings: repoMatches', linkURL: 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', }, }, }, { - goal: 'warn about incomplete config with missing repoMatch and fileMatch patterns', + goal: 'warn about incomplete config with missing repoMatches and fileMatches patterns', index: 1, match: 'cannot determine file path', - missingConfigData: ['repoMatch', 'fileMatch'], + missingConfigData: ['repoMatches', 'fileMatches'], sentryProjectId: '134412', expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -108,7 +104,7 @@ const data = [ color: 'rgba(255, 255, 255, 0.8)', contentText: ' View logs in Sentry (❕)» ', hoverMessage: - ' Please fill out the following configurations in your Sentry extension settings: repoMatch, fileMatch', + ' Please fill out the following configurations in your Sentry extension settings: repoMatches, fileMatches', linkURL: 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', }, @@ -118,7 +114,7 @@ const data = [ goal: 'render warning link hinting to add projectId and render link to general issues page', index: 1, match: 'cannot determine file path', - missingConfigData: ['repoMatch', 'fileMatch'], + missingConfigData: ['repoMatches', 'fileMatches'], sentryProjectId: undefined, expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -137,7 +133,7 @@ const data = [ 'match line based on common pattern, render warning link hinting to add projectId and render link to general issues page', index: 1, match: '', - missingConfigData: ['repoMatch', 'fileMatch'], + missingConfigData: ['repoMatches', 'fileMatches'], sentryProjectId: undefined, expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -154,10 +150,10 @@ const data = [ ] describe('decorate line', () => { - sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') sourcegraph.configuration.get().update('sentry.projects', projects) - for (const [, deco] of data.entries()) { + + for (const deco of data) { it('decorates the line with the following goal: ' + deco.goal, () => expect(decorateLine(deco.index, deco.match, deco.missingConfigData, deco.sentryProjectId)).toEqual( deco.expected @@ -290,10 +286,10 @@ of(codeView).pipe( ] describe('get Decorations', () => { - sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') sourcegraph.configuration.get().update('sentry.projects', projects) - for (const [, deco] of decorationsData.entries()) { + + for (const deco of decorationsData) { it('fulfills the following goal:' + deco.goal, () => expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(deco.expected) ) @@ -352,7 +348,6 @@ const expectedLanguageTestOutcome = [ ] describe('decorate Editor', () => { - sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') sourcegraph.configuration.get().update('sentry.projects', projects) diff --git a/yarn.lock b/yarn.lock index 452c27f2..9b5b83f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -781,16 +781,28 @@ resolved "https://registry.yarnpkg.com/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz#8da5c6530915653f3a1f38fd5f101d8c3f8079c5" integrity sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ== -"@sourcegraph/extension-api-stubs@^0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-stubs/-/extension-api-stubs-0.1.0.tgz#34cab8c9a4ddd3db0d34b34d1cd740cbe7662f57" - integrity sha512-IyBk1Vae8rXDi2AM4w3hT+XwveALDZCAswQErc3mlXBIlrG1zm5sHdFum6EQgxL1eAFLj9yaSNdtNB1uTY2gGg== +"@sourcegraph/extension-api-classes@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-classes/-/extension-api-classes-1.0.2.tgz#e76ff8394deacffb7cb1edd5f5d24d714e6026ee" + integrity sha512-2PUTf/hedG+5DTyUmA2QPK7I/qyiwIbgQHcmAeRGlysg17okOeNFRp4AVLJsAh+NLq8poxtbyXP+dIdrCzONgw== + dependencies: + "@sourcegraph/extension-api-types" "^2.0.0" + +"@sourcegraph/extension-api-stubs@^0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-stubs/-/extension-api-stubs-0.1.1.tgz#8e161adec70fd5b7a78ace649a456b99f9c78977" + integrity sha512-TMVbHFUM/BF9odoQaiUBDbhax7joqUutkU22DI/KdtW9wz5O1nWT0oJr1wdv0xvYRDvKGG/gOXypd2ZC+aNE2A== dependencies: + "@sourcegraph/extension-api-classes" "^1.0.2" "@types/sinon" "7.0.11" rxjs "^6.5.1" sinon "^7.3.2" - sourcegraph "^23.0.0" - vscode-languageserver-types "^3.14.0" + sourcegraph "^23.0.1" + +"@sourcegraph/extension-api-types@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-types/-/extension-api-types-2.0.0.tgz#b38145521c0549b2be300df53bac48b648ccbc2d" + integrity sha512-Te7F1RQJLBH4C8wQ2xz0nPC2vpe13F80V+Yv+c3GySOoh4DcLNN4P5u51Kh4aZPqeS5DJ7CKvHyX2SM/1EBXNg== "@sourcegraph/prettierrc@^2.2.0": version "2.2.0" @@ -6462,11 +6474,6 @@ vm-browserify@0.0.4: dependencies: indexof "0.0.1" -vscode-languageserver-types@^3.14.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz#d3b5952246d30e5241592b6dde8280e03942e743" - integrity sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A== - w3c-hr-time@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045" From 011c6ad39f877bc29ab88af8ad7554c6ebc2d545 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 1 May 2019 13:04:32 -0700 Subject: [PATCH 13/38] fix tests --- src/extension.ts | 1 + src/test/extension.test.ts | 45 +++++++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/extension.ts b/src/extension.ts index e25314db..86956857 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -50,6 +50,7 @@ export function activate(context: sourcegraph.ExtensionContext): void { switchMap(window => window.activeViewComponentChanges), filter((editor): editor is sourcegraph.CodeEditor => editor !== undefined) ) + // When the active editor changes, publish new decorations. context.subscriptions.add( combineLatest(configurationChanges, activeEditor).subscribe(([, editor]) => { diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index dcb733f9..e935c456 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -7,13 +7,56 @@ export const sourcegraph = createStubSourcegraphAPI() mock('sourcegraph', sourcegraph) import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' -import { SentryProject } from '../settings' +import { resolveSettings, SentryProject } from '../settings' describe('check for extension activation', () => { const context = createStubExtensionContext() it('activate extension', () => expect(activate(context)).toEqual(void 0)) }) +const settings = { + 'sentry.decorations.inline': false, + 'sentry.organization': 'sourcegraph', + 'sentry.projects': [ + { + additionalProperties: { + contentText: 'View sourcegraph/sourcegraph_dot_com errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + name: 'Webapp typescript errors', + patternProperties: { + fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + lineMatches: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], + }, + projectId: '1334031', + }, + { + additionalProperties: { + contentText: 'View sourcegraph/dev-repo errors', + hoverMessage: 'View errors matching "$1" in Sentry', + query: '$1', + }, + name: 'Dev env errors', + patternProperties: { + fileMatches: [/(dev)\/.*\\.go?/], + lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + repoMatches: [/dev-repo/], + }, + projectId: '213332', + }, + ], +} + +describe('check for configurations', () => { + it('activate extension', () => expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings)) +}) + export let projects: SentryProject[] = [ { name: 'Webapp typescript errors', From 0a0739b012a8a801d8b8e836e57a47b0e96d9a4d Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 8 May 2019 11:23:45 -0700 Subject: [PATCH 14/38] refactor code, increase text coverage to 88% --- package.json | 2 +- src/extension.ts | 1 - src/handler.ts | 4 +- src/test/extension.test.ts | 11 +++- src/test/handler.test.ts | 118 ++++++++++++++++++++++++++----------- yarn.lock | 8 +-- 6 files changed, 98 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index 0baf9a09..f13d2761 100644 --- a/package.json +++ b/package.json @@ -201,6 +201,6 @@ "typescript": "^3.4.2" }, "dependencies": { - "@sourcegraph/extension-api-stubs": "^0.1.1" + "@sourcegraph/extension-api-stubs": "^0.2.0" } } diff --git a/src/extension.ts b/src/extension.ts index 86956857..4ec35d9a 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -43,7 +43,6 @@ export function activate(context: sourcegraph.ExtensionContext): void { // TODO: Change this when https://github.com/sourcegraph/sourcegraph/issues/3557 is resolved const configurationChanges = new BehaviorSubject(undefined) context.subscriptions.add(sourcegraph.configuration.subscribe(() => configurationChanges.next(undefined))) - if (sourcegraph.app.activeWindowChanges) { const activeEditor = from(sourcegraph.app.activeWindowChanges).pipe( filter((window): window is sourcegraph.Window => window !== undefined), diff --git a/src/handler.ts b/src/handler.ts index 93204899..5deff639 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -5,7 +5,7 @@ interface Params { file: string | null } -interface LineDecorationText { +export interface LineDecorationText { content: string hover: string backgroundColor: string @@ -74,7 +74,7 @@ export function isFileMatched(params: Params, project: SentryProject): boolean | * Check for missing configurations in the Sentry extension settings * @param settings */ -export function checkMissingConfig(settings: SentryProject): string[] { +export function checkMissingConfig(settings?: SentryProject): string[] { if (!settings) { return [] } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index e935c456..ed5497cb 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -205,7 +205,7 @@ describe('decorate line', () => { } }) -const decorationsData = [ +const getDecorationsInput = [ { goal: 'receive two decorations', documentUri: @@ -256,7 +256,6 @@ const decorationsData = [ } return { ...rest, codeView, headFilePath, baseFilePath } }),`, - // receive one decoration expected: [ { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -326,13 +325,19 @@ of(codeView).pipe( }, ], }, + { + goal: 'returns empty array due to missing documentUri, documentText and projects list', + documentUri: '', + documentText: ``, + expected: [], + }, ] describe('get Decorations', () => { sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') sourcegraph.configuration.get().update('sentry.projects', projects) - for (const deco of decorationsData) { + for (const deco of getDecorationsInput) { it('fulfills the following goal:' + deco.goal, () => expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(deco.expected) ) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 7695a95d..5b7f32eb 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -1,6 +1,5 @@ import { createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' -import { uniqueId } from 'lodash' import mock from 'mock-require' import { projects } from './extension.test' @@ -8,13 +7,10 @@ export const sourcegraph = createStubSourcegraphAPI() // For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) -sourcegraph.internal.sourcegraphURL = 'https://sourcegraph.test' sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') sourcegraph.configuration.get().update('sentry.projects', projects) -sourcegraph.app.createDecorationType = () => ({ key: uniqueId('decorationType') }) -import { checkMissingConfig, getParamsFromUriPath, matchSentryProject } from '../handler' -import { SentryProject } from '../settings' +import { checkMissingConfig, createDecoration, getParamsFromUriPath, matchSentryProject } from '../handler' describe('getParamsFromUriPath', () => { it('extracts repo and file params from root folder', () => @@ -41,42 +37,94 @@ describe('getParamsFromUriPath', () => { })) }) -const paramsWeb = { - repo: 'sourcegraph/sourcegraph', - file: '#web/src/storm/index.tsx', -} - -export const paramsDev = { - repo: 'sourcegraph/dev-repo', - file: '#dev/backend/main.go', -} - -export const paramsNone = { - repo: 'sourcegraph/test-repo', - file: '#dev/test/start.rb', -} +const paramsInput = [ + { + goal: 'returns a web project that matches the repo and file patterns', + params: { + repo: 'sourcegraph/sourcegraph', + file: '#web/src/storm/index.tsx', + }, + expected: projects[0], + }, + { + goal: 'returns a dev project that matches the repo and file patterns', + params: { + repo: 'sourcegraph/dev-repo', + file: '#dev/backend/main.go', + }, + expected: projects[1], + }, + { + goal: 'returns undefined for not matching repo and file patterns', + params: { + repo: 'sourcegraph/test-repo', + file: '#dev/test/start.rb', + }, + expected: undefined, + }, + { + goal: 'returns undefined for not matching repo and file patterns', + params: { + repo: 'sourcegraph/test-repo', + file: '#dev/test/start.rb', + }, + expected: undefined, + }, +] describe('matchSentryProject', () => { - it('returns a web project that matches the repo and file patterns', () => - expect(matchSentryProject(paramsWeb, projects)).toEqual(projects[0])) + for (const paramsCase of paramsInput) { + it('fullfils the following goal: ' + paramsCase.goal, () => + expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected) + ) + } +}) - it('returns a dev project that matches the repo and file patterns', () => - expect(matchSentryProject(paramsDev, projects)).toEqual(projects[1])) +const incompleteConfigs = [ + { + goal: 'return one missing config', + settings: { + name: 'sourcegraph', + projectId: '1334031', + patternProperties: { + repoMatches: undefined, + fileMatches: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + lineMatches: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], + }, + }, + expected: ['repoMatches'], + }, + { + goal: 'return two missing configs', + settings: { + name: 'sourcegraph', + projectId: '', + patternProperties: { + repoMatches: undefined, + fileMatches: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + lineMatches: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], + }, + }, + expected: ['projectId', 'repoMatches'], + }, +] - it('returns undefined for not matching repo and file patterns', () => - expect(matchSentryProject(paramsNone, projects)).toEqual(undefined)) +describe('missingConfig', () => { + for (const config of incompleteConfigs) { + it('check missing configs with goal to ' + config.goal, () => + expect(checkMissingConfig(config.settings)).toEqual(config.expected) + ) + } + it('handle empty settings', () => expect(checkMissingConfig()).toEqual([])) }) -const incompleteConfigs: SentryProject = { - name: 'sourcegraph', - projectId: '1334031', - patternProperties: { - repoMatches: undefined, - fileMatches: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], - lineMatches: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], - }, +const createDecorationWithoutOrgOutcome = { + content: ' Configure the Sentry extension to view logs. ', + hover: ' Configure the Sentry extension to view logs in Sentry. ', + backgroundColor: '#e03e2f', } -describe('missingConfig', () => { - it('check missing configs', () => expect(checkMissingConfig(incompleteConfigs)).toEqual(['repoMatches'])) +describe('createDecoration', () => { + it('handle empty organization setting', () => + expect(createDecoration([])).toEqual(createDecorationWithoutOrgOutcome)) }) diff --git a/yarn.lock b/yarn.lock index 9b5b83f8..2ab067cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -788,10 +788,10 @@ dependencies: "@sourcegraph/extension-api-types" "^2.0.0" -"@sourcegraph/extension-api-stubs@^0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-stubs/-/extension-api-stubs-0.1.1.tgz#8e161adec70fd5b7a78ace649a456b99f9c78977" - integrity sha512-TMVbHFUM/BF9odoQaiUBDbhax7joqUutkU22DI/KdtW9wz5O1nWT0oJr1wdv0xvYRDvKGG/gOXypd2ZC+aNE2A== +"@sourcegraph/extension-api-stubs@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@sourcegraph/extension-api-stubs/-/extension-api-stubs-0.2.0.tgz#4deee465d96cb49c7790da95fa28aefbdf995177" + integrity sha512-EhI65jZnDB+/pnRHrwzlFq7JN9NuabJBiZoBmAMghnqtbVD/5pEqm9XJD0LPCg/Uc3FEIVTkVXjNylGn4s0JNA== dependencies: "@sourcegraph/extension-api-classes" "^1.0.2" "@types/sinon" "7.0.11" From c780656557e842bc06e38624f626e1b4dc1afaf4 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 8 May 2019 18:58:17 -0700 Subject: [PATCH 15/38] improve repo matching with better repoMatch param, update tests --- src/extension.ts | 3 ++- src/handler.ts | 4 ++-- src/test/handler.test.ts | 9 ++++++--- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 4ec35d9a..b6327410 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -30,7 +30,7 @@ const COMMON_ERRORLOG_PATTERNS = [ /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/gi, /fmt\.Errorf\(['"]([^'"]+)['"]\)/gi, /errors\.New\(['"]([^'"]+)['"]\)/gi, - /err\.message\(['"`]([^'"`]+)['"`]\)/gi, + /err\.message\(['"`]([^'"`$]+)['"`]\)/gi, /panic\(['"]([^'"]+)['"]\)/gi, // python /raise (TypeError|ValueError)\(['"`]([^'"`]+)['"`]\)/gi, @@ -88,6 +88,7 @@ export function getDecorations( sentryProjects?: SentryProject[] ): sourcegraph.TextDocumentDecoration[] { const params: Params = getParamsFromUriPath(documentUri) + const sentryProject = sentryProjects && matchSentryProject(params, sentryProjects) let missingConfigData: string[] = [] let fileMatched: boolean | null diff --git a/src/handler.ts b/src/handler.ts index 5deff639..99495e95 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -19,9 +19,9 @@ export interface LineDecorationText { * @returns repo and file part of URI. */ export function getParamsFromUriPath(textDocumentURI: string): Params { - // TODO: Support more than just GitHub. + // TODO: Support more than just GitHub & Gitlab. // TODO: Safeguard for cases where repo/fileMatch are null. - const repoPattern = /(github\.com|gitlab\.com)\/([^\?\#\/]+\/[^\?\#\/]*)/gi + const repoPattern = /(github\.com|gitlab\.com)\/([^\?\#\/]+\/[^\?\#\/].*)/gi const filePattern = /#.*\.(.*)$/gi const repoMatch = repoPattern.exec(textDocumentURI) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 5b7f32eb..5aa67270 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -15,14 +15,17 @@ import { checkMissingConfig, createDecoration, getParamsFromUriPath, matchSentry describe('getParamsFromUriPath', () => { it('extracts repo and file params from root folder', () => expect(getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph?264...#index.tsx')).toEqual({ - repo: 'sourcegraph/sourcegraph', + repo: 'sourcegraph/sourcegraph?264...#index.tsx', file: '#index.tsx', })) it('extracts repo and file params from subfolder', () => expect( getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph?264...#web/src/e2e/index.e2e.test.tsx') - ).toEqual({ repo: 'sourcegraph/sourcegraph', file: '#web/src/e2e/index.e2e.test.tsx' })) + ).toEqual({ + repo: 'sourcegraph/sourcegraph?264...#web/src/e2e/index.e2e.test.tsx', + file: '#web/src/e2e/index.e2e.test.tsx', + })) it('return empty repo if host is not GitHub', () => expect(getParamsFromUriPath('git://unknownhost.com/sourcegraph/testrepo#http/req/main.go')).toEqual({ @@ -32,7 +35,7 @@ describe('getParamsFromUriPath', () => { it('return empty file if document has no file format', () => expect(getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph/testrepo#formatless')).toEqual({ - repo: 'sourcegraph/sourcegraph', + repo: 'sourcegraph/sourcegraph/testrepo#formatless', file: null, })) }) From c58b09333b483f568a9c085494570626cbe12bd7 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Thu, 9 May 2019 10:44:33 -0700 Subject: [PATCH 16/38] update package.json and combineLatest implementation --- package.json | 14 +- src/extension.ts | 2 +- yarn.lock | 343 ++++++++++++++++++++++++++--------------------- 3 files changed, 200 insertions(+), 159 deletions(-) diff --git a/package.json b/package.json index f13d2761..86e8bf17 100644 --- a/package.json +++ b/package.json @@ -187,18 +187,18 @@ "lnfs-cli": "^2.1.0", "lodash": "^4.17.11", "mkdirp": "^0.5.1", - "mocha": "^6.1.2", + "mocha": "^6.1.4", "mock-require": "^3.0.3", - "nyc": "^13.3.0", + "nyc": "^14.1.0", "parcel-bundler": "^1.12.3", "prettier": "1.17.0", - "rxjs": "^6.4.0", - "sinon": "^7.3.1", + "rxjs": "^6.5.1", + "sinon": "^7.3.2", "source-map-support": "^0.5.12", "sourcegraph": "^23.0.1", - "ts-node": "^8.0.3", - "tslint": "^5.15.0", - "typescript": "^3.4.2" + "ts-node": "^8.1.0", + "tslint": "^5.16.0", + "typescript": "^3.4.5" }, "dependencies": { "@sourcegraph/extension-api-stubs": "^0.2.0" diff --git a/src/extension.ts b/src/extension.ts index b6327410..db6e3829 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -52,7 +52,7 @@ export function activate(context: sourcegraph.ExtensionContext): void { // When the active editor changes, publish new decorations. context.subscriptions.add( - combineLatest(configurationChanges, activeEditor).subscribe(([, editor]) => { + combineLatest([configurationChanges, activeEditor]).subscribe(([, editor]) => { const settings = resolveSettings(sourcegraph.configuration.get().value) const sentryProjects = settings['sentry.projects'] diff --git a/yarn.lock b/yarn.lock index 2ab067cb..39b22fde 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,7 +29,7 @@ semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@^7.0.0", "@babel/generator@^7.0.0 <7.4.0", "@babel/generator@^7.3.4": +"@babel/generator@^7.0.0 <7.4.0", "@babel/generator@^7.3.4": version "7.3.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.3.4.tgz#9aa48c1989257877a9d971296e5b73bfe72e446e" integrity sha512-8EXhHRFqlVVWXPezBW5keTiQi/rJMQTg/Y9uVCEZ0CAF3PKtCCaVRnp64Ii1ujhkoDhhF1fVsImoN4yJ2uz4Wg== @@ -40,6 +40,17 @@ source-map "^0.5.0" trim-right "^1.0.1" +"@babel/generator@^7.4.0", "@babel/generator@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.4.4.tgz#174a215eb843fc392c7edcaabeaa873de6e8f041" + integrity sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ== + dependencies: + "@babel/types" "^7.4.4" + jsesc "^2.5.1" + lodash "^4.17.11" + source-map "^0.5.0" + trim-right "^1.0.1" + "@babel/helper-annotate-as-pure@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32" @@ -193,6 +204,13 @@ dependencies: "@babel/types" "^7.0.0" +"@babel/helper-split-export-declaration@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677" + integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q== + dependencies: + "@babel/types" "^7.4.4" + "@babel/helper-wrap-function@^7.1.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa" @@ -221,11 +239,16 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@babel/parser@^7.0.0", "@babel/parser@^7.0.0 <7.4.0", "@babel/parser@^7.2.2", "@babel/parser@^7.3.4": +"@babel/parser@^7.0.0 <7.4.0", "@babel/parser@^7.2.2", "@babel/parser@^7.3.4": version "7.3.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.3.4.tgz#a43357e4bbf4b92a437fb9e465c192848287f27c" integrity sha512-tXZCqWtlOOP4wgCp6RjRvLmfuhnqTLy9VHwRochJBCP2nDm27JnnuFEnXFASVyQNHk36jD1tAammsCEEqgscIQ== +"@babel/parser@^7.4.3", "@babel/parser@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.4.4.tgz#5977129431b8fe33471730d255ce8654ae1250b6" + integrity sha512-5pCS4mOsL+ANsFZGdvNLybx4wtqAZJ0MJjMHxvzI3bvIsz6sQvzW8XX92EYIkiPtIvcfG3Aj+Ir5VNyjnZhP7w== + "@babel/plugin-proposal-async-generator-functions@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e" @@ -613,7 +636,7 @@ dependencies: regenerator-runtime "^0.12.0" -"@babel/template@^7.0.0", "@babel/template@^7.0.0 <7.4.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": +"@babel/template@^7.0.0 <7.4.0", "@babel/template@^7.1.0", "@babel/template@^7.1.2", "@babel/template@^7.2.2": version "7.2.2" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.2.2.tgz#005b3fdf0ed96e88041330379e0da9a708eb2907" integrity sha512-zRL0IMM02AUDwghf5LMSSDEz7sBCO2YnNmpg3uWTZj/v1rcG2BmQUvaGU8GhU8BvfMh1k2KIAYZ7Ji9KXPUg7g== @@ -622,7 +645,16 @@ "@babel/parser" "^7.2.2" "@babel/types" "^7.2.2" -"@babel/traverse@^7.0.0", "@babel/traverse@^7.0.0 <7.4.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.3.4": +"@babel/template@^7.4.0": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237" + integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + +"@babel/traverse@^7.0.0 <7.4.0", "@babel/traverse@^7.1.0", "@babel/traverse@^7.1.5", "@babel/traverse@^7.3.4": version "7.3.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.3.4.tgz#1330aab72234f8dea091b08c4f8b9d05c7119e06" integrity sha512-TvTHKp6471OYEcE/91uWmhR6PrrYywQntCHSaZ8CM8Vmp+pjAusal4nGB2WCCQd0rvI7nOMKn9GnbcvTUz3/ZQ== @@ -637,6 +669,21 @@ globals "^11.1.0" lodash "^4.17.11" +"@babel/traverse@^7.4.3": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.4.4.tgz#0776f038f6d78361860b6823887d4f3937133fe8" + integrity sha512-Gw6qqkw/e6AGzlyj9KnkabJX7VcubqPtkUQVAwkc0wUMldr3A/hezNB3Rc5eIvId95iSGkGIOe5hh1kMKf951A== + dependencies: + "@babel/code-frame" "^7.0.0" + "@babel/generator" "^7.4.4" + "@babel/helper-function-name" "^7.1.0" + "@babel/helper-split-export-declaration" "^7.4.4" + "@babel/parser" "^7.4.4" + "@babel/types" "^7.4.4" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.11" + "@babel/types@^7.0.0", "@babel/types@^7.0.0 <7.4.0", "@babel/types@^7.2.0", "@babel/types@^7.2.2", "@babel/types@^7.3.0", "@babel/types@^7.3.4": version "7.3.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.3.4.tgz#bf482eaeaffb367a28abbf9357a94963235d90ed" @@ -646,6 +693,15 @@ lodash "^4.17.11" to-fast-properties "^2.0.0" +"@babel/types@^7.4.0", "@babel/types@^7.4.4": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.4.4.tgz#8db9e9a629bb7c29370009b4b779ed93fe57d5f0" + integrity sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ== + dependencies: + esutils "^2.0.2" + lodash "^4.17.11" + to-fast-properties "^2.0.0" + "@iarna/toml@^2.2.0": version "2.2.3" resolved "https://registry.yarnpkg.com/@iarna/toml/-/toml-2.2.3.tgz#f060bf6eaafae4d56a7dac618980838b0696e2ab" @@ -1054,11 +1110,6 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - asn1.js@^4.0.0: version "4.10.1" resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" @@ -1102,13 +1153,6 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.0.tgz#78faed8c3d074ab81f22b4e985d79e8738f720f8" integrity sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg== -async@^2.5.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381" - integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg== - dependencies: - lodash "^4.17.11" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1129,15 +1173,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f" integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== -babel-code-frame@^6.22.0: - version "6.26.0" - resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha1-Y/1D99weO7fONZR9uP42mj9Yx0s= - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - babel-runtime@^6.11.6, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" @@ -1381,7 +1416,7 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -caching-transform@^3.0.1: +caching-transform@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-3.0.2.tgz#601d46b91eca87687a281e71cef99791b0efca70" integrity sha512-Mtgcv3lh3U0zRii/6qVgQODdPA4G3zhG+jtbCWj39RXuUFTMzH0vcdMtaJS1jPowd+It2Pqr6y3NJMQqOqCE2w== @@ -1711,6 +1746,17 @@ cosmiconfig@^5.0.0: lodash.get "^4.4.2" parse-json "^4.0.0" +cp-file@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-6.2.0.tgz#40d5ea4a1def2a9acdd07ba5c0b0246ef73dc10d" + integrity sha512-fmvV4caBnofhPe8kOcitBwSn2f39QLjnAnGq3gO9dfd75mUytzKNZB1hde6QHunW2Rt+OwuBOMc3i1tNElbszA== + dependencies: + graceful-fs "^4.1.2" + make-dir "^2.0.0" + nested-error-stacks "^2.0.0" + pify "^4.0.1" + safe-buffer "^5.0.1" + create-ecdh@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" @@ -2506,7 +2552,7 @@ fill-range@^4.0.0: repeat-string "^1.6.1" to-regex-range "^2.1.0" -find-cache-dir@^2.0.0: +find-cache-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== @@ -2718,12 +2764,12 @@ growl@1.10.5: resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== -handlebars@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.0.tgz#0d6a6f34ff1f63cecec8423aa4169827bf787c3a" - integrity sha512-l2jRuU1NAWK6AW5qqcTATWQJvNPEwkM7NEKSiv/gqOsoSQbVoWyqVEY5GS+XPQ88zLNmqASRpzfdm8d79hJS+w== +handlebars@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67" + integrity sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw== dependencies: - async "^2.5.0" + neo-async "^2.6.0" optimist "^0.6.1" source-map "^0.6.1" optionalDependencies: @@ -3308,57 +3354,57 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= -istanbul-lib-coverage@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#0b891e5ad42312c2b9488554f603795f9a2211ba" - integrity sha512-dKWuzRGCs4G+67VfW9pBFFz2Jpi4vSp/k7zBcJ888ofV5Mi1g5CUML5GvMvV6u9Cjybftu+E8Cgp+k0dI1E5lw== +istanbul-lib-coverage@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" + integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== -istanbul-lib-hook@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.3.tgz#e0e581e461c611be5d0e5ef31c5f0109759916fb" - integrity sha512-CLmEqwEhuCYtGcpNVJjLV1DQyVnIqavMLFHV/DP+np/g3qvdxu3gsPqYoJMXm15sN84xOlckFB3VNvRbf5yEgA== +istanbul-lib-hook@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-2.0.7.tgz#c95695f383d4f8f60df1f04252a9550e15b5b133" + integrity sha512-vrRztU9VRRFDyC+aklfLoeXyNdTfga2EI3udDGn4cZ6fpSXpHLV9X6CHvfoMCPtggg8zvDDmC4b9xfu0z6/llA== dependencies: append-transform "^1.0.0" -istanbul-lib-instrument@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.1.0.tgz#a2b5484a7d445f1f311e93190813fa56dfb62971" - integrity sha512-ooVllVGT38HIk8MxDj/OIHXSYvH+1tq/Vb38s8ixt9GoJadXska4WkGY+0wkmtYCZNYtaARniH/DixUGGLZ0uA== - dependencies: - "@babel/generator" "^7.0.0" - "@babel/parser" "^7.0.0" - "@babel/template" "^7.0.0" - "@babel/traverse" "^7.0.0" - "@babel/types" "^7.0.0" - istanbul-lib-coverage "^2.0.3" - semver "^5.5.0" +istanbul-lib-instrument@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" + integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== + dependencies: + "@babel/generator" "^7.4.0" + "@babel/parser" "^7.4.3" + "@babel/template" "^7.4.0" + "@babel/traverse" "^7.4.3" + "@babel/types" "^7.4.0" + istanbul-lib-coverage "^2.0.5" + semver "^6.0.0" -istanbul-lib-report@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.4.tgz#bfd324ee0c04f59119cb4f07dab157d09f24d7e4" - integrity sha512-sOiLZLAWpA0+3b5w5/dq0cjm2rrNdAfHWaGhmn7XEFW6X++IV9Ohn+pnELAl9K3rfpaeBfbmH9JU5sejacdLeA== +istanbul-lib-report@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" + integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== dependencies: - istanbul-lib-coverage "^2.0.3" - make-dir "^1.3.0" - supports-color "^6.0.0" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + supports-color "^6.1.0" -istanbul-lib-source-maps@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.2.tgz#f1e817229a9146e8424a28e5d69ba220fda34156" - integrity sha512-JX4v0CiKTGp9fZPmoxpu9YEkPbEqCqBbO3403VabKjH+NRXo72HafD5UgnjTEqHL2SAjaZK1XDuDOkn6I5QVfQ== +istanbul-lib-source-maps@^3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" + integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== dependencies: debug "^4.1.1" - istanbul-lib-coverage "^2.0.3" - make-dir "^1.3.0" - rimraf "^2.6.2" + istanbul-lib-coverage "^2.0.5" + make-dir "^2.1.0" + rimraf "^2.6.3" source-map "^0.6.1" -istanbul-reports@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.1.1.tgz#72ef16b4ecb9a4a7bd0e2001e00f95d1eec8afa9" - integrity sha512-FzNahnidyEPBCI0HcufJoSEoKykesRlFcSzQqjH9x0+LC8tnnE/p/90PBLu8iZTxr8yYZNyTtiAujUqyN+CIxw== +istanbul-reports@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.4.tgz#4e0d0ddf0f0ad5b49a314069d31b4f06afe49ad3" + integrity sha512-QCHGyZEK0bfi9GR215QSm+NJwFKEShbtc7tfbUdLAEzn3kKhLDDZqvljn8rPZM9v8CEOhzL1nlYoO4r1ryl67w== dependencies: - handlebars "^4.1.0" + handlebars "^4.1.2" jest-diff@^24.7.0: version "24.7.0" @@ -3425,12 +3471,15 @@ js-levenshtein@^1.1.3: resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha1-mGbfOVECEw449/mWvOtlRDIJwls= +js-yaml@3.13.1, js-yaml@^3.13.1: + version "3.13.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" + integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" -js-yaml@3.13.0, js-yaml@^3.10.0, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.9.0: +js-yaml@^3.10.0, js-yaml@^3.12.0, js-yaml@^3.13.0, js-yaml@^3.9.0: version "3.13.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.0.tgz#38ee7178ac0eea2c97ff6d96fff4b18c7d8cf98e" integrity sha512-pZZoSxcCYco+DIKBTimr67J6Hy+EYGZDY/HCWC+iAEA9h1ByhMXAIVUXMcMFpOCxQ/xjXmPI2MkDL5HRm5eFrQ== @@ -3672,11 +3721,6 @@ lolex@^2.3.2: resolved "https://registry.yarnpkg.com/lolex/-/lolex-2.7.5.tgz#113001d56bfc7e02d56e36291cc5c413d1aa0733" integrity sha512-l9x0+1offnKKIzYVjyXU2SiwhXDLekRzKyhnbyldPHvC7BvLPVpdNUNR2KeMAiCN2D/kLNttZgQD5WjSxuBx3Q== -lolex@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lolex/-/lolex-3.1.0.tgz#1a7feb2fefd75b3e3a7f79f0e110d9476e294434" - integrity sha512-zFo5MgCJ0rZ7gQg69S4pqBsLURbFw11X68C18OcJjJQbqaXm2NoTrGl1IMM3TIz0/BnN1tIs2tzmmqvCsOMMjw== - lolex@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/lolex/-/lolex-4.0.1.tgz#4a99c2251579d693c6a083446dae0e5c3844d3fa" @@ -3712,14 +3756,14 @@ magic-string@^0.22.4: dependencies: vlq "^0.2.2" -make-dir@^1.0.0, make-dir@^1.3.0: +make-dir@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== dependencies: pify "^3.0.0" -make-dir@^2.0.0: +make-dir@^2.0.0, make-dir@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== @@ -3920,10 +3964,10 @@ mkdirp@0.5.1, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: dependencies: minimist "0.0.8" -mocha@^6.1.2: - version "6.1.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.2.tgz#31e960580ef709ef5f26bbe760547cf5207b44df" - integrity sha512-BgD2/RozoSC3uQK5R0isDcxjqaWw2n5HWdk8njYUyZf2NC79ErO5FtYVX52+rfqGoEgMfJf4fuG0IWh2TMzFoA== +mocha@^6.1.4: + version "6.1.4" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-6.1.4.tgz#e35fada242d5434a7e163d555c705f6875951640" + integrity sha512-PN8CIy4RXsIoxoFJzS4QNnCH4psUCPWc4/rPrst/ecSJJbLBkubMiyGCP2Kj/9YnWbotFqAoeXyXMucj7gwCFg== dependencies: ansi-colors "3.2.3" browser-stdout "1.3.1" @@ -3934,12 +3978,12 @@ mocha@^6.1.2: glob "7.1.3" growl "1.10.5" he "1.2.0" - js-yaml "3.13.0" + js-yaml "3.13.1" log-symbols "2.2.0" minimatch "3.0.4" mkdirp "0.5.1" ms "2.1.1" - node-environment-flags "1.0.4" + node-environment-flags "1.0.5" object.assign "4.1.0" strip-json-comments "2.0.1" supports-color "6.0.0" @@ -3998,6 +4042,16 @@ needle@^2.2.1: iconv-lite "^0.4.4" sax "^1.2.4" +neo-async@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.0.tgz#b9d15e4d71c6762908654b5183ed38b753340835" + integrity sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA== + +nested-error-stacks@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz#0fbdcf3e13fe4994781280524f8b96b0cdff9c61" + integrity sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug== + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -4019,12 +4073,13 @@ node-addon-api@^1.6.0: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.6.2.tgz#d8aad9781a5cfc4132cc2fecdbdd982534265217" integrity sha512-479Bjw9nTE5DdBSZZWprFryHGjUaQC31y1wHo19We/k0BZlrmhqQitWoUL0cD8+scljCbIUL+E58oRDEakdGGA== -node-environment-flags@1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.4.tgz#0b784a6551426bfc16d3b2208424dcbc2b2ff038" - integrity sha512-M9rwCnWVLW7PX+NUWe3ejEdiLYinRpsEre9hMkU/6NS4h+EEulYaDH1gCEZ2gyXsmw+RXYDaV2JkkTNcsPDJ0Q== +node-environment-flags@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/node-environment-flags/-/node-environment-flags-1.0.5.tgz#fa930275f5bf5dae188d6192b24b4c8bbac3d76a" + integrity sha512-VNYPRfGfmZLx0Ye20jWzHUjyTW/c+6Wq+iLhDzUI4XmhrDd9l/FozXV3F2xOaXjvp0co0+v1YSR3CMP6g+VvLQ== dependencies: object.getownpropertydescriptors "^2.0.3" + semver "^5.7.0" node-forge@^0.7.1: version "0.7.6" @@ -4170,35 +4225,36 @@ nwsapi@^2.0.7: resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.1.1.tgz#08d6d75e69fd791bdea31507ffafe8c843b67e9c" integrity sha512-T5GaA1J/d34AC8mkrFD2O0DR17kwJ702ZOtJOsS8RpbsQZVOC2/xYFb1i/cw+xdM54JIlMuojjDOYct8GIWtwg== -nyc@^13.3.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/nyc/-/nyc-13.3.0.tgz#da4dbe91a9c8b9ead3f4f3344c76f353e3c78c75" - integrity sha512-P+FwIuro2aFG6B0Esd9ZDWUd51uZrAEoGutqZxzrVmYl3qSfkLgcQpBPBjtDFsUQLFY1dvTQJPOyeqr8S9GF8w== +nyc@^14.1.0: + version "14.1.0" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-14.1.0.tgz#ae864913a4c5a947bfaebeb66a488bdb1868c9a3" + integrity sha512-iy9fEV8Emevz3z/AanIZsoGa8F4U2p0JKevZ/F0sk+/B2r9E6Qn+EPs0bpxEhnAt6UPlTL8mQZIaSJy8sK0ZFw== dependencies: archy "^1.0.0" - arrify "^1.0.1" - caching-transform "^3.0.1" + caching-transform "^3.0.2" convert-source-map "^1.6.0" - find-cache-dir "^2.0.0" + cp-file "^6.2.0" + find-cache-dir "^2.1.0" find-up "^3.0.0" foreground-child "^1.5.6" glob "^7.1.3" - istanbul-lib-coverage "^2.0.3" - istanbul-lib-hook "^2.0.3" - istanbul-lib-instrument "^3.1.0" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.2" - istanbul-reports "^2.1.1" - make-dir "^1.3.0" + istanbul-lib-coverage "^2.0.5" + istanbul-lib-hook "^2.0.7" + istanbul-lib-instrument "^3.3.0" + istanbul-lib-report "^2.0.8" + istanbul-lib-source-maps "^3.0.6" + istanbul-reports "^2.2.4" + js-yaml "^3.13.1" + make-dir "^2.1.0" merge-source-map "^1.1.0" resolve-from "^4.0.0" rimraf "^2.6.3" signal-exit "^3.0.2" spawn-wrap "^1.4.2" - test-exclude "^5.1.0" + test-exclude "^5.2.3" uuid "^3.3.2" - yargs "^12.0.5" - yargs-parser "^11.1.1" + yargs "^13.2.2" + yargs-parser "^13.0.0" oauth-sign@~0.9.0: version "0.9.0" @@ -5503,13 +5559,6 @@ rxjs-tslint-rules@^4.23.0: tsutils "^3.0.0" tsutils-etc "^1.1.0" -rxjs@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.4.0.tgz#f3bb0fe7bda7fb69deac0c16f17b50b0b8790504" - integrity sha512-Z9Yfa11F6B9Sg/BK9MnqnQ+aQYicPLtilXBp2yUtDt2JRCE0h26d33EnfO3ZxoNxG0T92OUucP3Ct7cpfkdFfw== - dependencies: - tslib "^1.9.0" - rxjs@^6.5.1: version "6.5.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.1.tgz#f7a005a9386361921b8524f38f54cbf80e5d08f4" @@ -5551,6 +5600,11 @@ sax@^1.2.4, sax@~1.2.4: resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +semver@^5.7.0: + version "5.7.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b" + integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA== + semver@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.0.0.tgz#05e359ee571e5ad7ed641a6eec1e547ba52dea65" @@ -5670,19 +5724,6 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" -sinon@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.1.tgz#e8276522104e6c08d1cb52a907270b0e316655c4" - integrity sha512-eQKMaeWovtOtYe2xThEvaHmmxf870Di+bim10c3ZPrL5bZhLGtu8cz+rOBTFz0CwBV4Q/7dYwZiqZbGVLZ+vjQ== - dependencies: - "@sinonjs/commons" "^1.4.0" - "@sinonjs/formatio" "^3.2.1" - "@sinonjs/samsam" "^3.3.1" - diff "^3.5.0" - lolex "^3.1.0" - nise "^1.4.10" - supports-color "^5.5.0" - sinon@^7.3.2: version "7.3.2" resolved "https://registry.yarnpkg.com/sinon/-/sinon-7.3.2.tgz#82dba3a6d85f6d2181e1eca2c10d8657c2161f28" @@ -6027,7 +6068,7 @@ supports-color@^5.3.0, supports-color@^5.4.0, supports-color@^5.5.0: dependencies: has-flag "^3.0.0" -supports-color@^6.0.0, supports-color@^6.1.0: +supports-color@^6.1.0: version "6.1.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== @@ -6081,15 +6122,15 @@ terser@^3.16.1, terser@^3.7.3: source-map "~0.6.1" source-map-support "~0.5.9" -test-exclude@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.1.0.tgz#6ba6b25179d2d38724824661323b73e03c0c1de1" - integrity sha512-gwf0S2fFsANC55fSeSqpb8BYk6w3FDvwZxfNjeF6FRgvFa43r+7wRiA/Q0IxoRU37wB/LE8IQ4221BsNucTaCA== +test-exclude@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" + integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== dependencies: - arrify "^1.0.1" + glob "^7.1.3" minimatch "^3.0.4" read-pkg-up "^4.0.0" - require-main-filename "^1.0.1" + require-main-filename "^2.0.0" through2@^2.0.0, through2@~2.0.3: version "2.0.5" @@ -6181,10 +6222,10 @@ trim-right@^1.0.1: resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM= -ts-node@^8.0.3: - version "8.0.3" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.0.3.tgz#aa60b836a24dafd8bf21b54766841a232fdbc641" - integrity sha512-2qayBA4vdtVRuDo11DEFSsD/SFsBXQBRZZhbRGSIkmYmVkWjULn/GGMdG10KVqkaGndljfaTD8dKjWgcejO8YA== +ts-node@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.1.0.tgz#8c4b37036abd448577db22a061fd7a67d47e658e" + integrity sha512-34jpuOrxDuf+O6iW1JpgTRDFynUZ1iEqtYruBqh35gICNjN8x+LpVcPAcwzLPi9VU6mdA3ym+x233nZmZp445A== dependencies: arg "^4.1.0" diff "^3.1.0" @@ -6209,12 +6250,12 @@ tslint-react@^4.0.0: dependencies: tsutils "^3.9.1" -tslint@^5.15.0: - version "5.15.0" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.15.0.tgz#6ffb180986d63afa1e531feb2a134dbf961e27d3" - integrity sha512-6bIEujKR21/3nyeoX2uBnE8s+tMXCQXhqMmaIPJpHmXJoBJPTLcI7/VHRtUwMhnLVdwLqqY3zmd8Dxqa5CVdJA== +tslint@^5.16.0: + version "5.16.0" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.16.0.tgz#ae61f9c5a98d295b9a4f4553b1b1e831c1984d67" + integrity sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA== dependencies: - babel-code-frame "^6.22.0" + "@babel/code-frame" "^7.0.0" builtin-modules "^1.1.1" chalk "^2.3.0" commander "^2.12.1" @@ -6281,10 +6322,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.4.2: - version "3.4.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.2.tgz#9ed4e6475d906f589200193be056f5913caed481" - integrity sha512-Og2Vn6Mk7JAuWA1hQdDQN/Ekm/SchX80VzLhjKN9ETYrIepBFAd8PkOdOTK2nKt0FCkmMZKBJvQ1dV1gIxPu/A== +typescript@^3.4.5: + version "3.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" + integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== uglify-js@^3.1.4: version "3.4.9" @@ -6638,7 +6679,7 @@ yargs-unparser@1.5.0: lodash "^4.17.11" yargs "^12.0.5" -yargs@13.2.2: +yargs@13.2.2, yargs@^13.2.2: version "13.2.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.2.tgz#0c101f580ae95cea7f39d927e7770e3fdc97f993" integrity sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA== From d76f9cff43d988aee6f81289fa78ed70dbf97bb7 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Thu, 9 May 2019 13:25:25 -0700 Subject: [PATCH 17/38] handle promises with beforeEach and await --- src/test/extension.test.ts | 30 ++++++++++++++++++++---------- src/test/handler.test.ts | 11 ++++++++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index ed5497cb..6fd6cd99 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -53,10 +53,6 @@ const settings = { ], } -describe('check for configurations', () => { - it('activate extension', () => expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings)) -}) - export let projects: SentryProject[] = [ { name: 'Webapp typescript errors', @@ -93,6 +89,14 @@ export let projects: SentryProject[] = [ }, ] +describe('check for configurations', () => { + beforeEach(async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) + }) + it('activate extension', () => expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings)) +}) + const data = [ { goal: 'render complete Sentry link', @@ -193,8 +197,10 @@ const data = [ ] describe('decorate line', () => { - sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - sourcegraph.configuration.get().update('sentry.projects', projects) + beforeEach(async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) + }) for (const deco of data) { it('decorates the line with the following goal: ' + deco.goal, () => @@ -334,8 +340,10 @@ of(codeView).pipe( ] describe('get Decorations', () => { - sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - sourcegraph.configuration.get().update('sentry.projects', projects) + beforeEach(async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) + }) for (const deco of getDecorationsInput) { it('fulfills the following goal:' + deco.goal, () => @@ -396,8 +404,10 @@ const expectedLanguageTestOutcome = [ ] describe('decorate Editor', () => { - sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - sourcegraph.configuration.get().update('sentry.projects', projects) + beforeEach(async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) + }) projects[0].patternProperties.lineMatches = [] for (const [i, codeExample] of supportedLanguageCode.entries()) { diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 5aa67270..48af49fb 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -7,12 +7,13 @@ export const sourcegraph = createStubSourcegraphAPI() // For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) -sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') -sourcegraph.configuration.get().update('sentry.projects', projects) - import { checkMissingConfig, createDecoration, getParamsFromUriPath, matchSentryProject } from '../handler' describe('getParamsFromUriPath', () => { + beforeEach(async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) + }) it('extracts repo and file params from root folder', () => expect(getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph?264...#index.tsx')).toEqual({ repo: 'sourcegraph/sourcegraph?264...#index.tsx', @@ -76,6 +77,10 @@ const paramsInput = [ ] describe('matchSentryProject', () => { + beforeEach(async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) + }) for (const paramsCase of paramsInput) { it('fullfils the following goal: ' + paramsCase.goal, () => expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected) From d6b86c87d83958456c34bade2852d4f04cbdf28f Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Thu, 9 May 2019 16:55:20 -0700 Subject: [PATCH 18/38] use URLSearchParams instead of encodeURIComponent --- src/extension.ts | 21 ++++++++------------- src/test/extension.test.ts | 14 +++++++------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index db6e3829..accab4a4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -197,20 +197,15 @@ export function decorateLine( * @param sentryProjectId from the associated Sentry project receiving logs from the document's repo. * @return URL to the Sentry unresolved issues stream page for this kind of query. */ -// TODO: Use URLSearchParams instead of encodeURIComponent function buildUrl(errorQuery: string, sentryProjectId?: string): URL { const sentryOrg = resolveSettings(sourcegraph.configuration.get().value)['sentry.organization'] - const url = new URL( - 'https://sentry.io/organizations/' + - encodeURIComponent(sentryOrg!) + - '/issues/' + - (sentryProjectId - ? '?project=' + - encodeURIComponent(sentryProjectId) + - '&query=is%3Aunresolved+' + - encodeURIComponent(errorQuery) + - '&statsPeriod=14d' - : '') - ) + const url = new URL('https://sentry.io/organizations/' + sentryOrg + '/issues/') + + if (sentryProjectId) { + url.searchParams.set('project', sentryProjectId) + url.searchParams.set('query', 'is:unresolved ' + errorQuery) + url.searchParams.set('statsPeriod', '14d') + } + return url } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 6fd6cd99..1ebf9d64 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -113,7 +113,7 @@ const data = [ contentText: ' View logs in Sentry » ', hoverMessage: ' View logs in Sentry » ', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, }, @@ -133,7 +133,7 @@ const data = [ hoverMessage: ' Please fill out the following configurations in your Sentry extension settings: repoMatches', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, }, @@ -153,7 +153,7 @@ const data = [ hoverMessage: ' Please fill out the following configurations in your Sentry extension settings: repoMatches, fileMatches', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, }, @@ -236,7 +236,7 @@ const getDecorationsInput = [ contentText: ' View logs in Sentry » ', hoverMessage: ' View logs in Sentry » ', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, { @@ -248,7 +248,7 @@ const getDecorationsInput = [ contentText: ' View logs in Sentry » ', hoverMessage: ' View logs in Sentry » ', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20delta%20info&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot+determine+delta+info&statsPeriod=14d', }, }, ], @@ -272,7 +272,7 @@ const getDecorationsInput = [ contentText: ' View logs in Sentry » ', hoverMessage: ' View logs in Sentry » ', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, ], @@ -326,7 +326,7 @@ of(codeView).pipe( contentText: ' View logs in Sentry » ', hoverMessage: ' View logs in Sentry » ', linkURL: - 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot%20determine%20file%20path&statsPeriod=14d', + 'https://sentry.io/organizations/sourcegraph/issues/?project=1334031&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, ], From 0c328e377701d158567aad64b84a426a6f8f5292 Mon Sep 17 00:00:00 2001 From: Vanesa Date: Mon, 13 May 2019 09:33:54 -0700 Subject: [PATCH 19/38] Update src/test/handler.test.ts wording Co-Authored-By: Felix Becker --- src/test/handler.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 48af49fb..0a0e09ee 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -123,7 +123,7 @@ describe('missingConfig', () => { expect(checkMissingConfig(config.settings)).toEqual(config.expected) ) } - it('handle empty settings', () => expect(checkMissingConfig()).toEqual([])) + it('handles empty settings', () => expect(checkMissingConfig()).toEqual([])) }) const createDecorationWithoutOrgOutcome = { From dfb48aa53880c9ad43dcf4ac1c296550b512918c Mon Sep 17 00:00:00 2001 From: Vanesa Date: Mon, 13 May 2019 09:34:19 -0700 Subject: [PATCH 20/38] Update src/test/handler.test.ts wording Co-Authored-By: Felix Becker --- src/test/handler.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 0a0e09ee..e73080a2 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -117,7 +117,7 @@ const incompleteConfigs = [ }, ] -describe('missingConfig', () => { +describe('checkMissingConfig()', () => { for (const config of incompleteConfigs) { it('check missing configs with goal to ' + config.goal, () => expect(checkMissingConfig(config.settings)).toEqual(config.expected) From c126f17a8bea64b4b2a4e4ec0c0908b01933ba9f Mon Sep 17 00:00:00 2001 From: Vanesa Date: Mon, 13 May 2019 09:34:45 -0700 Subject: [PATCH 21/38] Update src/test/handler.test.ts wording Co-Authored-By: Felix Becker --- src/test/handler.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index e73080a2..679d304a 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -119,7 +119,7 @@ const incompleteConfigs = [ describe('checkMissingConfig()', () => { for (const config of incompleteConfigs) { - it('check missing configs with goal to ' + config.goal, () => + it('checks missing configs with goal to ' + config.goal, () => expect(checkMissingConfig(config.settings)).toEqual(config.expected) ) } From c089c03910b0f5d518f321439621aa3def21101a Mon Sep 17 00:00:00 2001 From: Vanesa Date: Mon, 13 May 2019 09:35:15 -0700 Subject: [PATCH 22/38] Update src/test/extension.test.ts wording Co-Authored-By: Felix Becker --- src/test/extension.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 1ebf9d64..1fba5c5e 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -9,7 +9,7 @@ mock('sourcegraph', sourcegraph) import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' import { resolveSettings, SentryProject } from '../settings' -describe('check for extension activation', () => { +describe('activation', () => { const context = createStubExtensionContext() it('activate extension', () => expect(activate(context)).toEqual(void 0)) }) From 6e27835245e3ad9e4bf59bc0850429a70e4917fc Mon Sep 17 00:00:00 2001 From: Vanesa Date: Mon, 13 May 2019 09:35:56 -0700 Subject: [PATCH 23/38] Update src/test/handler.test.ts wording Co-Authored-By: Felix Becker --- src/test/handler.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 679d304a..76de2bad 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -133,6 +133,6 @@ const createDecorationWithoutOrgOutcome = { } describe('createDecoration', () => { - it('handle empty organization setting', () => + it('handles an empty organization setting', () => expect(createDecoration([])).toEqual(createDecorationWithoutOrgOutcome)) }) From f00abd6004635db4f6d74a5d44469897091a1bc9 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Mon, 13 May 2019 09:57:37 -0700 Subject: [PATCH 24/38] refactor based on code review --- package.json | 4 +--- src/test/extension.test.ts | 7 ++++--- src/test/handler.test.ts | 4 +--- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 86e8bf17..0ccf648f 100644 --- a/package.json +++ b/package.json @@ -174,6 +174,7 @@ "last 1 Safari versions" ], "devDependencies": { + "@sourcegraph/extension-api-stubs": "^0.2.0", "@sourcegraph/prettierrc": "^2.2.0", "@sourcegraph/tsconfig": "^4.0.0", "@sourcegraph/tslint-config": "^13.1.0", @@ -199,8 +200,5 @@ "ts-node": "^8.1.0", "tslint": "^5.16.0", "typescript": "^3.4.5" - }, - "dependencies": { - "@sourcegraph/extension-api-stubs": "^0.2.0" } } diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 1fba5c5e..0ac55432 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -11,7 +11,7 @@ import { resolveSettings, SentryProject } from '../settings' describe('activation', () => { const context = createStubExtensionContext() - it('activate extension', () => expect(activate(context)).toEqual(void 0)) + it('does not throw an error', () => expect(activate(context)).toEqual(void 0)) }) const settings = { @@ -89,12 +89,13 @@ export let projects: SentryProject[] = [ }, ] -describe('check for configurations', () => { +describe('resolveSettings()', () => { beforeEach(async () => { await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') await sourcegraph.configuration.get().update('sentry.projects', projects) }) - it('activate extension', () => expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings)) + it('should return configuration with applied defaults', () => + expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings)) }) const data = [ diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 76de2bad..4586e6f8 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -82,9 +82,7 @@ describe('matchSentryProject', () => { await sourcegraph.configuration.get().update('sentry.projects', projects) }) for (const paramsCase of paramsInput) { - it('fullfils the following goal: ' + paramsCase.goal, () => - expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected) - ) + it(paramsCase.goal, () => expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected)) } }) From 4480b93ad6353e5b4be8d02267a5124a3cc41c5c Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 12:04:26 -0700 Subject: [PATCH 25/38] refactor for better config structure and based on code review --- src/extension.ts | 43 +++---- src/handler.ts | 99 +++++++++------ src/settings.ts | 13 +- src/test/extension.test.ts | 249 +++++++++++++++++++------------------ src/test/handler.test.ts | 117 ++++++++++------- 5 files changed, 292 insertions(+), 229 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index accab4a4..a7959da0 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,13 +1,7 @@ import { BehaviorSubject, combineLatest, from } from 'rxjs' import { filter, switchMap } from 'rxjs/operators' import * as sourcegraph from 'sourcegraph' -import { - checkMissingConfig, - createDecoration, - getParamsFromUriPath, - isFileMatched, - matchSentryProject, -} from './handler' +import { createDecoration, findEmptyConfigs, getParamsFromUriPath, matchSentryProject } from './handler' import { resolveSettings, SentryProject, Settings } from './settings' /** @@ -89,28 +83,25 @@ export function getDecorations( ): sourcegraph.TextDocumentDecoration[] { const params: Params = getParamsFromUriPath(documentUri) - const sentryProject = sentryProjects && matchSentryProject(params, sentryProjects) + const matched = sentryProjects && matchSentryProject(params, sentryProjects) let missingConfigData: string[] = [] - let fileMatched: boolean | null - if (sentryProject) { - missingConfigData = checkMissingConfig(sentryProject) - fileMatched = isFileMatched(params, sentryProject) - - // Do not decorate lines if the document file format does not match the - // file matching patterns listed in the Sentry extension configurations. - if (fileMatched === false) { - return [] - } + // Do not decorate lines if the document file format does not match the + // file matching patterns listed in the Sentry extension configurations. + if (matched && matched.fileMatched === false) { + return [] + } + if (matched && matched.project) { + missingConfigData = findEmptyConfigs(matched.project) - return decorateEditor( + return buildDecorations( missingConfigData, documentText, - sentryProject.projectId, - sentryProject.patternProperties.lineMatches + matched.project.projectId, + matched.project.linePatterns ) } - return decorateEditor(missingConfigData, documentText) + return buildDecorations(missingConfigData, documentText) } /** @@ -118,22 +109,22 @@ export function getDecorations( * @param missingConfigData list of missing configs that will appear as a hover warning on the Sentry link * @param documentText content of the document being scanned for error handling code * @param sentryProjectId Sentry project id retrieved from Sentry extension settings - * @param lineMatches line patching patterns set in the user's Sentry extension configurations + * @param linePatterns line patching patterns set in the user's Sentry extension configurations * @return a list of decorations to render as links on each matching line */ // TODO: add tests for that new function (kind of like getBlameDecorations()) -export function decorateEditor( +export function buildDecorations( missingConfigData: string[], documentText: string, sentryProjectId?: string, - lineMatches?: RegExp[] + linePatterns?: RegExp[] ): sourcegraph.TextDocumentDecoration[] { const decorations: sourcegraph.TextDocumentDecoration[] = [] for (const [index, line] of documentText.split('\n').entries()) { let match: RegExpExecArray | null - for (let pattern of lineMatches && lineMatches.length > 0 ? lineMatches : COMMON_ERRORLOG_PATTERNS) { + for (let pattern of linePatterns && linePatterns.length > 0 ? linePatterns : COMMON_ERRORLOG_PATTERNS) { pattern = new RegExp(pattern, 'gi') do { diff --git a/src/handler.ts b/src/handler.ts index 99495e95..81940a69 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -21,14 +21,14 @@ export interface LineDecorationText { export function getParamsFromUriPath(textDocumentURI: string): Params { // TODO: Support more than just GitHub & Gitlab. // TODO: Safeguard for cases where repo/fileMatch are null. - const repoPattern = /(github\.com|gitlab\.com)\/([^\?\#\/]+\/[^\?\#\/].*)/gi - const filePattern = /#.*\.(.*)$/gi + const repoPattern = /(github\.com|gitlab\.com)\/([^\?\#\/]+\/[^\?\#\/]*)/gi + const filePattern = /#(:?.*\.(.*))$/gi const repoMatch = repoPattern.exec(textDocumentURI) const fileMatch = filePattern.exec(textDocumentURI) return { repo: repoMatch && repoMatch[2], - file: fileMatch && fileMatch[0], + file: fileMatch && fileMatch[1], } } @@ -40,57 +40,84 @@ export function getParamsFromUriPath(textDocumentURI: string): Params { * @param projects Sentry extension projects configurations. * @return Sentry projectID this document reports to. */ -export function matchSentryProject(params: Params, projects: SentryProject[]): SentryProject | undefined { +export function matchSentryProject( + params: Params, + projects: SentryProject[] +): { project: SentryProject | undefined; fileMatched: boolean | undefined } { if (!projects || !params.repo || !params.file) { - return undefined + return { project: undefined, fileMatched: undefined } } - // Check if a Sentry project is associated with this document's repo and retrieve the project. + // Check if a Sentry project is associated with this document's repository and/or file and retrieve the project. // TODO: Handle the null case instead of using a non-null assertion ! // TODO: Handle cases where the wrong project is matched due to similar repo name, // e.g. `sourcegraph-jetbrains` repo will match the `sourcegraph` project - const project = projects.find(p => - p.patternProperties.repoMatches - ? !!p.patternProperties.repoMatches.find(repo => !!new RegExp(repo).exec(params.repo!)) - : false - ) - if (!project) { - return undefined + for (const project of projects) { + for (const filter of project.filters) { + // both repository and file match + if ( + filter.repository && + filter.file && + !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && + filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + return { project, fileMatched: true } + } + // repository matches but file does not match + if ( + filter.repository && + filter.file && + !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && + !filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + return { project, fileMatched: false } + } + // repository matches and there is no filter for file matching + if ( + filter.repository && + (!filter.file || filter.file.length === 0) && + !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) + ) { + return { project, fileMatched: undefined } + } + // file matches and there is no filter for repository matching + if ( + filter.file && + (!filter.repository || filter.repository.length === 0) && + filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + return { project: undefined, fileMatched: true } + } + } } - - return project -} - -// Check if document file format matches the file pattern set of the project -export function isFileMatched(params: Params, project: SentryProject): boolean | null { - // TODO: Handle edge case of when project.patternProperties.fileMatches is falsy and add a unit test for it. - return project.patternProperties.fileMatches && project.patternProperties.fileMatches.length > 0 - ? project.patternProperties.fileMatches.some(pattern => !!new RegExp(pattern).exec(params.file!)) - : null + return { project: undefined, fileMatched: undefined } } /** * Check for missing configurations in the Sentry extension settings * @param settings */ -export function checkMissingConfig(settings?: SentryProject): string[] { +export function findEmptyConfigs(settings?: SentryProject, path?: string): string[] { + if (!path) { + path = 'settings' + } if (!settings) { - return [] + return [path] } - const missingConfig: string[] = [] - for (const [key, value] of Object.entries(settings)) { - if (value instanceof Object) { - for (const [k, v] of Object.entries(value)) { - if (!v || (v instanceof Object && Object.keys(v).length === 0)) { - missingConfig.push(k) - } - } - } else if (!value) { - missingConfig.push(key) + + let missingConfigurations: string[] = [] + + if (settings instanceof Array) { + for (const [index, element] of settings.entries()) { + missingConfigurations = missingConfigurations.concat(findEmptyConfigs(element, path + '[' + index + ']')) + } + } else if (settings instanceof Object) { + for (const [k, v] of Object.entries(settings)) { + missingConfigurations = missingConfigurations.concat(findEmptyConfigs(v, path + '.' + k)) } } - return missingConfig + return missingConfigurations } export function createDecoration( diff --git a/src/settings.ts b/src/settings.ts index 3715d85e..cf30cdff 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -13,12 +13,13 @@ export interface Settings { export interface SentryProject { name: string projectId: string - patternProperties: { - repoMatches?: RegExp[] - fileMatches: RegExp[] - // RexExp patterns to match log handeling code, e.g. /log\.(Printf|Print)\(['"]([^'"]+)['"]\)/ - lineMatches: RegExp[] - } + // RexExp patterns to match log handeling code, e.g. /log\.(Printf|Print)\(['"]([^'"]+)['"]\)/ + linePatterns: RegExp[] + filters: { + repository?: RegExp[] + file?: RegExp[] + }[] + // TODO: Add these to v1. additionalProperties?: { contentText?: string // e.g. "View sourcegraph/sourcegraph_dot_com errors" diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 0ac55432..e7404ad4 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -2,105 +2,97 @@ import { createStubExtensionContext, createStubSourcegraphAPI } from '@sourcegra import expect from 'expect' import mock from 'mock-require' -export const sourcegraph = createStubSourcegraphAPI() +const sourcegraph = createStubSourcegraphAPI() // For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) -import { activate, decorateEditor, decorateLine, getDecorations } from '../extension' +import { activate, buildDecorations, decorateLine, getDecorations } from '../extension' import { resolveSettings, SentryProject } from '../settings' describe('activation', () => { - const context = createStubExtensionContext() - it('does not throw an error', () => expect(activate(context)).toEqual(void 0)) + it('does not throw an error', () => { + const context = createStubExtensionContext() + expect(activate(context)).toEqual(void 0) + }) }) -const settings = { - 'sentry.decorations.inline': false, - 'sentry.organization': 'sourcegraph', - 'sentry.projects': [ - { - additionalProperties: { - contentText: 'View sourcegraph/sourcegraph_dot_com errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - name: 'Webapp typescript errors', - patternProperties: { - fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], - lineMatches: [ - /throw new Error+\(['"]([^'"]+)['"]\)/, - /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, - /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], - repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], - }, - projectId: '1334031', - }, - { - additionalProperties: { - contentText: 'View sourcegraph/dev-repo errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, - name: 'Dev env errors', - patternProperties: { - fileMatches: [/(dev)\/.*\\.go?/], - lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], - repoMatches: [/dev-repo/], - }, - projectId: '213332', - }, - ], -} - -export let projects: SentryProject[] = [ +const projects: SentryProject[] = [ { name: 'Webapp typescript errors', projectId: '1334031', - patternProperties: { - repoMatches: [/sourcegraph\/sourcegraph/, /bucket/], - fileMatches: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], - lineMatches: [ - /throw new Error+\(['"]([^'"]+)['"]\)/, - /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, - /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], - }, - additionalProperties: { - contentText: 'View sourcegraph/sourcegraph_dot_com errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, + linePatterns: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + filters: [ + { + repository: [/sourcegraph\/sourcegraph/, /bucket/], + file: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + }, + ], }, { name: 'Dev env errors', projectId: '213332', - patternProperties: { - repoMatches: [/dev-repo/], - fileMatches: [/(dev)\/.*\\.go?/], - lineMatches: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], - }, - additionalProperties: { - contentText: 'View sourcegraph/dev-repo errors', - hoverMessage: 'View errors matching "$1" in Sentry', - query: '$1', - }, + linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + filters: [ + { + repository: [/dev-repo/], + file: [/(dev)\/.*\\.go?/], + }, + ], }, ] +const setDefaults = async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) +} + describe('resolveSettings()', () => { - beforeEach(async () => { - await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - await sourcegraph.configuration.get().update('sentry.projects', projects) + beforeEach(setDefaults) + it('should return configuration with applied defaults', () => { + const settings = { + 'sentry.decorations.inline': false, + 'sentry.organization': 'sourcegraph', + 'sentry.projects': [ + { + projectId: '1334031', + name: 'Webapp typescript errors', + linePatterns: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + filters: [ + { + repository: [/sourcegraph\/sourcegraph/, /bucket/], + file: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + }, + ], + }, + { + projectId: '213332', + name: 'Dev env errors', + linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + filters: [ + { + repository: [/dev-repo/], + file: [/(dev)\/.*\\.go?/], + }, + ], + }, + ], + } + expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings) }) - it('should return configuration with applied defaults', () => - expect(resolveSettings(sourcegraph.configuration.get().value)).toEqual(settings)) }) const data = [ { - goal: 'render complete Sentry link', + goal: 'renders complete Sentry link', index: 1, match: 'cannot determine file path', missingConfigData: [], @@ -119,7 +111,7 @@ const data = [ }, }, { - goal: 'warn about incomplete config with missing repoMatches', + goal: 'warns about incomplete config with missing repoMatches', index: 1, match: 'cannot determine file path', missingConfigData: ['repoMatches'], @@ -139,7 +131,7 @@ const data = [ }, }, { - goal: 'warn about incomplete config with missing repoMatches and fileMatches patterns', + goal: 'warns about incomplete config with missing repoMatches and fileMatches patterns', index: 1, match: 'cannot determine file path', missingConfigData: ['repoMatches', 'fileMatches'], @@ -159,7 +151,7 @@ const data = [ }, }, { - goal: 'render warning link hinting to add projectId and render link to general issues page', + goal: 'renders warning link hinting to add projectId and render link to general issues page', index: 1, match: 'cannot determine file path', missingConfigData: ['repoMatches', 'fileMatches'], @@ -178,7 +170,7 @@ const data = [ }, { goal: - 'match line based on common pattern, render warning link hinting to add projectId and render link to general issues page', + 'matches line based on common pattern, render warning link hinting to add projectId and render link to general issues page', index: 1, match: '', missingConfigData: ['repoMatches', 'fileMatches'], @@ -197,14 +189,11 @@ const data = [ }, ] -describe('decorate line', () => { - beforeEach(async () => { - await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - await sourcegraph.configuration.get().update('sentry.projects', projects) - }) +describe('decorateLine()', () => { + beforeEach(setDefaults) for (const deco of data) { - it('decorates the line with the following goal: ' + deco.goal, () => + it(deco.goal, () => expect(decorateLine(deco.index, deco.match, deco.missingConfigData, deco.sentryProjectId)).toEqual( deco.expected ) @@ -340,14 +329,11 @@ of(codeView).pipe( }, ] -describe('get Decorations', () => { - beforeEach(async () => { - await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - await sourcegraph.configuration.get().update('sentry.projects', projects) - }) +describe('getDecorations()', () => { + beforeEach(setDefaults) for (const deco of getDecorationsInput) { - it('fulfills the following goal:' + deco.goal, () => + it(deco.goal, () => expect(getDecorations(deco.documentUri, deco.documentText, projects)).toEqual(deco.expected) ) } @@ -360,23 +346,67 @@ const supportedLanguageCode = [ code: `// ErrInvalidToken is returned by DiscussionMailReplyTokens.Get when the token is invalid var ErrInvalidToken = errors.New("invalid token") // Get returns the user and thread ID found for the given token. If there`, + expected: { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, }, { lang: 'typescript', code: ` if (!headFilePath) { throw new Error('cannot determine file path') }`, + expected: { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, }, { lang: 'python', code: `def create_app(): raise TypeError('bad bad factory!')`, + expected: { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, }, { lang: 'java', code: ` } catch (UnsupportedEncodingException err) { logger.debug("failed to build URL"); err.printStackTrace();`, + expected: { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' View logs in Sentry (❕)» ', + hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, }, ] @@ -390,39 +420,22 @@ const unsupportedLanguageCode = [ }, ] -const expectedLanguageTestOutcome = [ - { - range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), - isWholeLine: true, - after: { - backgroundColor: '#f2736d', - color: 'rgba(255, 255, 255, 0.8)', - contentText: ' View logs in Sentry (❕)» ', - hoverMessage: ' Add Sentry projects to your Sentry extension settings for project matching.', - linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', - }, - }, -] - -describe('decorate Editor', () => { - beforeEach(async () => { - await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - await sourcegraph.configuration.get().update('sentry.projects', projects) - }) +describe('buildDecorations()', () => { + beforeEach(setDefaults) - projects[0].patternProperties.lineMatches = [] - for (const [i, codeExample] of supportedLanguageCode.entries()) { - it('check common pattern matching for ' + supportedLanguageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual(expectedLanguageTestOutcome) + projects[0].linePatterns = [] + for (const [, codeExample] of supportedLanguageCode.entries()) { + it('check common pattern matching for ' + codeExample.lang, () => + expect(buildDecorations([], codeExample.code)).toEqual([codeExample.expected]) ) } - for (const [i, codeExample] of unsupportedLanguageCode.entries()) { - it('should not render due to unsupported language ' + unsupportedLanguageCode[i].lang, () => - expect(decorateEditor([], codeExample.code)).toEqual([]) + for (const [, codeExample] of unsupportedLanguageCode.entries()) { + it('should not render due to unsupported language ' + codeExample.lang, () => + expect(buildDecorations([], codeExample.code)).toEqual([]) ) } - // set lineMatches back to original state for the other tests - projects[0].patternProperties.lineMatches = [ + // set linePatterns back to original state for the other tests + projects[0].linePatterns = [ /throw new Error+\(['"]([^'"]+)['"]\)/, /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 4586e6f8..6bb91b7d 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -1,42 +1,74 @@ import { createStubSourcegraphAPI } from '@sourcegraph/extension-api-stubs' import expect from 'expect' import mock from 'mock-require' -import { projects } from './extension.test' -export const sourcegraph = createStubSourcegraphAPI() +const sourcegraph = createStubSourcegraphAPI() // For modules importing Range/Location/Position/URI/etc mock('sourcegraph', sourcegraph) -import { checkMissingConfig, createDecoration, getParamsFromUriPath, matchSentryProject } from '../handler' +import { createDecoration, findEmptyConfigs, getParamsFromUriPath, matchSentryProject } from '../handler' +import { SentryProject } from '../settings' + +const projects: SentryProject[] = [ + { + name: 'Webapp typescript errors', + projectId: '1334031', + linePatterns: [ + /throw new Error+\(['"]([^'"]+)['"]\)/, + /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, + /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, + ], + filters: [ + { + repository: [/sourcegraph\/sourcegraph/, /bucket/], + file: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + }, + ], + }, + + { + name: 'Dev env errors', + projectId: '213332', + linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + filters: [ + { + repository: [/dev-repo/], + file: [/dev\/.*.go?/], + }, + ], + }, +] + +const setDefaults = async () => { + await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') + await sourcegraph.configuration.get().update('sentry.projects', projects) +} describe('getParamsFromUriPath', () => { - beforeEach(async () => { - await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - await sourcegraph.configuration.get().update('sentry.projects', projects) - }) + beforeEach(setDefaults) it('extracts repo and file params from root folder', () => expect(getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph?264...#index.tsx')).toEqual({ - repo: 'sourcegraph/sourcegraph?264...#index.tsx', - file: '#index.tsx', + repo: 'sourcegraph/sourcegraph', + file: 'index.tsx', })) it('extracts repo and file params from subfolder', () => expect( getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph?264...#web/src/e2e/index.e2e.test.tsx') ).toEqual({ - repo: 'sourcegraph/sourcegraph?264...#web/src/e2e/index.e2e.test.tsx', - file: '#web/src/e2e/index.e2e.test.tsx', + repo: 'sourcegraph/sourcegraph', + file: 'web/src/e2e/index.e2e.test.tsx', })) it('return empty repo if host is not GitHub', () => expect(getParamsFromUriPath('git://unknownhost.com/sourcegraph/testrepo#http/req/main.go')).toEqual({ repo: null, - file: '#http/req/main.go', + file: 'http/req/main.go', })) it('return empty file if document has no file format', () => expect(getParamsFromUriPath('git://github.com/sourcegraph/sourcegraph/testrepo#formatless')).toEqual({ - repo: 'sourcegraph/sourcegraph/testrepo#formatless', + repo: 'sourcegraph/sourcegraph', file: null, })) }) @@ -46,41 +78,38 @@ const paramsInput = [ goal: 'returns a web project that matches the repo and file patterns', params: { repo: 'sourcegraph/sourcegraph', - file: '#web/src/storm/index.tsx', + file: 'web/src/storm/index.tsx', }, - expected: projects[0], + expected: { project: projects[0], fileMatched: true }, }, { goal: 'returns a dev project that matches the repo and file patterns', params: { repo: 'sourcegraph/dev-repo', - file: '#dev/backend/main.go', + file: 'dev/backend/main.go', }, - expected: projects[1], + expected: { project: projects[1], fileMatched: true }, }, { goal: 'returns undefined for not matching repo and file patterns', params: { repo: 'sourcegraph/test-repo', - file: '#dev/test/start.rb', + file: 'dev/test/start.rb', }, - expected: undefined, + expected: { project: undefined, fileMatched: undefined }, }, { goal: 'returns undefined for not matching repo and file patterns', params: { repo: 'sourcegraph/test-repo', - file: '#dev/test/start.rb', + file: 'dev/test/start.rb', }, - expected: undefined, + expected: { project: undefined, fileMatched: undefined }, }, ] describe('matchSentryProject', () => { - beforeEach(async () => { - await sourcegraph.configuration.get().update('sentry.organization', 'sourcegraph') - await sourcegraph.configuration.get().update('sentry.projects', projects) - }) + beforeEach(setDefaults) for (const paramsCase of paramsInput) { it(paramsCase.goal, () => expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected)) } @@ -88,40 +117,42 @@ describe('matchSentryProject', () => { const incompleteConfigs = [ { - goal: 'return one missing config', + goal: 'returns one missing config', settings: { name: 'sourcegraph', projectId: '1334031', - patternProperties: { - repoMatches: undefined, - fileMatches: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], - lineMatches: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], - }, + linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], + filters: [ + { + repository: undefined, + file: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + }, + ], }, - expected: ['repoMatches'], + expected: ['settings.filters[0].repository'], }, { - goal: 'return two missing configs', + goal: 'returns two missing configs', settings: { name: 'sourcegraph', projectId: '', - patternProperties: { - repoMatches: undefined, - fileMatches: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], - lineMatches: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], - }, + linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], + filters: [ + { + repository: undefined, + file: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + }, + ], }, - expected: ['projectId', 'repoMatches'], + expected: ['settings.projectId', 'settings.filters[0].repository'], }, ] describe('checkMissingConfig()', () => { for (const config of incompleteConfigs) { - it('checks missing configs with goal to ' + config.goal, () => - expect(checkMissingConfig(config.settings)).toEqual(config.expected) - ) + it(config.goal, () => expect(findEmptyConfigs(config.settings)).toEqual(config.expected)) } - it('handles empty settings', () => expect(checkMissingConfig()).toEqual([])) + it('handles empty settings', () => expect(findEmptyConfigs()).toEqual(['settings'])) }) const createDecorationWithoutOrgOutcome = { From 9dc20f0d383715e10691e2296cf1ab54887a5d9f Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 12:10:41 -0700 Subject: [PATCH 26/38] update test name, improve missing configs hover message --- src/handler.ts | 3 +++ src/test/handler.test.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/handler.ts b/src/handler.ts index 81940a69..105ab530 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -135,6 +135,9 @@ export function createDecoration( } else if (!sentryProjectId) { contentText = ' View logs in Sentry (❕)» ' hoverText = ' Add Sentry projects to your Sentry extension settings for project matching.' + } else if (missingConfigData.length > 0 && missingConfigData[0] === 'settings') { + contentText = ' View logs in Sentry (❕)» ' + hoverText = ' Please fill out the configurations in your Sentry extension settings.' } else if (missingConfigData.length > 0) { contentText = ' View logs in Sentry (❕)» ' hoverText = diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 6bb91b7d..99ff14fb 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -148,7 +148,7 @@ const incompleteConfigs = [ }, ] -describe('checkMissingConfig()', () => { +describe('findEmptyConfigs()', () => { for (const config of incompleteConfigs) { it(config.goal, () => expect(findEmptyConfigs(config.settings)).toEqual(config.expected)) } From 929426408d44f9d0e74fc6b1e519adad9dfd6d24 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 17:39:57 -0700 Subject: [PATCH 27/38] improve matching and add more tests --- src/handler.ts | 84 ++++++++++++++++++++++++---------------- src/test/handler.test.ts | 75 ++++++++++++++++++++++++++++++----- 2 files changed, 115 insertions(+), 44 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index 105ab530..a4a4d4e4 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -32,6 +32,10 @@ export function getParamsFromUriPath(textDocumentURI: string): Params { } } +interface Matched { + project: SentryProject | undefined + fileMatched: boolean | undefined +} /** * Verify if the params from the document URI match with the repo and file formats specified * in the Sentry extension settings. If there is a match we know the document is enabled to send logs @@ -40,58 +44,73 @@ export function getParamsFromUriPath(textDocumentURI: string): Params { * @param projects Sentry extension projects configurations. * @return Sentry projectID this document reports to. */ -export function matchSentryProject( - params: Params, - projects: SentryProject[] -): { project: SentryProject | undefined; fileMatched: boolean | undefined } { +export function matchSentryProject(params: Params, projects: SentryProject[]): Matched { + let matched: Matched = { project: undefined, fileMatched: undefined } + if (!projects || !params.repo || !params.file) { - return { project: undefined, fileMatched: undefined } + return matched } // Check if a Sentry project is associated with this document's repository and/or file and retrieve the project. // TODO: Handle the null case instead of using a non-null assertion ! // TODO: Handle cases where the wrong project is matched due to similar repo name, // e.g. `sourcegraph-jetbrains` repo will match the `sourcegraph` project - for (const project of projects) { for (const filter of project.filters) { // both repository and file match - if ( - filter.repository && - filter.file && - !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && - filter.file.some(file => !!new RegExp(file).exec(params.file!)) - ) { - return { project, fileMatched: true } - } - // repository matches but file does not match - if ( - filter.repository && - filter.file && - !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && - !filter.file.some(file => !!new RegExp(file).exec(params.file!)) - ) { - return { project, fileMatched: false } + if (filter.repository && filter.file) { + if ( + !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && + filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + matched = { project, fileMatched: true } + } + // repository doesn't match and file matches + if ( + !!!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && + filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + matched = { project: undefined, fileMatched: true } + } + // repository matches and file does not match + if ( + !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && + !filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + matched = { project, fileMatched: false } + } + // repository doesn't match and file does not match + if ( + !!!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && + !filter.file.some(file => !!new RegExp(file).exec(params.file!)) + ) { + matched = { project: undefined, fileMatched: false } + } } // repository matches and there is no filter for file matching if ( - filter.repository && (!filter.file || filter.file.length === 0) && + filter.repository && !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) ) { - return { project, fileMatched: undefined } + matched = { project, fileMatched: undefined } } // file matches and there is no filter for repository matching if ( - filter.file && (!filter.repository || filter.repository.length === 0) && + filter.file && filter.file.some(file => !!new RegExp(file).exec(params.file!)) ) { - return { project: undefined, fileMatched: true } + matched = { project, fileMatched: true } + } + + // if project is matched return project + if (matched.project) { + return matched } } } - return { project: undefined, fileMatched: undefined } + return matched } /** @@ -129,16 +148,13 @@ export function createDecoration( let hoverText = ' View logs in Sentry » ' const color = '#e03e2f' - if (!sentryOrg) { - contentText = ' Configure the Sentry extension to view logs. ' - hoverText = ' Configure the Sentry extension to view logs in Sentry. ' + if ((missingConfigData.length > 0 && missingConfigData[0] === 'settings') || !sentryOrg) { + contentText = ' Configure the Sentry extension to view logs (❕)» ' + hoverText = ' Please fill out the configurations in your Sentry extension settings.' } else if (!sentryProjectId) { contentText = ' View logs in Sentry (❕)» ' hoverText = ' Add Sentry projects to your Sentry extension settings for project matching.' - } else if (missingConfigData.length > 0 && missingConfigData[0] === 'settings') { - contentText = ' View logs in Sentry (❕)» ' - hoverText = ' Please fill out the configurations in your Sentry extension settings.' - } else if (missingConfigData.length > 0) { + } else if (missingConfigData.length > 0 && missingConfigData[0] !== 'settings') { contentText = ' View logs in Sentry (❕)» ' hoverText = ' Please fill out the following configurations in your Sentry extension settings: ' + diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 99ff14fb..bec678a8 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -25,7 +25,6 @@ const projects: SentryProject[] = [ }, ], }, - { name: 'Dev env errors', projectId: '213332', @@ -37,6 +36,26 @@ const projects: SentryProject[] = [ }, ], }, + { + name: 'docs pages errors', + projectId: '544533', + linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/], + filters: [ + { + repository: [/sourcegraph\/docs/], + }, + ], + }, + { + name: 'dot com errors', + projectId: '242677', + linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/], + filters: [ + { + file: [/\.tsx?/], + }, + ], + }, ] const setDefaults = async () => { @@ -91,12 +110,20 @@ const paramsInput = [ expected: { project: projects[1], fileMatched: true }, }, { - goal: 'returns undefined for not matching repo and file patterns', + goal: 'returns file false for not matching file patterns', + params: { + repo: 'sourcegraph/dev-repo', + file: 'dev/test/start.rb', + }, + expected: { project: projects[1], fileMatched: false }, + }, + { + goal: 'returns undefined for not matching repo and false for not matching file patterns', params: { repo: 'sourcegraph/test-repo', file: 'dev/test/start.rb', }, - expected: { project: undefined, fileMatched: undefined }, + expected: { project: undefined, fileMatched: false }, }, { goal: 'returns undefined for not matching repo and file patterns', @@ -104,13 +131,30 @@ const paramsInput = [ repo: 'sourcegraph/test-repo', file: 'dev/test/start.rb', }, - expected: { project: undefined, fileMatched: undefined }, + expected: { project: undefined, fileMatched: false }, + }, + { + goal: 'returns project for matching repo and undefined for not having file patterns', + params: { + repo: 'sourcegraph/docs', + file: 'src/development/tutorial.tsx', + }, + expected: { project: projects[2], fileMatched: undefined }, + }, + { + goal: 'returns project for matching file patterns', + params: { + repo: 'sourcegraph/website', + file: 'web/search/start.tsx', + }, + expected: { project: projects[3], fileMatched: true }, }, ] describe('matchSentryProject', () => { beforeEach(setDefaults) for (const paramsCase of paramsInput) { + // tslint:disable-next-line:ban it(paramsCase.goal, () => expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected)) } }) @@ -155,13 +199,24 @@ describe('findEmptyConfigs()', () => { it('handles empty settings', () => expect(findEmptyConfigs()).toEqual(['settings'])) }) -const createDecorationWithoutOrgOutcome = { - content: ' Configure the Sentry extension to view logs. ', - hover: ' Configure the Sentry extension to view logs in Sentry. ', +const createDecorationInputs = [ + { + goal: 'handles an empty organization setting', + params: [], + }, + { + goal: 'informs user to fill out settings.', + params: ['settings'], + }, +] + +const createDecorationOutput = { + content: ' Configure the Sentry extension to view logs (❕)» ', + hover: ' Please fill out the configurations in your Sentry extension settings.', backgroundColor: '#e03e2f', } - describe('createDecoration', () => { - it('handles an empty organization setting', () => - expect(createDecoration([])).toEqual(createDecorationWithoutOrgOutcome)) + for (const decoInput of createDecorationInputs) { + it(decoInput.goal, () => expect(createDecoration(decoInput.params)).toEqual(createDecorationOutput)) + } }) From b959cf61d9ef15514cb23d92c7d138c2a499b650 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 17:53:55 -0700 Subject: [PATCH 28/38] capture group after # in fileMatch regexp pattern --- src/handler.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index a4a4d4e4..3ab323e7 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -22,8 +22,7 @@ export function getParamsFromUriPath(textDocumentURI: string): Params { // TODO: Support more than just GitHub & Gitlab. // TODO: Safeguard for cases where repo/fileMatch are null. const repoPattern = /(github\.com|gitlab\.com)\/([^\?\#\/]+\/[^\?\#\/]*)/gi - const filePattern = /#(:?.*\.(.*))$/gi - + const filePattern = /#(.*\.(.*))$/gi const repoMatch = repoPattern.exec(textDocumentURI) const fileMatch = filePattern.exec(textDocumentURI) return { From 8fd14dc6e5ac18d72b0d2154161e5e76d5ef641f Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 20:57:16 -0700 Subject: [PATCH 29/38] improve hover messages --- src/extension.ts | 4 ++++ src/handler.ts | 48 +++++++++++++++++++++++----------------- src/test/handler.test.ts | 35 +++++++++++++++++++++-------- 3 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index a7959da0..482ce3e4 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -101,6 +101,10 @@ export function getDecorations( matched.project.linePatterns ) } + if (matched && !matched.project) { + missingConfigData.push('repository') + return buildDecorations(missingConfigData, documentText) + } return buildDecorations(missingConfigData, documentText) } diff --git a/src/handler.ts b/src/handler.ts index 3ab323e7..a1bcf961 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -8,7 +8,6 @@ interface Params { export interface LineDecorationText { content: string hover: string - backgroundColor: string } /** @@ -32,7 +31,7 @@ export function getParamsFromUriPath(textDocumentURI: string): Params { } interface Matched { - project: SentryProject | undefined + project: SentryProject | undefined | false fileMatched: boolean | undefined } /** @@ -143,26 +142,35 @@ export function createDecoration( sentryOrg?: string, sentryProjectId?: string ): LineDecorationText { - let contentText = ' View logs in Sentry » ' - let hoverText = ' View logs in Sentry » ' - const color = '#e03e2f' - - if ((missingConfigData.length > 0 && missingConfigData[0] === 'settings') || !sentryOrg) { - contentText = ' Configure the Sentry extension to view logs (❕)» ' - hoverText = ' Please fill out the configurations in your Sentry extension settings.' - } else if (!sentryProjectId) { - contentText = ' View logs in Sentry (❕)» ' - hoverText = ' Add Sentry projects to your Sentry extension settings for project matching.' - } else if (missingConfigData.length > 0 && missingConfigData[0] !== 'settings') { - contentText = ' View logs in Sentry (❕)» ' - hoverText = - ' Please fill out the following configurations in your Sentry extension settings: ' + - missingConfigData.join(', ') + if ((missingConfigData.length > 0 && missingConfigData.includes('settings')) || !sentryOrg) { + return { + content: ' Configure the Sentry extension to view logs (❕)» ', + hover: ' Please fill out the configurations in your Sentry extension settings.', + } + } + if (missingConfigData.length > 0 && missingConfigData.includes('repository')) { + return { + content: ' View logs in Sentry (❕)» ', + hover: ' Add this repository to your Sentry extension settings for project matching.', + } + } + if (!sentryProjectId) { + return { + content: ' View logs in Sentry (❕)» ', + hover: ' Add Sentry projects to your Sentry extension settings for project matching.', + } + } + if (missingConfigData.length > 0 && missingConfigData[0] !== 'settings') { + return { + content: ' View logs in Sentry (❕)» ', + hover: + ' Please fill out the following configurations in your Sentry extension settings: ' + + missingConfigData.join(', '), + } } return { - content: contentText, - hover: hoverText, - backgroundColor: color, + content: ' View logs in Sentry » ', + hover: ' View logs in Sentry » ', } } diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index bec678a8..a27fbc4b 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -154,7 +154,6 @@ const paramsInput = [ describe('matchSentryProject', () => { beforeEach(setDefaults) for (const paramsCase of paramsInput) { - // tslint:disable-next-line:ban it(paramsCase.goal, () => expect(matchSentryProject(paramsCase.params, projects)).toEqual(paramsCase.expected)) } }) @@ -202,21 +201,39 @@ describe('findEmptyConfigs()', () => { const createDecorationInputs = [ { goal: 'handles an empty organization setting', - params: [], + params: { missingConfigData: [] }, + expected: { + content: ' Configure the Sentry extension to view logs (❕)» ', + hover: ' Please fill out the configurations in your Sentry extension settings.', + }, }, { goal: 'informs user to fill out settings.', - params: ['settings'], + params: { missingConfigData: ['settings'] }, + expected: { + content: ' Configure the Sentry extension to view logs (❕)» ', + hover: ' Please fill out the configurations in your Sentry extension settings.', + }, + }, + { + goal: 'informs user to add the repository to their Sentry settings.', + params: { missingConfigData: ['repository'], sentryOrg: 'sourcegraph' }, + expected: { + content: ' View logs in Sentry (❕)» ', + hover: ' Add this repository to your Sentry extension settings for project matching.', + }, }, ] -const createDecorationOutput = { - content: ' Configure the Sentry extension to view logs (❕)» ', - hover: ' Please fill out the configurations in your Sentry extension settings.', - backgroundColor: '#e03e2f', -} describe('createDecoration', () => { for (const decoInput of createDecorationInputs) { - it(decoInput.goal, () => expect(createDecoration(decoInput.params)).toEqual(createDecorationOutput)) + it(decoInput.goal, () => + expect( + createDecoration( + decoInput.params.missingConfigData, + decoInput.params.sentryOrg ? decoInput.params.sentryOrg : '' + ) + ).toEqual(decoInput.expected) + ) } }) From aa93c7ae79f71f0a7bad904f93c3c49f54245a73 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 21:58:48 -0700 Subject: [PATCH 30/38] update test and clean code --- src/handler.ts | 35 ++++++++++++++++------------------- src/test/extension.test.ts | 30 ++++++++++++++---------------- 2 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index a1bcf961..25c16df2 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -55,33 +55,22 @@ export function matchSentryProject(params: Params, projects: SentryProject[]): M // e.g. `sourcegraph-jetbrains` repo will match the `sourcegraph` project for (const project of projects) { for (const filter of project.filters) { - // both repository and file match + // if repository and file filter are grouped if (filter.repository && filter.file) { - if ( - !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && - filter.file.some(file => !!new RegExp(file).exec(params.file!)) - ) { + // both repository and file match + if (matchesRepository(filter.repository, params.repo) && matchesFile(filter.file, params.file)) { matched = { project, fileMatched: true } } // repository doesn't match and file matches - if ( - !!!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && - filter.file.some(file => !!new RegExp(file).exec(params.file!)) - ) { + if (!matchesRepository(filter.repository, params.repo) && matchesFile(filter.file, params.file)) { matched = { project: undefined, fileMatched: true } } // repository matches and file does not match - if ( - !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && - !filter.file.some(file => !!new RegExp(file).exec(params.file!)) - ) { + if (matchesRepository(filter.repository, params.repo) && !matchesFile(filter.file, params.file)) { matched = { project, fileMatched: false } } // repository doesn't match and file does not match - if ( - !!!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) && - !filter.file.some(file => !!new RegExp(file).exec(params.file!)) - ) { + if (!matchesRepository(filter.repository, params.repo) && !matchesFile(filter.file, params.file)) { matched = { project: undefined, fileMatched: false } } } @@ -89,7 +78,7 @@ export function matchSentryProject(params: Params, projects: SentryProject[]): M if ( (!filter.file || filter.file.length === 0) && filter.repository && - !!filter.repository.find(repo => !!new RegExp(repo).exec(params.repo!)) + matchesRepository(filter.repository, params.repo) ) { matched = { project, fileMatched: undefined } } @@ -97,7 +86,7 @@ export function matchSentryProject(params: Params, projects: SentryProject[]): M if ( (!filter.repository || filter.repository.length === 0) && filter.file && - filter.file.some(file => !!new RegExp(file).exec(params.file!)) + matchesFile(filter.file, params.file) ) { matched = { project, fileMatched: true } } @@ -111,6 +100,14 @@ export function matchSentryProject(params: Params, projects: SentryProject[]): M return matched } +function matchesRepository(repository: RegExp[], repoParam: string): boolean { + return !!repository.find(repo => !!new RegExp(repo).exec(repoParam)) +} + +function matchesFile(file: RegExp[], fileParam: string): boolean { + return file.some(file => !!new RegExp(file).exec(fileParam)) +} + /** * Check for missing configurations in the Sentry extension settings * @param settings diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index e7404ad4..f37abeec 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -90,7 +90,7 @@ describe('resolveSettings()', () => { }) }) -const data = [ +const decorateLineInput = [ { goal: 'renders complete Sentry link', index: 1, @@ -111,10 +111,10 @@ const data = [ }, }, { - goal: 'warns about incomplete config with missing repoMatches', + goal: 'warns about incomplete config with missing repository', index: 1, match: 'cannot determine file path', - missingConfigData: ['repoMatches'], + missingConfigData: ['repository'], sentryProjectId: '134412', expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -123,18 +123,17 @@ const data = [ backgroundColor: '#f2736d', color: 'rgba(255, 255, 255, 0.8)', contentText: ' View logs in Sentry (❕)» ', - hoverMessage: - ' Please fill out the following configurations in your Sentry extension settings: repoMatches', + hoverMessage: ' Add this repository to your Sentry extension settings for project matching.', linkURL: 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, }, }, { - goal: 'warns about incomplete config with missing repoMatches and fileMatches patterns', + goal: 'warns about incomplete config with missing repository and file patterns', index: 1, match: 'cannot determine file path', - missingConfigData: ['repoMatches', 'fileMatches'], + missingConfigData: ['repository', 'file'], sentryProjectId: '134412', expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -143,8 +142,7 @@ const data = [ backgroundColor: '#f2736d', color: 'rgba(255, 255, 255, 0.8)', contentText: ' View logs in Sentry (❕)» ', - hoverMessage: - ' Please fill out the following configurations in your Sentry extension settings: repoMatches, fileMatches', + hoverMessage: ' Add this repository to your Sentry extension settings for project matching.', linkURL: 'https://sentry.io/organizations/sourcegraph/issues/?project=134412&query=is%3Aunresolved+cannot+determine+file+path&statsPeriod=14d', }, @@ -154,7 +152,7 @@ const data = [ goal: 'renders warning link hinting to add projectId and render link to general issues page', index: 1, match: 'cannot determine file path', - missingConfigData: ['repoMatches', 'fileMatches'], + missingConfigData: ['file'], sentryProjectId: undefined, expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -173,7 +171,7 @@ const data = [ 'matches line based on common pattern, render warning link hinting to add projectId and render link to general issues page', index: 1, match: '', - missingConfigData: ['repoMatches', 'fileMatches'], + missingConfigData: ['file'], sentryProjectId: undefined, expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -192,11 +190,11 @@ const data = [ describe('decorateLine()', () => { beforeEach(setDefaults) - for (const deco of data) { - it(deco.goal, () => - expect(decorateLine(deco.index, deco.match, deco.missingConfigData, deco.sentryProjectId)).toEqual( - deco.expected - ) + for (const decoInput of decorateLineInput) { + it(decoInput.goal, () => + expect( + decorateLine(decoInput.index, decoInput.match, decoInput.missingConfigData, decoInput.sentryProjectId) + ).toEqual(decoInput.expected) ) } }) From 870178f26232feb78c62b28e769b3737658145ed Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Wed, 15 May 2019 23:26:07 -0700 Subject: [PATCH 31/38] fix hover message matching --- src/extension.ts | 1 - src/handler.ts | 2 +- src/test/handler.test.ts | 12 +++++++++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 482ce3e4..c0a39521 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -82,7 +82,6 @@ export function getDecorations( sentryProjects?: SentryProject[] ): sourcegraph.TextDocumentDecoration[] { const params: Params = getParamsFromUriPath(documentUri) - const matched = sentryProjects && matchSentryProject(params, sentryProjects) let missingConfigData: string[] = [] diff --git a/src/handler.ts b/src/handler.ts index 25c16df2..ec70f988 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -145,7 +145,7 @@ export function createDecoration( hover: ' Please fill out the configurations in your Sentry extension settings.', } } - if (missingConfigData.length > 0 && missingConfigData.includes('repository')) { + if (missingConfigData.includes('repository')) { return { content: ' View logs in Sentry (❕)» ', hover: ' Add this repository to your Sentry extension settings for project matching.', diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index a27fbc4b..39834afe 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -223,6 +223,15 @@ const createDecorationInputs = [ hover: ' Add this repository to your Sentry extension settings for project matching.', }, }, + { + goal: 'informs user to add to add missing configs to their Sentry settings.', + params: { missingConfigData: ['linePatterns', 'file'], sentryProjectId: '1334031', sentryOrg: 'sourcegraph' }, + expected: { + content: ' View logs in Sentry (❕)» ', + hover: + ' Please fill out the following configurations in your Sentry extension settings: linePatterns, file', + }, + }, ] describe('createDecoration', () => { @@ -231,7 +240,8 @@ describe('createDecoration', () => { expect( createDecoration( decoInput.params.missingConfigData, - decoInput.params.sentryOrg ? decoInput.params.sentryOrg : '' + decoInput.params.sentryOrg, + decoInput.params.sentryProjectId ) ).toEqual(decoInput.expected) ) From 9c44d1592d1254e693a8af6664d29ce06579c9d6 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Mon, 20 May 2019 17:34:07 -0700 Subject: [PATCH 32/38] simplify repo matching, add tests, restructure configs --- src/extension.ts | 37 +++++++++++------------ src/handler.ts | 60 +++++++++----------------------------- src/settings.ts | 4 +-- src/test/extension.test.ts | 50 ++++++++++++++++++++++--------- src/test/handler.test.ts | 44 ++++++++++++++-------------- 5 files changed, 92 insertions(+), 103 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index c0a39521..072debb3 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -1,7 +1,7 @@ import { BehaviorSubject, combineLatest, from } from 'rxjs' import { filter, switchMap } from 'rxjs/operators' import * as sourcegraph from 'sourcegraph' -import { createDecoration, findEmptyConfigs, getParamsFromUriPath, matchSentryProject } from './handler' +import { createDecoration, getParamsFromUriPath, matchSentryProject } from './handler' import { resolveSettings, SentryProject, Settings } from './settings' /** @@ -51,12 +51,19 @@ export function activate(context: sourcegraph.ExtensionContext): void { const sentryProjects = settings['sentry.projects'] if (editor.document.text) { - const decorationSettings = settings['sentry.decorations.inline'] - if (!decorationSettings) { + const showDecorations = settings['sentry.decorations.inline'] + if (!showDecorations) { editor.setDecorations(DECORATION_TYPE, []) // clear decorations return } + // render links by matching common error handling code + // TODO: safegaurd for when sentryProjects is an empty array + if (!sentryProjects) { + const decorations = buildDecorations(['settings'], editor.document.text) + editor.setDecorations(DECORATION_TYPE, decorations) + } + const decorations = getDecorations(editor.document.uri, editor.document.text, sentryProjects) if (decorations.length === 0) { @@ -83,28 +90,18 @@ export function getDecorations( ): sourcegraph.TextDocumentDecoration[] { const params: Params = getParamsFromUriPath(documentUri) const matched = sentryProjects && matchSentryProject(params, sentryProjects) - let missingConfigData: string[] = [] // Do not decorate lines if the document file format does not match the // file matching patterns listed in the Sentry extension configurations. - if (matched && matched.fileMatched === false) { + if (!matched) { return [] } - if (matched && matched.project) { - missingConfigData = findEmptyConfigs(matched.project) - - return buildDecorations( - missingConfigData, - documentText, - matched.project.projectId, - matched.project.linePatterns - ) - } - if (matched && !matched.project) { - missingConfigData.push('repository') - return buildDecorations(missingConfigData, documentText) - } - return buildDecorations(missingConfigData, documentText) + return buildDecorations( + matched.missingConfigs, + documentText, + matched.project.projectId, + matched.project.linePatterns + ) } /** diff --git a/src/handler.ts b/src/handler.ts index ec70f988..214651a0 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -31,8 +31,8 @@ export function getParamsFromUriPath(textDocumentURI: string): Params { } interface Matched { - project: SentryProject | undefined | false - fileMatched: boolean | undefined + project: SentryProject + missingConfigs: string[] } /** * Verify if the params from the document URI match with the repo and file formats specified @@ -42,62 +42,30 @@ interface Matched { * @param projects Sentry extension projects configurations. * @return Sentry projectID this document reports to. */ -export function matchSentryProject(params: Params, projects: SentryProject[]): Matched { - let matched: Matched = { project: undefined, fileMatched: undefined } - +export function matchSentryProject(params: Params, projects: SentryProject[]): Matched | null { if (!projects || !params.repo || !params.file) { - return matched + return null } - // Check if a Sentry project is associated with this document's repository and/or file and retrieve the project. // TODO: Handle the null case instead of using a non-null assertion ! // TODO: Handle cases where the wrong project is matched due to similar repo name, // e.g. `sourcegraph-jetbrains` repo will match the `sourcegraph` project for (const project of projects) { + const missingConfigs = findEmptyConfigs(project) + for (const filter of project.filters) { - // if repository and file filter are grouped - if (filter.repository && filter.file) { - // both repository and file match - if (matchesRepository(filter.repository, params.repo) && matchesFile(filter.file, params.file)) { - matched = { project, fileMatched: true } - } - // repository doesn't match and file matches - if (!matchesRepository(filter.repository, params.repo) && matchesFile(filter.file, params.file)) { - matched = { project: undefined, fileMatched: true } - } - // repository matches and file does not match - if (matchesRepository(filter.repository, params.repo) && !matchesFile(filter.file, params.file)) { - matched = { project, fileMatched: false } - } - // repository doesn't match and file does not match - if (!matchesRepository(filter.repository, params.repo) && !matchesFile(filter.file, params.file)) { - matched = { project: undefined, fileMatched: false } - } - } - // repository matches and there is no filter for file matching - if ( - (!filter.file || filter.file.length === 0) && - filter.repository && - matchesRepository(filter.repository, params.repo) - ) { - matched = { project, fileMatched: undefined } - } - // file matches and there is no filter for repository matching - if ( - (!filter.repository || filter.repository.length === 0) && - filter.file && - matchesFile(filter.file, params.file) - ) { - matched = { project, fileMatched: true } + // both repository and file match + if (filter.files && !matchesFile(filter.files, params.file)) { + break } - // if project is matched return project - if (matched.project) { - return matched + if (filter.repositories && !matchesRepository(filter.repositories, params.repo)) { + break } + return { project, missingConfigs } } } - return matched + return null } function matchesRepository(repository: RegExp[], repoParam: string): boolean { @@ -145,7 +113,7 @@ export function createDecoration( hover: ' Please fill out the configurations in your Sentry extension settings.', } } - if (missingConfigData.includes('repository')) { + if (missingConfigData.includes('repositories')) { return { content: ' View logs in Sentry (❕)» ', hover: ' Add this repository to your Sentry extension settings for project matching.', diff --git a/src/settings.ts b/src/settings.ts index cf30cdff..a0d81f45 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -16,8 +16,8 @@ export interface SentryProject { // RexExp patterns to match log handeling code, e.g. /log\.(Printf|Print)\(['"]([^'"]+)['"]\)/ linePatterns: RegExp[] filters: { - repository?: RegExp[] - file?: RegExp[] + repositories?: RegExp[] + files?: RegExp[] }[] // TODO: Add these to v1. diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index f37abeec..772fd04d 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -27,8 +27,8 @@ const projects: SentryProject[] = [ ], filters: [ { - repository: [/sourcegraph\/sourcegraph/, /bucket/], - file: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + repositories: [/sourcegraph\/sourcegraph/, /bucket/], + files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], }, ], }, @@ -39,8 +39,8 @@ const projects: SentryProject[] = [ linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], filters: [ { - repository: [/dev-repo/], - file: [/(dev)\/.*\\.go?/], + repositories: [/dev-repo/], + files: [/(dev)\/.*\\.go?/], }, ], }, @@ -68,8 +68,8 @@ describe('resolveSettings()', () => { ], filters: [ { - repository: [/sourcegraph\/sourcegraph/, /bucket/], - file: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + repositories: [/sourcegraph\/sourcegraph/, /bucket/], + files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], }, ], }, @@ -79,8 +79,8 @@ describe('resolveSettings()', () => { linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], filters: [ { - repository: [/dev-repo/], - file: [/(dev)\/.*\\.go?/], + repositories: [/dev-repo/], + files: [/(dev)\/.*\\.go?/], }, ], }, @@ -114,7 +114,7 @@ const decorateLineInput = [ goal: 'warns about incomplete config with missing repository', index: 1, match: 'cannot determine file path', - missingConfigData: ['repository'], + missingConfigData: ['repositories'], sentryProjectId: '134412', expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -133,7 +133,7 @@ const decorateLineInput = [ goal: 'warns about incomplete config with missing repository and file patterns', index: 1, match: 'cannot determine file path', - missingConfigData: ['repository', 'file'], + missingConfigData: ['repositories', 'files'], sentryProjectId: '134412', expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -152,7 +152,7 @@ const decorateLineInput = [ goal: 'renders warning link hinting to add projectId and render link to general issues page', index: 1, match: 'cannot determine file path', - missingConfigData: ['file'], + missingConfigData: ['files'], sentryProjectId: undefined, expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -171,7 +171,7 @@ const decorateLineInput = [ 'matches line based on common pattern, render warning link hinting to add projectId and render link to general issues page', index: 1, match: '', - missingConfigData: ['file'], + missingConfigData: ['files'], sentryProjectId: undefined, expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), @@ -344,6 +344,7 @@ const supportedLanguageCode = [ code: `// ErrInvalidToken is returned by DiscussionMailReplyTokens.Get when the token is invalid var ErrInvalidToken = errors.New("invalid token") // Get returns the user and thread ID found for the given token. If there`, + missingConfig: ['sentryProjectId'], expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, @@ -361,6 +362,7 @@ const supportedLanguageCode = [ code: ` if (!headFilePath) { throw new Error('cannot determine file path') }`, + missingConfig: ['sentryProjectId'], expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, @@ -377,6 +379,7 @@ const supportedLanguageCode = [ lang: 'python', code: `def create_app(): raise TypeError('bad bad factory!')`, + missingConfig: ['sentryProjectId'], expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, @@ -394,6 +397,7 @@ const supportedLanguageCode = [ code: ` } catch (UnsupportedEncodingException err) { logger.debug("failed to build URL"); err.printStackTrace();`, + missingConfig: ['sentryProjectId'], expected: { range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), isWholeLine: true, @@ -406,6 +410,25 @@ const supportedLanguageCode = [ }, }, }, + { + // should render a link with warning to setup settings + lang: 'go', + code: `// ErrInvalidToken is returned by DiscussionMailReplyTokens.Get when the token is invalid + var ErrInvalidToken = errors.New("invalid token") + // Get returns the user and thread ID found for the given token. If there`, + missingConfig: ['settings'], + expected: { + range: new sourcegraph.Range(new sourcegraph.Position(1, 0), new sourcegraph.Position(1, 0)), + isWholeLine: true, + after: { + backgroundColor: '#f2736d', + color: 'rgba(255, 255, 255, 0.8)', + contentText: ' Configure the Sentry extension to view logs (❕)» ', + hoverMessage: ' Please fill out the configurations in your Sentry extension settings.', + linkURL: 'https://sentry.io/organizations/sourcegraph/issues/', + }, + }, + }, ] const unsupportedLanguageCode = [ @@ -424,7 +447,7 @@ describe('buildDecorations()', () => { projects[0].linePatterns = [] for (const [, codeExample] of supportedLanguageCode.entries()) { it('check common pattern matching for ' + codeExample.lang, () => - expect(buildDecorations([], codeExample.code)).toEqual([codeExample.expected]) + expect(buildDecorations(codeExample.missingConfig, codeExample.code)).toEqual([codeExample.expected]) ) } for (const [, codeExample] of unsupportedLanguageCode.entries()) { @@ -432,6 +455,7 @@ describe('buildDecorations()', () => { expect(buildDecorations([], codeExample.code)).toEqual([]) ) } + it('should not render anything due to missing code ', () => expect(buildDecorations([], '')).toEqual([])) // set linePatterns back to original state for the other tests projects[0].linePatterns = [ /throw new Error+\(['"]([^'"]+)['"]\)/, diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 39834afe..108831e0 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -20,8 +20,8 @@ const projects: SentryProject[] = [ ], filters: [ { - repository: [/sourcegraph\/sourcegraph/, /bucket/], - file: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + repositories: [/sourcegraph\/sourcegraph/, /bucket/], + files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], }, ], }, @@ -31,8 +31,8 @@ const projects: SentryProject[] = [ linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], filters: [ { - repository: [/dev-repo/], - file: [/dev\/.*.go?/], + repositories: [/dev-repo/], + files: [/dev\/.*.go?/], }, ], }, @@ -42,7 +42,7 @@ const projects: SentryProject[] = [ linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/], filters: [ { - repository: [/sourcegraph\/docs/], + repositories: [/sourcegraph\/docs/], }, ], }, @@ -52,7 +52,7 @@ const projects: SentryProject[] = [ linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/], filters: [ { - file: [/\.tsx?/], + files: [/\.tsx?/], }, ], }, @@ -99,7 +99,7 @@ const paramsInput = [ repo: 'sourcegraph/sourcegraph', file: 'web/src/storm/index.tsx', }, - expected: { project: projects[0], fileMatched: true }, + expected: { project: projects[0], missingConfigs: [] }, }, { goal: 'returns a dev project that matches the repo and file patterns', @@ -107,7 +107,7 @@ const paramsInput = [ repo: 'sourcegraph/dev-repo', file: 'dev/backend/main.go', }, - expected: { project: projects[1], fileMatched: true }, + expected: { project: projects[1], missingConfigs: [] }, }, { goal: 'returns file false for not matching file patterns', @@ -115,7 +115,7 @@ const paramsInput = [ repo: 'sourcegraph/dev-repo', file: 'dev/test/start.rb', }, - expected: { project: projects[1], fileMatched: false }, + expected: null, }, { goal: 'returns undefined for not matching repo and false for not matching file patterns', @@ -123,7 +123,7 @@ const paramsInput = [ repo: 'sourcegraph/test-repo', file: 'dev/test/start.rb', }, - expected: { project: undefined, fileMatched: false }, + expected: null, }, { goal: 'returns undefined for not matching repo and file patterns', @@ -131,7 +131,7 @@ const paramsInput = [ repo: 'sourcegraph/test-repo', file: 'dev/test/start.rb', }, - expected: { project: undefined, fileMatched: false }, + expected: null, }, { goal: 'returns project for matching repo and undefined for not having file patterns', @@ -139,7 +139,7 @@ const paramsInput = [ repo: 'sourcegraph/docs', file: 'src/development/tutorial.tsx', }, - expected: { project: projects[2], fileMatched: undefined }, + expected: { project: projects[2], missingConfigs: [] }, }, { goal: 'returns project for matching file patterns', @@ -147,7 +147,7 @@ const paramsInput = [ repo: 'sourcegraph/website', file: 'web/search/start.tsx', }, - expected: { project: projects[3], fileMatched: true }, + expected: { project: projects[3], missingConfigs: [] }, }, ] @@ -167,12 +167,12 @@ const incompleteConfigs = [ linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], filters: [ { - repository: undefined, - file: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + repositories: undefined, + files: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], }, ], }, - expected: ['settings.filters[0].repository'], + expected: ['settings.filters[0].repositories'], }, { goal: 'returns two missing configs', @@ -182,12 +182,12 @@ const incompleteConfigs = [ linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], filters: [ { - repository: undefined, - file: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + repositories: undefined, + files: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], }, ], }, - expected: ['settings.projectId', 'settings.filters[0].repository'], + expected: ['settings.projectId', 'settings.filters[0].repositories'], }, ] @@ -217,7 +217,7 @@ const createDecorationInputs = [ }, { goal: 'informs user to add the repository to their Sentry settings.', - params: { missingConfigData: ['repository'], sentryOrg: 'sourcegraph' }, + params: { missingConfigData: ['repositories'], sentryOrg: 'sourcegraph' }, expected: { content: ' View logs in Sentry (❕)» ', hover: ' Add this repository to your Sentry extension settings for project matching.', @@ -225,11 +225,11 @@ const createDecorationInputs = [ }, { goal: 'informs user to add to add missing configs to their Sentry settings.', - params: { missingConfigData: ['linePatterns', 'file'], sentryProjectId: '1334031', sentryOrg: 'sourcegraph' }, + params: { missingConfigData: ['linePatterns', 'files'], sentryProjectId: '1334031', sentryOrg: 'sourcegraph' }, expected: { content: ' View logs in Sentry (❕)» ', hover: - ' Please fill out the following configurations in your Sentry extension settings: linePatterns, file', + ' Please fill out the following configurations in your Sentry extension settings: linePatterns, files', }, }, ] From 7a63ea7bb8af1bea8e9fecd29a1625acdd0776a3 Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Mon, 20 May 2019 18:02:48 -0700 Subject: [PATCH 33/38] update ReadMe --- README.md | 79 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 60 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 0de11474..b9fe046a 100644 --- a/README.md +++ b/README.md @@ -35,24 +35,30 @@ Set the following configurations in your settings: { "name": "[Project name for the config overview, e.g. Webapp errors]", "projectId": "[Sentry project ID, e.g. "1334031"]", - "patternProperties": { - "repoMatches": "[RegExp[] repo names asociated with this Sentry project]", - "fileMatches": [ - [RegExp[] that matches file format, e.g. "\\.tsx?"] - ], - "lineMatches": [ - [RegExp[] that matches error handling code, e.g. "throw new Error+\\(['\"]([^'\"]+)['\"]\\)"], + "linePatterns": [ + // List of RegExp patterns that match error handling code, e.g. "throw new Error+\\(['\"]([^'\"]+)['\"]\\)", + // !! Make sure to capture the error message in a RegExp group !! ] + "filters": { + [ + "repositories": [ + // List of RegExp repo names asociated with this Sentry project + ], + "files": [ + // List of RegExp that matches file format, e.g. "\\.tsx?", + // or for more specific matching, folder matching, e.g. "(?:web|shared|src)\/.*\\.tsx?" + ], } } ``` +## Important features: -File matches can also be narrowed down to certain folders by specifying this in the RegExp: +File patterns can also be narrowed down to certain folders by specifying this in the RegExp: ``` ... -"fileMatches": ["(web|shared|src)\/.*\\.tsx?"] +"files": ["(?:web|shared|src)\/.*\\.tsx?"] ... ``` @@ -63,23 +69,58 @@ File matches can also be narrowed down to certain folders by specifying this in Configuration: ``` - ... - "patternProperties": { - "repoMatches": "sourcegraph", - "fileMatches": ["([^'\"]+)\/.*\\.ts?"], - "lineMatches": [ - "throw new Error+\\(['\"]([^'\"]+)['\"]\\)", - "console\\.(warn|debug|info|error)\\(['\"`]([^'\"`]+)['\"`]\\)" - ] +"sentry.decorations.inline": true, +"sentry.organization": "sourcegraph", +"sentry.projects": [ + { + "name": "sourcegraph", + "projectId": "1334031", + "linePatterns": [ + "throw new Error+\\(['\"]([^'\"]+)['\"]\\)", + "console\\.(warn|debug|info|error)\\(['\"`]([^'\"`]+)['\"`]\\)" + ] + "filters": [ + { + "repositories": "sourcegraph\/sourcegraph", + "files": ["web\/.*\\.ts?"], + }, + { + "files": ["sourcegraph-subfolder\/.*\\.tsx?"] + } + + ] } +] ``` - - [On Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/client/browser/src/libs/github/file_info.ts#L16) - - [On GitHub](https://github.com/sourcegraph/sourcegraph/blob/master/client/browser/src/libs/github/file_info.ts#L16) + - [On Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/browser/src/libs/github/file_info.ts#L22) + - [On GitHub](https://github.com/sourcegraph/sourcegraph/blob/master/browser/src/libs/github/file_info.ts#L22) - Go +Configuration: + + ``` +"sentry.decorations.inline": true, +"sentry.organization": "sourcegraph", +"sentry.projects": [ + "name": "Dev env errors", + "projectId": "213332", + "linePatterns": ["errors\\.New\\(['\"`](.*)['\"`]\\)"], + "filters": [ + { + "repositories": ["sourcegraph\/sourcegraph", "sourcegraph\/dev-repo"], + "files": ["/auth\/.*.go?/"], + }, + { + "repositories": ["/dev-env/"] + } + ], +] + + ``` + - [On Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/cmd/frontend/auth/user_test.go#L54:19) - [On GitHub](https://github.com/sourcegraph/sourcegraph/blob/master/cmd/frontend/auth/user_test.go#L54) From ddf84b1ac4689d23ce22a99cec7ca37b4d26300e Mon Sep 17 00:00:00 2001 From: Vanesa Ortiz Date: Tue, 21 May 2019 10:58:05 -0700 Subject: [PATCH 34/38] fix prettier --- README.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index b9fe046a..c4d8232d 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,7 @@ Set the following configurations in your settings: } ``` + ## Important features: File patterns can also be narrowed down to certain folders by specifying this in the RegExp: @@ -69,9 +70,9 @@ File patterns can also be narrowed down to certain folders by specifying this in Configuration: ``` -"sentry.decorations.inline": true, -"sentry.organization": "sourcegraph", -"sentry.projects": [ + "sentry.decorations.inline": true, + "sentry.organization": "sourcegraph", + "sentry.projects": [ { "name": "sourcegraph", "projectId": "1334031", @@ -90,7 +91,7 @@ File patterns can also be narrowed down to certain folders by specifying this in ] } -] + ] ``` @@ -101,28 +102,28 @@ File patterns can also be narrowed down to certain folders by specifying this in Configuration: - ``` +``` "sentry.decorations.inline": true, "sentry.organization": "sourcegraph", "sentry.projects": [ - "name": "Dev env errors", - "projectId": "213332", - "linePatterns": ["errors\\.New\\(['\"`](.*)['\"`]\\)"], - "filters": [ - { - "repositories": ["sourcegraph\/sourcegraph", "sourcegraph\/dev-repo"], - "files": ["/auth\/.*.go?/"], - }, - { - "repositories": ["/dev-env/"] - } - ], + "name": "Dev env errors", + "projectId": "213332", + "linePatterns": ["errors\\.New\\(['\"`](.*)['\"`]\\)"], + "filters": [ + { + "repositories": ["sourcegraph\/sourcegraph", "sourcegraph\/dev-repo"], + "files": ["/auth\/.*.go?/"], + }, + { + "repositories": ["/dev-env/"] + } + ], ] - ``` +``` - - [On Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/cmd/frontend/auth/user_test.go#L54:19) - - [On GitHub](https://github.com/sourcegraph/sourcegraph/blob/master/cmd/frontend/auth/user_test.go#L54) +- [On Sourcegraph](https://sourcegraph.com/github.com/sourcegraph/sourcegraph/-/blob/cmd/frontend/auth/user_test.go#L54:19) +- [On GitHub](https://github.com/sourcegraph/sourcegraph/blob/master/cmd/frontend/auth/user_test.go#L54) - JavaScript From e44aea36c22aa6c1bb61ab162544191646aa4e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guychard?= Date: Tue, 21 May 2019 12:19:49 -0700 Subject: [PATCH 35/38] Fix type of regexp properties in SentryProject linePatterns, repositories and files were typed as RegExp[], but the user would have actually entered them as string[]. Having them typed as RegExp[] hid potential bugs where their real type would not have been handled properly. --- src/extension.ts | 7 +++---- src/handler.ts | 4 ++-- src/settings.ts | 6 +++--- src/test/extension.test.ts | 28 +++++++++++++++------------- src/test/handler.test.ts | 32 +++++++++++++++++--------------- 5 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 072debb3..0f04f479 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -117,16 +117,15 @@ export function buildDecorations( missingConfigData: string[], documentText: string, sentryProjectId?: string, - linePatterns?: RegExp[] + linePatterns?: string[] ): sourcegraph.TextDocumentDecoration[] { const decorations: sourcegraph.TextDocumentDecoration[] = [] for (const [index, line] of documentText.split('\n').entries()) { let match: RegExpExecArray | null - for (let pattern of linePatterns && linePatterns.length > 0 ? linePatterns : COMMON_ERRORLOG_PATTERNS) { - pattern = new RegExp(pattern, 'gi') - + const patterns = linePatterns ? linePatterns.map(s => new RegExp(s, 'gi')) : COMMON_ERRORLOG_PATTERNS + for (const pattern of patterns) { do { match = pattern.exec(line) // Depending on the line matching pattern the query m is indexed in position 1 or 2. diff --git a/src/handler.ts b/src/handler.ts index 214651a0..7c70ad9f 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -68,11 +68,11 @@ export function matchSentryProject(params: Params, projects: SentryProject[]): M return null } -function matchesRepository(repository: RegExp[], repoParam: string): boolean { +function matchesRepository(repository: string[], repoParam: string): boolean { return !!repository.find(repo => !!new RegExp(repo).exec(repoParam)) } -function matchesFile(file: RegExp[], fileParam: string): boolean { +function matchesFile(file: string[], fileParam: string): boolean { return file.some(file => !!new RegExp(file).exec(fileParam)) } diff --git a/src/settings.ts b/src/settings.ts index a0d81f45..fdc8aec9 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -14,10 +14,10 @@ export interface SentryProject { name: string projectId: string // RexExp patterns to match log handeling code, e.g. /log\.(Printf|Print)\(['"]([^'"]+)['"]\)/ - linePatterns: RegExp[] + linePatterns: string[] filters: { - repositories?: RegExp[] - files?: RegExp[] + repositories?: string[] + files?: string[] }[] // TODO: Add these to v1. diff --git a/src/test/extension.test.ts b/src/test/extension.test.ts index 772fd04d..2d6ab393 100644 --- a/src/test/extension.test.ts +++ b/src/test/extension.test.ts @@ -16,6 +16,8 @@ describe('activation', () => { }) }) +const asString = (re: RegExp): string => re.source + const projects: SentryProject[] = [ { name: 'Webapp typescript errors', @@ -24,11 +26,11 @@ const projects: SentryProject[] = [ /throw new Error+\(['"]([^'"]+)['"]\)/, /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], + ].map(asString), filters: [ { - repositories: [/sourcegraph\/sourcegraph/, /bucket/], - files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + repositories: [/sourcegraph\/sourcegraph/, /bucket/].map(asString), + files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/].map(asString), }, ], }, @@ -36,11 +38,11 @@ const projects: SentryProject[] = [ { name: 'Dev env errors', projectId: '213332', - linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/].map(asString), filters: [ { - repositories: [/dev-repo/], - files: [/(dev)\/.*\\.go?/], + repositories: [/dev-repo/].map(asString), + files: [/(dev)\/.*\\.go?/].map(asString), }, ], }, @@ -65,22 +67,22 @@ describe('resolveSettings()', () => { /throw new Error+\(['"]([^'"]+)['"]\)/, /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], + ].map(asString), filters: [ { - repositories: [/sourcegraph\/sourcegraph/, /bucket/], - files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + repositories: [/sourcegraph\/sourcegraph/, /bucket/].map(asString), + files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/].map(asString), }, ], }, { projectId: '213332', name: 'Dev env errors', - linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/].map(asString), filters: [ { - repositories: [/dev-repo/], - files: [/(dev)\/.*\\.go?/], + repositories: [/dev-repo/].map(asString), + files: [/(dev)\/.*\\.go?/].map(asString), }, ], }, @@ -461,5 +463,5 @@ describe('buildDecorations()', () => { /throw new Error+\(['"]([^'"]+)['"]\)/, /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ] + ].map(asString) }) diff --git a/src/test/handler.test.ts b/src/test/handler.test.ts index 108831e0..35a9adee 100644 --- a/src/test/handler.test.ts +++ b/src/test/handler.test.ts @@ -9,6 +9,8 @@ mock('sourcegraph', sourcegraph) import { createDecoration, findEmptyConfigs, getParamsFromUriPath, matchSentryProject } from '../handler' import { SentryProject } from '../settings' +const asString = (re: RegExp): string => re.source + const projects: SentryProject[] = [ { name: 'Webapp typescript errors', @@ -17,42 +19,42 @@ const projects: SentryProject[] = [ /throw new Error+\(['"]([^'"]+)['"]\)/, /console\.(warn|debug|info|error|log)\(['"`]([^'"`]+)['"`]\)/, /log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/, - ], + ].map(asString), filters: [ { - repositories: [/sourcegraph\/sourcegraph/, /bucket/], - files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/], + repositories: [/sourcegraph\/sourcegraph/, /bucket/].map(asString), + files: [/(web|shared|src)\/.*\.tsx?/, /\/.*\\.ts?/].map(asString), }, ], }, { name: 'Dev env errors', projectId: '213332', - linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/], + linePatterns: [/log\.(Printf|Print|Println)\(['"]([^'"]+)['"]\)/].map(asString), filters: [ { - repositories: [/dev-repo/], - files: [/dev\/.*.go?/], + repositories: [/dev-repo/].map(asString), + files: [/dev\/.*.go?/].map(asString), }, ], }, { name: 'docs pages errors', projectId: '544533', - linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/], + linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/].map(asString), filters: [ { - repositories: [/sourcegraph\/docs/], + repositories: [/sourcegraph\/docs/].map(asString), }, ], }, { name: 'dot com errors', projectId: '242677', - linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/], + linePatterns: [/throw new Error+\(['"]([^'"]+)['"]\)/].map(asString), filters: [ { - files: [/\.tsx?/], + files: [/\.tsx?/].map(asString), }, ], }, @@ -158,17 +160,17 @@ describe('matchSentryProject', () => { } }) -const incompleteConfigs = [ +const incompleteConfigs: { goal: string; settings: SentryProject; expected: string[] }[] = [ { goal: 'returns one missing config', settings: { name: 'sourcegraph', projectId: '1334031', - linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], + linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/].map(asString), filters: [ { repositories: undefined, - files: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + files: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/].map(asString), }, ], }, @@ -179,11 +181,11 @@ const incompleteConfigs = [ settings: { name: 'sourcegraph', projectId: '', - linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/], + linePatterns: [/logger\.debug\(['"`]([^'"`]+)['"`]\);/].map(asString), filters: [ { repositories: undefined, - files: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/], + files: [/(web|shared|src).*\.java?/, /(dev|src).*\.java?/, /.java?/].map(asString), }, ], }, From e8aca8a56b4e574c4c220408ae74a58b7d00fa27 Mon Sep 17 00:00:00 2001 From: Loic Guychard Date: Tue, 21 May 2019 12:21:55 -0700 Subject: [PATCH 36/38] Update src/handler.ts --- src/handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/handler.ts b/src/handler.ts index 7c70ad9f..01378d16 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -107,7 +107,7 @@ export function createDecoration( sentryOrg?: string, sentryProjectId?: string ): LineDecorationText { - if ((missingConfigData.length > 0 && missingConfigData.includes('settings')) || !sentryOrg) { + if (missingConfigData.includes('settings') || !sentryOrg) { return { content: ' Configure the Sentry extension to view logs (❕)» ', hover: ' Please fill out the configurations in your Sentry extension settings.', From d165eee403f494a03ef7559fa0c0440e6066ed9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guychard?= Date: Tue, 21 May 2019 12:23:27 -0700 Subject: [PATCH 37/38] Use array.some, rename variables --- src/handler.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/handler.ts b/src/handler.ts index 01378d16..c2106017 100644 --- a/src/handler.ts +++ b/src/handler.ts @@ -68,12 +68,12 @@ export function matchSentryProject(params: Params, projects: SentryProject[]): M return null } -function matchesRepository(repository: string[], repoParam: string): boolean { - return !!repository.find(repo => !!new RegExp(repo).exec(repoParam)) +function matchesRepository(repositories: string[], repoParam: string): boolean { + return repositories.some(repo => !!new RegExp(repo).exec(repoParam)) } -function matchesFile(file: string[], fileParam: string): boolean { - return file.some(file => !!new RegExp(file).exec(fileParam)) +function matchesFile(files: string[], fileParam: string): boolean { + return files.some(file => !!new RegExp(file).exec(fileParam)) } /** From 622bf923910e25ccf9d19a7a47295a0bef704c18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Guychard?= Date: Tue, 21 May 2019 12:30:22 -0700 Subject: [PATCH 38/38] Add a return, remove a return --- src/extension.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/extension.ts b/src/extension.ts index 0f04f479..95f21a5b 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -62,14 +62,10 @@ export function activate(context: sourcegraph.ExtensionContext): void { if (!sentryProjects) { const decorations = buildDecorations(['settings'], editor.document.text) editor.setDecorations(DECORATION_TYPE, decorations) - } - - const decorations = getDecorations(editor.document.uri, editor.document.text, sentryProjects) - - if (decorations.length === 0) { return } + const decorations = getDecorations(editor.document.uri, editor.document.text, sentryProjects) editor.setDecorations(DECORATION_TYPE, decorations) } })