diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index b596e825af..501ad8e649 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vscode-nls'; +import * as path from 'path'; import { SqlTargetPlatform } from 'sqldbproj'; import * as utils from '../common/utils'; @@ -455,6 +456,7 @@ export const Sdk: string = 'Sdk'; export const DatabaseSource = 'DatabaseSource'; export const VisualStudioVersion = 'VisualStudioVersion'; export const SSDTExists = 'SSDTExists'; +export const OutputPath = 'OutputPath'; export const BuildElements = localize('buildElements', "Build Elements"); export const FolderElements = localize('folderElements', "Folder Elements"); @@ -493,6 +495,8 @@ export const RoundTripSqlDbNotPresentCondition = '\'$(NetCoreBuild)\' != \'true\ export const DacpacRootPath = '$(DacPacRootPath)'; export const ProjJsonToClean = '$(BaseIntermediateOutputPath)\\project.assets.json'; +export function defaultOutputPath() { return path.join('bin', 'Debug'); } + // Sqlproj VS property conditions export const VSVersionCondition = '\'$(VisualStudioVersion)\' == \'\''; export const SsdtExistsCondition = '\'$(SSDTExists)\' == \'\''; diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts index ce317aa992..26fc585481 100644 --- a/extensions/sql-database-projects/src/models/project.ts +++ b/extensions/sql-database-projects/src/models/project.ts @@ -36,9 +36,10 @@ export class Project implements ISqlProject { private _postDeployScripts: FileProjectEntry[] = []; private _noneDeployScripts: FileProjectEntry[] = []; private _isSdkStyleProject: boolean = false; // https://docs.microsoft.com/en-us/dotnet/core/project-sdk/overview + private _outputPath: string = ''; public get dacpacOutputPath(): string { - return path.join(this.projectFolderPath, 'bin', 'Debug', `${this._projectFileName}.dacpac`); + return path.join(this.outputPath, `${this._projectFileName}.dacpac`); } public get projectFolderPath() { @@ -93,6 +94,10 @@ export class Project implements ISqlProject { return this._isSdkStyleProject; } + public get outputPath(): string { + return this._outputPath; + } + private projFileXmlDoc: Document | undefined = undefined; constructor(projectFilePath: string) { @@ -155,6 +160,16 @@ export class Project implements ISqlProject { this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.PropertyGroup)[0]?.appendChild(newProjectGuidNode); await this.serializeToProjFile(this.projFileXmlDoc); } + + // get output path + const outputNodes = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.OutputPath); + if (outputNodes.length > 0) { + const outputPath = outputNodes[0].childNodes[0].nodeValue!; + this._outputPath = path.join(utils.getPlatformSafeFileEntryPath(this.projectFolderPath), utils.getPlatformSafeFileEntryPath(outputPath)); + } else { + // If output path isn't specified in .sqlproj, set it to the default output path .\bin\Debug\ + this._outputPath = path.join(utils.getPlatformSafeFileEntryPath(this.projectFolderPath), utils.getPlatformSafeFileEntryPath(constants.defaultOutputPath())); + } } /** diff --git a/extensions/sql-database-projects/src/test/baselines/openSdkStyleSqlProjectBaseline.xml b/extensions/sql-database-projects/src/test/baselines/openSdkStyleSqlProjectBaseline.xml index dbf2406a1a..a956694190 100644 --- a/extensions/sql-database-projects/src/test/baselines/openSdkStyleSqlProjectBaseline.xml +++ b/extensions/sql-database-projects/src/test/baselines/openSdkStyleSqlProjectBaseline.xml @@ -6,6 +6,7 @@ {2C283C5D-9E4A-4313-8FF9-4E0CEE20B063} Microsoft.Data.Tools.Schema.Sql.Sql150DatabaseSchemaProvider 1033, CI + ..\otherFolder diff --git a/extensions/sql-database-projects/src/test/project.test.ts b/extensions/sql-database-projects/src/test/project.test.ts index 69d0650a78..db73657d62 100644 --- a/extensions/sql-database-projects/src/test/project.test.ts +++ b/extensions/sql-database-projects/src/test/project.test.ts @@ -13,7 +13,7 @@ import * as constants from '../common/constants'; import { promises as fs } from 'fs'; import { Project } from '../models/project'; -import { exists, convertSlashesForSqlProj, getWellKnownDatabaseSources } from '../common/utils'; +import { exists, convertSlashesForSqlProj, getWellKnownDatabaseSources, getPlatformSafeFileEntryPath } from '../common/utils'; import { Uri, window } from 'vscode'; import { IDacpacReferenceSettings, IProjectReferenceSettings, ISystemDatabaseReferenceSettings } from '../models/IDatabaseReferenceSettings'; import { EntryType, ItemType, SqlTargetPlatform } from 'sqldbproj'; @@ -1430,6 +1430,30 @@ describe('Project: sdk style project content operations', function (): void { should(projFileText.includes(constants.ProjectGuid)).equal(true); }); + it('Should read OutputPath from sqlproj if there is one', async function (): Promise { + projFilePath = await testUtils.createTestSqlProjFile(baselines.openSdkStyleSqlProjectBaseline); + const projFileText = (await fs.readFile(projFilePath)).toString(); + + // Verify sqlproj has OutputPath + should(projFileText.includes(constants.OutputPath)).equal(true); + + const project: Project = await Project.openProject(projFilePath); + should(project.outputPath).equal(path.join(getPlatformSafeFileEntryPath(project.projectFolderPath), getPlatformSafeFileEntryPath('..\\otherFolder'))); + should(project.dacpacOutputPath).equal(path.join(getPlatformSafeFileEntryPath(project.projectFolderPath), getPlatformSafeFileEntryPath('..\\otherFolder'), `${project.projectFileName}.dacpac`)); + }); + + it('Should use default output path if OutputPath is not specified in sqlproj', async function (): Promise { + projFilePath = await testUtils.createTestSqlProjFile(baselines.openSdkStyleSqlProjectWithGlobsSpecifiedBaseline); + const projFileText = (await fs.readFile(projFilePath)).toString(); + + // Verify sqlproj doesn't have OutputPath + should(projFileText.includes(constants.OutputPath)).equal(true); + + const project: Project = await Project.openProject(projFilePath); + should(project.outputPath).equal(path.join(getPlatformSafeFileEntryPath(project.projectFolderPath), getPlatformSafeFileEntryPath(constants.defaultOutputPath()))); + should(project.dacpacOutputPath).equal(path.join(getPlatformSafeFileEntryPath(project.projectFolderPath), getPlatformSafeFileEntryPath(constants.defaultOutputPath()), `${project.projectFileName}.dacpac`)); + }); + it('Should handle adding existing items to project', async function (): Promise { projFilePath = await testUtils.createTestSqlProjFile(baselines.openSdkStyleSqlProjectBaseline); const projectFolder = path.dirname(projFilePath);