diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index af41b39e35..293e2df358 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -437,6 +437,8 @@ export const Type = 'Type'; export const ExternalStreamingJob: string = 'ExternalStreamingJob'; export const Sdk: string = 'Sdk'; export const DatabaseSource = 'DatabaseSource'; +export const VisualStudioVersion = 'VisualStudioVersion'; +export const SSDTExists = 'SSDTExists'; export const BuildElements = localize('buildElements', "Build Elements"); export const FolderElements = localize('folderElements', "Folder Elements"); @@ -475,6 +477,11 @@ export const RoundTripSqlDbNotPresentCondition = '\'$(NetCoreBuild)\' != \'true\ export const DacpacRootPath = '$(DacPacRootPath)'; export const ProjJsonToClean = '$(BaseIntermediateOutputPath)\\project.assets.json'; +// Sqlproj VS property conditions +export const VSVersionCondition = '\'$(VisualStudioVersion)\' == \'\''; +export const SsdtExistsCondition = '\'$(SSDTExists)\' == \'\''; +export const targetsExistsCondition = 'Exists(\'$(MSBuildExtensionsPath)\\Microsoft\\VisualStudio\\v$(VisualStudioVersion)\\SSDT\\Microsoft.Data.Tools.Schema.SqlTasks.targets\')'; + // SqlProj Reference Assembly Information export const NETFrameworkAssembly = 'Microsoft.NETFramework.ReferenceAssemblies'; export const VersionNumber = '1.0.0'; diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts index 4b09e128f9..dacb57e217 100644 --- a/extensions/sql-database-projects/src/models/project.ts +++ b/extensions/sql-database-projects/src/models/project.ts @@ -661,8 +661,42 @@ export class Project implements ISqlProject { } } - const parent = importsToRemove[0]?.parentNode; - importsToRemove.forEach(i => { parent?.removeChild(i); }); + const importsParent = importsToRemove[0]?.parentNode; + importsToRemove.forEach(i => { + importsParent?.removeChild(i); + }); + + // remove VisualStudio properties + const vsPropsToRemove = []; + for (let i = 0; i < this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.VisualStudioVersion).length; i++) { + const visualStudioVersionNode = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.VisualStudioVersion)[i]; + const conditionAttributeVal = visualStudioVersionNode.getAttribute(constants.Condition); + + if (conditionAttributeVal === constants.VSVersionCondition || conditionAttributeVal === constants.SsdtExistsCondition) { + vsPropsToRemove.push(visualStudioVersionNode); + } + } + + for (let i = 0; i < this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.SSDTExists).length; i++) { + const ssdtExistsNode = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.SSDTExists)[i]; + const conditionAttributeVal = ssdtExistsNode.getAttribute(constants.Condition); + + if (conditionAttributeVal === constants.targetsExistsCondition) { + vsPropsToRemove.push(ssdtExistsNode); + } + } + + const vsPropsParent = vsPropsToRemove[0]?.parentNode; + vsPropsToRemove.forEach(i => { + vsPropsParent?.removeChild(i); + + // Remove the parent PropertyGroup if there aren't any other nodes. Only count element nodes, not text nodes + const otherChildren = Array.from(vsPropsParent!.childNodes).filter((c: ChildNode) => c.childNodes); + + if (otherChildren.length === 0) { + vsPropsParent!.parentNode?.removeChild(vsPropsParent!); + } + }); // add SDK node const sdkNode = this.projFileXmlDoc!.createElement(constants.Sdk); diff --git a/extensions/sql-database-projects/src/test/project.test.ts b/extensions/sql-database-projects/src/test/project.test.ts index 1b1925afb5..d7984c45d2 100644 --- a/extensions/sql-database-projects/src/test/project.test.ts +++ b/extensions/sql-database-projects/src/test/project.test.ts @@ -1784,6 +1784,9 @@ describe('Project: legacy to SDK-style updates', function (): void { let projFileText = (await fs.readFile(projFilePath)).toString(); should(projFileText.includes('')).equal(true, 'sqlproj should have VisualStudioVersion property with empty condition before converting'); + should(projFileText.includes('')).equal(true, 'sqlproj should have SSDTExists property before converting'); + should(projFileText.includes('')).equal(true, 'sqlproj should have VisualStudioVersion property with SSDTExists condition before converting'); await project.convertProjectToSdkStyle(); @@ -1796,6 +1799,9 @@ describe('Project: legacy to SDK-style updates', function (): void { should(projFileText.includes(' f.type === EntryType.File).length).equal(beforeFileCount, 'Same number of files should be included after Build Includes are removed'); should(project.files.filter(f => f.type === EntryType.Folder).length).equal(beforeFolderCount, 'Same number of folders should be included after Folder Includes are removed'); + should(projFileText.includes('')).equal(false, 'VisualStudioVersion property with empty condition should be removed'); + should(projFileText.includes('')).equal(false, 'SSDTExists property should be removed'); + should(projFileText.includes('')).equal(false, 'VisualStudioVersion property with SSDTExists condition should be removed'); }); it('Should not fail if legacy style project does not have Properties folder in sqlproj', async function (): Promise {