Add generate script option to DacFx wizard (#3789)

* Add generate script option to deploy scenario

* add action to summary page and fixed page adding/removing so that summary page will have the correct step number

* updating contract based on change in sqltoolsservice

* added enums to make index checks more clear

* cleaned up onPageChanged()

* bump sqltoolsservice version to 68
This commit is contained in:
kisantia
2019-01-28 10:48:36 -08:00
committed by GitHub
parent 9cffe4d476
commit 565b7404f9
12 changed files with 405 additions and 45 deletions

View File

@@ -45,4 +45,6 @@ export interface DacFxDataModel extends BaseDataModel {
filePath: string; filePath: string;
version: string; version: string;
upgradeExisting: boolean; upgradeExisting: boolean;
scriptFilePath: string;
generateScriptAndDeploy: boolean;
} }

View File

@@ -8,6 +8,7 @@ import * as nls from 'vscode-nls';
import * as sqlops from 'sqlops'; import * as sqlops from 'sqlops';
import { SelectOperationPage } from './pages/selectOperationpage'; import { SelectOperationPage } from './pages/selectOperationpage';
import { DeployConfigPage } from './pages/deployConfigPage'; import { DeployConfigPage } from './pages/deployConfigPage';
import { DeployActionPage } from './pages/deployActionPage';
import { DacFxSummaryPage } from './pages/dacFxSummaryPage'; import { DacFxSummaryPage } from './pages/dacFxSummaryPage';
import { ExportConfigPage } from './pages/exportConfigPage'; import { ExportConfigPage } from './pages/exportConfigPage';
import { ExtractConfigPage } from './pages/extractConfigPage'; import { ExtractConfigPage } from './pages/extractConfigPage';
@@ -30,7 +31,33 @@ export enum Operation {
deploy, deploy,
extract, extract,
import, import,
export export,
generateDeployScript
}
export enum DeployOperationPath {
selectOperation,
deployOptions,
deployAction,
summary
}
export enum ExtractOperationPath {
selectOperation,
options,
summary
}
export enum ImportOperationPath {
selectOperation,
options,
summary
}
export enum ExportOperationPath {
selectOperation,
options,
summary
} }
export class DataTierApplicationWizard { export class DataTierApplicationWizard {
@@ -60,6 +87,7 @@ export class DataTierApplicationWizard {
this.wizard = sqlops.window.modelviewdialog.createWizard('Data-tier Application Wizard'); this.wizard = sqlops.window.modelviewdialog.createWizard('Data-tier Application Wizard');
let selectOperationWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.selectOperationPageName', 'Select an Operation')); let selectOperationWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.selectOperationPageName', 'Select an Operation'));
let deployConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.deployConfigPageName', 'Select Deploy Dacpac Settings')); let deployConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.deployConfigPageName', 'Select Deploy Dacpac Settings'));
let deployActionWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.deployActionPageName', 'Select Action'));
let summaryWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.summaryPageName', 'Summary')); let summaryWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.summaryPageName', 'Summary'));
let extractConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.extractConfigPageName', 'Select Extract Dacpac Settings')); let extractConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.extractConfigPageName', 'Select Extract Dacpac Settings'));
let importConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.importConfigPageName', 'Select Import Bacpac Settings')); let importConfigWizardPage = sqlops.window.modelviewdialog.createWizardPage(localize('dacFx.importConfigPageName', 'Select Import Bacpac Settings'));
@@ -67,6 +95,7 @@ export class DataTierApplicationWizard {
this.pages.set('selectOperation', new Page(selectOperationWizardPage)); this.pages.set('selectOperation', new Page(selectOperationWizardPage));
this.pages.set('deployConfig', new Page(deployConfigWizardPage)); this.pages.set('deployConfig', new Page(deployConfigWizardPage));
this.pages.set('deployAction', new Page(deployActionWizardPage));
this.pages.set('extractConfig', new Page(extractConfigWizardPage)); this.pages.set('extractConfig', new Page(extractConfigWizardPage));
this.pages.set('importConfig', new Page(importConfigWizardPage)); this.pages.set('importConfig', new Page(importConfigWizardPage));
this.pages.set('exportConfig', new Page(exportConfigWizardPage)); this.pages.set('exportConfig', new Page(exportConfigWizardPage));
@@ -87,6 +116,12 @@ export class DataTierApplicationWizard {
await deployConfigDacFxPage.start(); await deployConfigDacFxPage.start();
}); });
deployActionWizardPage.registerContent(async (view) => {
let deployActionDacFxPage = new DeployActionPage(this, deployActionWizardPage, this.model, view);
this.pages.get('deployAction').dacFxPage = deployActionDacFxPage;
await deployActionDacFxPage.start();
});
extractConfigWizardPage.registerContent(async (view) => { extractConfigWizardPage.registerContent(async (view) => {
let extractConfigDacFxPage = new ExtractConfigPage(this, extractConfigWizardPage, this.model, view); let extractConfigDacFxPage = new ExtractConfigPage(this, extractConfigWizardPage, this.model, view);
this.pages.get('extractConfig').dacFxPage = extractConfigDacFxPage; this.pages.get('extractConfig').dacFxPage = extractConfigDacFxPage;
@@ -113,39 +148,27 @@ export class DataTierApplicationWizard {
this.wizard.onPageChanged(async (event) => { this.wizard.onPageChanged(async (event) => {
let idx = event.newPage; let idx = event.newPage;
let page: Page; let page = this.getPage(idx);
if (idx === 1) {
switch (this.selectedOperation) {
case Operation.deploy: {
page = this.pages.get('deployConfig');
break;
}
case Operation.extract: {
page = this.pages.get('extractConfig');
break;
}
case Operation.import: {
page = this.pages.get('importConfig');
break;
}
case Operation.export: {
page = this.pages.get('exportConfig');
break;
}
}
} else if (idx === 2) {
page = this.pages.get('summary');
}
if (page !== undefined) { if (page !== undefined) {
page.dacFxPage.setupNavigationValidator(); page.dacFxPage.setupNavigationValidator();
page.dacFxPage.onPageEnter(); page.dacFxPage.onPageEnter();
} }
//do onPageLeave for summary page so that GenerateScript button only shows up if upgrading database
let idxLast = event.lastPage;
if (this.isSummaryPage(idxLast)) {
let lastPage = this.pages.get('summary');
if (lastPage) {
lastPage.dacFxPage.onPageLeave();
}
}
}); });
this.wizard.pages = [selectOperationWizardPage, deployConfigWizardPage, summaryWizardPage]; this.wizard.pages = [selectOperationWizardPage, deployConfigWizardPage, deployActionWizardPage, summaryWizardPage];
this.wizard.generateScriptButton.hidden = true; this.wizard.generateScriptButton.hidden = true;
this.wizard.generateScriptButton.onClick(async () => await this.generateDeployScript());
this.wizard.doneButton.onClick(async () => await this.executeOperation()); this.wizard.doneButton.onClick(async () => await this.executeOperation());
this.wizard.open(); this.wizard.open();
@@ -177,6 +200,15 @@ export class DataTierApplicationWizard {
this.selectedOperation = Operation.export; this.selectedOperation = Operation.export;
break; break;
} }
case Operation.generateDeployScript: {
this.wizard.doneButton.label = localize('dacFx.generateScriptButton', 'Generate Script');
this.selectedOperation = Operation.generateDeployScript;
break;
}
}
if (operation !== Operation.deploy && operation !== Operation.generateDeployScript) {
this.model.upgradeExisting = false;
} }
} }
@@ -198,6 +230,10 @@ export class DataTierApplicationWizard {
await this.export(); await this.export();
break; break;
} }
case Operation.generateDeployScript: {
await this.generateDeployScript();
break;
}
} }
} }
@@ -245,6 +281,64 @@ export class DataTierApplicationWizard {
} }
} }
private async generateDeployScript() {
if (!this.model.scriptFilePath) {
return;
}
let service = await DataTierApplicationWizard.getService(this.model.server.providerName);
let ownerUri = await sqlops.connection.getUriForConnection(this.model.server.connectionId);
this.wizard.message = {
text: localize('dacfx.scriptGeneratingMessage', 'You can view the status of script generation in the Task History once the wizard is closed'),
level: sqlops.window.modelviewdialog.MessageLevel.Information,
description: ''
};
let result = await service.generateDeployScript(this.model.filePath, this.model.database, this.model.scriptFilePath, ownerUri, sqlops.TaskExecutionMode.execute);
if (!result || !result.success) {
vscode.window.showErrorMessage(
localize('alertData.deployErrorMessage', "Deploy failed '{0}'", result.errorMessage ? result.errorMessage : 'Unknown'));
}
}
private getPage(idx: number): Page {
let page: Page;
if (idx === 1) {
switch (this.selectedOperation) {
case Operation.deploy: {
page = this.pages.get('deployConfig');
break;
}
case Operation.extract: {
page = this.pages.get('extractConfig');
break;
}
case Operation.import: {
page = this.pages.get('importConfig');
break;
}
case Operation.export: {
page = this.pages.get('exportConfig');
break;
}
}
} else if ((this.selectedOperation === Operation.deploy || this.selectedOperation === Operation.generateDeployScript) && idx === DeployOperationPath.deployAction) {
page = this.pages.get('deployAction');
} else if (this.isSummaryPage(idx)) {
page = this.pages.get('summary');
}
return page;
}
private isSummaryPage(idx: number): boolean {
return this.selectedOperation === Operation.import && idx === ImportOperationPath.summary
|| this.selectedOperation === Operation.export && idx === ExportOperationPath.summary
|| this.selectedOperation === Operation.extract && idx === ExtractOperationPath.summary
|| (this.selectedOperation === Operation.deploy || this.selectedOperation === Operation.generateDeployScript) && idx === DeployOperationPath.summary;
}
private static async getService(providerName: string): Promise<sqlops.DacFxServicesProvider> { private static async getService(providerName: string): Promise<sqlops.DacFxServicesProvider> {
let service = sqlops.dataprotocol.getProvider<sqlops.DacFxServicesProvider>(providerName, sqlops.DataProviderType.DacFxServicesProvider); let service = sqlops.dataprotocol.getProvider<sqlops.DacFxServicesProvider>(providerName, sqlops.DataProviderType.DacFxServicesProvider);
return service; return service;

View File

@@ -49,6 +49,14 @@ export class DacFxSummaryPage extends BasePage {
async onPageEnter(): Promise<boolean> { async onPageEnter(): Promise<boolean> {
this.populateTable(); this.populateTable();
this.loader.loading = false; this.loader.loading = false;
if (this.model.upgradeExisting && this.model.generateScriptAndDeploy) {
this.instance.wizard.generateScriptButton.hidden = false;
}
return true;
}
async onPageLeave(): Promise<boolean> {
this.instance.wizard.generateScriptButton.hidden = true;
return true; return true;
} }
@@ -68,6 +76,10 @@ export class DacFxSummaryPage extends BasePage {
let sourceServer = localize('dacfx.sourceServerName', 'Source Server'); let sourceServer = localize('dacfx.sourceServerName', 'Source Server');
let sourceDatabase = localize('dacfx.sourceDatabaseName', 'Source Database'); let sourceDatabase = localize('dacfx.sourceDatabaseName', 'Source Database');
let fileLocation = localize('dacfx.fileLocation', 'File Location'); let fileLocation = localize('dacfx.fileLocation', 'File Location');
let scriptLocation = localize('dacfx.scriptLocation', 'Deployment Script Location');
let action = localize('dacfx.action', 'Action');
let deploy = localize('dacfx.deploy', 'Deploy');
let generateScript = localize('dacfx.generateScript', 'Generate Deployment Script');
switch (this.instance.selectedOperation) { switch (this.instance.selectedOperation) {
case Operation.deploy: { case Operation.deploy: {
@@ -75,6 +87,13 @@ export class DacFxSummaryPage extends BasePage {
[targetServer, this.model.serverName], [targetServer, this.model.serverName],
[fileLocation, this.model.filePath], [fileLocation, this.model.filePath],
[targetDatabase, this.model.database]]; [targetDatabase, this.model.database]];
if (this.model.generateScriptAndDeploy) {
data[3] = [scriptLocation, this.model.scriptFilePath];
data[4] = [action, generateScript + ', ' + deploy];
}
else {
data[3] = [action, deploy];
}
break; break;
} }
case Operation.extract: { case Operation.extract: {
@@ -99,12 +118,21 @@ export class DacFxSummaryPage extends BasePage {
[fileLocation, this.model.filePath]]; [fileLocation, this.model.filePath]];
break; break;
} }
case Operation.generateDeployScript: {
data = [
[targetServer, this.model.serverName],
[fileLocation, this.model.filePath],
[targetDatabase, this.model.database],
[scriptLocation, this.model.scriptFilePath],
[action, generateScript]];
break;
}
} }
this.table.updateProperties({ this.table.updateProperties({
data: data, data: data,
columns: ['Setting', 'Value'], columns: ['Setting', 'Value'],
width: 600, width: 700,
height: 200 height: 200
}); });
} }

