Skip to content

Commit 84bd335

Browse files
author
Kartik Raj
committed
Improve information collected by the Python: Report Issue command
1 parent 20ff560 commit 84bd335

6 files changed

Lines changed: 88 additions & 16 deletions

File tree

news/1 Enhancements/19067.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve information collected by the `Python: Report Issue` command.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -922,6 +922,7 @@
922922
"type": "string"
923923
},
924924
"python.tensorBoard.logDirectory": {
925+
"default":"",
925926
"description": "Set this setting to your preferred TensorBoard log directory to skip log directory prompt when starting TensorBoard.",
926927
"scope": "application",
927928
"type": "string"

resources/report_issue_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ XXX
2626
<p>
2727

2828
```
29-
{3}
29+
{3}{4}
3030
```
3131

3232
</p>

resources/report_issue_user_settings.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"pythonPath": "placeholder",
44
"onDidChange": false,
55
"defaultInterpreterPath": "placeholder",
6-
"defaultLS": true,
6+
"defaultLS": false,
77
"envFile": "placeholder",
88
"venvPath": "placeholder",
99
"venvFolders": "placeholder",
@@ -25,7 +25,7 @@
2525
"linting": {
2626
"enabled": true,
2727
"cwd": "placeholder",
28-
"Flake8Args": "placeholder",
28+
"flake8Args": "placeholder",
2929
"flake8CategorySeverity": false,
3030
"flake8Enabled": true,
3131
"flake8Path": "placeholder",
@@ -85,9 +85,6 @@
8585
"testing": {
8686
"cwd": "placeholder",
8787
"debugPort": true,
88-
"nosetestArgs": "placeholder",
89-
"nosetestsEnabled": true,
90-
"nosetestPath": "placeholder",
9188
"promptToConfigure": true,
9289
"pytestArgs": "placeholder",
9390
"pytestEnabled": true,

src/client/common/application/commands/reportIssueCommand.ts

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,18 @@ import * as fs from 'fs-extra';
77
import * as os from 'os';
88
import * as path from 'path';
99
import { inject, injectable } from 'inversify';
10+
import { isEqual } from 'lodash';
1011
import { IExtensionSingleActivationService } from '../../../activation/types';
11-
import { ICommandManager, IWorkspaceService } from '../types';
12+
import { IApplicationEnvironment, ICommandManager, IWorkspaceService } from '../types';
1213
import { EXTENSION_ROOT_DIR } from '../../../constants';
1314
import { IInterpreterService } from '../../../interpreter/contracts';
1415
import { Commands } from '../../constants';
1516
import { IConfigurationService, IPythonSettings } from '../../types';
1617
import { sendTelemetryEvent } from '../../../telemetry';
1718
import { EventName } from '../../../telemetry/constants';
1819
import { EnvironmentType } from '../../../pythonEnvironments/info';
20+
import { PythonSettings } from '../../configSettings';
21+
import { SystemVariables } from '../../variables/systemVariables';
1922

2023
/**
2124
* Allows the user to report an issue related to the Python extension using our template.
@@ -24,12 +27,18 @@ import { EnvironmentType } from '../../../pythonEnvironments/info';
2427
export class ReportIssueCommandHandler implements IExtensionSingleActivationService {
2528
public readonly supportedWorkspaceTypes = { untrustedWorkspace: false, virtualWorkspace: true };
2629

30+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
31+
private readonly packageJSONSettings: any;
32+
2733
constructor(
2834
@inject(ICommandManager) private readonly commandManager: ICommandManager,
2935
@inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService,
3036
@inject(IInterpreterService) private readonly interpreterService: IInterpreterService,
3137
@inject(IConfigurationService) protected readonly configurationService: IConfigurationService,
32-
) {}
38+
@inject(IApplicationEnvironment) appEnvironment: IApplicationEnvironment,
39+
) {
40+
this.packageJSONSettings = appEnvironment.packageJson?.contributes?.configuration?.properties;
41+
}
3342

3443
public async activate(): Promise<void> {
3544
this.commandManager.registerCommand(Commands.ReportIssue, this.openReportIssue, this);
@@ -48,20 +57,31 @@ export class ReportIssueCommandHandler implements IExtensionSingleActivationServ
4857
const argSetting = argSettings[property];
4958
if (argSetting) {
5059
if (typeof argSetting === 'object') {
51-
userSettings = userSettings.concat(os.EOL, property, os.EOL);
60+
let propertyHeaderAdded = false;
5261
const argSettingsDict = (settings[property] as unknown) as Record<string, unknown>;
5362
if (typeof argSettingsDict === 'object') {
5463
Object.keys(argSetting).forEach((item) => {
5564
const prop = argSetting[item];
5665
if (prop) {
57-
const value = prop === true ? JSON.stringify(argSettingsDict[item]) : '"<placeholder>"';
58-
userSettings = userSettings.concat('• ', item, ': ', value, os.EOL);
66+
const defaultValue = this.getDefaultValue(`${property}.${item}`);
67+
if (defaultValue === undefined || !isEqual(defaultValue, argSettingsDict[item])) {
68+
if (!propertyHeaderAdded) {
69+
userSettings = userSettings.concat(os.EOL, property, os.EOL);
70+
propertyHeaderAdded = true;
71+
}
72+
const value =
73+
prop === true ? JSON.stringify(argSettingsDict[item]) : '"<placeholder>"';
74+
userSettings = userSettings.concat('• ', item, ': ', value, os.EOL);
75+
}
5976
}
6077
});
6178
}
6279
} else {
63-
const value = argSetting === true ? JSON.stringify(settings[property]) : '"<placeholder>"';
64-
userSettings = userSettings.concat(os.EOL, property, ': ', value, os.EOL);
80+
const defaultValue = this.getDefaultValue(property);
81+
if (defaultValue === undefined || !isEqual(defaultValue, settings[property])) {
82+
const value = argSetting === true ? JSON.stringify(settings[property]) : '"<placeholder>"';
83+
userSettings = userSettings.concat(os.EOL, property, ': ', value, os.EOL);
84+
}
6585
}
6686
}
6787
});
@@ -72,10 +92,30 @@ export class ReportIssueCommandHandler implements IExtensionSingleActivationServ
7292
this.workspaceService.getConfiguration('python').get<string>('languageServer') || 'Not Found';
7393
const virtualEnvKind = interpreter?.envType || EnvironmentType.Unknown;
7494

95+
const hasMultipleFolders = (this.workspaceService.workspaceFolders?.length ?? 0) > 1;
96+
const hasMultipleFoldersText =
97+
hasMultipleFolders && userSettings !== ''
98+
? `Multiroot scenario, following user settings may not apply:${os.EOL}`
99+
: '';
75100
await this.commandManager.executeCommand('workbench.action.openIssueReporter', {
76101
extensionId: 'ms-python.python',
77-
issueBody: template.format(pythonVersion, virtualEnvKind, languageServer, userSettings),
102+
issueBody: template.format(
103+
pythonVersion,
104+
virtualEnvKind,
105+
languageServer,
106+
hasMultipleFoldersText,
107+
userSettings,
108+
),
78109
});
79110
sendTelemetryEvent(EventName.USE_REPORT_ISSUE_COMMAND, undefined, {});
80111
}
112+
113+
private getDefaultValue(settingKey: string) {
114+
if (!this.packageJSONSettings) {
115+
return undefined;
116+
}
117+
const resource = PythonSettings.getSettingsUriAndTarget(undefined, this.workspaceService).uri;
118+
const systemVariables = new SystemVariables(resource, undefined, this.workspaceService);
119+
return systemVariables.resolveAny(this.packageJSONSettings[`python.${settingKey}`]?.default);
120+
}
81121
}

src/test/common/application/commands/reportIssueCommand.unit.test.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@ import * as Telemetry from '../../../../client/telemetry';
1212
import { LanguageServerType } from '../../../../client/activation/types';
1313
import { CommandManager } from '../../../../client/common/application/commandManager';
1414
import { ReportIssueCommandHandler } from '../../../../client/common/application/commands/reportIssueCommand';
15-
import { ICommandManager, IWorkspaceService } from '../../../../client/common/application/types';
15+
import {
16+
IApplicationEnvironment,
17+
ICommandManager,
18+
IWorkspaceService,
19+
} from '../../../../client/common/application/types';
1620
import { WorkspaceService } from '../../../../client/common/application/workspace';
1721
import { IInterpreterService } from '../../../../client/interpreter/contracts';
1822
import { MockWorkspaceConfiguration } from '../../../mocks/mockWorkspaceConfig';
@@ -31,12 +35,14 @@ suite('Report Issue Command', () => {
3135
let workspaceService: IWorkspaceService;
3236
let interpreterService: IInterpreterService;
3337
let configurationService: IConfigurationService;
38+
let appEnvironment: IApplicationEnvironment;
3439

3540
setup(async () => {
3641
workspaceService = mock(WorkspaceService);
3742
cmdManager = mock(CommandManager);
3843
interpreterService = mock(InterpreterService);
3944
configurationService = mock(ConfigurationService);
45+
appEnvironment = mock<IApplicationEnvironment>();
4046

4147
when(cmdManager.executeCommand('workbench.action.openIssueReporter', anything())).thenResolve();
4248
when(workspaceService.getConfiguration('python')).thenReturn(
@@ -67,6 +73,7 @@ suite('Report Issue Command', () => {
6773
instance(workspaceService),
6874
instance(interpreterService),
6975
instance(configurationService),
76+
instance(appEnvironment),
7077
);
7178
await reportIssueCommandHandler.activate();
7279
});
@@ -75,7 +82,33 @@ suite('Report Issue Command', () => {
7582
sinon.restore();
7683
});
7784

78-
test('Test if issue body is filled', async () => {
85+
test('Test if issue body is filled including all the settings', async () => {
86+
await reportIssueCommandHandler.openReportIssue();
87+
88+
const templatePath = path.join(
89+
EXTENSION_ROOT_DIR_FOR_TESTS,
90+
'src',
91+
'test',
92+
'common',
93+
'application',
94+
'commands',
95+
'issueTemplateVenv1.md',
96+
);
97+
const expectedIssueBody = fs.readFileSync(templatePath, 'utf8');
98+
99+
const args: [string, { extensionId: string; issueBody: string }] = capture<
100+
AllCommands,
101+
{ extensionId: string; issueBody: string }
102+
>(cmdManager.executeCommand).last();
103+
104+
verify(cmdManager.registerCommand(Commands.ReportIssue, anything(), anything())).once();
105+
verify(cmdManager.executeCommand('workbench.action.openIssueReporter', anything())).once();
106+
expect(args[0]).to.be.equal('workbench.action.openIssueReporter');
107+
const actual = args[1].issueBody;
108+
expect(actual).to.be.equal(expectedIssueBody);
109+
});
110+
111+
test('Test if issue body is filled, if every setting is explicitly set', async () => {
79112
await reportIssueCommandHandler.openReportIssue();
80113

81114
const templatePath = path.join(

0 commit comments

Comments
 (0)