Support advanced options in command line arguments (#23104)

This commit is contained in:
Cheena Malhotra
2023-05-12 12:24:34 -07:00
committed by GitHub
parent 39087ba5ce
commit 9847d9dbc1
4 changed files with 144 additions and 20 deletions

View File

@@ -31,17 +31,61 @@ import { IEnvironmentService, INativeEnvironmentService } from 'vs/platform/envi
import { NativeParsedArgs } from 'vs/platform/environment/common/argv';
export interface SqlArgs {
/**
* Used to determine file paths to be opened with SQL Editor.
* If provided, we connect the given profile to to it.
* More than one files can be passed to connect to provided profile.
*/
_?: string[];
/**
* Provide authenticationType to be used.
* accepted values: AzureMFA, SqlLogin, Integrated, etc.
*/
authenticationType?: string
/**
* Name of database
*/
database?: string;
/**
* Name of server
*/
server?: string;
/**
* User name/email address
*/
user?: string;
/**
* Operation to perform:
* accepted values: connect, openConnectionDialog
*/
command?: string;
/**
* Name of connection provider,
* accepted values: mssql (by default), pgsql, etc.
*/
provider?: string;
aad?: boolean; // deprecated - used by SSMS - authenticationType should be used instead
integrated?: boolean; // deprecated - used by SSMS - authenticationType should be used instead.
/**
* Deprecated - used by SSMS - authenticationType should be used instead
*/
aad?: boolean;
/**
* Deprecated - used by SSMS - authenticationType should be used instead.
*/
integrated?: boolean;
/**
* Whether or not to show dashboard
* accepted values: true, false (by default).
*/
showDashboard?: boolean;
/**
* Supports providing applicationName that will be used for connection profile app name.
*/
applicationName?: string;
/**
* Supports providing advanced connection properties that providers support.
* Value must be a json object containing key-value pairs in format: '{"key1":"value1","key2":"value2",...}'
*/
connectionProperties?: string;
}
//#region decorators
@@ -324,9 +368,33 @@ export class CommandLineWorkbenchContribution implements IWorkbenchContribution,
profile.setOptionValue('applicationName', applicationName);
profile.setOptionValue('databaseDisplayName', profile.databaseName);
profile.setOptionValue('groupId', profile.groupId);
// Set all advanced options
let advancedOptions = this.getAdvancedOptions(args.connectionProperties, profile.getOptionKeyIdNames());
advancedOptions.forEach((v, k) => {
profile.setOptionValue(k, v);
});
return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile;
}
private getAdvancedOptions(options: string, idNames: string[]): Map<string, string> {
const ignoredProperties = idNames.concat(['password', 'azureAccountToken']);
let advancedOptionsMap = new Map<string, string>();
if (options) {
try {
// Decode options if they contain any encoded URL characters
options = decodeURI(options);
JSON.parse(options, (k, v) => {
if (!(k in ignoredProperties)) {
advancedOptionsMap.set(k, v);
}
});
} catch (e) {
throw new Error(localize('commandline.propertiesFormatError', 'Advanced connection properties could not be parsed as JSON, error occurred: {0} Received properties value: {1}', e, options));
}
}
return advancedOptionsMap;
}
private tryMatchSavedProfile(profile: ConnectionProfile) {
let match: ConnectionProfile = undefined;
// If we can find a saved mssql provider connection that matches the args, use it

View File

@@ -96,6 +96,7 @@ class TestParsedArgs implements NativeParsedArgs, SqlArgs {
waitMarkerFilePath?: string;
authenticationType?: string;
applicationName?: string;
connectionProperties?: string;
}
suite('commandLineService tests', () => {
@@ -219,6 +220,42 @@ suite('commandLineService tests', () => {
connectionManagementService.verifyAll();
});
test('processCommandLine loads advanced options in args', async () => {
const connectionManagementService: TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Strict);
const args: TestParsedArgs = new TestParsedArgs();
args.server = 'myserver';
args.database = 'mydatabase';
args.user = 'myuser';
args.authenticationType = Constants.AuthenticationType.SqlLogin;
args.applicationName = 'myapplication';
// Pass advanced connection properties
args.connectionProperties = `{"trustServerCertificate":"true"}`;
connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never());
connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce());
connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []);
let originalProfile: IConnectionProfile = undefined;
connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is<ConnectionProfile>(
p => p.serverName === 'myserver'
&& p.authenticationType === Constants.AuthenticationType.SqlLogin
&& p.options['applicationName'] === 'myapplication-azdata'), 'connection', true))
.returns((conn) => {
originalProfile = conn;
return Promise.resolve('unused');
})
.verifiable(TypeMoq.Times.once());
connectionManagementService.setup(c => c.getConnectionProfileById(TypeMoq.It.isAnyString())).returns(() => originalProfile);
const configurationService = getConfigurationServiceMock(true);
const logService = new NullLogService();
let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, undefined, logService);
await contribution.processCommandLine(args);
assert.equal(originalProfile.options['applicationName'], 'myapplication-azdata', 'Application Name not received as expected.');
assert.equal(originalProfile.options['trustServerCertificate'], 'true', 'Advanced option not received as expected.');
connectionManagementService.verifyAll();
});
test('processCommandLine invokes a command without a profile parameter when no server is passed', async () => {
const connectionManagementService: TypeMoq.Mock<IConnectionManagementService>
= TypeMoq.Mock.ofType<IConnectionManagementService>(TestConnectionManagementService, TypeMoq.MockBehavior.Loose);
@@ -568,7 +605,5 @@ suite('commandLineService tests', () => {
notificationService.verifyAll();
connectionManagementService.verifyAll();
});
});
});