mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
176
extensions/import/src/wizard/pages/deployActionPage.ts
Normal file
176
extensions/import/src/wizard/pages/deployActionPage.ts
Normal 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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 > ------------------------------------
|
||||||
@@ -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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
9
src/sql/sqlops.d.ts
vendored
@@ -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 ------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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(); }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user