mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-26 17:23:15 -05:00
Add publish profile to sql proj and tree (#22008)
* Read publish profiles stored in sqlproj file and present it in the projects tree * Save publish profile and add it to sqlproj file, and present it in the tree * Fix context menu operations * Add tests * Address comments
This commit is contained in:
@@ -14,6 +14,7 @@ const localize = nls.loadMessageBundle();
|
||||
export const dataSourcesFileName = 'datasources.json';
|
||||
export const sqlprojExtension = '.sqlproj';
|
||||
export const sqlFileExtension = '.sql';
|
||||
export const publishProfileExtension = '.publish.xml';
|
||||
export const openApiSpecFileExtensions = ['yaml', 'yml', 'json'];
|
||||
export const schemaCompareExtensionId = 'microsoft.schema-compare';
|
||||
export const master = 'master';
|
||||
@@ -485,6 +486,7 @@ export const ImportElements = localize('importElements', "Import Elements");
|
||||
export const ProjectReferenceNameElement = localize('projectReferenceNameElement', "Project reference name element");
|
||||
export const ProjectReferenceElement = localize('projectReferenceElement', "Project reference");
|
||||
export const DacpacReferenceElement = localize('dacpacReferenceElement', "Dacpac reference");
|
||||
export const PublishProfileElements = localize('publishProfileElements', "Publish profile elements");
|
||||
|
||||
/** Name of the property item in the project file that defines default database collation. */
|
||||
export const DefaultCollationProperty = 'DefaultCollation';
|
||||
|
||||
@@ -771,3 +771,13 @@ export function isValidBasename(name?: string): boolean {
|
||||
export function isValidBasenameErrorMessage(name?: string): string {
|
||||
return getDataWorkspaceExtensionApi().isValidBasenameErrorMessage(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the provided file is a publish profile
|
||||
* @param fileName filename to check
|
||||
* @returns True if it is a publish profile, otherwise false
|
||||
*/
|
||||
export function isPublishProfile(fileName: string): boolean {
|
||||
const hasPublishExtension = fileName.trim().toLowerCase().endsWith(constants.publishProfileExtension);
|
||||
return hasPublishExtension;
|
||||
}
|
||||
|
||||
@@ -1444,7 +1444,7 @@ export class ProjectsController {
|
||||
|
||||
if (fileOrFolder) {
|
||||
// use relative path and not tree paths for files and folder
|
||||
const allFileEntries = project.files.concat(project.preDeployScripts).concat(project.postDeployScripts).concat(project.noneDeployScripts);
|
||||
const allFileEntries = project.files.concat(project.preDeployScripts).concat(project.postDeployScripts).concat(project.noneDeployScripts).concat(project.publishProfiles);
|
||||
|
||||
// trim trailing slash since folders with and without a trailing slash are allowed in a sqlproj
|
||||
const trimmedUri = utils.trimChars(utils.getPlatformSafeFileEntryPath(utils.trimUri(fileOrFolder.projectFileUri, fileOrFolder.fileSystemUri)), '/');
|
||||
|
||||
@@ -947,6 +947,9 @@ export class PublishDatabaseDialog {
|
||||
|
||||
this.profileUsed = true;
|
||||
this.publishProfileUri = filePath;
|
||||
|
||||
await this.project.addPublishProfileToProjFile(filePath.fsPath);
|
||||
void vscode.commands.executeCommand(constants.refreshDataWorkspaceCommand); //refresh data workspace to load the newly added profile to the tree
|
||||
});
|
||||
|
||||
return saveProfileAsButton;
|
||||
|
||||
@@ -46,6 +46,7 @@ export class Project implements ISqlProject {
|
||||
private _isSdkStyleProject: boolean = false; // https://docs.microsoft.com/en-us/dotnet/core/project-sdk/overview
|
||||
private _outputPath: string = '';
|
||||
private _configuration: Configuration = Configuration.Debug;
|
||||
private _publishProfiles: FileProjectEntry[] = [];
|
||||
|
||||
public get dacpacOutputPath(): string {
|
||||
return path.join(this.outputPath, `${this._projectFileName}.dacpac`);
|
||||
@@ -111,6 +112,10 @@ export class Project implements ISqlProject {
|
||||
return this._configuration;
|
||||
}
|
||||
|
||||
public get publishProfiles(): FileProjectEntry[] {
|
||||
return this._publishProfiles;
|
||||
}
|
||||
|
||||
private projFileXmlDoc: Document | undefined = undefined;
|
||||
|
||||
constructor(projectFilePath: string) {
|
||||
@@ -153,6 +158,9 @@ export class Project implements ISqlProject {
|
||||
this._databaseReferences = this.readDatabaseReferences();
|
||||
this._importedTargets = this.readImportedTargets();
|
||||
|
||||
// get publish profiles specified in the sqlproj
|
||||
this._publishProfiles = this.readPublishProfiles();
|
||||
|
||||
// find all SQLCMD variables to include
|
||||
try {
|
||||
this._sqlCmdVariables = utils.readSqlCmdVariables(this.projFileXmlDoc, false);
|
||||
@@ -468,7 +476,7 @@ export class Project implements ISqlProject {
|
||||
const noneItems = itemGroup.getElementsByTagName(constants.None);
|
||||
for (let n = 0; n < noneItems.length; n++) {
|
||||
const includeAttribute = noneItems[n].getAttribute(constants.Include);
|
||||
if (includeAttribute) {
|
||||
if (includeAttribute && !utils.isPublishProfile(includeAttribute)) {
|
||||
noneDeployScripts.push(this.createFileProjectEntry(includeAttribute, EntryType.File));
|
||||
}
|
||||
}
|
||||
@@ -505,6 +513,34 @@ export class Project implements ISqlProject {
|
||||
return noneRemoveScripts;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @returns all the publish profiles (ending with *.publish.xml) specified as <None Include="file.publish.xml" /> in the sqlproj
|
||||
*/
|
||||
private readPublishProfiles(): FileProjectEntry[] {
|
||||
const publishProfiles: FileProjectEntry[] = [];
|
||||
|
||||
for (let ig = 0; ig < this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ItemGroup).length; ig++) {
|
||||
const itemGroup = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ItemGroup)[ig];
|
||||
|
||||
// find all publish profile scripts to include
|
||||
try {
|
||||
const noneItems = itemGroup.getElementsByTagName(constants.None);
|
||||
for (let n = 0; n < noneItems.length; n++) {
|
||||
const includeAttribute = noneItems[n].getAttribute(constants.Include);
|
||||
if (includeAttribute && utils.isPublishProfile(includeAttribute)) {
|
||||
publishProfiles.push(this.createFileProjectEntry(includeAttribute, EntryType.File));
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
void window.showErrorMessage(constants.errorReadingProject(constants.PublishProfileElements, this.projectFilePath));
|
||||
console.error(utils.getErrorMessage(e));
|
||||
}
|
||||
}
|
||||
|
||||
return publishProfiles;
|
||||
}
|
||||
|
||||
private readDatabaseReferences(): IDatabaseReferenceProjectEntry[] {
|
||||
const databaseReferenceEntries: IDatabaseReferenceProjectEntry[] = [];
|
||||
|
||||
@@ -949,18 +985,19 @@ export class Project implements ISqlProject {
|
||||
}
|
||||
|
||||
public async exclude(entry: FileProjectEntry): Promise<void> {
|
||||
const toExclude: FileProjectEntry[] = this._files.concat(this._preDeployScripts).concat(this._postDeployScripts).concat(this._noneDeployScripts).filter(x => x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
const toExclude: FileProjectEntry[] = this._files.concat(this._preDeployScripts).concat(this._postDeployScripts).concat(this._noneDeployScripts).concat(this._publishProfiles).filter(x => x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
await this.removeFromProjFile(toExclude);
|
||||
|
||||
this._files = this._files.filter(x => !x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
this._preDeployScripts = this._preDeployScripts.filter(x => !x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
this._postDeployScripts = this._postDeployScripts.filter(x => !x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
this._noneDeployScripts = this._noneDeployScripts.filter(x => !x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
this._publishProfiles = this._publishProfiles.filter(x => !x.fsUri.fsPath.startsWith(entry.fsUri.fsPath));
|
||||
}
|
||||
|
||||
public async deleteFileFolder(entry: FileProjectEntry): Promise<void> {
|
||||
// compile a list of folder contents to delete; if entry is a file, contents will contain only itself
|
||||
const toDeleteFiles: FileProjectEntry[] = this._files.concat(this._preDeployScripts).concat(this._postDeployScripts).concat(this._noneDeployScripts).filter(x => x.fsUri.fsPath.startsWith(entry.fsUri.fsPath) && x.type === EntryType.File);
|
||||
const toDeleteFiles: FileProjectEntry[] = this._files.concat(this._preDeployScripts).concat(this._postDeployScripts).concat(this._noneDeployScripts).concat(this._publishProfiles).filter(x => x.fsUri.fsPath.startsWith(entry.fsUri.fsPath) && x.type === EntryType.File);
|
||||
const toDeleteFolders: FileProjectEntry[] = this._files.filter(x => x.fsUri.fsPath.startsWith(entry.fsUri.fsPath) && x.type === EntryType.Folder);
|
||||
|
||||
await Promise.all(toDeleteFiles.map(x => fs.unlink(x.fsUri.fsPath)));
|
||||
@@ -1165,6 +1202,24 @@ export class Project implements ISqlProject {
|
||||
return this.getCollectionProjectPropertyValue(constants.DatabaseSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds publish profile to the project
|
||||
*
|
||||
* @param relativeFilePath Relative path of the file
|
||||
*/
|
||||
public async addPublishProfileToProjFile(absolutePublishProfilePath: string): Promise<FileProjectEntry> {
|
||||
const relativePublishProfilePath = (utils.trimUri(Uri.file(this.projectFilePath), Uri.file(absolutePublishProfilePath)));
|
||||
|
||||
// Update sqlproj XML
|
||||
|
||||
const fileEntry = this.createFileProjectEntry(relativePublishProfilePath, EntryType.File);
|
||||
this._publishProfiles.push(fileEntry);
|
||||
|
||||
await this.addToProjFile(fileEntry, constants.None);
|
||||
|
||||
return fileEntry;
|
||||
}
|
||||
|
||||
public createFileProjectEntry(relativePath: string, entryType: EntryType, sqlObjectType?: string, containsCreateTableStatement?: boolean): FileProjectEntry {
|
||||
let platformSafeRelativePath = utils.getPlatformSafeFileEntryPath(relativePath);
|
||||
return new FileProjectEntry(
|
||||
@@ -1176,7 +1231,8 @@ export class Project implements ISqlProject {
|
||||
}
|
||||
|
||||
private findOrCreateItemGroup(containedTag?: string, prePostScriptExist?: { scriptExist: boolean; }): Element {
|
||||
let outputItemGroup = undefined;
|
||||
let outputItemGroup: Element[] = []; // "None" can have more than one ItemGroup, for "None Include" (for pre/post deploy scripts and publish profiles), "None Remove"
|
||||
let returnItemGroup;
|
||||
|
||||
// search for a particular item goup if a child type is provided
|
||||
if (containedTag) {
|
||||
@@ -1184,25 +1240,45 @@ export class Project implements ISqlProject {
|
||||
for (let ig = 0; ig < this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ItemGroup).length; ig++) {
|
||||
const currentItemGroup = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ItemGroup)[ig];
|
||||
|
||||
// if we find the tag, use the ItemGroup
|
||||
if (currentItemGroup.getElementsByTagName(containedTag).length > 0) {
|
||||
outputItemGroup = currentItemGroup;
|
||||
break;
|
||||
outputItemGroup.push(currentItemGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if none already exist, make a new ItemGroup for it
|
||||
if (!outputItemGroup) {
|
||||
outputItemGroup = this.projFileXmlDoc!.createElement(constants.ItemGroup);
|
||||
this.projFileXmlDoc!.documentElement.appendChild(outputItemGroup);
|
||||
if (outputItemGroup.length === 0) {
|
||||
returnItemGroup = this.projFileXmlDoc!.createElement(constants.ItemGroup);
|
||||
this.projFileXmlDoc!.documentElement.appendChild(returnItemGroup);
|
||||
|
||||
if (prePostScriptExist) {
|
||||
prePostScriptExist.scriptExist = false;
|
||||
}
|
||||
} else { // if item group exists and containedTag = None, read the content to find None Include with publish profile
|
||||
if (containedTag === constants.None) {
|
||||
for (let ig = 0; ig < outputItemGroup.length; ig++) {
|
||||
const itemGroup = outputItemGroup[ig];
|
||||
|
||||
// find all none include scripts specified in the sqlproj
|
||||
const noneItems = itemGroup.getElementsByTagName(constants.None);
|
||||
for (let n = 0; n < noneItems.length; n++) {
|
||||
let noneIncludeItem = noneItems[n].getAttribute(constants.Include);
|
||||
if (noneIncludeItem && utils.isPublishProfile(noneIncludeItem)) {
|
||||
returnItemGroup = itemGroup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!returnItemGroup) {
|
||||
returnItemGroup = this.projFileXmlDoc!.createElement(constants.ItemGroup);
|
||||
this.projFileXmlDoc!.documentElement.appendChild(returnItemGroup);
|
||||
}
|
||||
} else {
|
||||
returnItemGroup = outputItemGroup[0]; // Return the first item group that was found, to match prior implementation
|
||||
}
|
||||
}
|
||||
|
||||
return outputItemGroup;
|
||||
return returnItemGroup;
|
||||
}
|
||||
|
||||
private async addFileToProjFile(filePath: string, xmlTag: string, attributes?: Map<string, string>): Promise<void> {
|
||||
@@ -1220,6 +1296,8 @@ export class Project implements ISqlProject {
|
||||
void window.showInformationMessage(constants.deployScriptExists(xmlTag));
|
||||
xmlTag = constants.None; // Add only one pre-deploy and post-deploy script. All additional ones get added in the same item group with None tag
|
||||
}
|
||||
} else if (xmlTag === constants.None) { // Add publish profiles with None tag
|
||||
itemGroup = this.findOrCreateItemGroup(xmlTag);
|
||||
}
|
||||
else {
|
||||
if (this.isSdkStyleProject) {
|
||||
@@ -1260,7 +1338,7 @@ export class Project implements ISqlProject {
|
||||
itemGroup.appendChild(newFileNode);
|
||||
}
|
||||
|
||||
private async removeFileFromProjFile(path: string): Promise<void> {
|
||||
private async removeFileFromProjFile(path: string): Promise<void> {//TODO: publish profile
|
||||
const fileNodes = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.Build);
|
||||
const preDeployNodes = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.PreDeploy);
|
||||
const postDeployNodes = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.PostDeploy);
|
||||
|
||||
@@ -65,7 +65,8 @@ export class ProjectRootTreeItem extends BaseProjectTreeItem {
|
||||
let treeItemList = this.project.files
|
||||
.concat(this.project.preDeployScripts)
|
||||
.concat(this.project.postDeployScripts)
|
||||
.concat(this.project.noneDeployScripts);
|
||||
.concat(this.project.noneDeployScripts)
|
||||
.concat(this.project.publishProfiles);
|
||||
|
||||
for (const entry of treeItemList) {
|
||||
if (entry.type !== EntryType.File && entry.relativePath.startsWith(RelativeOuterPath)) {
|
||||
|
||||
@@ -40,6 +40,7 @@ export let openSdkStyleSqlProjectWithFilesSpecifiedBaseline: string;
|
||||
export let openSdkStyleSqlProjectWithGlobsSpecifiedBaseline: string;
|
||||
export let openSdkStyleSqlProjectWithBuildRemoveBaseline: string;
|
||||
export let openSdkStyleSqlProjectNoProjectGuidBaseline: string;
|
||||
export let openSqlProjectWithAdditionalPublishProfileBaseline: string;
|
||||
|
||||
const baselineFolderPath = __dirname;
|
||||
|
||||
@@ -77,6 +78,7 @@ export async function loadBaselines() {
|
||||
openSdkStyleSqlProjectWithGlobsSpecifiedBaseline = await loadBaseline(baselineFolderPath, 'openSdkStyleSqlProjectWithGlobsSpecifiedBaseline.xml');
|
||||
openSdkStyleSqlProjectWithBuildRemoveBaseline = await loadBaseline(baselineFolderPath, 'openSdkStyleSqlProjectWithBuildRemoveBaseline.xml');
|
||||
openSdkStyleSqlProjectNoProjectGuidBaseline = await loadBaseline(baselineFolderPath, 'openSdkStyleSqlProjectNoProjectGuidBaseline.xml');
|
||||
openSqlProjectWithAdditionalPublishProfileBaseline = await loadBaseline(baselineFolderPath, 'openSqlProjectWithAdditionalPublishProfileBaseline.xml');
|
||||
}
|
||||
|
||||
async function loadBaseline(baselineFolderPath: string, fileName: string): Promise<string> {
|
||||
|
||||
@@ -105,6 +105,11 @@
|
||||
<PostDeploy Include="Script.PostDeployment1.sql" />
|
||||
<None Include="Tables\Script.PostDeployment1.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestProjectName_1.publish.xml" />
|
||||
<None Include="TestProjectName_2.publish.xml" />
|
||||
<None Include="TestProjectName_3.publish.xml" />
|
||||
</ItemGroup>
|
||||
<Target Name="BeforeBuild">
|
||||
<Delete Files="$(BaseIntermediateOutputPath)\project.assets.json" />
|
||||
</Target>
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="4.0">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<Name>TestProjectName</Name>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectVersion>4.1</ProjectVersion>
|
||||
<ProjectGuid>{BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575}</ProjectGuid>
|
||||
<DSP>Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider</DSP>
|
||||
<OutputType>Database</OutputType>
|
||||
<RootPath>
|
||||
</RootPath>
|
||||
<RootNamespace>TestProjectName</RootNamespace>
|
||||
<AssemblyName>TestProjectName</AssemblyName>
|
||||
<ModelCollation>1033, CI</ModelCollation>
|
||||
<DefaultFileStructure>BySchemaAndSchemaType</DefaultFileStructure>
|
||||
<DeployToDatabase>True</DeployToDatabase>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<TargetLanguage>CS</TargetLanguage>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<SqlServerVerification>False</SqlServerVerification>
|
||||
<IncludeCompositeObjects>True</IncludeCompositeObjects>
|
||||
<TargetDatabaseSet>True</TargetDatabaseSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<BuildScriptName>$(MSBuildProjectName).sql</BuildScriptName>
|
||||
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<DefineDebug>true</DefineDebug>
|
||||
<DefineTrace>true</DefineTrace>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">11.0</VisualStudioVersion>
|
||||
<!-- Default to the v11.0 targets path if the targets file for the current VS version is not found -->
|
||||
<SSDTExists Condition="Exists('$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets')">True</SSDTExists>
|
||||
<VisualStudioVersion Condition="'$(SSDTExists)' == ''">11.0</VisualStudioVersion>
|
||||
</PropertyGroup>
|
||||
<Import Condition="'$(NetCoreBuild)' == 'true'" Project="$(NETCoreTargetsPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||
<Import Condition="'$(NetCoreBuild)' != 'true' AND '$(SQLDBExtensionsRefPath)' != ''" Project="$(SQLDBExtensionsRefPath)\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||
<Import Condition="'$(NetCoreBuild)' != 'true' AND '$(SQLDBExtensionsRefPath)' == ''" Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v$(VisualStudioVersion)\SSDT\Microsoft.Data.Tools.Schema.SqlTasks.targets" />
|
||||
<ItemGroup>
|
||||
<PackageReference Condition="'$(NetCoreBuild)' == 'true'" Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" PrivateAssets="All" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties" />
|
||||
<Folder Include="Tables" />
|
||||
<Folder Include="Views" />
|
||||
<Folder Include="Views\Maintenance" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Build Include="Tables\Users.sql" />
|
||||
<Build Include="Tables\Action History.sql" />
|
||||
<Build Include="Views\Maintenance\Database Performance.sql" />
|
||||
<Build Include="..\Test\Test.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Views\User" />
|
||||
<Build Include="Views\User\Profile.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Build Include="MyExternalStreamingJob.sql" Type="ExternalStreamingJob" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<SqlCmdVariable Include="ProdDatabaseName">
|
||||
<DefaultValue>MyProdDatabase</DefaultValue>
|
||||
<Value>$(SqlCmdVar__1)</Value>
|
||||
</SqlCmdVariable>
|
||||
<SqlCmdVariable Include="BackupDatabaseName">
|
||||
<DefaultValue>MyBackupDatabase</DefaultValue>
|
||||
<Value>$(SqlCmdVar__2)</Value>
|
||||
</SqlCmdVariable>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ArtifactReference Condition="'$(NetCoreBuild)' == 'true'" Include="$(NETCoreTargetsPath)\SystemDacpacs\150\master.dacpac">
|
||||
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
|
||||
<DatabaseVariableLiteralValue>master</DatabaseVariableLiteralValue>
|
||||
</ArtifactReference>
|
||||
<ArtifactReference Condition="'$(NetCoreBuild)' != 'true'" Include="$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\150\SqlSchemas\master.dacpac">
|
||||
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
|
||||
<DatabaseVariableLiteralValue>master</DatabaseVariableLiteralValue>
|
||||
</ArtifactReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PreDeploy Include="Script.PreDeployment1.sql" />
|
||||
<None Include="Script.PreDeployment2.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PostDeploy Include="Script.PostDeployment1.sql" />
|
||||
<None Include="Tables\Script.PostDeployment1.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestProjectName_1.publish.xml" />
|
||||
<None Include="TestProjectName_2.publish.xml" />
|
||||
<None Include="TestProjectName_3.publish.xml" />
|
||||
<None Include="TestProjectName_4.publish.xml" />
|
||||
</ItemGroup>
|
||||
<Target Name="BeforeBuild">
|
||||
<Delete Files="$(BaseIntermediateOutputPath)\project.assets.json" />
|
||||
</Target>
|
||||
</Project>
|
||||
@@ -109,6 +109,11 @@
|
||||
<PostDeploy Include="Script.PostDeployment1.sql" />
|
||||
<None Include="Tables\Script.PostDeployment1.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="TestProjectName_1.publish.xml" />
|
||||
<None Include="TestProjectName_2.publish.xml" />
|
||||
<None Include="TestProjectName_3.publish.xml" />
|
||||
</ItemGroup>
|
||||
<Target Name="BeforeBuild">
|
||||
<Delete Files="$(BaseIntermediateOutputPath)\project.assets.json" />
|
||||
</Target>
|
||||
|
||||
@@ -66,6 +66,12 @@ describe('Project: sqlproj content operations', function (): void {
|
||||
should(project.postDeployScripts.find(f => f.type === EntryType.File && f.relativePath === 'Script.PostDeployment1.sql')).not.equal(undefined, 'File Script.PostDeployment1.sql not read');
|
||||
should(project.noneDeployScripts.find(f => f.type === EntryType.File && f.relativePath === 'Script.PreDeployment2.sql')).not.equal(undefined, 'File Script.PostDeployment2.sql not read');
|
||||
should(project.noneDeployScripts.find(f => f.type === EntryType.File && f.relativePath === 'Tables\\Script.PostDeployment1.sql')).not.equal(undefined, 'File Tables\\Script.PostDeployment1.sql not read');
|
||||
|
||||
// Publish profiles
|
||||
should(project.publishProfiles.length).equal(3);
|
||||
should(project.publishProfiles.find(f => f.type === EntryType.File && f.relativePath === 'TestProjectName_1.publish.xml')).not.equal(undefined, 'Profile TestProjectName_1.publish.xml not read');
|
||||
should(project.publishProfiles.find(f => f.type === EntryType.File && f.relativePath === 'TestProjectName_2.publish.xml')).not.equal(undefined, 'Profile TestProjectName_2.publish.xml not read');
|
||||
should(project.publishProfiles.find(f => f.type === EntryType.File && f.relativePath === 'TestProjectName_3.publish.xml')).not.equal(undefined, 'Profile TestProjectName_3.publish.xml not read');
|
||||
});
|
||||
|
||||
it('Should read Project with Project reference from sqlproj', async function (): Promise<void> {
|
||||
@@ -1592,6 +1598,30 @@ describe('Project: add SQLCMD Variables', function (): void {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Project: add publish profiles', function (): void {
|
||||
before(async function (): Promise<void> {
|
||||
await baselines.loadBaselines();
|
||||
});
|
||||
|
||||
after(async function (): Promise<void> {
|
||||
await testUtils.deleteGeneratedTestFolder();
|
||||
});
|
||||
|
||||
it('Should update .sqlproj with new publish profiles', async function (): Promise<void> {
|
||||
projFilePath = await testUtils.createTestSqlProjFile(baselines.openProjectFileBaseline);
|
||||
const project = await Project.openProject(projFilePath);
|
||||
should(Object.keys(project.publishProfiles).length).equal(3);
|
||||
|
||||
// add a new publish profile
|
||||
await project.addPublishProfileToProjFile(path.join(projFilePath, 'TestProjectName_4.publish.xml'));
|
||||
|
||||
should(Object.keys(project.publishProfiles).length).equal(4);
|
||||
|
||||
const projFileText = (await fs.readFile(projFilePath)).toString();
|
||||
should(projFileText).equal(baselines.openSqlProjectWithAdditionalPublishProfileBaseline.trim());
|
||||
});
|
||||
});
|
||||
|
||||
describe('Project: properties', function (): void {
|
||||
before(async function (): Promise<void> {
|
||||
await baselines.loadBaselines();
|
||||
|
||||
Reference in New Issue
Block a user