mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Initial project references changes (#11648)
* first changes for showing project references * add tests * fix interface and formatting * add try so that project still gets loaded even if dependency project loading fails * use instanceof * add circular reference error
This commit is contained in:
@@ -118,6 +118,7 @@ export function fileAlreadyExists(filename: string) { return localize('fileAlrea
|
|||||||
export function folderAlreadyExists(filename: string) { return localize('folderAlreadyExists', "A folder with the name '{0}' already exists on disk at this location. Please choose another name.", filename); }
|
export function folderAlreadyExists(filename: string) { return localize('folderAlreadyExists', "A folder with the name '{0}' already exists on disk at this location. Please choose another name.", filename); }
|
||||||
export function invalidInput(input: string) { return localize('invalidInput', "Invalid input: {0}", input); }
|
export function invalidInput(input: string) { return localize('invalidInput', "Invalid input: {0}", input); }
|
||||||
export function unableToCreatePublishConnection(input: string) { return localize('unableToCreatePublishConnection', "Unable to construct connection: {0}", input); }
|
export function unableToCreatePublishConnection(input: string) { return localize('unableToCreatePublishConnection', "Unable to construct connection: {0}", input); }
|
||||||
|
export function circularProjectReference(project1: string, project2: string) { return localize('cicularProjectReference', "Circular reference from project {0} to project {1}", project1, project2); }
|
||||||
|
|
||||||
export function mssqlNotFound(mssqlConfigDir: string) { return localize('mssqlNotFound', "Could not get mssql extension's install location at {0}", mssqlConfigDir); }
|
export function mssqlNotFound(mssqlConfigDir: string) { return localize('mssqlNotFound', "Could not get mssql extension's install location at {0}", mssqlConfigDir); }
|
||||||
export function projBuildFailed(errorMessage: string) { return localize('projBuildFailed', "Build failed. Check output pane for more details. {0}", errorMessage); }
|
export function projBuildFailed(errorMessage: string) { return localize('projBuildFailed', "Build failed. Check output pane for more details. {0}", errorMessage); }
|
||||||
@@ -166,6 +167,8 @@ export const DatabaseVariableLiteralValue = 'DatabaseVariableLiteralValue';
|
|||||||
export const DSP = 'DSP';
|
export const DSP = 'DSP';
|
||||||
export const Properties = 'Properties';
|
export const Properties = 'Properties';
|
||||||
export const RelativeOuterPath = '..';
|
export const RelativeOuterPath = '..';
|
||||||
|
export const ProjectReference = 'ProjectReference';
|
||||||
|
export const TargetConnectionString = 'TargetConnectionString';
|
||||||
|
|
||||||
// SqlProj File targets
|
// SqlProj File targets
|
||||||
export const NetCoreTargets = '$(NETCoreTargetsPath)\\Microsoft.Data.Tools.Schema.SqlTasks.targets';
|
export const NetCoreTargets = '$(NETCoreTargetsPath)\\Microsoft.Data.Tools.Schema.SqlTasks.targets';
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import * as vscode from 'vscode';
|
|||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog';
|
import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog';
|
||||||
import { Project, DatabaseReferenceLocation, SystemDatabase, TargetPlatform, ProjectEntry, reservedProjectFolders } from '../models/project';
|
import { Project, DatabaseReferenceLocation, SystemDatabase, TargetPlatform, ProjectEntry, reservedProjectFolders, SqlProjectReferenceProjectEntry } from '../models/project';
|
||||||
import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider';
|
import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider';
|
||||||
import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem';
|
import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem';
|
||||||
import { IPublishSettings, IGenerateScriptSettings } from '../models/IPublishSettings';
|
import { IPublishSettings, IGenerateScriptSettings } from '../models/IPublishSettings';
|
||||||
@@ -47,11 +47,15 @@ export class ProjectsController {
|
|||||||
this.projectTreeViewProvider.load(this.projects);
|
this.projectTreeViewProvider.load(this.projects);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async openProject(projectFile: vscode.Uri, focusProject: boolean = true): Promise<Project> {
|
public async openProject(projectFile: vscode.Uri, focusProject: boolean = true, isReferencedProject: boolean = false): Promise<Project> {
|
||||||
for (const proj of this.projects) {
|
for (const proj of this.projects) {
|
||||||
if (proj.projectFilePath === projectFile.fsPath) {
|
if (proj.projectFilePath === projectFile.fsPath) {
|
||||||
vscode.window.showInformationMessage(constants.projectAlreadyOpened(projectFile.fsPath));
|
if (!isReferencedProject) {
|
||||||
return proj;
|
vscode.window.showInformationMessage(constants.projectAlreadyOpened(projectFile.fsPath));
|
||||||
|
return proj;
|
||||||
|
} else {
|
||||||
|
throw new Error(constants.projectAlreadyOpened(projectFile.fsPath));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,6 +66,17 @@ export class ProjectsController {
|
|||||||
newProject = await Project.openProject(projectFile.fsPath);
|
newProject = await Project.openProject(projectFile.fsPath);
|
||||||
this.projects.push(newProject);
|
this.projects.push(newProject);
|
||||||
|
|
||||||
|
// open any reference projects (don't need to worry about circular dependencies because those aren't allowed)
|
||||||
|
const referencedProjects = newProject.databaseReferences.filter(r => r instanceof SqlProjectReferenceProjectEntry);
|
||||||
|
for (const proj of referencedProjects) {
|
||||||
|
const projUri = vscode.Uri.file(path.join(newProject.projectFolderPath, proj.fsUri.fsPath));
|
||||||
|
try {
|
||||||
|
await this.openProject(projUri, false, true);
|
||||||
|
} catch (e) {
|
||||||
|
vscode.window.showErrorMessage(e.message === constants.projectAlreadyOpened(projUri.fsPath) ? constants.circularProjectReference(newProject.projectFileName, proj.databaseName) : e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update for round tripping as needed
|
// Update for round tripping as needed
|
||||||
await this.updateProjectForRoundTrip(newProject);
|
await this.updateProjectForRoundTrip(newProject);
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export class Project {
|
|||||||
public files: ProjectEntry[] = [];
|
public files: ProjectEntry[] = [];
|
||||||
public dataSources: DataSource[] = [];
|
public dataSources: DataSource[] = [];
|
||||||
public importedTargets: string[] = [];
|
public importedTargets: string[] = [];
|
||||||
public databaseReferences: DatabaseReferenceProjectEntry[] = [];
|
public databaseReferences: IDatabaseReferenceProjectEntry[] = [];
|
||||||
public sqlCmdVariables: Record<string, string> = {};
|
public sqlCmdVariables: Record<string, string> = {};
|
||||||
|
|
||||||
public get projectFolderPath() {
|
public get projectFolderPath() {
|
||||||
@@ -91,11 +91,24 @@ export class Project {
|
|||||||
throw new Error(constants.invalidDatabaseReference);
|
throw new Error(constants.invalidDatabaseReference);
|
||||||
}
|
}
|
||||||
|
|
||||||
let nameNodes = references[r].getElementsByTagName(constants.DatabaseVariableLiteralValue);
|
const nameNodes = references[r].getElementsByTagName(constants.DatabaseVariableLiteralValue);
|
||||||
let name = nameNodes.length === 1 ? nameNodes[0].childNodes[0].nodeValue : undefined;
|
const name = nameNodes.length === 1 ? nameNodes[0].childNodes[0].nodeValue : undefined;
|
||||||
this.databaseReferences.push(new DatabaseReferenceProjectEntry(Uri.parse(filepath), name ? DatabaseReferenceLocation.differentDatabaseSameServer : DatabaseReferenceLocation.sameDatabase, name));
|
this.databaseReferences.push(new DacpacReferenceProjectEntry(Uri.file(filepath), name ? DatabaseReferenceLocation.differentDatabaseSameServer : DatabaseReferenceLocation.sameDatabase, name));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
const nameNodes = projectReferences[r].getElementsByTagName(constants.Name);
|
||||||
|
const name = nameNodes[0].childNodes[0].nodeValue;
|
||||||
|
this.databaseReferences.push(new SqlProjectReferenceProjectEntry(Uri.file(utils.getPlatformSafeFileEntryPath(filepath)), name));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async updateProjectForRoundTrip() {
|
public async updateProjectForRoundTrip() {
|
||||||
@@ -284,7 +297,7 @@ export class Project {
|
|||||||
* @param databaseName name of the database
|
* @param databaseName name of the database
|
||||||
*/
|
*/
|
||||||
public async addDatabaseReference(uri: Uri, databaseLocation: DatabaseReferenceLocation, databaseName?: string): Promise<void> {
|
public async addDatabaseReference(uri: Uri, databaseLocation: DatabaseReferenceLocation, databaseName?: string): Promise<void> {
|
||||||
let databaseReferenceEntry = new DatabaseReferenceProjectEntry(uri, databaseLocation, databaseName);
|
let databaseReferenceEntry = new DacpacReferenceProjectEntry(uri, databaseLocation, databaseName);
|
||||||
await this.addToProjFile(databaseReferenceEntry);
|
await this.addToProjFile(databaseReferenceEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,7 +372,7 @@ export class Project {
|
|||||||
throw new Error(constants.unableToFindObject(path, constants.folderObject));
|
throw new Error(constants.unableToFindObject(path, constants.folderObject));
|
||||||
}
|
}
|
||||||
|
|
||||||
private addDatabaseReferenceToProjFile(entry: DatabaseReferenceProjectEntry): void {
|
private addDatabaseReferenceToProjFile(entry: IDatabaseReferenceProjectEntry): void {
|
||||||
// check if reference to this database already exists
|
// check if reference to this database already exists
|
||||||
if (this.databaseReferenceExists(entry)) {
|
if (this.databaseReferenceExists(entry)) {
|
||||||
throw new Error(constants.databaseReferenceAlreadyExists);
|
throw new Error(constants.databaseReferenceAlreadyExists);
|
||||||
@@ -374,7 +387,7 @@ export class Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
referenceNode.setAttribute(constants.Include, entry.pathForSqlProj());
|
referenceNode.setAttribute(constants.Include, entry.pathForSqlProj());
|
||||||
this.addDatabaseReferenceChildren(referenceNode, entry.name);
|
this.addDatabaseReferenceChildren(referenceNode, entry.sqlCmdName);
|
||||||
this.findOrCreateItemGroup(constants.ArtifactReference).appendChild(referenceNode);
|
this.findOrCreateItemGroup(constants.ArtifactReference).appendChild(referenceNode);
|
||||||
this.databaseReferences.push(entry);
|
this.databaseReferences.push(entry);
|
||||||
|
|
||||||
@@ -383,12 +396,12 @@ export class Project {
|
|||||||
let ssdtReferenceNode = this.projFileXmlDoc.createElement(constants.ArtifactReference);
|
let ssdtReferenceNode = this.projFileXmlDoc.createElement(constants.ArtifactReference);
|
||||||
ssdtReferenceNode.setAttribute(constants.Condition, constants.NotNetCoreCondition);
|
ssdtReferenceNode.setAttribute(constants.Condition, constants.NotNetCoreCondition);
|
||||||
ssdtReferenceNode.setAttribute(constants.Include, (<SystemDatabaseReferenceProjectEntry>entry).ssdtPathForSqlProj());
|
ssdtReferenceNode.setAttribute(constants.Include, (<SystemDatabaseReferenceProjectEntry>entry).ssdtPathForSqlProj());
|
||||||
this.addDatabaseReferenceChildren(ssdtReferenceNode, entry.name);
|
this.addDatabaseReferenceChildren(ssdtReferenceNode, entry.sqlCmdName);
|
||||||
this.findOrCreateItemGroup(constants.ArtifactReference).appendChild(ssdtReferenceNode);
|
this.findOrCreateItemGroup(constants.ArtifactReference).appendChild(ssdtReferenceNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private databaseReferenceExists(entry: DatabaseReferenceProjectEntry): boolean {
|
private databaseReferenceExists(entry: IDatabaseReferenceProjectEntry): boolean {
|
||||||
const found = this.databaseReferences.find(reference => reference.fsUri.fsPath === entry.fsUri.fsPath) !== undefined;
|
const found = this.databaseReferences.find(reference => reference.fsUri.fsPath === entry.fsUri.fsPath) !== undefined;
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
@@ -479,7 +492,7 @@ export class Project {
|
|||||||
this.addFolderToProjFile(entry.relativePath);
|
this.addFolderToProjFile(entry.relativePath);
|
||||||
break;
|
break;
|
||||||
case EntryType.DatabaseReference:
|
case EntryType.DatabaseReference:
|
||||||
this.addDatabaseReferenceToProjFile(<DatabaseReferenceProjectEntry>entry);
|
this.addDatabaseReferenceToProjFile(<IDatabaseReferenceProjectEntry>entry);
|
||||||
break; // not required but adding so that we dont miss when we add new items
|
break; // not required but adding so that we dont miss when we add new items
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -567,9 +580,18 @@ export class ProjectEntry {
|
|||||||
/**
|
/**
|
||||||
* Represents a database reference entry in a project file
|
* Represents a database reference entry in a project file
|
||||||
*/
|
*/
|
||||||
export class DatabaseReferenceProjectEntry extends ProjectEntry {
|
|
||||||
constructor(uri: Uri, public databaseLocation: DatabaseReferenceLocation, public name?: string) {
|
export interface IDatabaseReferenceProjectEntry extends ProjectEntry {
|
||||||
|
databaseName: string;
|
||||||
|
sqlCmdName?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DacpacReferenceProjectEntry extends ProjectEntry implements IDatabaseReferenceProjectEntry {
|
||||||
|
sqlCmdName: string | undefined;
|
||||||
|
|
||||||
|
constructor(uri: Uri, public databaseLocation: DatabaseReferenceLocation, name?: string) {
|
||||||
super(uri, '', EntryType.DatabaseReference);
|
super(uri, '', EntryType.DatabaseReference);
|
||||||
|
this.sqlCmdName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get databaseName(): string {
|
public get databaseName(): string {
|
||||||
@@ -577,9 +599,10 @@ export class DatabaseReferenceProjectEntry extends ProjectEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SystemDatabaseReferenceProjectEntry extends DatabaseReferenceProjectEntry {
|
class SystemDatabaseReferenceProjectEntry extends DacpacReferenceProjectEntry {
|
||||||
constructor(uri: Uri, public ssdtUri: Uri, public name: string) {
|
constructor(uri: Uri, public ssdtUri: Uri, name: string) {
|
||||||
super(uri, DatabaseReferenceLocation.differentDatabaseSameServer, name);
|
super(uri, DatabaseReferenceLocation.differentDatabaseSameServer, name);
|
||||||
|
this.sqlCmdName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public pathForSqlProj(): string {
|
public pathForSqlProj(): string {
|
||||||
@@ -593,6 +616,19 @@ class SystemDatabaseReferenceProjectEntry extends DatabaseReferenceProjectEntry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SqlProjectReferenceProjectEntry extends ProjectEntry implements IDatabaseReferenceProjectEntry {
|
||||||
|
projectName: string;
|
||||||
|
|
||||||
|
constructor(uri: Uri, name: string) {
|
||||||
|
super(uri, '', EntryType.DatabaseReference);
|
||||||
|
this.projectName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get databaseName(): string {
|
||||||
|
return this.projectName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export enum EntryType {
|
export enum EntryType {
|
||||||
File,
|
File,
|
||||||
Folder,
|
Folder,
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ async function readConnectionString(xmlDoc: any): Promise<{ connectionId: string
|
|||||||
let targetConnectionString: string = '';
|
let targetConnectionString: string = '';
|
||||||
let connId: string = '';
|
let connId: string = '';
|
||||||
|
|
||||||
if (xmlDoc.documentElement.getElementsByTagName('TargetConnectionString').length > 0) {
|
if (xmlDoc.documentElement.getElementsByTagName(constants.targetConnectionString).length > 0) {
|
||||||
targetConnectionString = xmlDoc.documentElement.getElementsByTagName('TargetConnectionString')[0].textContent;
|
targetConnectionString = xmlDoc.documentElement.getElementsByTagName(constants.TargetConnectionString)[0].textContent;
|
||||||
const dataSource = new SqlConnectionDataSource('temp', targetConnectionString);
|
const dataSource = new SqlConnectionDataSource('temp', targetConnectionString);
|
||||||
const connectionProfile = dataSource.getConnectionProfile();
|
const connectionProfile = dataSource.getConnectionProfile();
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import * as constants from '../../common/constants';
|
|||||||
import { BaseProjectTreeItem } from './baseTreeItem';
|
import { BaseProjectTreeItem } from './baseTreeItem';
|
||||||
import { ProjectRootTreeItem } from './projectTreeItem';
|
import { ProjectRootTreeItem } from './projectTreeItem';
|
||||||
import { IconPathHelper } from '../../common/iconHelper';
|
import { IconPathHelper } from '../../common/iconHelper';
|
||||||
import { DatabaseReferenceProjectEntry } from '../../models/project';
|
import { IDatabaseReferenceProjectEntry } from '../../models/project';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Folder for containing references nodes in the tree
|
* Folder for containing references nodes in the tree
|
||||||
@@ -44,7 +44,7 @@ export class DatabaseReferencesTreeItem extends BaseProjectTreeItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class DatabaseReferenceTreeItem extends BaseProjectTreeItem {
|
export class DatabaseReferenceTreeItem extends BaseProjectTreeItem {
|
||||||
constructor(private reference: DatabaseReferenceProjectEntry, referencesTreeItem: DatabaseReferencesTreeItem) {
|
constructor(private reference: IDatabaseReferenceProjectEntry, referencesTreeItem: DatabaseReferencesTreeItem) {
|
||||||
super(vscode.Uri.file(path.join(referencesTreeItem.uri.path, reference.databaseName)), referencesTreeItem);
|
super(vscode.Uri.file(path.join(referencesTreeItem.uri.path, reference.databaseName)), referencesTreeItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ export let SSDTProjectBaselineWithCleanTarget: string;
|
|||||||
export let SSDTProjectBaselineWithCleanTargetAfterUpdate: string;
|
export let SSDTProjectBaselineWithCleanTargetAfterUpdate: string;
|
||||||
export let publishProfileIntegratedSecurityBaseline: string;
|
export let publishProfileIntegratedSecurityBaseline: string;
|
||||||
export let publishProfileSqlLoginBaseline: string;
|
export let publishProfileSqlLoginBaseline: string;
|
||||||
|
export let openProjectWithProjectReferencesBaseline: string;
|
||||||
|
|
||||||
const baselineFolderPath = __dirname;
|
const baselineFolderPath = __dirname;
|
||||||
|
|
||||||
@@ -33,6 +34,7 @@ export async function loadBaselines() {
|
|||||||
SSDTProjectBaselineWithCleanTargetAfterUpdate = await loadBaseline(baselineFolderPath, 'SSDTProjectBaselineWithCleanTargetAfterUpdate.xml');
|
SSDTProjectBaselineWithCleanTargetAfterUpdate = await loadBaseline(baselineFolderPath, 'SSDTProjectBaselineWithCleanTargetAfterUpdate.xml');
|
||||||
publishProfileIntegratedSecurityBaseline = await loadBaseline(baselineFolderPath, 'publishProfileIntegratedSecurityBaseline.publish.xml');
|
publishProfileIntegratedSecurityBaseline = await loadBaseline(baselineFolderPath, 'publishProfileIntegratedSecurityBaseline.publish.xml');
|
||||||
publishProfileSqlLoginBaseline = await loadBaseline(baselineFolderPath, 'publishProfileSqlLoginBaseline.publish.xml');
|
publishProfileSqlLoginBaseline = await loadBaseline(baselineFolderPath, 'publishProfileSqlLoginBaseline.publish.xml');
|
||||||
|
openProjectWithProjectReferencesBaseline = await loadBaseline(baselineFolderPath, 'openSqlProjectWithProjectReferenceBaseline.xml');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadBaseline(baselineFolderPath: string, fileName: string): Promise<string> {
|
async function loadBaseline(baselineFolderPath: string, fileName: string): Promise<string> {
|
||||||
|
|||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?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>TestProjectWithReferenceName</Name>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectVersion>4.1</ProjectVersion>
|
||||||
|
<ProjectGuid>{BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575}</ProjectGuid>
|
||||||
|
<DSP>Microsoft.Data.Tools.Schema.Sql.Sql130DatabaseSchemaProvider</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>
|
||||||
|
<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\130\master.dacpac">
|
||||||
|
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
|
||||||
|
<DatabaseVariableLiteralValue>master</DatabaseVariableLiteralValue>
|
||||||
|
</ArtifactReference>
|
||||||
|
<ArtifactReference Condition="'$(NetCoreBuild)' != 'true'" Include="$(DacPacRootPath)\Extensions\Microsoft\SQLDB\Extensions\SqlServer\130\SqlSchemas\master.dacpac">
|
||||||
|
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
|
||||||
|
<DatabaseVariableLiteralValue>master</DatabaseVariableLiteralValue>
|
||||||
|
</ArtifactReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ReferencedProject\TestProject.sqlproj">
|
||||||
|
<Name>TestProjectName</Name>
|
||||||
|
<Project>{f9008554-068f-4f91-979a-58bd1f7c8f6e}</Project>
|
||||||
|
<Private>True</Private>
|
||||||
|
<SuppressMissingDependenciesErrors>False</SuppressMissingDependenciesErrors>
|
||||||
|
<DatabaseSqlCmdVariable>TestProjectName</DatabaseSqlCmdVariable>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Target Name="AfterClean">
|
||||||
|
<Delete Files="$(BaseIntermediateOutputPath)\project.assets.json" />
|
||||||
|
</Target>
|
||||||
|
</Project>
|
||||||
@@ -10,7 +10,7 @@ import * as testUtils from './testUtils';
|
|||||||
import * as constants from '../common/constants';
|
import * as constants from '../common/constants';
|
||||||
|
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { Project, EntryType, TargetPlatform, SystemDatabase, DatabaseReferenceLocation } from '../models/project';
|
import { Project, EntryType, TargetPlatform, SystemDatabase, DatabaseReferenceLocation, DacpacReferenceProjectEntry, SqlProjectReferenceProjectEntry } from '../models/project';
|
||||||
import { exists, convertSlashesForSqlProj } from '../common/utils';
|
import { exists, convertSlashesForSqlProj } from '../common/utils';
|
||||||
import { Uri } from 'vscode';
|
import { Uri } from 'vscode';
|
||||||
|
|
||||||
@@ -45,6 +45,20 @@ describe('Project: sqlproj content operations', function (): void {
|
|||||||
// should only have one database reference even though there are two master.dacpac references (1 for ADS and 1 for SSDT)
|
// should only have one database reference even though there are two master.dacpac references (1 for ADS and 1 for SSDT)
|
||||||
should(project.databaseReferences.length).equal(1);
|
should(project.databaseReferences.length).equal(1);
|
||||||
should(project.databaseReferences[0].databaseName).containEql(constants.master);
|
should(project.databaseReferences[0].databaseName).containEql(constants.master);
|
||||||
|
should(project.databaseReferences[0] instanceof DacpacReferenceProjectEntry).equal(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('Should read Project with Project reference from sqlproj', async function (): Promise<void> {
|
||||||
|
projFilePath = await testUtils.createTestSqlProjFile(baselines.openProjectWithProjectReferencesBaseline);
|
||||||
|
const project: Project = await Project.openProject(projFilePath);
|
||||||
|
|
||||||
|
// Database references
|
||||||
|
// should only have two database references even though there are two master.dacpac references (1 for ADS and 1 for SSDT)
|
||||||
|
should(project.databaseReferences.length).equal(2);
|
||||||
|
should(project.databaseReferences[0].databaseName).containEql(constants.master);
|
||||||
|
should(project.databaseReferences[0] instanceof DacpacReferenceProjectEntry).equal(true);
|
||||||
|
should(project.databaseReferences[1].databaseName).containEql('TestProjectName');
|
||||||
|
should(project.databaseReferences[1] instanceof SqlProjectReferenceProjectEntry).equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should add Folder and Build entries to sqlproj', async function (): Promise<void> {
|
it('Should add Folder and Build entries to sqlproj', async function (): Promise<void> {
|
||||||
|
|||||||
@@ -87,6 +87,21 @@ describe('ProjectsController', function (): void {
|
|||||||
should(project.dataSources.length).equal(2); // detailed datasources tests in their own test file
|
should(project.dataSources.length).equal(2); // detailed datasources tests in their own test file
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should load both project and referenced project', async function (): Promise<void> {
|
||||||
|
// setup test projects
|
||||||
|
const folderPath = await testUtils.generateTestFolderPath();
|
||||||
|
await fs.mkdir(path.join(folderPath, 'proj1'));
|
||||||
|
await fs.mkdir(path.join(folderPath, 'ReferencedProject'));
|
||||||
|
|
||||||
|
const sqlProjPath = await testUtils.createTestSqlProjFile(baselines.openProjectWithProjectReferencesBaseline, path.join(folderPath, 'proj1'));
|
||||||
|
await testUtils.createTestSqlProjFile(baselines.openProjectFileBaseline, path.join(folderPath, 'ReferencedProject'));
|
||||||
|
|
||||||
|
const projController = new ProjectsController(new SqlDatabaseProjectTreeViewProvider());
|
||||||
|
await projController.openProject(vscode.Uri.file(sqlProjPath));
|
||||||
|
|
||||||
|
should(projController.projects.length).equal(2, 'Referenced project should have been opened when the project referencing it was opened');
|
||||||
|
});
|
||||||
|
|
||||||
it('Should not keep failed to load project in project list.', async function (): Promise<void> {
|
it('Should not keep failed to load project in project list.', async function (): Promise<void> {
|
||||||
const folderPath = await testUtils.generateTestFolderPath();
|
const folderPath = await testUtils.generateTestFolderPath();
|
||||||
const sqlProjPath = await testUtils.createTestSqlProjFile('empty file with no valid xml', folderPath);
|
const sqlProjPath = await testUtils.createTestSqlProjFile('empty file with no valid xml', folderPath);
|
||||||
|
|||||||
Reference in New Issue
Block a user