diff --git a/src/vs/code/electron-main/menus.ts b/src/vs/code/electron-main/menus.ts index a51b0cee2fe..424aaffb74c 100644 --- a/src/vs/code/electron-main/menus.ts +++ b/src/vs/code/electron-main/menus.ts @@ -6,6 +6,7 @@ 'use strict'; import * as nls from 'vs/nls'; +import * as os from 'os'; import * as platform from 'vs/base/common/platform'; import * as arrays from 'vs/base/common/arrays'; import * as env from 'vs/code/electron-main/env'; @@ -15,7 +16,24 @@ import { IPath, VSCodeWindow } from 'vs/code/electron-main/window'; import { IStorageService } from 'vs/code/electron-main/storage'; import { IUpdateService, State as UpdateState } from 'vs/code/electron-main/update-manager'; import { Keybinding } from 'vs/base/common/keyCodes'; -import { generateNewIssueUrl } from 'vs/code/electron-main/utils'; +import product from 'vs/platform/product'; +import pkg from 'vs/platform/package'; + +export function generateNewIssueUrl(baseUrl: string, name: string, version: string, commit: string, date: string): string { + const osVersion = `${ os.type() } ${ os.arch() }`; + const queryStringPrefix = baseUrl.indexOf('?') === -1 ? '?' : '&'; + const body = encodeURIComponent( +`- VSCode Version: ${name} ${version} (${product.commit || 'Commit unknown'}, ${product.date || 'Date unknown'}) +- OS Version: ${osVersion} + +Steps to Reproduce: + +1. +2.` + ); + + return `${ baseUrl }${queryStringPrefix}body=${body}`; +} interface IResolvedKeybinding { id: string; @@ -651,13 +669,15 @@ export class VSCodeMenu { enabled: (this.windowsService.getWindowCount() > 0) }); + const issueUrl = generateNewIssueUrl(product.reportIssueUrl, pkg.name, pkg.version, product.commit, product.date); + arrays.coalesce([ this.envService.product.documentationUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miDocumentation', comment: ['&& denotes a mnemonic'] }, "&&Documentation")), click: () => this.openUrl(this.envService.product.documentationUrl, 'openDocumentationUrl') }) : null, this.envService.product.releaseNotesUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReleaseNotes', comment: ['&& denotes a mnemonic'] }, "&&Release Notes")), click: () => this.openUrl(this.envService.product.releaseNotesUrl, 'openReleaseNotesUrl') }) : null, (this.envService.product.documentationUrl || this.envService.product.releaseNotesUrl) ? __separator__() : null, this.envService.product.twitterUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join us on Twitter")), click: () => this.openUrl(this.envService.product.twitterUrl, 'openTwitterUrl') }) : null, this.envService.product.requestFeatureUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miUserVoice', comment: ['&& denotes a mnemonic'] }, "&&Request Features")), click: () => this.openUrl(this.envService.product.requestFeatureUrl, 'openUserVoiceUrl') }) : null, - this.envService.product.reportIssueUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReportIssues', comment: ['&& denotes a mnemonic'] }, "Report &&Issues")), click: () => this.openUrl(generateNewIssueUrl(app.getVersion(), this.envService.product), 'openReportIssues') }) : null, + this.envService.product.reportIssueUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miReportIssues', comment: ['&& denotes a mnemonic'] }, "Report &&Issues")), click: () => this.openUrl(issueUrl, 'openReportIssues') }) : null, (this.envService.product.twitterUrl || this.envService.product.requestFeatureUrl || this.envService.product.reportIssueUrl) ? __separator__() : null, this.envService.product.licenseUrl ? new MenuItem({ label: mnemonicLabel(nls.localize({ key: 'miLicense', comment: ['&& denotes a mnemonic'] }, "&&View License")), click: () => { diff --git a/src/vs/code/electron-main/utils.ts b/src/vs/code/electron-main/utils.ts deleted file mode 100644 index 6fe58a6ccb7..00000000000 --- a/src/vs/code/electron-main/utils.ts +++ /dev/null @@ -1,23 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import os = require('os'); -import { IProductConfiguration } from 'vs/platform/product'; - -export function generateNewIssueUrl(version: string, product: IProductConfiguration): string { - let quality = process.env['VSCODE_DEV'] ? 'dev' : product.quality; - let vscodeVersion = `${version}-${quality}`; - if (product.commit || product.date) { - vscodeVersion += ` (${product.commit || 'Unknown'}, ${product.date || 'Unknown'})`; - } - let osVersion = `${os.type()} ${os.arch()}`; - let queryStringPrefix = product.reportIssueUrl.indexOf('?') === -1 ? '?' : '&'; - return `${product.reportIssueUrl}${queryStringPrefix}body=` + - `- VSCode Version: ${vscodeVersion}%0A` + - `- OS Version: ${osVersion}%0A%0A` + - 'Steps to Reproduce:%0A%0A1.%0A2.'; -} \ No newline at end of file diff --git a/src/vs/code/test/utils.test.ts b/src/vs/code/test/utils.test.ts deleted file mode 100644 index a01431056e1..00000000000 --- a/src/vs/code/test/utils.test.ts +++ /dev/null @@ -1,97 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -'use strict'; - -import os = require('os'); -import * as assert from 'assert'; -import * as Utils from 'vs/code/electron-main/utils'; -import { IProductConfiguration } from 'vs/platform/product'; - -class MockProductConfiguration implements IProductConfiguration { - public nameShort: string; - public nameLong: string; - public applicationName: string; - public win32AppUserModelId: string; - public win32MutexName: string; - public darwinBundleIdentifier: string; - public dataFolderName: string; - public downloadUrl: string; - public updateUrl: string; - public quality: string; - public commit: string; - public date: string; - public extensionsGallery: { - serviceUrl: string; - itemUrl: string; - }; - public extensionTips: { [id: string]: string; }; - public crashReporter: Electron.CrashReporterStartOptions; - public welcomePage: string; - public enableTelemetry: boolean; - public aiConfig: { - key: string; - asimovKey: string; - }; - public sendASmile: { - reportIssueUrl: string, - requestFeatureUrl: string - }; - public documentationUrl: string; - public releaseNotesUrl: string; - public twitterUrl: string; - public requestFeatureUrl: string; - public reportIssueUrl: string; - public licenseUrl: string; - public privacyStatementUrl: string; -} - -suite('utils', () => { - test('generateNewIssueUrl', () => { - if (process.env['VSCODE_DEV']) { - delete process.env['VSCODE_DEV']; - } - - let product = new MockProductConfiguration(); - product.commit = 'COMMIT'; - product.quality = 'QUALITY'; - product.date = 'DATE'; - product.reportIssueUrl = 'URL'; - let version = 'VERSION'; - let osVersion = `${os.type()} ${os.arch()}`; - assert.equal(Utils.generateNewIssueUrl(version, product), - `URL?body=- VSCode Version: VERSION-QUALITY (COMMIT, DATE)%0A- OS Version: ${osVersion}%0A%0ASteps to Reproduce:%0A%0A1.%0A2.`, - 'generateNewIssueUrl should generate correct URL when all information is provided'); - - product.commit = null; - product.date = 'DATE'; - assert.equal(Utils.generateNewIssueUrl(version, product), - `URL?body=- VSCode Version: VERSION-QUALITY (Unknown, DATE)%0A- OS Version: ${osVersion}%0A%0ASteps to Reproduce:%0A%0A1.%0A2.`, - 'generateNewIssueUrl should include date if commit is missing'); - - product.commit = 'COMMIT'; - product.date = null; - assert.equal(Utils.generateNewIssueUrl(version, product), - `URL?body=- VSCode Version: VERSION-QUALITY (COMMIT, Unknown)%0A- OS Version: ${osVersion}%0A%0ASteps to Reproduce:%0A%0A1.%0A2.`, - 'generateNewIssueUrl should include commit if date is missing'); - - product.commit = null; - product.date = null; - assert.equal(Utils.generateNewIssueUrl(version, product), - `URL?body=- VSCode Version: VERSION-QUALITY%0A- OS Version: ${osVersion}%0A%0ASteps to Reproduce:%0A%0A1.%0A2.`, - 'generateNewIssueUrl should exclude commit and date is they\'re both missing'); - - product.reportIssueUrl = 'URL?foo=bar'; - assert.equal(Utils.generateNewIssueUrl(version, product), - `URL?foo=bar&body=- VSCode Version: VERSION-QUALITY%0A- OS Version: ${osVersion}%0A%0ASteps to Reproduce:%0A%0A1.%0A2.`, - 'generateNewIssueUrl should use an & to join the query string parameter if a ? is in reportIssueUrl'); - - process.env['VSCODE_DEV'] = 1; - product.quality = null; - assert.equal(Utils.generateNewIssueUrl(version, product), - `URL?foo=bar&body=- VSCode Version: VERSION-dev%0A- OS Version: ${osVersion}%0A%0ASteps to Reproduce:%0A%0A1.%0A2.`, - 'generateNewIssueUrl should use a quality of \'dev\' if the VSCODE_DEV environment variable is set'); - }); -});