View File

@@ -0,0 +1,176 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as sqlops from 'sqlops';
import * as nls from 'vscode-nls';
import * as vscode from 'vscode';
import * as path from 'path';
import * as os from 'os';
import { DacFxDataModel } from '../api/models';
import { DataTierApplicationWizard, Operation } from '../dataTierApplicationWizard';
import { DacFxConfigPage } from '../api/dacFxConfigPage';
const localize = nls.loadMessageBundle();
export class DeployActionPage extends DacFxConfigPage {
protected readonly wizardPage: sqlops.window.modelviewdialog.WizardPage;
protected readonly instance: DataTierApplicationWizard;
protected readonly model: DacFxDataModel;
protected readonly view: sqlops.ModelView;
private deployRadioButton: sqlops.RadioButtonComponent;
private deployScriptRadioButton: sqlops.RadioButtonComponent;
private scriptRadioButton: sqlops.RadioButtonComponent;
private form: sqlops.FormContainer;
public constructor(instance: DataTierApplicationWizard, wizardPage: sqlops.window.modelviewdialog.WizardPage, model: DacFxDataModel, view: sqlops.ModelView) {
super(instance, wizardPage, model, view);
}
async start(): Promise<boolean> {
let deployComponent = await this.createDeployRadioButton();
let deployScriptComponent = await this.createDeployScriptRadioButton();
let scriptComponent = await this.createScriptRadioButton();
let fileBrowserComponent = await this.createFileBrowser();
this.form = this.view.modelBuilder.formContainer()
.withFormItems(
[
deployComponent,
scriptComponent,
deployScriptComponent,
fileBrowserComponent
]).component();
await this.view.initializeModel(this.form);
//default have the first radio button checked
this.deployRadioButton.checked = true;
this.toggleFileBrowser(false);
return true;
}
async onPageEnter(): Promise<boolean> {
return true;
}
private async createDeployRadioButton(): Promise<sqlops.FormComponent> {
this.deployRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedDeployAction',
label: localize('dacFx.deployRadioButtonLabel', 'Deploy'),
}).component();
this.deployRadioButton.onDidClick(() => {
this.model.generateScriptAndDeploy = false;
this.instance.setDoneButton(Operation.deploy);
this.toggleFileBrowser(false);
});
return {
component: this.deployRadioButton,
title: ''
};
}
private async createDeployScriptRadioButton(): Promise<sqlops.FormComponent> {
this.deployScriptRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedDeployAction',
label: localize('dacFx.deployScriptRadioButtonLabel', 'Generate Deployment Script and Deploy'),
}).component();
this.deployScriptRadioButton.onDidClick(() => {
this.model.generateScriptAndDeploy = true;
this.instance.setDoneButton(Operation.deploy);
this.toggleFileBrowser(true);
});
return {
component: this.deployScriptRadioButton,
title: ''
};
}
private async createScriptRadioButton(): Promise<sqlops.FormComponent> {
this.scriptRadioButton = this.view.modelBuilder.radioButton()
.withProperties({
name: 'selectedDeployAction',
label: localize('dacFx.scriptRadioButtonLabel', 'Generate Deployment Script'),
}).component();
this.scriptRadioButton.onDidClick(() => {
this.model.generateScriptAndDeploy = false;
this.toggleFileBrowser(true);
//change button text and operation
this.instance.setDoneButton(Operation.generateDeployScript);
});
return {
component: this.scriptRadioButton,
title: ''
};
}
private async createFileBrowser(): Promise<sqlops.FormComponentGroup> {
this.createFileBrowserParts();
//default filepath
let now = new Date();
let datetime = now.getFullYear() + '-' + (now.getMonth() + 1) + '-' + now.getDate() + '-' + now.getHours() + '-' + now.getMinutes();
this.fileTextBox.value= path.join(os.homedir(), this.model.database + '_UpgradeDACScript_' + datetime + '.sql');
this.model.scriptFilePath = this.fileTextBox.value;
this.fileButton.onDidClick(async (click) => {
let fileUri = await vscode.window.showSaveDialog(
{
defaultUri: vscode.Uri.file(this.fileTextBox.value),
saveLabel: localize('dacfxDeployScript.saveFile', 'Save'),
filters: {
'SQL Files': ['sql'],
}
}
);
if (!fileUri) {
return;
}
this.fileTextBox.value = fileUri.fsPath;
this.model.scriptFilePath = fileUri.fsPath;
});
this.fileTextBox.onTextChanged(async () => {
this.model.scriptFilePath = this.fileTextBox.value;
});
return {
title: '',
components: [
{
title: localize('dacfx.generatedScriptLocation','Deployment Script Location'),
component: this.fileTextBox,
layout: {
horizontal: true,
componentWidth: 400
},
actions: [this.fileButton]
},],
};
}
private toggleFileBrowser(enable: boolean): void {
this.fileTextBox.enabled = enable;
this.fileButton.enabled = enable;
}
public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => {
return true;
});
}
}

