Load connection from publish profile (#11263)

* initial changes for reading connection from profile

* connection string can now be read from publish.xml

* fix build errors and update test

* move publish profile tests to their own file

* cleanup

* update message

* fix string

* remove apiWrapper
This commit is contained in:
Kim Santiago
2020-07-15 17:03:25 -07:00
committed by GitHub
parent aae013d498
commit 0a1c2583cc
13 changed files with 247 additions and 69 deletions

View File

@@ -0,0 +1,96 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as xmldom from 'xmldom';
import * as constants from '../../common/constants';
import * as utils from '../../common/utils';
import { promises as fs } from 'fs';
import { Uri } from 'vscode';
import { SqlConnectionDataSource } from '../dataSources/sqlConnectionStringSource';
// only reading db name, connection string, and SQLCMD vars from profile for now
export interface PublishProfile {
databaseName: string;
connectionId: string;
connectionString: string;
sqlCmdVariables: Record<string, string>;
}
/**
* parses the specified file to load publish settings
*/
export async function load(profileUri: Uri): Promise<PublishProfile> {
const profileText = await fs.readFile(profileUri.fsPath);
const profileXmlDoc = new xmldom.DOMParser().parseFromString(profileText.toString());
// read target database name
let targetDbName: string = '';
let targetDatabaseNameCount = profileXmlDoc.documentElement.getElementsByTagName(constants.targetDatabaseName).length;
if (targetDatabaseNameCount > 0) {
// if there is more than one TargetDatabaseName nodes, SSDT uses the name in the last one so we'll do the same here
targetDbName = profileXmlDoc.documentElement.getElementsByTagName(constants.targetDatabaseName)[targetDatabaseNameCount - 1].textContent;
}
const connectionInfo = await readConnectionString(profileXmlDoc);
// get all SQLCMD variables to include from the profile
const sqlCmdVariables = readSqlCmdVariables(profileXmlDoc);
return {
databaseName: targetDbName,
connectionId: connectionInfo.connectionId,
connectionString: connectionInfo.connectionString,
sqlCmdVariables: sqlCmdVariables
};
}
/**
* Read SQLCMD variables from xmlDoc and return them
* @param xmlDoc xml doc to read SQLCMD variables from. Format must be the same that sqlproj and publish profiles use
*/
export function readSqlCmdVariables(xmlDoc: any): Record<string, string> {
let sqlCmdVariables: Record<string, string> = {};
for (let i = 0; i < xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable).length; i++) {
const sqlCmdVar = xmlDoc.documentElement.getElementsByTagName(constants.SqlCmdVariable)[i];
const varName = sqlCmdVar.getAttribute(constants.Include);
const varValue = sqlCmdVar.getElementsByTagName(constants.DefaultValue)[0].childNodes[0].nodeValue;
sqlCmdVariables[varName] = varValue;
}
return sqlCmdVariables;
}
async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string, connectionString: string }> {
let targetConnectionString: string = '';
let connId: string = '';
if (xmlDoc.documentElement.getElementsByTagName('TargetConnectionString').length > 0) {
targetConnectionString = xmlDoc.documentElement.getElementsByTagName('TargetConnectionString')[0].textContent;
const dataSource = new SqlConnectionDataSource('temp', targetConnectionString);
const connectionProfile = dataSource.getConnectionProfile();
try {
if (dataSource.integratedSecurity) {
connId = (await azdata.connection.connect(connectionProfile, false, false)).connectionId;
}
else {
connId = (await azdata.connection.openConnectionDialog(undefined, connectionProfile)).connectionId;
}
} catch (err) {
throw new Error(constants.unableToCreatePublishConnection(utils.getErrorMessage(err)));
}
}
// mask password in connection string
targetConnectionString = await azdata.connection.getConnectionString(connId, false);
return {
connectionId: connId,
connectionString: targetConnectionString
};
}