Remove references to root in sql projects (#21911)

* update getFileProjectEntry and getRelativePath

* remove root and fix tests
This commit is contained in:
Kim Santiago
2023-02-14 10:34:46 -08:00
committed by GitHub
parent d5384cad0e
commit 71c12883fe
4 changed files with 78 additions and 61 deletions

View File

@@ -21,7 +21,6 @@ import { Project, reservedProjectFolders } from '../models/project';
import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider';
import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem';
import { BaseProjectTreeItem } from '../models/tree/baseTreeItem';
import { ProjectRootTreeItem } from '../models/tree/projectTreeItem';
import { ImportDataModel } from '../models/api/import';
import { NetCoreTool, DotNetError } from '../tools/netcoreTool';
import { ShellCommandOptions } from '../tools/shellExecutionHelper';
@@ -257,7 +256,7 @@ export class ProjectsController {
*/
public async buildProject(project: Project): Promise<string>;
public async buildProject(context: Project | dataworkspace.WorkspaceTreeItem): Promise<string> {
const project: Project = this.getProjectFromContext(context);
const project: Project = await this.getProjectFromContext(context);
const startTime = new Date();
const currentBuildTimeInfo = `${startTime.toLocaleDateString()} ${constants.at} ${startTime.toLocaleTimeString()}`;
@@ -332,7 +331,7 @@ export class ProjectsController {
public async publishToNewAzureServer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: ISqlDbDeployProfile): Promise<void> {
try {
TelemetryReporter.sendActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishToNewAzureServer);
const project: Project = this.getProjectFromContext(context);
const project: Project = await this.getProjectFromContext(context);
if (deployProfile?.deploySettings && deployProfile?.sqlDbSetting) {
void utils.showInfoMessageWithOutputChannel(constants.creatingAzureSqlServer(deployProfile?.sqlDbSetting?.serverName), this._outputChannel);
const connectionUri = await this.deployService.createNewAzureSqlServer(deployProfile);
@@ -365,7 +364,7 @@ export class ProjectsController {
* @param deployProfile
*/
public async publishToDockerContainer(context: Project | dataworkspace.WorkspaceTreeItem, deployProfile: IPublishToDockerSettings): Promise<void> {
const project: Project = this.getProjectFromContext(context);
const project: Project = await this.getProjectFromContext(context);
// Removing the path separator from the image base name to be able to add that in the telemetry. With the separator the name is flagged as user path which is not true
// We only need to know the image base parts so it's ok to use a different separator when adding to telemetry
const dockerImageNameForTelemetry = deployProfile.dockerSettings.dockerBaseImage.replace(/\//gi, '_');
@@ -411,7 +410,7 @@ export class ProjectsController {
*/
public async publishProject(project: Project): Promise<void>;
public async publishProject(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> {
const project: Project = this.getProjectFromContext(context);
const project: Project = await this.getProjectFromContext(context);
if (utils.getAzdataApi()) {
let publishDatabaseDialog = this.getPublishDialog(project);
@@ -589,7 +588,7 @@ export class ProjectsController {
let sourceParam;
if (source as dataworkspace.WorkspaceTreeItem) {
sourceParam = this.getProjectFromContext(source as dataworkspace.WorkspaceTreeItem).projectFilePath;
sourceParam = (await this.getProjectFromContext(source as dataworkspace.WorkspaceTreeItem)).projectFilePath;
} else {
sourceParam = source as azdataType.IConnectionProfile;
}
@@ -623,8 +622,9 @@ export class ProjectsController {
//#region Add/Exclude/Delete Item
public async addFolderPrompt(treeNode: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(treeNode);
const relativePathToParent = this.getRelativePath(treeNode.element);
const project = await this.getProjectFromContext(treeNode);
const projectRelativeUri = vscode.Uri.file(path.basename((treeNode.element as BaseProjectTreeItem).sqlprojUri.fsPath, constants.sqlprojExtension));
const relativePathToParent = this.getRelativePath(projectRelativeUri, treeNode.element);
const absolutePathToParent = path.join(project.projectFolderPath, relativePathToParent);
const newFolderName = await this.promptForNewObjectName(new templates.ProjectScriptType(ItemType.folder, constants.folderFriendlyName, ''),
project, absolutePathToParent);
@@ -679,7 +679,8 @@ export class ProjectsController {
}
public async addItemPromptFromNode(treeNode: dataworkspace.WorkspaceTreeItem, itemTypeName?: string): Promise<void> {
await this.addItemPrompt(this.getProjectFromContext(treeNode), this.getRelativePath(treeNode.element), { itemType: itemTypeName }, treeNode.treeDataProvider as SqlDatabaseProjectTreeViewProvider);
const projectRelativeUri = vscode.Uri.file(path.basename((treeNode.element as BaseProjectTreeItem).sqlprojUri.fsPath, constants.sqlprojExtension));
await this.addItemPrompt(await this.getProjectFromContext(treeNode), this.getRelativePath(projectRelativeUri, treeNode.element), { itemType: itemTypeName }, treeNode.treeDataProvider as SqlDatabaseProjectTreeViewProvider);
}
public async addItemPrompt(project: ISqlProject, relativePath: string, options?: AddItemOptions, treeDataProvider?: SqlDatabaseProjectTreeViewProvider): Promise<void> {
@@ -743,7 +744,7 @@ export class ProjectsController {
}
public async addExistingItemPrompt(treeNode: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(treeNode);
const project = await this.getProjectFromContext(treeNode);
const uris = await vscode.window.showOpenDialog({
canSelectFiles: true,
@@ -769,7 +770,7 @@ export class ProjectsController {
public async exclude(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const node = context.element as BaseProjectTreeItem;
const project = this.getProjectFromContext(node);
const project = await this.getProjectFromContext(node);
const fileEntry = this.getFileProjectEntry(project, node);
@@ -786,7 +787,7 @@ export class ProjectsController {
public async delete(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const node = context.element as BaseProjectTreeItem;
const project = this.getProjectFromContext(node);
const project = await this.getProjectFromContext(node);
let confirmationPrompt;
if (node instanceof DatabaseReferenceTreeItem) {
@@ -842,7 +843,7 @@ export class ProjectsController {
public async rename(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const node = context.element as BaseProjectTreeItem;
const project = this.getProjectFromContext(node);
const project = await this.getProjectFromContext(node);
const file = this.getFileProjectEntry(project, node);
// need to use quickpick because input box isn't supported in treeviews
@@ -881,7 +882,7 @@ export class ProjectsController {
*/
public async editSqlCmdVariable(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const node = context.element as SqlCmdVariableTreeItem;
const project = this.getProjectFromContext(node);
const project = await this.getProjectFromContext(node);
const originalValue = project.sqlCmdVariables[node.friendlyName]; // TODO: update to hookup with however sqlcmd vars work after swap
const newValue = await vscode.window.showInputBox(
@@ -903,7 +904,7 @@ export class ProjectsController {
* @param context
*/
public async addSqlCmdVariable(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
const variableName = await vscode.window.showInputBox(
{
@@ -939,10 +940,9 @@ export class ProjectsController {
}
private getDatabaseReference(project: Project, context: BaseProjectTreeItem): IDatabaseReferenceProjectEntry | undefined {
const root = context.root as ProjectRootTreeItem;
const databaseReference = context as DatabaseReferenceTreeItem;
if (root && databaseReference) {
if (databaseReference) {
return project.databaseReferences.find(r => r.databaseName === databaseReference.treeItem.label);
}
@@ -956,7 +956,7 @@ export class ProjectsController {
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async openContainingFolder(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
await vscode.commands.executeCommand(constants.revealFileInOsCommand, vscode.Uri.file(project.projectFilePath));
}
@@ -966,7 +966,7 @@ export class ProjectsController {
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async editProjectFile(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
try {
await vscode.commands.executeCommand(constants.vscodeOpenCommand, vscode.Uri.file(project.projectFilePath));
@@ -1004,7 +1004,8 @@ export class ProjectsController {
*/
public async openFileWithWatcher(fileSystemUri: vscode.Uri, node: FileNode): Promise<void> {
await vscode.commands.executeCommand(constants.vscodeOpenCommand, fileSystemUri);
const projectTargetVersion = (node.root as ProjectRootTreeItem).project.getProjectTargetVersion();
const project = await Project.openProject(node.sqlprojUri.fsPath);
const projectTargetVersion = project.getProjectTargetVersion();
const initiallyContainsCreateTableStatement = await utils.fileContainsCreateTableStatement(fileSystemUri.fsPath, projectTargetVersion);
const fileWatcher: vscode.FileSystemWatcher = vscode.workspace.createFileSystemWatcher(fileSystemUri.fsPath);
@@ -1037,7 +1038,7 @@ export class ProjectsController {
* @param context
*/
public async reloadProject(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
if (project) {
// won't open any newly referenced projects, but otherwise matches the behavior of reopening the project
await project.readProjFile();
@@ -1052,7 +1053,7 @@ export class ProjectsController {
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async changeTargetPlatform(context: Project | dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
const selectedTargetPlatform = (await vscode.window.showQuickPick((Array.from(constants.targetPlatformToVersion.keys())).map(version => { return { label: version }; }),
{
canPickMany: false,
@@ -1070,7 +1071,7 @@ export class ProjectsController {
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async convertToSdkStyleProject(context: dataworkspace.WorkspaceTreeItem): Promise<void> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
// confirm that user wants to update the project and knows the SSDT doesn't have support for displaying glob files yet
await vscode.window.showWarningMessage(constants.convertToSdkStyleConfirmation(project.projectFileName), { modal: true }, constants.yesString).then(async (result) => {
@@ -1101,7 +1102,7 @@ export class ProjectsController {
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async addDatabaseReference(context: Project | dataworkspace.WorkspaceTreeItem): Promise<AddDatabaseReferenceDialog | undefined> {
const project = this.getProjectFromContext(context);
const project = await this.getProjectFromContext(context);
if (utils.getAzdataApi()) {
const addDatabaseReferenceDialog = this.getAddDatabaseReferenceDialog(project);
@@ -1173,7 +1174,7 @@ export class ProjectsController {
* @param node a treeItem in a project's hierarchy, to be used to obtain a Project
*/
public async validateExternalStreamingJob(node: dataworkspace.WorkspaceTreeItem): Promise<mssql.ValidateStreamingJobResult> {
const project: Project = this.getProjectFromContext(node);
const project: Project = await this.getProjectFromContext(node);
let dacpacPath: string = project.dacpacOutputPath;
const preExistingDacpac = await utils.exists(dacpacPath);
@@ -1444,38 +1445,38 @@ export class ProjectsController {
//#region Helper methods
private getFileProjectEntry(project: Project, context: BaseProjectTreeItem): FileProjectEntry | undefined {
const root = context.root as ProjectRootTreeItem;
const fileOrFolder = context as FileNode ? context as FileNode : context as FolderNode;
if (root && fileOrFolder) {
if (fileOrFolder) {
// use relative path and not tree paths for files and folder
const allFileEntries = project.files.concat(project.preDeployScripts).concat(project.postDeployScripts).concat(project.noneDeployScripts);
// trim trailing slash since folders with and without a trailing slash are allowed in a sqlproj
const trimmedUri = utils.trimChars(utils.getPlatformSafeFileEntryPath(utils.trimUri(root.fileSystemUri, fileOrFolder.fileSystemUri)), '/');
const trimmedUri = utils.trimChars(utils.getPlatformSafeFileEntryPath(utils.trimUri(fileOrFolder.sqlprojUri, fileOrFolder.fileSystemUri)), '/');
return allFileEntries.find(x => utils.trimChars(utils.getPlatformSafeFileEntryPath(x.relativePath), '/') === trimmedUri);
}
return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(context.root.relativeProjectUri, context.relativeProjectUri)));
const projectRelativeUri = vscode.Uri.file(path.basename(context.sqlprojUri.fsPath, constants.sqlprojExtension));
return project.files.find(x => utils.getPlatformSafeFileEntryPath(x.relativePath) === utils.getPlatformSafeFileEntryPath(utils.trimUri(projectRelativeUri, context.relativeProjectUri)));
}
private getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Project {
private async getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Promise<Project> {
if ('element' in context) {
return context.element.root.project;
context = context.element;
}
if (context instanceof Project) {
return context;
}
if (context.root instanceof ProjectRootTreeItem) {
return (<ProjectRootTreeItem>context.root).project;
if (context instanceof BaseProjectTreeItem) {
return Project.openProject(context.sqlprojUri.fsPath);
} else {
throw new Error(constants.unexpectedProjectContext(context.relativeProjectUri.path));
throw new Error(constants.unexpectedProjectContext(JSON.stringify(context)));
}
}
private getRelativePath(treeNode: BaseProjectTreeItem): string {
return treeNode instanceof FolderNode ? utils.trimUri(treeNode.root.relativeProjectUri, treeNode.relativeProjectUri) : '';
private getRelativePath(rootProjectUri: vscode.Uri, treeNode: BaseProjectTreeItem): string {
return treeNode instanceof FolderNode ? utils.trimUri(rootProjectUri, treeNode.relativeProjectUri) : '';
}
private getConnectionProfileFromContext(context: azdataType.IConnectionProfile | mssqlVscode.ITreeNodeInfo | undefined): azdataType.IConnectionProfile | mssqlVscode.IConnectionInfo | undefined {
@@ -1666,7 +1667,7 @@ export class ProjectsController {
try {
if ('treeDataProvider' in context) {
project = this.getProjectFromContext(context as dataworkspace.WorkspaceTreeItem);
project = await this.getProjectFromContext(context as dataworkspace.WorkspaceTreeItem);
}
} catch { }