diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index a58a2fb47b..f0b01a2cb2 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -105,7 +105,7 @@ export const dataSourceDropdownTitle = localize('dataSourceDropdownTitle', "Data export const noDataSourcesText = localize('noDataSourcesText', "No data sources in this project"); export const loadProfilePlaceholderText = localize('loadProfilePlaceholderText', "Load profile..."); export const profileReadError = (err: any) => localize('profileReadError', "Error loading the publish profile. {0}", utils.getErrorMessage(err)); -export const sqlCmdTableLabel = localize('sqlCmdTableLabel', "SQLCMD Variables"); +export const sqlCmdVariables = localize('sqlCmdTableLabel', "SQLCMD Variables"); export const sqlCmdVariableColumn = localize('sqlCmdVariableColumn', "Name"); export const sqlCmdValueColumn = localize('sqlCmdValueColumn', "Value"); export const loadSqlCmdVarsButtonTitle = localize('reloadValuesFromProjectButtonTitle', "Reload values from project"); @@ -286,7 +286,7 @@ export function unableToFindSqlCmdVariable(variableName: string) { return locali export function unableToFindDatabaseReference(reference: string) { return localize('unableToFindReference', "Unable to find database reference {0}", reference); } export function invalidGuid(guid: string) { return localize('invalidGuid', "Specified GUID is invalid: {0}", guid); } export function invalidTargetPlatform(targetPlatform: string, supportedTargetPlatforms: string[]) { return localize('invalidTargetPlatform', "Invalid target platform: {0}. Supported target platforms: {1}", targetPlatform, supportedTargetPlatforms.toString()); } - +export function errorReadingProject(section: string, path: string) { return localize('errorReadingProjectGuid', "Error trying to read {0} of project '{1}'", section, path); } // Action types export const deleteAction = localize('deleteAction', 'Delete'); @@ -363,6 +363,16 @@ export const Type = 'Type'; export const ExternalStreamingJob: string = 'ExternalStreamingJob'; export const Sdk: string = 'Sdk'; +export const BuildElements = localize('buildElements', "Build Elements"); +export const FolderElements = localize('folderElements', "Folder Elements"); +export const PreDeployElements = localize('preDeployElements', "PreDeploy Elements"); +export const PostDeployElements = localize('postDeployElements', "PostDeploy Elements"); +export const NoneElements = localize('noneElements', "None Elements"); +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"); + /** Name of the property item in the project file that defines default database collation. */ export const DefaultCollationProperty = 'DefaultCollation'; diff --git a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts index d565757378..f402b76644 100644 --- a/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts +++ b/extensions/sql-database-projects/src/dialogs/publishDatabaseDialog.ts @@ -111,7 +111,7 @@ export class PublishDatabaseDialog { component: this.sqlCmdVariablesTable } ], - title: constants.sqlCmdTableLabel + title: constants.sqlCmdVariables }; const profileRow = this.createProfileRow(view); @@ -423,7 +423,7 @@ export class PublishDatabaseDialog { this.sqlCmdVars = { ...this.project.sqlCmdVariables }; const table = view.modelBuilder.declarativeTable().withProps({ - ariaLabel: constants.sqlCmdTableLabel, + ariaLabel: constants.sqlCmdVariables, dataValues: this.convertSqlCmdVarsToTableFormat(this.sqlCmdVars), columns: [ { diff --git a/extensions/sql-database-projects/src/models/project.ts b/extensions/sql-database-projects/src/models/project.ts index aa070c8c57..57be983690 100644 --- a/extensions/sql-database-projects/src/models/project.ts +++ b/extensions/sql-database-projects/src/models/project.ts @@ -120,40 +120,66 @@ export class Project implements ISqlProject { // check if this is a new msbuild sdk style project this._isMsbuildSdkStyleProject = this.CheckForMsbuildSdkStyleProject(); + // get projectGUID - this._projectGuid = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ProjectGuid)[0].childNodes[0].nodeValue!; + try { + this._projectGuid = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ProjectGuid)[0].childNodes[0].nodeValue!; + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.ProjectGuid, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); + } // find all folders and files to include for (let ig = 0; ig < this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ItemGroup).length; ig++) { const itemGroup = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ItemGroup)[ig]; - const buildElements = itemGroup.getElementsByTagName(constants.Build); - for (let b = 0; b < buildElements.length; b++) { - this._files.push(this.createFileProjectEntry(buildElements[b].getAttribute(constants.Include)!, EntryType.File, buildElements[b].getAttribute(constants.Type)!)); + try { + const buildElements = itemGroup.getElementsByTagName(constants.Build); + for (let b = 0; b < buildElements.length; b++) { + this._files.push(this.createFileProjectEntry(buildElements[b].getAttribute(constants.Include)!, EntryType.File, buildElements[b].getAttribute(constants.Type)!)); + } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.BuildElements, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } - const folderElements = itemGroup.getElementsByTagName(constants.Folder); - for (let f = 0; f < folderElements.length; f++) { - // don't add Properties folder since it isn't supported for now - if (folderElements[f].getAttribute(constants.Include) !== constants.Properties) { - this._files.push(this.createFileProjectEntry(folderElements[f].getAttribute(constants.Include)!, EntryType.Folder)); + try { + const folderElements = itemGroup.getElementsByTagName(constants.Folder); + for (let f = 0; f < folderElements.length; f++) { + // don't add Properties folder since it isn't supported for now + if (folderElements[f].getAttribute(constants.Include) !== constants.Properties) { + this._files.push(this.createFileProjectEntry(folderElements[f].getAttribute(constants.Include)!, EntryType.Folder)); + } } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.Folder, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } // find all pre-deployment scripts to include let preDeployScriptCount: number = 0; - const preDeploy = itemGroup.getElementsByTagName(constants.PreDeploy); - for (let pre = 0; pre < preDeploy.length; pre++) { - this._preDeployScripts.push(this.createFileProjectEntry(preDeploy[pre].getAttribute(constants.Include)!, EntryType.File)); - preDeployScriptCount++; + try { + const preDeploy = itemGroup.getElementsByTagName(constants.PreDeploy); + for (let pre = 0; pre < preDeploy.length; pre++) { + this._preDeployScripts.push(this.createFileProjectEntry(preDeploy[pre].getAttribute(constants.Include)!, EntryType.File)); + preDeployScriptCount++; + } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.PreDeployElements, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } // find all post-deployment scripts to include let postDeployScriptCount: number = 0; - const postDeploy = itemGroup.getElementsByTagName(constants.PostDeploy); - for (let post = 0; post < postDeploy.length; post++) { - this._postDeployScripts.push(this.createFileProjectEntry(postDeploy[post].getAttribute(constants.Include)!, EntryType.File)); - postDeployScriptCount++; + try { + const postDeploy = itemGroup.getElementsByTagName(constants.PostDeploy); + for (let post = 0; post < postDeploy.length; post++) { + this._postDeployScripts.push(this.createFileProjectEntry(postDeploy[post].getAttribute(constants.Include)!, EntryType.File)); + postDeployScriptCount++; + } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.PostDeployElements, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } if (preDeployScriptCount > 1 || postDeployScriptCount > 1) { @@ -161,74 +187,105 @@ export class Project implements ISqlProject { } // find all none-deployment scripts to include - const noneItems = itemGroup.getElementsByTagName(constants.None); - for (let n = 0; n < noneItems.length; n++) { - this._noneDeployScripts.push(this.createFileProjectEntry(noneItems[n].getAttribute(constants.Include)!, EntryType.File)); + try { + const noneItems = itemGroup.getElementsByTagName(constants.None); + for (let n = 0; n < noneItems.length; n++) { + this._noneDeployScripts.push(this.createFileProjectEntry(noneItems[n].getAttribute(constants.Include)!, EntryType.File)); + } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.NoneElements, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } } // find all import statements to include - const importElements = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.Import); - for (let i = 0; i < importElements.length; i++) { - const importTarget = importElements[i]; - this._importedTargets.push(importTarget.getAttribute(constants.Project)!); + try { + const importElements = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.Import); + for (let i = 0; i < importElements.length; i++) { + const importTarget = importElements[i]; + this._importedTargets.push(importTarget.getAttribute(constants.Project)!); + } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.ImportElements, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } // find all SQLCMD variables to include - this._sqlCmdVariables = utils.readSqlCmdVariables(this.projFileXmlDoc, false); + try { + this._sqlCmdVariables = utils.readSqlCmdVariables(this.projFileXmlDoc, false); + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.sqlCmdVariables, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); + } // find all database references to include const references = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ArtifactReference); for (let r = 0; r < references.length; r++) { - if (references[r].getAttribute(constants.Condition) !== constants.NotNetCoreCondition) { - const filepath = references[r].getAttribute(constants.Include); - if (!filepath) { - throw new Error(constants.invalidDatabaseReference); - } - - const nameNodes = references[r].getElementsByTagName(constants.DatabaseVariableLiteralValue); - const name = nameNodes.length === 1 ? nameNodes[0].childNodes[0].nodeValue! : undefined; - - const suppressMissingDependenciesErrorNode = references[r].getElementsByTagName(constants.SuppressMissingDependenciesErrors); - const suppressMissingDependencies = suppressMissingDependenciesErrorNode[0].childNodes[0].nodeValue === constants.True; - - const path = utils.convertSlashesForSqlProj(this.getSystemDacpacUri(`${name}.dacpac`).fsPath); - if (path.includes(filepath)) { - this._databaseReferences.push(new SystemDatabaseReferenceProjectEntry( - Uri.file(filepath), - this.getSystemDacpacSsdtUri(`${name}.dacpac`), - name, - suppressMissingDependencies)); - } else { - this._databaseReferences.push(new DacpacReferenceProjectEntry({ - dacpacFileLocation: Uri.file(utils.getPlatformSafeFileEntryPath(filepath)), - databaseName: name, - suppressMissingDependenciesErrors: suppressMissingDependencies - })); + try { + if (references[r].getAttribute(constants.Condition) !== constants.NotNetCoreCondition) { + const filepath = references[r].getAttribute(constants.Include); + if (!filepath) { + throw new Error(constants.invalidDatabaseReference); + } + + const nameNodes = references[r].getElementsByTagName(constants.DatabaseVariableLiteralValue); + const name = nameNodes.length === 1 ? nameNodes[0].childNodes[0].nodeValue! : undefined; + + const suppressMissingDependenciesErrorNode = references[r].getElementsByTagName(constants.SuppressMissingDependenciesErrors); + const suppressMissingDependencies = suppressMissingDependenciesErrorNode.length === 1 ? (suppressMissingDependenciesErrorNode[0].childNodes[0].nodeValue === constants.True) : false; + + const path = utils.convertSlashesForSqlProj(this.getSystemDacpacUri(`${name}.dacpac`).fsPath); + if (path.includes(filepath)) { + this._databaseReferences.push(new SystemDatabaseReferenceProjectEntry( + Uri.file(filepath), + this.getSystemDacpacSsdtUri(`${name}.dacpac`), + name, + suppressMissingDependencies)); + } else { + this._databaseReferences.push(new DacpacReferenceProjectEntry({ + dacpacFileLocation: Uri.file(utils.getPlatformSafeFileEntryPath(filepath)), + databaseName: name, + suppressMissingDependenciesErrors: suppressMissingDependencies + })); + } } + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.DacpacReferenceElement, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } } // find project references const projectReferences = this.projFileXmlDoc!.documentElement.getElementsByTagName(constants.ProjectReference); for (let r = 0; r < projectReferences.length; r++) { - const filepath = projectReferences[r].getAttribute(constants.Include); - if (!filepath) { - throw new Error(constants.invalidDatabaseReference); + try { + const filepath = projectReferences[r].getAttribute(constants.Include); + if (!filepath) { + throw new Error(constants.invalidDatabaseReference); + } + + const nameNodes = projectReferences[r].getElementsByTagName(constants.Name); + let name = ''; + try { + name = nameNodes[0].childNodes[0].nodeValue!; + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.ProjectReferenceNameElement, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); + } + + const suppressMissingDependenciesErrorNode = projectReferences[r].getElementsByTagName(constants.SuppressMissingDependenciesErrors); + const suppressMissingDependencies = suppressMissingDependenciesErrorNode.length === 1 ? (suppressMissingDependenciesErrorNode[0].childNodes[0].nodeValue === constants.True) : false; + + this._databaseReferences.push(new SqlProjectReferenceProjectEntry({ + projectRelativePath: Uri.file(utils.getPlatformSafeFileEntryPath(filepath)), + projectName: name, + projectGuid: '', // don't care when just reading project as a reference + suppressMissingDependenciesErrors: suppressMissingDependencies + })); + } catch (e) { + void window.showErrorMessage(constants.errorReadingProject(constants.ProjectReferenceElement, this.projectFilePath)); + console.error(utils.getErrorMessage(e)); } - - const nameNodes = projectReferences[r].getElementsByTagName(constants.Name); - const name = nameNodes[0].childNodes[0].nodeValue!; - - const suppressMissingDependenciesErrorNode = projectReferences[r].getElementsByTagName(constants.SuppressMissingDependenciesErrors); - const suppressMissingDependencies = suppressMissingDependenciesErrorNode[0].childNodes[0].nodeValue === constants.True; - - this._databaseReferences.push(new SqlProjectReferenceProjectEntry({ - projectRelativePath: Uri.file(utils.getPlatformSafeFileEntryPath(filepath)), - projectName: name, - projectGuid: '', // don't care when just reading project as a reference - suppressMissingDependenciesErrors: suppressMissingDependencies - })); } }