mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
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:
@@ -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');
|
||||
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
|
||||
@@ -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
|
||||
});
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 |
3
extensions/schema-compare/src/media/open-scmp.svg
Normal file
3
extensions/schema-compare/src/media/open-scmp.svg
Normal 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 |
@@ -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
|
||||
});
|
||||
});
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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.');
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
17
src/sql/azdata.proposed.d.ts
vendored
17
src/sql/azdata.proposed.d.ts
vendored
@@ -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>;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
@@ -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
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user