Schema Compare open scmp file (#6118)

* can compare scmp with databases

* show error if can't connect to db

* excludes now work

* fixes after rebase and other small fixes

* Addressing comments

* fixes after rebasing

* fix excludes not always being remembered correctly

* fix switched check

* addressing comments
This commit is contained in:
Kim Santiago
2019-06-25 17:30:07 -07:00
committed by GitHub
parent f01c318c30
commit 144a7f941b
14 changed files with 345 additions and 92 deletions

View File

@@ -57,22 +57,24 @@ class SchemaCompareTester {
const now = new Date();
const operationId = 'testOperationId_' + now.getTime().toString();
let source: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Dacpac,
packageFilePath: dacpac1,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
};
let target: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Dacpac,
packageFilePath: dacpac2,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
};
let source: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Dacpac,
packageFilePath: dacpac1,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
connectionDetails: undefined
};
let target: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Dacpac,
packageFilePath: dacpac2,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: '',
connectionDetails: undefined
};
let schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null);
this.assertSchemaCompareResult(schemaCompareResult, operationId);
@@ -109,22 +111,24 @@ class SchemaCompareTester {
assert(schemaCompareService, 'Schema Compare Service Provider is not available');
let source: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Database,
packageFilePath: '',
serverDisplayName: '',
serverName: server.serverName,
databaseName: sourceDB,
ownerUri: ownerUri,
};
let target: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Database,
packageFilePath: '',
serverDisplayName: '',
serverName: server.serverName,
databaseName: targetDB,
ownerUri: ownerUri,
};
let source: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Database,
packageFilePath: '',
serverDisplayName: '',
serverName: server.serverName,
databaseName: sourceDB,
ownerUri: ownerUri,
connectionDetails: undefined
};
let target: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Database,
packageFilePath: '',
serverDisplayName: '',
serverName: server.serverName,
databaseName: targetDB,
ownerUri: ownerUri,
connectionDetails: undefined
};
let schemaCompareResult = await schemaCompareService.schemaCompare(operationId, source, target, azdata.TaskExecutionMode.execute, null);
this.assertSchemaCompareResult(schemaCompareResult, operationId);
@@ -164,22 +168,24 @@ class SchemaCompareTester {
assert(result.success === true, 'Deploy database 2 (target) should succeed');
let source: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Dacpac,
packageFilePath: dacpac1,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: ownerUri,
};
let target: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Database,
packageFilePath: '',
serverDisplayName: '',
serverName: server.serverName,
databaseName: targetDB,
ownerUri: ownerUri,
};
let source: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Dacpac,
packageFilePath: dacpac1,
serverDisplayName: '',
serverName: '',
databaseName: '',
ownerUri: ownerUri,
connectionDetails: undefined
};
let target: azdata.SchemaCompareEndpointInfo = {
endpointType: azdata.SchemaCompareEndpointType.Database,
packageFilePath: '',
serverDisplayName: '',
serverName: server.serverName,
databaseName: targetDB,
ownerUri: ownerUri,
connectionDetails: undefined
};
assert(schemaCompareService, 'Schema Compare Service Provider is not available');

View File

