mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Add option to save Publish profile in VScode (#23067)
* Publish profile save changes for VSCode * Fix publish settings * Fix publish settings * Address comments * Address comments * Address comments * Address comment
This commit is contained in:
@@ -167,6 +167,7 @@ export const selectDatabase = localize('selectDatabase', "Select database");
|
||||
export const done = localize('done', "Done");
|
||||
export const nameMustNotBeEmpty = localize('nameMustNotBeEmpty', "Name must not be empty");
|
||||
export const versionMustNotBeEmpty = localize('versionMustNotBeEmpty', "Version must not be empty");
|
||||
export const saveProfile = localize('saveProfile', "Would you like to save the settings in a profile (.publish.xml)?");
|
||||
|
||||
//#endregion
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import { ImportDataModel } from '../models/api/import';
|
||||
import { NetCoreTool, DotNetError } from '../tools/netcoreTool';
|
||||
import { ShellCommandOptions } from '../tools/shellExecutionHelper';
|
||||
import { BuildHelper } from '../tools/buildHelper';
|
||||
import { readPublishProfile, savePublishProfile } from '../models/publishProfile/publishProfile';
|
||||
import { readPublishProfile, promptForSavingProfile, savePublishProfile } from '../models/publishProfile/publishProfile';
|
||||
import { AddDatabaseReferenceDialog } from '../dialogs/addDatabaseReferenceDialog';
|
||||
import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectReferenceSettings, INugetPackageReferenceSettings } from '../models/IDatabaseReferenceSettings';
|
||||
import { DatabaseReferenceTreeItem } from '../models/tree/databaseReferencesTreeItem';
|
||||
@@ -474,6 +474,7 @@ export class ProjectsController {
|
||||
|
||||
if (publishTarget === constants.PublishTargetType.docker) {
|
||||
const publishToDockerSettings = await getPublishToDockerSettings(project);
|
||||
void promptForSavingProfile(project, publishToDockerSettings); // not awaiting this call, because saving profile should not stop the actual publish workflow
|
||||
if (!publishToDockerSettings) {
|
||||
// User cancelled
|
||||
return;
|
||||
@@ -482,6 +483,7 @@ export class ProjectsController {
|
||||
} else if (publishTarget === constants.PublishTargetType.newAzureServer) {
|
||||
try {
|
||||
const settings = await launchCreateAzureServerQuickPick(project, this.azureSqlClient);
|
||||
void promptForSavingProfile(project, settings); // not awaiting this call, because saving profile should not stop the actual publish workflow
|
||||
if (settings?.deploySettings && settings?.sqlDbSetting) {
|
||||
await this.publishToNewAzureServer(project, settings);
|
||||
}
|
||||
@@ -492,6 +494,7 @@ export class ProjectsController {
|
||||
} else {
|
||||
let settings: ISqlProjectPublishSettings | undefined = await getPublishDatabaseSettings(project);
|
||||
|
||||
void promptForSavingProfile(project, settings); // not awaiting this call, because saving profile should not stop the actual publish workflow
|
||||
if (settings) {
|
||||
// 5. Select action to take
|
||||
const action = await vscode.window.showQuickPick(
|
||||
@@ -537,7 +540,7 @@ export class ProjectsController {
|
||||
const dacFxService = await utils.getDacFxService();
|
||||
|
||||
let result: mssql.DacFxResult;
|
||||
telemetryProps.profileUsed = (settings.profileUsed ?? false).toString();
|
||||
telemetryProps.profileUsed = (settings.publishProfileUri !== undefined ? true : false).toString();
|
||||
const currentDate = new Date();
|
||||
const actionStartTime = currentDate.getTime();
|
||||
const currentPublishTimeInfo = `${currentDate.toLocaleDateString()} ${constants.at} ${currentDate.toLocaleTimeString()}`;
|
||||
|
||||
@@ -20,7 +20,7 @@ import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/t
|
||||
import { Deferred } from '../common/promise';
|
||||
import { PublishOptionsDialog } from './publishOptionsDialog';
|
||||
import { IPublishToDockerSettings, ISqlProjectPublishSettings } from '../models/deploy/publishSettings';
|
||||
import { PublishProfile } from '../models/publishProfile/publishProfile';
|
||||
import { PublishProfile, promptToSaveProfile } from '../models/publishProfile/publishProfile';
|
||||
|
||||
interface DataSourceDropdownValue extends azdataType.CategoryValue {
|
||||
dataSource: SqlConnectionDataSource;
|
||||
@@ -56,7 +56,6 @@ export class PublishDatabaseDialog {
|
||||
private connectionIsDataSource: boolean | undefined;
|
||||
private sqlCmdVars: Map<string, string> | undefined;
|
||||
private deploymentOptions: DeploymentOptions | undefined;
|
||||
private profileUsed: boolean = false;
|
||||
private serverName: string | undefined;
|
||||
protected optionsButton: azdataType.ButtonComponent | undefined;
|
||||
private publishOptionsDialog: PublishOptionsDialog | undefined;
|
||||
@@ -240,7 +239,7 @@ export class PublishDatabaseDialog {
|
||||
connectionUri: await this.getConnectionUri(),
|
||||
sqlCmdVariables: this.getSqlCmdVariablesForPublish(),
|
||||
deploymentOptions: await this.getDeploymentOptions(),
|
||||
profileUsed: this.profileUsed
|
||||
publishProfileUri: this.publishProfileUri
|
||||
};
|
||||
|
||||
utils.getAzdataApi()!.window.closeDialog(this.dialog);
|
||||
@@ -273,7 +272,7 @@ export class PublishDatabaseDialog {
|
||||
connectionUri: '',
|
||||
sqlCmdVariables: this.getSqlCmdVariablesForPublish(),
|
||||
deploymentOptions: await this.getDeploymentOptions(),
|
||||
profileUsed: this.profileUsed
|
||||
publishProfileUri: this.publishProfileUri
|
||||
}
|
||||
};
|
||||
|
||||
@@ -294,7 +293,7 @@ export class PublishDatabaseDialog {
|
||||
connectionUri: await this.getConnectionUri(),
|
||||
sqlCmdVariables: sqlCmdVars,
|
||||
deploymentOptions: await this.getDeploymentOptions(),
|
||||
profileUsed: this.profileUsed
|
||||
publishProfileUri: this.publishProfileUri
|
||||
};
|
||||
|
||||
utils.getAzdataApi()!.window.closeDialog(this.dialog);
|
||||
@@ -831,7 +830,6 @@ export class PublishDatabaseDialog {
|
||||
this.loadProfileTextBox!.value = fileUris[0].fsPath;
|
||||
await this.loadProfileTextBox!.updateProperty('title', fileUris[0].fsPath);
|
||||
|
||||
this.profileUsed = true;
|
||||
this.publishProfileUri = fileUris[0];
|
||||
}
|
||||
});
|
||||
@@ -850,15 +848,7 @@ export class PublishDatabaseDialog {
|
||||
}).component();
|
||||
|
||||
saveProfileAsButton.onDidClick(async () => {
|
||||
const filePath = await vscode.window.showSaveDialog(
|
||||
{
|
||||
defaultUri: this.publishProfileUri ?? vscode.Uri.file(path.join(this.project.projectFolderPath, `${this.project.projectFileName}_1.publish.xml`)),
|
||||
saveLabel: constants.save,
|
||||
filters: {
|
||||
'Publish Settings Files': ['publish.xml'],
|
||||
}
|
||||
}
|
||||
);
|
||||
const filePath = await promptToSaveProfile(this.project, this.publishProfileUri);
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
@@ -873,7 +863,6 @@ export class PublishDatabaseDialog {
|
||||
TelemetryReporter.sendActionEvent(TelemetryViews.SqlProjectPublishDialog, TelemetryActions.profileSaved);
|
||||
}
|
||||
|
||||
this.profileUsed = true;
|
||||
this.publishProfileUri = filePath;
|
||||
|
||||
await this.project.addNoneItem(path.relative(this.project.projectFolderPath, filePath.fsPath));
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ISqlProjectPublishSettings } from '../models/deploy/publishSettings';
|
||||
export async function getPublishDatabaseSettings(project: ISqlProject, promptForConnection: boolean = true): Promise<ISqlProjectPublishSettings | undefined> {
|
||||
|
||||
// 1. Select publish settings file (optional)
|
||||
let publishProfileUri;
|
||||
// Create custom quickpick so we can control stuff like displaying the loading indicator
|
||||
const quickPick = vscode.window.createQuickPick();
|
||||
quickPick.items = [{ label: constants.dontUseProfile }, { label: constants.browseForProfileWithIcon }];
|
||||
@@ -42,7 +43,7 @@ export async function getPublishDatabaseSettings(project: ISqlProject, promptFor
|
||||
// If the user cancels out of the file picker then just return and let them choose another option
|
||||
return;
|
||||
}
|
||||
let publishProfileUri = locations[0];
|
||||
publishProfileUri = locations[0];
|
||||
try {
|
||||
// Show loading state while reading profile
|
||||
quickPick.busy = true;
|
||||
@@ -214,7 +215,7 @@ export async function getPublishDatabaseSettings(project: ISqlProject, promptFor
|
||||
connectionUri: connectionUri || '',
|
||||
sqlCmdVariables: sqlCmdVariables,
|
||||
deploymentOptions: publishProfile?.options ?? await getDefaultPublishDeploymentOptions(project),
|
||||
profileUsed: !!publishProfile
|
||||
publishProfileUri: publishProfileUri
|
||||
};
|
||||
return settings;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { ISqlConnectionProperties } from 'sqldbproj';
|
||||
import { DeploymentOptions as mssqlDeploymentOptions } from 'mssql';
|
||||
import { DeploymentOptions as vscodeMssqlDeploymentOptions } from 'vscode-mssql';
|
||||
@@ -18,7 +19,7 @@ export interface ISqlProjectPublishSettings {
|
||||
connectionUri: string;
|
||||
sqlCmdVariables?: Map<string, string>;
|
||||
deploymentOptions?: DeploymentOptions;
|
||||
profileUsed?: boolean;
|
||||
publishProfileUri?: vscode.Uri;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,10 +9,14 @@ import * as utils from '../../common/utils';
|
||||
import * as mssql from 'mssql';
|
||||
import * as vscodeMssql from 'vscode-mssql';
|
||||
import * as vscode from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
import { promises as fs } from 'fs';
|
||||
import { SqlConnectionDataSource } from '../dataSources/sqlConnectionStringSource';
|
||||
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../../common/telemetry';
|
||||
import { Project } from '../project';
|
||||
import { IPublishToDockerSettings, ISqlProjectPublishSettings } from '../deploy/publishSettings';
|
||||
import { ISqlDbDeployProfile } from '../deploy/deployProfile';
|
||||
|
||||
// only reading db name, connection string, and SQLCMD vars from profile for now
|
||||
export interface PublishProfile {
|
||||
@@ -129,7 +133,181 @@ async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string
|
||||
/**
|
||||
* saves publish settings to the specified profile file
|
||||
*/
|
||||
export async function savePublishProfile(profilePath: string, databaseName: string, connectionString: string, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions): Promise<void> {
|
||||
export async function savePublishProfile(profilePath: string, databaseName: string, connectionString: string, sqlCommandVariableValues?: Map<string, string>, deploymentOptions?: mssql.DeploymentOptions | vscodeMssql.DeploymentOptions): Promise<void> {
|
||||
const dacFxService = await utils.getDacFxService();
|
||||
await dacFxService.savePublishProfile(profilePath, databaseName, connectionString, sqlCommandVariableValues, deploymentOptions);
|
||||
if (utils.getAzdataApi()) {
|
||||
await (dacFxService as mssql.IDacFxService).savePublishProfile(profilePath, databaseName, connectionString, sqlCommandVariableValues, deploymentOptions as mssql.DeploymentOptions);
|
||||
} else {
|
||||
await (dacFxService as vscodeMssql.IDacFxService).savePublishProfile(profilePath, databaseName, connectionString, sqlCommandVariableValues, deploymentOptions as vscodeMssql.DeploymentOptions);
|
||||
}
|
||||
}
|
||||
|
||||
export function promptToSaveProfile(project: Project, publishProfileUri?: vscode.Uri) {
|
||||
return vscode.window.showSaveDialog(
|
||||
{
|
||||
defaultUri: publishProfileUri ?? vscode.Uri.file(path.join(project.projectFolderPath, `${project.projectFileName}_1.publish.xml`)),
|
||||
saveLabel: constants.save,
|
||||
filters: {
|
||||
'Publish files': ['publish.xml'],
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt to save publish profile and add to the tree
|
||||
* @param project
|
||||
* @param settings Publish settings
|
||||
* @returns
|
||||
*/
|
||||
export async function promptForSavingProfile(project: Project, settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined) {
|
||||
const result = await vscode.window.showInformationMessage(constants.saveProfile, constants.yesString, constants.noString);
|
||||
if (result === constants.yesString) {
|
||||
let publishProfileUri: vscode.Uri | undefined;
|
||||
if (settings) {
|
||||
if (isISqlProjectPublishSettings(settings)) {
|
||||
publishProfileUri = settings.publishProfileUri;
|
||||
} else if (isISqlDbDeployProfile(settings)) {
|
||||
publishProfileUri = settings.deploySettings?.publishProfileUri;
|
||||
} else if (isIPublishToDockerSettings(settings)) {
|
||||
publishProfileUri = settings.sqlProjectPublishSettings.publishProfileUri;
|
||||
}
|
||||
}
|
||||
const filePath = await promptToSaveProfile(project, publishProfileUri);
|
||||
|
||||
if (!filePath) {
|
||||
return;
|
||||
}
|
||||
|
||||
const targetConnectionString = await getConnectionString(settings);
|
||||
const targetDatabaseName = getDatabaseName(settings, project.projectFileName);
|
||||
const deploymentOptions = await getDeploymentOptions(settings, project);
|
||||
const sqlCmdVariables = getSqlCmdVariables(settings);
|
||||
await savePublishProfile(filePath.fsPath, targetDatabaseName, targetConnectionString, sqlCmdVariables, deploymentOptions);
|
||||
|
||||
setProfileParameters(settings, filePath);
|
||||
|
||||
await project.addNoneItem(path.relative(project.projectFolderPath, filePath.fsPath));
|
||||
void vscode.commands.executeCommand(constants.refreshDataWorkspaceCommand); //refresh data workspace to load the newly added profile to the tree
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to confirm the Publish to existing server workflow
|
||||
* @param settings
|
||||
* @returns true if the settings is of type ISqlProjectPublishSettings
|
||||
*/
|
||||
function isISqlProjectPublishSettings(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined): settings is ISqlProjectPublishSettings {
|
||||
if ((settings as ISqlProjectPublishSettings).connectionUri) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to confirm the Publish to New Azure server workflow
|
||||
* @param settings
|
||||
* @returns true if the settings is of type ISqlDbDeployProfile
|
||||
*/
|
||||
function isISqlDbDeployProfile(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined): settings is ISqlDbDeployProfile {
|
||||
if ((settings as ISqlDbDeployProfile).deploySettings) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to confirm the Publish to Docker workflow
|
||||
* @param settings
|
||||
* @returns true if the settings is of type IPublishToDockerSettings
|
||||
*/
|
||||
function isIPublishToDockerSettings(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined): settings is IPublishToDockerSettings {
|
||||
if ((settings as IPublishToDockerSettings).dockerSettings) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
async function getConnectionString(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined): Promise<string> {
|
||||
let connectionUri: string = '';
|
||||
let connectionString: string = '';
|
||||
|
||||
if (settings) {
|
||||
if (isISqlProjectPublishSettings(settings)) {
|
||||
connectionUri = settings.connectionUri;
|
||||
} else if (isISqlDbDeployProfile(settings)) {
|
||||
connectionUri = settings.deploySettings?.connectionUri ?? '';
|
||||
} else if (isIPublishToDockerSettings(settings)) {
|
||||
connectionUri = settings.sqlProjectPublishSettings.connectionUri;
|
||||
}
|
||||
}
|
||||
|
||||
if (connectionUri) {
|
||||
connectionString = await (await utils.getVscodeMssqlApi()).getConnectionString(connectionUri, false);
|
||||
}
|
||||
return connectionString;
|
||||
}
|
||||
|
||||
function getDatabaseName(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined, projectName: string): string {
|
||||
let databaseName: string = projectName;
|
||||
|
||||
if (settings) {
|
||||
if (isISqlProjectPublishSettings(settings)) {
|
||||
databaseName = settings.databaseName;
|
||||
} else if (isISqlDbDeployProfile(settings)) {
|
||||
databaseName = settings.deploySettings?.databaseName ?? '';
|
||||
} else if (isIPublishToDockerSettings(settings)) {
|
||||
databaseName = settings.sqlProjectPublishSettings.databaseName;
|
||||
}
|
||||
}
|
||||
|
||||
return databaseName;
|
||||
}
|
||||
|
||||
async function getDeploymentOptions(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined, project: Project): Promise<vscodeMssql.DeploymentOptions | undefined> {
|
||||
let deploymentOptions: vscodeMssql.DeploymentOptions | undefined;
|
||||
|
||||
if (settings) {
|
||||
if (isISqlProjectPublishSettings(settings)) {
|
||||
deploymentOptions = settings.deploymentOptions;
|
||||
} else if (isISqlDbDeployProfile(settings)) {
|
||||
deploymentOptions = settings.deploySettings?.deploymentOptions;
|
||||
} else if (isIPublishToDockerSettings(settings)) {
|
||||
deploymentOptions = settings.sqlProjectPublishSettings.deploymentOptions;
|
||||
}
|
||||
} else {
|
||||
deploymentOptions = await utils.getDefaultPublishDeploymentOptions(project);
|
||||
}
|
||||
|
||||
return deploymentOptions;
|
||||
}
|
||||
|
||||
function getSqlCmdVariables(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined): Map<string, string> | undefined {
|
||||
let sqlCmdVariables: Map<string, string> | undefined;
|
||||
|
||||
if (settings) {
|
||||
if (isISqlProjectPublishSettings(settings)) {
|
||||
sqlCmdVariables = settings.sqlCmdVariables;
|
||||
} else if (isISqlDbDeployProfile(settings)) {
|
||||
sqlCmdVariables = settings.deploySettings?.sqlCmdVariables;
|
||||
} else if (isIPublishToDockerSettings(settings)) {
|
||||
sqlCmdVariables = settings.sqlProjectPublishSettings.sqlCmdVariables;
|
||||
}
|
||||
}
|
||||
|
||||
return sqlCmdVariables;
|
||||
}
|
||||
|
||||
function setProfileParameters(settings: ISqlProjectPublishSettings | ISqlDbDeployProfile | IPublishToDockerSettings | undefined, profilePath: vscode.Uri) {
|
||||
if (settings) {
|
||||
if (isISqlProjectPublishSettings(settings)) {
|
||||
settings.publishProfileUri = profilePath;
|
||||
} else if (isISqlDbDeployProfile(settings)) {
|
||||
if (settings.deploySettings) {
|
||||
settings.deploySettings.publishProfileUri = profilePath;
|
||||
}
|
||||
} else if (isIPublishToDockerSettings(settings)) {
|
||||
settings.sqlProjectPublishSettings.publishProfileUri = profilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,8 +87,7 @@ describe('Publish Database Dialog', () => {
|
||||
['ProdDatabaseName', 'MyProdDatabase'],
|
||||
['BackupDatabaseName', 'MyBackupDatabase']
|
||||
]),
|
||||
deploymentOptions: mockDacFxOptionsResult.deploymentOptions,
|
||||
profileUsed: false
|
||||
deploymentOptions: mockDacFxOptionsResult.deploymentOptions
|
||||
};
|
||||
|
||||
dialog.object.publish = (_, prof) => { profile = prof; };
|
||||
@@ -104,8 +103,7 @@ describe('Publish Database Dialog', () => {
|
||||
['ProdDatabaseName', 'MyProdDatabase'],
|
||||
['BackupDatabaseName', 'MyBackupDatabase']
|
||||
]),
|
||||
deploymentOptions: mockDacFxOptionsResult.deploymentOptions,
|
||||
profileUsed: false
|
||||
deploymentOptions: mockDacFxOptionsResult.deploymentOptions
|
||||
};
|
||||
|
||||
dialog.object.generateScript = (_, prof) => { profile = prof; };
|
||||
@@ -132,8 +130,7 @@ describe('Publish Database Dialog', () => {
|
||||
['ProdDatabaseName', 'MyProdDatabase'],
|
||||
['BackupDatabaseName', 'MyBackupDatabase']
|
||||
]),
|
||||
deploymentOptions: mockDacFxOptionsResult.deploymentOptions,
|
||||
profileUsed: false
|
||||
deploymentOptions: mockDacFxOptionsResult.deploymentOptions
|
||||
}
|
||||
};
|
||||
dialog.object.publishToExistingServer = false;
|
||||
|
||||
Reference in New Issue
Block a user