diff --git a/extensions/sql-database-projects/src/common/utils.ts b/extensions/sql-database-projects/src/common/utils.ts index 01bc81756c..3815472618 100644 --- a/extensions/sql-database-projects/src/common/utils.ts +++ b/extensions/sql-database-projects/src/common/utils.ts @@ -100,6 +100,14 @@ export function getPlatformSafeFileEntryPath(filePath: string): string { return parts.join('/'); } +/** + * Standardizes slashes to be "\\" for consistency between platforms and compatibility with SSDT + */ +export function convertSlashesForSqlProj(filePath: string): string { + const parts = filePath.split('/'); + return parts.join('\\'); +} + /** * Read SQLCMD variables from xmlDoc and return them * @param xmlDoc xml doc to read SQLCMD variables from. Format must be the same that sqlproj and publish profiles use diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts index 1dc3afcc9f..276ca1b564 100644 --- a/extensions/sql-database-projects/src/models/project.ts +++ b/extensions/sql-database-projects/src/models/project.ts @@ -311,7 +311,7 @@ export class Project { private addFileToProjFile(path: string) { const newFileNode = this.projFileXmlDoc.createElement(constants.Build); - newFileNode.setAttribute(constants.Include, path); + newFileNode.setAttribute(constants.Include, utils.convertSlashesForSqlProj(path)); this.findOrCreateItemGroup(constants.Build).appendChild(newFileNode); } @@ -320,7 +320,7 @@ export class Project { const fileNodes = this.projFileXmlDoc.documentElement.getElementsByTagName(constants.Build); for (let i = 0; i < fileNodes.length; i++) { - if (fileNodes[i].getAttribute(constants.Include) === path) { + if (fileNodes[i].getAttribute(constants.Include) === utils.convertSlashesForSqlProj(path)) { fileNodes[i].parentNode.removeChild(fileNodes[i]); return; } @@ -331,7 +331,7 @@ export class Project { private addFolderToProjFile(path: string) { const newFolderNode = this.projFileXmlDoc.createElement(constants.Folder); - newFolderNode.setAttribute(constants.Include, path); + newFolderNode.setAttribute(constants.Include, utils.convertSlashesForSqlProj(path)); this.findOrCreateItemGroup(constants.Folder).appendChild(newFolderNode); } @@ -340,7 +340,7 @@ export class Project { const folderNodes = this.projFileXmlDoc.documentElement.getElementsByTagName(constants.Folder); for (let i = 0; i < folderNodes.length; i++) { - if (folderNodes[i].getAttribute(constants.Include) === path) { + if (folderNodes[i].getAttribute(constants.Include) === utils.convertSlashesForSqlProj(path)) { folderNodes[i].parentNode.removeChild(folderNodes[i]); return; } @@ -363,7 +363,7 @@ export class Project { referenceNode.setAttribute(constants.Condition, constants.NetCoreCondition); } - referenceNode.setAttribute(constants.Include, isSystemDatabaseProjectEntry ? entry.fsUri.fsPath.substring(1) : entry.fsUri.fsPath); // need to remove the leading slash for system database path for build to work on Windows + referenceNode.setAttribute(constants.Include, entry.pathForSqlProj()); this.addDatabaseReferenceChildren(referenceNode, entry.name); this.findOrCreateItemGroup(constants.ArtifactReference).appendChild(referenceNode); this.databaseReferences.push(entry); @@ -372,7 +372,7 @@ export class Project { if (isSystemDatabaseProjectEntry) { let ssdtReferenceNode = this.projFileXmlDoc.createElement(constants.ArtifactReference); ssdtReferenceNode.setAttribute(constants.Condition, constants.NotNetCoreCondition); - ssdtReferenceNode.setAttribute(constants.Include, (entry).ssdtUri.fsPath.substring(1)); // need to remove the leading slash for system database path for build to work on Windows + ssdtReferenceNode.setAttribute(constants.Include, (entry).ssdtPathForSqlProj()); this.addDatabaseReferenceChildren(ssdtReferenceNode, entry.name); this.findOrCreateItemGroup(constants.ArtifactReference).appendChild(ssdtReferenceNode); } @@ -548,6 +548,10 @@ export class ProjectEntry { public toString(): string { return this.fsUri.path; } + + public pathForSqlProj(): string { + return utils.convertSlashesForSqlProj(this.fsUri.path); + } } /** @@ -567,6 +571,16 @@ class SystemDatabaseReferenceProjectEntry extends DatabaseReferenceProjectEntry constructor(uri: Uri, public ssdtUri: Uri, public name: string) { super(uri, DatabaseReferenceLocation.differentDatabaseSameServer, name); } + + public pathForSqlProj(): string { + // need to remove the leading slash for system database path for build to work on Windows + return utils.convertSlashesForSqlProj(this.fsUri.path.substring(1)); + } + + public ssdtPathForSqlProj(): string { + // need to remove the leading slash for system database path for build to work on Windows + return utils.convertSlashesForSqlProj(this.ssdtUri.path.substring(1)); + } } export enum EntryType { diff --git a/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaseline.xml b/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaseline.xml index cea51b847f..0930ef4985 100644 --- a/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaseline.xml +++ b/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaseline.xml @@ -77,11 +77,11 @@ - + False master - + False master diff --git a/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaselineWindows.xml b/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaselineWindows.xml deleted file mode 100644 index 0930ef4985..0000000000 --- a/extensions/sql-database-projects/src/test/baselines/SSDTProjectAfterUpdateBaselineWindows.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - Debug - AnyCPU - TestProjectName - 2.0 - 4.1 - {BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575} - Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider - Database - - - TestProjectName - TestProjectName - 1033, CI - BySchemaAndSchemaType - True - v4.5 - CS - Properties - False - True - True - - - bin\Release\ - $(MSBuildProjectName).sql - False - pdbonly - true - false - true - prompt - 4 - - - bin\Debug\ - $(MSBuildProjectName).sql - false - true - full - false - true - true - prompt - 4 - - - 11.0 - - True - 11.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - master - - - False - master - - - diff --git a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaseline.xml b/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaseline.xml index 8ee0fb0595..039d30f87e 100644 --- a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaseline.xml +++ b/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaseline.xml @@ -77,19 +77,19 @@ - + False master - + False master - + False msdb - + False msdb diff --git a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows.xml b/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows.xml deleted file mode 100644 index 039d30f87e..0000000000 --- a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - Debug - AnyCPU - TestProjectName - 2.0 - 4.1 - {BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575} - Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider - Database - - - TestProjectName - TestProjectName - 1033, CI - BySchemaAndSchemaType - True - v4.5 - CS - Properties - False - True - True - - - bin\Release\ - $(MSBuildProjectName).sql - False - pdbonly - true - false - true - prompt - 4 - - - bin\Debug\ - $(MSBuildProjectName).sql - false - true - full - false - true - true - prompt - 4 - - - 11.0 - - True - 11.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - master - - - False - master - - - False - msdb - - - False - msdb - - - diff --git a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaseline.xml b/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaseline.xml index 2b05d96a3f..b7af463f15 100644 --- a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaseline.xml +++ b/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaseline.xml @@ -77,11 +77,7 @@ - - False - master - - + False master @@ -90,5 +86,9 @@ False msdb + + False + master + diff --git a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaselineWindows.xml b/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaselineWindows.xml deleted file mode 100644 index b7af463f15..0000000000 --- a/extensions/sql-database-projects/src/test/baselines/SSDTUpdatedProjectBaselineWindows.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - Debug - AnyCPU - TestProjectName - 2.0 - 4.1 - {BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575} - Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider - Database - - - TestProjectName - TestProjectName - 1033, CI - BySchemaAndSchemaType - True - v4.5 - CS - Properties - False - True - True - - - bin\Release\ - $(MSBuildProjectName).sql - False - pdbonly - true - false - true - prompt - 4 - - - bin\Debug\ - $(MSBuildProjectName).sql - false - true - full - false - true - true - prompt - 4 - - - 11.0 - - True - 11.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - master - - - $(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\130\SqlSchemas\msdb.dacpac - False - msdb - - - False - master - - - diff --git a/extensions/sql-database-projects/src/test/baselines/baselines.ts b/extensions/sql-database-projects/src/test/baselines/baselines.ts index 1f54144e53..47de66866c 100644 --- a/extensions/sql-database-projects/src/test/baselines/baselines.ts +++ b/extensions/sql-database-projects/src/test/baselines/baselines.ts @@ -11,11 +11,8 @@ export let newProjectFileBaseline: string; export let openProjectFileBaseline: string; export let openDataSourcesBaseline: string; export let SSDTProjectFileBaseline: string; -export let SSDTProjectAfterUpdateBaselineWindows: string; export let SSDTProjectAfterUpdateBaseline: string; -export let SSDTUpdatedProjectBaselineWindows: string; export let SSDTUpdatedProjectBaseline: string; -export let SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows: string; export let SSDTUpdatedProjectAfterSystemDbUpdateBaseline: string; export let SSDTProjectBaselineWithCleanTarget: string; export let SSDTProjectBaselineWithCleanTargetAfterUpdate: string; @@ -28,11 +25,8 @@ export async function loadBaselines() { openProjectFileBaseline = await loadBaseline(baselineFolderPath, 'openSqlProjectBaseline.xml'); openDataSourcesBaseline = await loadBaseline(baselineFolderPath, 'openDataSourcesBaseline.json'); SSDTProjectFileBaseline = await loadBaseline(baselineFolderPath, 'SSDTProjectBaseline.xml'); - SSDTProjectAfterUpdateBaselineWindows = await loadBaseline(baselineFolderPath, 'SSDTProjectAfterUpdateBaselineWindows.xml'); SSDTProjectAfterUpdateBaseline = await loadBaseline(baselineFolderPath, 'SSDTProjectAfterUpdateBaseline.xml'); - SSDTUpdatedProjectBaselineWindows = await loadBaseline(baselineFolderPath, 'SSDTUpdatedProjectBaselineWindows.xml'); SSDTUpdatedProjectBaseline = await loadBaseline(baselineFolderPath, 'SSDTUpdatedProjectBaseline.xml'); - SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows = await loadBaseline(baselineFolderPath, 'SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows.xml'); SSDTUpdatedProjectAfterSystemDbUpdateBaseline = await loadBaseline(baselineFolderPath, 'SSDTUpdatedProjectAfterSystemDbUpdateBaseline.xml'); SSDTProjectBaselineWithCleanTarget = await loadBaseline(baselineFolderPath, 'SSDTProjectBaselineWithCleanTarget.xml'); SSDTProjectBaselineWithCleanTargetAfterUpdate = await loadBaseline(baselineFolderPath, 'SSDTProjectBaselineWithCleanTargetAfterUpdate.xml'); diff --git a/extensions/sql-database-projects/src/test/project.test.ts b/extensions/sql-database-projects/src/test/project.test.ts index c429074919..e82150884b 100644 --- a/extensions/sql-database-projects/src/test/project.test.ts +++ b/extensions/sql-database-projects/src/test/project.test.ts @@ -5,18 +5,16 @@ import * as should from 'should'; import * as path from 'path'; -import * as os from 'os'; import * as baselines from './baselines/baselines'; import * as testUtils from './testUtils'; import * as constants from '../common/constants'; import { promises as fs } from 'fs'; import { Project, EntryType, TargetPlatform, SystemDatabase, DatabaseReferenceLocation } from '../models/project'; -import { exists } from '../common/utils'; +import { exists, convertSlashesForSqlProj } from '../common/utils'; import { Uri } from 'vscode'; let projFilePath: string; -const isWindows = os.platform() === 'win32'; describe('Project: sqlproj content operations', function (): void { before(async function (): Promise { @@ -63,8 +61,8 @@ describe('Project: sqlproj content operations', function (): void { const newProject = new Project(projFilePath); await newProject.readProjFile(); - should(newProject.files.find(f => f.type === EntryType.Folder && f.relativePath === folderPath)).not.equal(undefined); - should(newProject.files.find(f => f.type === EntryType.File && f.relativePath === filePath)).not.equal(undefined); + should(newProject.files.find(f => f.type === EntryType.Folder && f.relativePath === convertSlashesForSqlProj(folderPath))).not.equal(undefined); + should(newProject.files.find(f => f.type === EntryType.File && f.relativePath === convertSlashesForSqlProj(filePath))).not.equal(undefined); const newFileContents = (await fs.readFile(path.join(newProject.projectFolderPath, filePath))).toString(); @@ -164,14 +162,14 @@ describe('Project: sqlproj content operations', function (): void { should(project.databaseReferences[0].databaseName).equal(constants.master, 'The database reference should be master'); // make sure reference to SSDT master dacpac was added let projFileText = (await fs.readFile(projFilePath)).toString(); - should(projFileText).containEql(project.getSystemDacpacSsdtUri(constants.master).fsPath.substring(1)); + should(projFileText).containEql(convertSlashesForSqlProj(project.getSystemDacpacSsdtUri(constants.master).fsPath.substring(1))); await project.addSystemDatabaseReference(SystemDatabase.msdb); should(project.databaseReferences.length).equal(2, 'There should be two database references after adding a reference to msdb'); should(project.databaseReferences[1].databaseName).equal(constants.msdb, 'The database reference should be msdb'); // make sure reference to SSDT msdb dacpac was added projFileText = (await fs.readFile(projFilePath)).toString(); - should(projFileText).containEql(project.getSystemDacpacSsdtUri(constants.msdb).fsPath.substring(1)); + should(projFileText).containEql(convertSlashesForSqlProj(project.getSystemDacpacSsdtUri(constants.msdb).fsPath.substring(1))); await project.addDatabaseReference(Uri.parse('test.dacpac'), DatabaseReferenceLocation.sameDatabase); should(project.databaseReferences.length).equal(3, 'There should be three database references after adding a reference to test'); @@ -208,15 +206,11 @@ describe('Project: round trip updates', function (): void { }); it('Should update SSDT project to work in ADS', async function (): Promise { - const fileBeforeUpdate = baselines.SSDTProjectFileBaseline; - const fileAfterUpdate = isWindows ? baselines.SSDTProjectAfterUpdateBaselineWindows : baselines.SSDTProjectAfterUpdateBaseline; - await testUpdateInRoundTrip(fileBeforeUpdate, fileAfterUpdate, true, true); + await testUpdateInRoundTrip( baselines.SSDTProjectFileBaseline, baselines.SSDTProjectAfterUpdateBaseline, true, true); }); it('Should update SSDT project with new system database references', async function (): Promise { - const fileBeforeUpdate = isWindows ? baselines.SSDTUpdatedProjectBaselineWindows : baselines.SSDTUpdatedProjectBaseline; - const fileAfterUpdate = isWindows ? baselines.SSDTUpdatedProjectAfterSystemDbUpdateBaselineWindows : baselines.SSDTUpdatedProjectAfterSystemDbUpdateBaseline; - await testUpdateInRoundTrip(fileBeforeUpdate, fileAfterUpdate, false, true); + await testUpdateInRoundTrip(baselines.SSDTUpdatedProjectBaseline, baselines.SSDTUpdatedProjectAfterSystemDbUpdateBaseline, false, true); }); it('Should update SSDT project to work in ADS handling pre-exsiting targets', async function (): Promise {