@@ -467,6 +467,10 @@ export interface SchemaCompareNodeParams {
taskExecutionMode: TaskExecutionMode;
}
export interface SchemaCompareOpenScmpParams {
filePath: string;
}
export interface SchemaCompareSaveScmpParams {
sourceEndpointInfo: azdata.SchemaCompareEndpointInfo;
targetEndpointInfo: azdata.SchemaCompareEndpointInfo;
@@ -501,6 +505,10 @@ export namespace SchemaCompareIncludeExcludeNodeRequest {
export const type = new RequestType<SchemaCompareNodeParams, azdata.ResultStatus, void, void>('schemaCompare/includeExcludeNode');
}
export namespace SchemaCompareOpenScmpRequest {
export const type = new RequestType<SchemaCompareOpenScmpParams, azdata.ResultStatus, void, void>('schemaCompare/openScmp');
}
export namespace SchemaCompareSaveScmpRequest {
export const type = new RequestType<SchemaCompareSaveScmpParams, azdata.ResultStatus, void, void>('schemaCompare/saveScmp');
}

View File

@@ -146,8 +146,10 @@ export class SchemaCompareServicesFeature extends SqlOpsFeature<undefined> {
private static readonly messageTypes: RPCMessageType[] = [
contracts.SchemaCompareRequest.type,
contracts.SchemaCompareGenerateScriptRequest.type,
contracts.SchemaComparePublishChangesRequest.type,
contracts.SchemaCompareGetDefaultOptionsRequest.type,
contracts.SchemaCompareIncludeExcludeNodeRequest.type,
contracts.SchemaCompareOpenScmpRequest.type,
contracts.SchemaCompareSaveScmpRequest.type
];
@@ -233,6 +235,19 @@ export class SchemaCompareServicesFeature extends SqlOpsFeature<undefined> {
);
};
let schemaCompareOpenScmp = (filePath: string): Thenable<azdata.SchemaCompareOpenScmpResult> => {
let params: contracts.SchemaCompareOpenScmpParams = { filePath: filePath };
return client.sendRequest(contracts.SchemaCompareOpenScmpRequest.type, params).then(
r => {
return r;
},
e => {
client.logFailedRequest(contracts.SchemaCompareOpenScmpRequest.type, e);
return Promise.resolve(undefined);
}
);
};
let schemaCompareSaveScmp = (sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: azdata.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: azdata.SchemaCompareObjectId[], excludedTargetObjects: azdata.SchemaCompareObjectId[]): Thenable<azdata.ResultStatus> => {
let params: contracts.SchemaCompareSaveScmpParams = { sourceEndpointInfo: sourceEndpointInfo, targetEndpointInfo: targetEndpointInfo, taskExecutionMode: taskExecutionMode, deploymentOptions: deploymentOptions, scmpFilePath: scmpFilePath, excludedSourceObjects: excludedSourceObjects, excludedTargetObjects: excludedTargetObjects };
return client.sendRequest(contracts.SchemaCompareSaveScmpRequest.type, params).then(
@@ -266,6 +281,7 @@ export class SchemaCompareServicesFeature extends SqlOpsFeature<undefined> {
schemaComparePublishChanges,
schemaCompareGetDefaultOptions,
schemaCompareIncludeExcludeNode,
schemaCompareOpenScmp,
schemaCompareSaveScmp,
schemaCompareCancel
});

View File

@@ -102,7 +102,8 @@ export class SchemaCompareDialog {
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: this.sourceTextBox.value
packageFilePath: this.sourceTextBox.value,
connectionDetails: undefined
};
} else {
let ownerUri = await azdata.connection.getUriForConnection((this.sourceServerDropdown.value as ConnectionDropdownValue).connection.connectionId);
@@ -113,7 +114,8 @@ export class SchemaCompareDialog {
serverName: (this.sourceServerDropdown.value as ConnectionDropdownValue).name,
databaseName: (<azdata.CategoryValue>this.sourceDatabaseDropdown.value).name,
ownerUri: ownerUri,
packageFilePath: ''
packageFilePath: '',
connectionDetails: undefined
};
}
@@ -124,7 +126,8 @@ export class SchemaCompareDialog {
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: this.targetTextBox.value
packageFilePath: this.targetTextBox.value,
connectionDetails: undefined
};
} else {
let ownerUri = await azdata.connection.getUriForConnection((this.targetServerDropdown.value as ConnectionDropdownValue).connection.connectionId);
@@ -135,7 +138,8 @@ export class SchemaCompareDialog {
serverName: (this.targetServerDropdown.value as ConnectionDropdownValue).name,
databaseName: (<azdata.CategoryValue>this.targetDatabaseDropdown.value).name,
ownerUri: ownerUri,
packageFilePath: ''
packageFilePath: '',
connectionDetails: undefined
};
}
@@ -541,7 +545,7 @@ export class SchemaCompareDialog {
console.error('finalname: ' + finalName + ' endpointname: ' + endpointInfo.serverDisplayName);
}
// use previously selected server or current connection if there is one
if (endpointInfo && endpointInfo.serverName !== null
if (endpointInfo && !isNullOrUndefined(endpointInfo.serverName) && !isNullOrUndefined(endpointInfo.serverDisplayName)
&& c.options.server.toLowerCase() === endpointInfo.serverName.toLowerCase()
&& finalName.toLowerCase() === endpointInfo.serverDisplayName.toLowerCase()) {
idx = count;

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.2734 11.9766L14 10.7109V16H13V10.7109L11.7266 11.9766L11.0234 11.2734L13.5 8.79688L15.9766 11.2734L15.2734 11.9766ZM2 15H12V16H1V0H9.71094L14 4.28906V8H13V5H9V1H2V15ZM10 4H12.2891L10 1.71094V4Z" fill="#4894FE"/>
</svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -0,0 +1,3 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.2734 11.9766L14 10.7109V16H13V10.7109L11.7266 11.9766L11.0234 11.2734L13.5 8.79688L15.9766 11.2734L15.2734 11.9766ZM2 15H12V16H1V0H9.71094L14 4.28906V8H13V5H9V1H2V15ZM10 4H12.2891L10 1.71094V4Z" fill="#015CDA"/>
</svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -10,7 +10,7 @@ import * as os from 'os';
import * as path from 'path';
import { SchemaCompareOptionsDialog } from './dialogs/schemaCompareOptionsDialog';
import { Telemetry } from './telemetry';
import { getTelemetryErrorType, getEndpointName } from './utils';
import { getTelemetryErrorType, getEndpointName, verifyConnectionAndGetOwnerUri } from './utils';
import { SchemaCompareDialog } from './dialogs/schemaCompareDialog';
import { isNullOrUndefined } from 'util';
const localize = nls.loadMessageBundle();
@@ -26,6 +26,11 @@ const applyNoChangesMessage = localize('schemaCompare.applyNoChanges', 'No chang
// TODO : In future icon should be decided based on language id (scmp) and not resource name
const schemaCompareResourceName = 'Schema Compare';
enum ResetButtonState {
noSourceTarget,
beforeCompareStart,
comparing,
}
export class SchemaCompareResult {
private differencesTable: azdata.TableComponent;
@@ -44,6 +49,7 @@ export class SchemaCompareResult {
private optionsButton: azdata.ButtonComponent;
private generateScriptButton: azdata.ButtonComponent;
private applyButton: azdata.ButtonComponent;
private openScmpButton: azdata.ButtonComponent;
private selectSourceButton: azdata.ButtonComponent;
private selectTargetButton: azdata.ButtonComponent;
private saveScmpButton: azdata.ButtonComponent;
@@ -60,6 +66,8 @@ export class SchemaCompareResult {
private sourceTargetSwitched = false;
private sourceName: string;
private targetName: string;
private scmpSourceExcludes: azdata.SchemaCompareObjectId[];
private scmpTargetExcludes: azdata.SchemaCompareObjectId[];
public sourceEndpointInfo: azdata.SchemaCompareEndpointInfo;
public targetEndpointInfo: azdata.SchemaCompareEndpointInfo;
@@ -84,7 +92,8 @@ export class SchemaCompareResult {
serverName: profile.serverName,
databaseName: profile.databaseName,
ownerUri: ownerUri,
packageFilePath: ''
packageFilePath: '',
connectionDetails: undefined
};
}
@@ -121,9 +130,10 @@ export class SchemaCompareResult {
this.createGenerateScriptButton(view);
this.createApplyButton(view);
this.createOptionsButton(view);
this.createSourceAndTargetButtons(view);
this.createOpenScmpButton(view);
this.createSaveScmpButton(view);
this.resetButtons(false); // disable buttons because source and target aren't both selected yet
this.createSourceAndTargetButtons(view);
this.resetButtons(ResetButtonState.noSourceTarget);
let toolBar = view.modelBuilder.toolbarContainer();
toolBar.addToolbarItems([{
@@ -140,6 +150,8 @@ export class SchemaCompareResult {
}, {
component: this.switchButton,
toolbarSeparatorAfter: true
}, {
component: this.openScmpButton
}, {
component: this.saveScmpButton
}]);
@@ -158,7 +170,8 @@ export class SchemaCompareResult {
value: localize('schemaCompare.switchLabel', '➔')
}).component();
this.sourceName = this.sourceEndpointInfo ? `${this.sourceEndpointInfo.serverName}.${this.sourceEndpointInfo.databaseName}` : ' ';
this.sourceName = getEndpointName(this.sourceEndpointInfo);
this.targetName = ' ';
this.sourceNameComponent = view.modelBuilder.table().withProperties({
columns: [
{
@@ -172,9 +185,9 @@ export class SchemaCompareResult {
this.targetNameComponent = view.modelBuilder.table().withProperties({
columns: [
{
value: ' ',
value: this.targetName,
headerCssClass: 'no-borders',
toolTip: ''
toolTip: this.targetName
},
]
}).component();
@@ -239,7 +252,7 @@ export class SchemaCompareResult {
]);
// reset buttons to before comparison state
this.resetButtons(true);
this.resetButtons(ResetButtonState.beforeCompareStart);
}
// only for test
@@ -330,6 +343,7 @@ export class SchemaCompareResult {
this.switchButton.enabled = true;
this.compareButton.enabled = true;
this.optionsButton.enabled = true;
this.openScmpButton.enabled = true;
this.cancelCompareButton.enabled = false;
if (this.comparisonResult.differences.length > 0) {
@@ -393,6 +407,8 @@ export class SchemaCompareResult {
if (key) {
if (!this.sourceTargetSwitched) {
this.originalSourceExcludes.delete(key);
this.removeExcludeEntry(this.scmpSourceExcludes, key);
if (!rowState.checked) {
this.originalSourceExcludes.set(key, diff);
if (this.originalSourceExcludes.size === this.comparisonResult.differences.length) {
@@ -405,6 +421,8 @@ export class SchemaCompareResult {
}
else {
this.originalTargetExcludes.delete(key);
this.removeExcludeEntry(this.scmpTargetExcludes, key);
if (!rowState.checked) {
this.originalTargetExcludes.set(key, diff);
if (this.originalTargetExcludes.size === this.comparisonResult.differences.length) {
@@ -422,12 +440,14 @@ export class SchemaCompareResult {
private shouldDiffBeIncluded(diff: azdata.DiffEntry): boolean {
let key = (diff.sourceValue && diff.sourceValue.length > 0) ? this.createName(diff.sourceValue) : this.createName(diff.targetValue);
if (key) {
if (this.sourceTargetSwitched === true && this.originalTargetExcludes.has(key)) {
this.originalTargetExcludes[key] = diff;
if (this.sourceTargetSwitched === true
&& (this.originalTargetExcludes.has(key) || this.hasExcludeEntry(this.scmpTargetExcludes, key))) {
this.originalTargetExcludes.set(key, diff);
return false;
}
if (this.sourceTargetSwitched === false && this.originalSourceExcludes.has(key)) {
this.originalSourceExcludes[key] = diff;
if (this.sourceTargetSwitched === false
&& (this.originalSourceExcludes.has(key) || this.hasExcludeEntry(this.scmpSourceExcludes, key))) {
this.originalSourceExcludes.set(key, diff);
return false;
}
return true;
@@ -435,6 +455,23 @@ export class SchemaCompareResult {
return true;
}
private hasExcludeEntry(collection: azdata.SchemaCompareObjectId[], entryName: string): boolean {
let found = false;
if (collection) {
const index = collection.findIndex(e => this.createName(e.nameParts) === entryName);
found = index !== -1;
}
return found;
}
private removeExcludeEntry(collection: azdata.SchemaCompareObjectId[], entryName: string) {
if (collection) {
console.error('removing ' + entryName);
const index = collection.findIndex(e => this.createName(e.nameParts) === entryName);
collection.splice(index, 1);
}
}
private getAllDifferences(differences: azdata.DiffEntry[]): string[][] {
let data = [];
if (differences) {
@@ -502,7 +539,7 @@ export class SchemaCompareResult {
if (this.tablelistenersToDispose) {
this.tablelistenersToDispose.forEach(x => x.dispose());
}
this.resetButtons(false);
this.resetButtons(ResetButtonState.comparing);
this.execute();
}
@@ -547,7 +584,7 @@ export class SchemaCompareResult {
this.flexModel.removeItem(this.loader);
this.flexModel.removeItem(this.waitText);
this.flexModel.addItem(this.startText, { CSSStyles: { 'margin': 'auto' } });
this.resetButtons(true);
this.resetButtons(ResetButtonState.beforeCompareStart);
// cancel compare
if (this.operationId) {
@@ -611,16 +648,12 @@ export class SchemaCompareResult {
}).component();
this.optionsButton.onDidClick(async (click) => {
Telemetry.sendTelemetryEvent('SchemaCompareOptionsOpened', {
'operationId': this.comparisonResult.operationId
});
//restore options from last time
if (this.schemaCompareOptionDialog && this.schemaCompareOptionDialog.deploymentOptions) {
this.deploymentOptions = this.schemaCompareOptionDialog.deploymentOptions;
}
Telemetry.sendTelemetryEvent('SchemaCompareOptionsOpened');
// create fresh every time
this.schemaCompareOptionDialog = new SchemaCompareOptionsDialog(this.deploymentOptions, this);
await this.schemaCompareOptionDialog.openDialog();
this.deploymentOptions = this.schemaCompareOptionDialog.deploymentOptions;
});
}
@@ -673,20 +706,35 @@ export class SchemaCompareResult {
});
}
private resetButtons(beforeCompareStart: boolean): void {
if (beforeCompareStart) {
this.compareButton.enabled = true;
this.optionsButton.enabled = true;
this.switchButton.enabled = true;
this.cancelCompareButton.enabled = false;
this.saveScmpButton.enabled = true;
}
else {
this.compareButton.enabled = false;
this.optionsButton.enabled = false;
this.switchButton.enabled = false;
this.cancelCompareButton.enabled = true;
private resetButtons(resetButtonState: ResetButtonState): void {
switch (resetButtonState) {
case (ResetButtonState.noSourceTarget): {
this.compareButton.enabled = false;
this.optionsButton.enabled = false;
this.switchButton.enabled = this.sourceEndpointInfo ? true : false; // allows switching if the source is set
this.openScmpButton.enabled = true;
this.cancelCompareButton.enabled = false;
break;
}
case (ResetButtonState.beforeCompareStart): {
this.compareButton.enabled = true;
this.optionsButton.enabled = true;
this.switchButton.enabled = true;
this.openScmpButton.enabled = true;
this.saveScmpButton.enabled = true;
this.cancelCompareButton.enabled = false;
break;
}
case (ResetButtonState.comparing): {
this.compareButton.enabled = false;
this.optionsButton.enabled = false;
this.switchButton.enabled = false;
this.openScmpButton.enabled = false;
this.cancelCompareButton.enabled = true;
break;
}
}
this.generateScriptButton.enabled = false;
this.applyButton.enabled = false;
this.generateScriptButton.title = generateScriptEnabledMessage;
@@ -700,6 +748,14 @@ export class SchemaCompareResult {
this.applyButton.title = reCompareToRefeshMessage;
}
// reset state afer loading an scmp
private resetForNewCompare(): void {
this.resetButtons(ResetButtonState.beforeCompareStart);
this.flexModel.removeItem(this.splitView);
this.flexModel.removeItem(this.noDifferencesLabel);
this.flexModel.addItem(this.startText, { CSSStyles: { 'margin': 'auto' } });
}
private createSwitchButton(view: azdata.ModelView): void {
this.switchButton = view.modelBuilder.button().withProperties({
label: localize('schemaCompare.switchDirectionButton', 'Switch direction'),
@@ -739,7 +795,11 @@ export class SchemaCompareResult {
// remember that source target have been toggled
this.sourceTargetSwitched = this.sourceTargetSwitched ? false : true;
this.startCompare();
// only compare if both source and target are set
if (this.sourceEndpointInfo && this.targetEndpointInfo) {
this.startCompare();
}
});
}
@@ -767,6 +827,85 @@ export class SchemaCompareResult {
});
}
private createOpenScmpButton(view: azdata.ModelView) {
this.openScmpButton = view.modelBuilder.button().withProperties({
label: localize('schemaCompare.openScmpButton', 'Open .scmp file'),
iconPath: {
light: path.join(__dirname, 'media', 'open-scmp.svg'),
dark: path.join(__dirname, 'media', 'open-scmp-inverse.svg')
},
title: localize('schemaCompare.openScmpButtonTitle', 'Load source, target, and options saved in an .scmp file')
}).component();
this.openScmpButton.onDidClick(async (click) => {
Telemetry.sendTelemetryEvent('SchemaCompareOpenScmpStarted');
const rootPath = vscode.workspace.rootPath ? vscode.workspace.rootPath : os.homedir();
let fileUris = await vscode.window.showOpenDialog(
{
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
defaultUri: vscode.Uri.file(rootPath),
openLabel: localize('schemaCompare.openFile', 'Open'),
filters: {
'scmp Files': ['scmp'],
}
}
);
if (!fileUris || fileUris.length === 0) {
return;
}
let fileUri = fileUris[0];
const service = await SchemaCompareResult.getService('MSSQL');
let startTime = Date.now();
const result = await service.schemaCompareOpenScmp(fileUri.fsPath);
if (!result || !result.success) {
Telemetry.sendTelemetryEvent('SchemaCompareOpenScmpFailed', {
'errorType': getTelemetryErrorType(result.errorMessage)
});
vscode.window.showErrorMessage(
localize('schemaCompare.openScmpErrorMessage', "Open scmp failed: '{0}'", (result && result.errorMessage) ? result.errorMessage : 'Unknown'));
return;
}
if (result.sourceEndpointInfo && result.sourceEndpointInfo.endpointType === azdata.SchemaCompareEndpointType.Database) {
// only set endpoint info if able to connect to the database
const ownerUri = await verifyConnectionAndGetOwnerUri(result.sourceEndpointInfo);
if (ownerUri) {
this.sourceEndpointInfo = result.sourceEndpointInfo;
this.sourceEndpointInfo.ownerUri = ownerUri;
}
} else {
this.sourceEndpointInfo = result.sourceEndpointInfo;
}
if (result.targetEndpointInfo && result.targetEndpointInfo.endpointType === azdata.SchemaCompareEndpointType.Database) {
const ownerUri = await verifyConnectionAndGetOwnerUri(result.targetEndpointInfo);
if (ownerUri) {
this.targetEndpointInfo = result.targetEndpointInfo;
this.targetEndpointInfo.ownerUri = ownerUri;
}
} else {
this.targetEndpointInfo = result.targetEndpointInfo;
}
this.updateSourceAndTarget();
this.deploymentOptions = result.deploymentOptions;
this.scmpSourceExcludes = result.excludedSourceElements;
this.scmpTargetExcludes = result.excludedTargetElements;
this.sourceTargetSwitched = result.originalTargetName !== this.targetEndpointInfo.databaseName;
// clear out any old results
this.resetForNewCompare();
Telemetry.sendTelemetryEvent('SchemaCompareOpenScmpEnded', {
'elapsedTime:': (Date.now() - startTime).toString()
});
});
}
private createSaveScmpButton(view: azdata.ModelView): void {
this.saveScmpButton = view.modelBuilder.button().withProperties({
label: localize('schemaCompare.saveScmpButton', 'Save .scmp file'),
@@ -812,7 +951,7 @@ export class SchemaCompareResult {
}
Telemetry.sendTelemetryEvent('SchemaCompareSaveScmpEnded', {
'totalSaveTime:': (Date.now() - startTime).toString(),
'elapsedTime:': (Date.now() - startTime).toString(),
'operationId': this.comparisonResult.operationId
});
});

View File

@@ -38,7 +38,8 @@ const mockSourceEndpoint: azdata.SchemaCompareEndpointInfo = {
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: mocksource
packageFilePath: mocksource,
connectionDetails: undefined
};
const mockTargetEndpoint: azdata.SchemaCompareEndpointInfo = {
@@ -47,7 +48,8 @@ const mockTargetEndpoint: azdata.SchemaCompareEndpointInfo = {
serverName: '',
databaseName: '',
ownerUri: '',
packageFilePath: mocktarget
packageFilePath: mocktarget,
connectionDetails: undefined
};
describe('SchemaCompareDialog.openDialog', function (): void {

View File

@@ -27,6 +27,10 @@ export class SchemaCompareTestService implements azdata.SchemaCompareServicesPro
throw new Error('Method not implemented.');
}
schemaCompareOpenScmp(filePath: string): Thenable<azdata.SchemaCompareOpenScmpResult> {
throw new Error('Method not implemented.');
}
schemaCompareSaveScmp(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: azdata.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: azdata.SchemaCompareObjectId[], excludedTargetObjects: azdata.SchemaCompareObjectId[]): Thenable<azdata.ResultStatus> {
throw new Error('Method not implemented.');

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as azdata from 'azdata';
import * as vscode from 'vscode';
export interface IPackageInfo {
name: string;
@@ -40,12 +41,46 @@ export function getTelemetryErrorType(msg: string): string {
*/
export function getEndpointName(endpoint: azdata.SchemaCompareEndpointInfo): string {
if (!endpoint) {
return undefined;
return ' ';
}
if (endpoint.endpointType === azdata.SchemaCompareEndpointType.Database) {
if (!endpoint.serverName && endpoint.connectionDetails) {
endpoint.serverName = endpoint.connectionDetails['serverName'];
}
return `${endpoint.serverName}.${endpoint.databaseName}`;
} else {
return endpoint.packageFilePath;
}
}
function connectionInfoToConnectionProfile(details: azdata.ConnectionInfo): azdata.IConnectionProfile {
return {
serverName: details['serverName'],
databaseName: details['databaseName'],
authenticationType: details['authenticationType'],
providerName: 'MSSQL',
connectionName: '',
userName: details['userName'],
password: details['password'],
savePassword: false,
groupFullName: undefined,
saveProfile: true,
id: undefined,
groupId: undefined,
options: details['options']
};
}
export async function verifyConnectionAndGetOwnerUri(endpoint: azdata.SchemaCompareEndpointInfo): Promise<string> {
if (endpoint.endpointType === azdata.SchemaCompareEndpointType.Database && endpoint.connectionDetails) {
let connection = await azdata.connection.connect(connectionInfoToConnectionProfile(endpoint.connectionDetails), false, false);
// show error message if the can't connect to the database
if (connection.errorMessage) {
vscode.window.showErrorMessage(connection.errorMessage);
}
return await azdata.connection.getUriForConnection(connection.connectionId);
}
return undefined;
}

View File

@@ -1779,6 +1779,7 @@ declare module 'azdata' {
serverName: string;
databaseName: string;
ownerUri: string;
connectionDetails: ConnectionInfo;
}
export interface SchemaCompareObjectId {
@@ -1940,12 +1941,28 @@ declare module 'azdata' {
ServerTriggers = 65
}
export interface SchemaCompareObjectId {
nameParts: string[];
sqlObjectType: string;
}
export interface SchemaCompareOpenScmpResult extends ResultStatus {
sourceEndpointInfo: SchemaCompareEndpointInfo;
targetEndpointInfo: SchemaCompareEndpointInfo;
originalTargetName: string;
originalConnectionString: string;
deploymentOptions: DeploymentOptions;
excludedSourceElements: SchemaCompareObjectId[];
excludedTargetElements: SchemaCompareObjectId[];
}
export interface SchemaCompareServicesProvider extends DataProvider {
schemaCompare(operationId: string, sourceEndpointInfo: SchemaCompareEndpointInfo, targetEndpointInfo: SchemaCompareEndpointInfo, taskExecutionMode: TaskExecutionMode, deploymentOptions: DeploymentOptions): Thenable<SchemaCompareResult>;
schemaCompareGenerateScript(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: TaskExecutionMode): Thenable<ResultStatus>;
schemaComparePublishChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: TaskExecutionMode): Thenable<ResultStatus>;
schemaCompareGetDefaultOptions(): Thenable<SchemaCompareOptionsResult>;
schemaCompareIncludeExcludeNode(operationId: string, diffEntry: DiffEntry, IncludeRequest: boolean, taskExecutionMode: TaskExecutionMode): Thenable<ResultStatus>;
schemaCompareOpenScmp(filePath: string): Thenable<SchemaCompareOpenScmpResult>;
schemaCompareSaveScmp(sourceEndpointInfo: SchemaCompareEndpointInfo, targetEndpointInfo: SchemaCompareEndpointInfo, taskExecutionMode: TaskExecutionMode, deploymentOptions: DeploymentOptions, scmpFilePath: string, excludedSourceObjects: SchemaCompareObjectId[], excludedTargetObjects: SchemaCompareObjectId[]): Thenable<ResultStatus>;
schemaCompareCancel(operationId: string): Thenable<ResultStatus>;
}

View File

@@ -20,6 +20,7 @@ export interface ISchemaCompareService {
schemaComparePublishChanges(operationId: string, targetServerName: string, targetDatabaseName: string, taskExecutionMode: azdata.TaskExecutionMode): void;
schemaCompareGetDefaultOptions(): void;
schemaCompareIncludeExcludeNode(operationId: string, diffEntry: azdata.DiffEntry, includeRequest: boolean, taskExecutionMode: azdata.TaskExecutionMode): void;
schemaCompareOpenScmp(filePath: string): void;
schemaCompareSaveScmp(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: azdata.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: azdata.SchemaCompareObjectId[], excludedTargetObjects: azdata.SchemaCompareObjectId[]);
schemaCompareCancel(operationId: string): void;
}
@@ -64,6 +65,12 @@ export class SchemaCompareService implements ISchemaCompareService {
});
}
schemaCompareOpenScmp(filePath: string): Thenable<azdata.SchemaCompareOpenScmpResult> {
return this._runAction('', (runner) => {
return runner.schemaCompareOpenScmp(filePath);
});
}
schemaCompareSaveScmp(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: azdata.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: azdata.SchemaCompareObjectId[], excludedTargetObjects: azdata.SchemaCompareObjectId[]) {
return this._runAction('', (runner) => {
return runner.schemaCompareSaveScmp(sourceEndpointInfo, targetEndpointInfo, taskExecutionMode, deploymentOptions, scmpFilePath, excludedSourceObjects, excludedTargetObjects);

View File

@@ -485,6 +485,9 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
schemaCompareIncludeExcludeNode(operationId: string, diffEntry: azdata.DiffEntry, includeRequest: boolean, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> {
return self._proxy.$schemaCompareIncludeExcludeNode(handle, operationId, diffEntry, includeRequest, taskExecutionMode);
},
schemaCompareOpenScmp(filePath: string): Thenable<azdata.SchemaCompareOpenScmpResult> {
return self._proxy.$schemaCompareOpenScmp(handle, filePath);
},
schemaCompareSaveScmp(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode, deploymentOptions: azdata.DeploymentOptions, scmpFilePath: string, excludedSourceObjects: azdata.SchemaCompareObjectId[], excludedTargetObjects: azdata.SchemaCompareObjectId[]): Thenable<azdata.ResultStatus> {
return self._proxy.$schemaCompareSaveScmp(handle, sourceEndpointInfo, targetEndpointInfo, taskExecutionMode, deploymentOptions, scmpFilePath, excludedSourceObjects, excludedTargetObjects);
},

View File

@@ -488,6 +488,12 @@ export abstract class ExtHostDataProtocolShape {
*/
$schemaCompareIncludeExcludeNode(handle: number, operationId: string, diffEntry: azdata.DiffEntry, includeRequest: boolean, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> { throw ni(); }
/**
* Schema compare open scmp
*/
$schemaCompareOpenScmp(handle: number, filePath: string): Thenable<azdata.SchemaCompareOpenScmpResult> { throw ni(); }
/**
* Schema compare save scmp
*/