View File

@@ -58,11 +58,6 @@ export class SelectOperationPage extends BasePage {
} }
async onPageEnter(): Promise<boolean> { async onPageEnter(): Promise<boolean> {
let numPages = this.instance.wizard.pages.length;
for (let i = numPages - 1; i > 2; --i) {
await this.instance.wizard.removePage(i);
}
return true; return true;
} }
@@ -74,12 +69,14 @@ export class SelectOperationPage extends BasePage {
}).component(); }).component();
this.deployRadioButton.onDidClick(() => { this.deployRadioButton.onDidClick(() => {
// remove the previous page this.removePages();
this.instance.wizard.removePage(1);
// add deploy page //add deploy pages
let page = this.instance.pages.get('deployConfig'); let configPage = this.instance.pages.get('deployConfig');
this.instance.wizard.addPage(page.wizardPage, 1); this.instance.wizard.addPage(configPage.wizardPage, 1);
let actionPage = this.instance.pages.get('deployAction');
this.instance.wizard.addPage(actionPage.wizardPage, 2);
this.addSummaryPage(3);
// change button text and operation // change button text and operation
this.instance.setDoneButton(Operation.deploy); this.instance.setDoneButton(Operation.deploy);
@@ -99,12 +96,12 @@ export class SelectOperationPage extends BasePage {
}).component(); }).component();
this.extractRadioButton.onDidClick(() => { this.extractRadioButton.onDidClick(() => {
// remove the previous pages this.removePages();
this.instance.wizard.removePage(1);
// add the extract page // add the extract page
let page = this.instance.pages.get('extractConfig'); let page = this.instance.pages.get('extractConfig');
this.instance.wizard.addPage(page.wizardPage, 1); this.instance.wizard.addPage(page.wizardPage, 1);
this.addSummaryPage(2);
// change button text and operation // change button text and operation
this.instance.setDoneButton(Operation.extract); this.instance.setDoneButton(Operation.extract);
@@ -124,12 +121,12 @@ export class SelectOperationPage extends BasePage {
}).component(); }).component();
this.importRadioButton.onDidClick(() => { this.importRadioButton.onDidClick(() => {
// remove the previous page this.removePages();
this.instance.wizard.removePage(1);
// add the import page // add the import page
let page = this.instance.pages.get('importConfig'); let page = this.instance.pages.get('importConfig');
this.instance.wizard.addPage(page.wizardPage, 1); this.instance.wizard.addPage(page.wizardPage, 1);
this.addSummaryPage(2);
// change button text and operation // change button text and operation
this.instance.setDoneButton(Operation.import); this.instance.setDoneButton(Operation.import);
@@ -149,12 +146,12 @@ export class SelectOperationPage extends BasePage {
}).component(); }).component();
this.exportRadioButton.onDidClick(() => { this.exportRadioButton.onDidClick(() => {
// remove the 2 previous pages this.removePages();
this.instance.wizard.removePage(1);
// add the export pages // add the export pages
let page = this.instance.pages.get('exportConfig'); let page = this.instance.pages.get('exportConfig');
this.instance.wizard.addPage(page.wizardPage, 1); this.instance.wizard.addPage(page.wizardPage, 1);
this.addSummaryPage(2);
// change button text and operation // change button text and operation
this.instance.setDoneButton(Operation.export); this.instance.setDoneButton(Operation.export);
@@ -166,6 +163,18 @@ export class SelectOperationPage extends BasePage {
}; };
} }
private removePages() {
let numPages = this.instance.wizard.pages.length;
for (let i = numPages - 1; i > 0; --i) {
this.instance.wizard.removePage(i);
}
}
private addSummaryPage(index: number) {
let summaryPage = this.instance.pages.get('summary');
this.instance.wizard.addPage(summaryPage.wizardPage, index);
}
public setupNavigationValidator() { public setupNavigationValidator() {
this.instance.registerNavigationValidator(() => { this.instance.registerNavigationValidator(() => {
return true; return true;

View File

@@ -1,6 +1,6 @@
{ {
"downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/v{#version#}/microsoft.sqltools.servicelayer-{#fileName#}",
"version": "1.5.0-alpha.67", "version": "1.5.0-alpha.68",
"downloadFileNames": { "downloadFileNames": {
"Windows_86": "win-x86-netcoreapp2.2.zip", "Windows_86": "win-x86-netcoreapp2.2.zip",
"Windows_64": "win-x64-netcoreapp2.2.zip", "Windows_64": "win-x64-netcoreapp2.2.zip",

View File

@@ -331,6 +331,14 @@ export interface DeployParams {
taskExecutionMode: TaskExecutionMode; taskExecutionMode: TaskExecutionMode;
} }
export interface GenerateDeployScriptParams {
packageFilePath: string;
databaseName: string;
scriptFilePath: string;
ownerUri: string;
taskExecutionMode: TaskExecutionMode;
}
export namespace ExportRequest { export namespace ExportRequest {
export const type = new RequestType<ExportParams, sqlops.DacFxResult, void, void>('dacfx/export'); export const type = new RequestType<ExportParams, sqlops.DacFxResult, void, void>('dacfx/export');
} }
@@ -347,4 +355,8 @@ export namespace DeployRequest {
export const type = new RequestType<DeployParams, sqlops.DacFxResult, void, void>('dacfx/deploy'); export const type = new RequestType<DeployParams, sqlops.DacFxResult, void, void>('dacfx/deploy');
} }
export namespace GenerateDeployScriptRequest {
export const type = new RequestType<GenerateDeployScriptParams, sqlops.DacFxResult, void, void>('dacfx/generateDeploymentScript');
}
// ------------------------------- < DacFx > ------------------------------------ // ------------------------------- < DacFx > ------------------------------------

View File

@@ -106,12 +106,26 @@ export class DacFxServicesFeature extends SqlOpsFeature<undefined> {
); );
}; };
let generateDeployScript = (packageFilePath: string, targetDatabaseName: string, scriptFilePath: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> => {
let params: contracts.GenerateDeployScriptParams = { packageFilePath: packageFilePath, databaseName: targetDatabaseName, scriptFilePath: scriptFilePath, ownerUri: ownerUri, taskExecutionMode: taskExecutionMode };
return client.sendRequest(contracts.GenerateDeployScriptRequest.type, params).then(
r => {
return r;
},
e => {
client.logFailedRequest(contracts.DeployRequest.type, e);
return Promise.resolve(undefined);
}
);
};
return sqlops.dataprotocol.registerDacFxServicesProvider({ return sqlops.dataprotocol.registerDacFxServicesProvider({
providerId: client.providerId, providerId: client.providerId,
exportBacpac, exportBacpac,
importBacpac, importBacpac,
extractDacpac, extractDacpac,
deployDacpac deployDacpac,
generateDeployScript
}); });
} }
} }

View File

@@ -22,6 +22,7 @@ export interface IDacFxService {
importBacpac(packageFilePath: string, targetDatabaseName: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void; importBacpac(packageFilePath: string, targetDatabaseName: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void;
extractDacpac(sourceDatabaseName: string, packageFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void; extractDacpac(sourceDatabaseName: string, packageFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void;
deployDacpac(packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void; deployDacpac(packageFilePath: string, targetDatabaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void;
generateDeployScript(packageFilePath: string, targetDatabaseName: string, scriptFilePath: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): void;
} }
export class DacFxService implements IDacFxService { export class DacFxService implements IDacFxService {
@@ -61,6 +62,12 @@ export class DacFxService implements IDacFxService {
}); });
} }
generateDeployScript(packageFilePath: string, databaseName: string, generateDeployScript: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> {
return this._runAction(ownerUri, (runner) => {
return runner.generateDeployScript(packageFilePath, databaseName, generateDeployScript, ownerUri, taskExecutionMode);
});
}
private _runAction<T>(uri: string, action: (handler: sqlops.DacFxServicesProvider) => Thenable<T>): Thenable<T> { private _runAction<T>(uri: string, action: (handler: sqlops.DacFxServicesProvider) => Thenable<T>): Thenable<T> {
let providerId: string = this._connectionService.getProviderIdFromUri(uri); let providerId: string = this._connectionService.getProviderIdFromUri(uri);

9
src/sql/sqlops.d.ts vendored
View File

@@ -1626,11 +1626,20 @@ declare module 'sqlops' {
taskExecutionMode: TaskExecutionMode; taskExecutionMode: TaskExecutionMode;
} }
export interface GenerateDeployScriptParams {
packageFilePath: string;
databaseName: string;
scriptFilePath: string;
ownerUri: string;
taskExecutionMode: TaskExecutionMode;
}
export interface DacFxServicesProvider extends DataProvider { export interface DacFxServicesProvider extends DataProvider {
exportBacpac(databaseName: string, packageFilePath: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>; exportBacpac(databaseName: string, packageFilePath: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>;
importBacpac(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>; importBacpac(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>;
extractDacpac(databaseName: string, packageFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>; extractDacpac(databaseName: string, packageFilePath: string, applicationName: string, applicationVersion: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>;
deployDacpac(packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>; deployDacpac(packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>;
generateDeployScript(packageFilePath: string, databaseName: string, scriptFilePath: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<DacFxResult>;
} }
// Security service interfaces ------------------------------------------------------------------------ // Security service interfaces ------------------------------------------------------------------------

View File

@@ -415,6 +415,9 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
}, },
deployDacpac(packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> { deployDacpac(packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> {
return self._proxy.$deployDacpac(handle, packageFilePath, databaseName, upgradeExisting, ownerUri, taskExecutionMode); return self._proxy.$deployDacpac(handle, packageFilePath, databaseName, upgradeExisting, ownerUri, taskExecutionMode);
},
generateDeployScript(packageFilePath: string, databaseName: string, scriptFilePath: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> {
return self._proxy.$generateDeployScript(handle, packageFilePath, databaseName, scriptFilePath, ownerUri, taskExecutionMode);
} }
}); });

View File

@@ -440,6 +440,12 @@ export abstract class ExtHostDataProtocolShape {
* DacFx deploy dacpac * DacFx deploy dacpac
*/ */
$deployDacpac(handle: number, packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> { throw ni(); } $deployDacpac(handle: number, packageFilePath: string, databaseName: string, upgradeExisting: boolean, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> { throw ni(); }
/**
* DacFx generate deploy script
*/
$generateDeployScript(handle: number, packageFilePath: string, databaseName: string, scriptFilePath: string, ownerUri: string, taskExecutionMode: sqlops.TaskExecutionMode): Thenable<sqlops.DacFxResult> { throw ni(); }
} }
/** /**