From 0413b95343e4db08a58530179fdebd2de2aa984a Mon Sep 17 00:00:00 2001 From: Kim Santiago <31145923+kisantia@users.noreply.github.com> Date: Tue, 28 Feb 2023 11:59:09 -0800 Subject: [PATCH] Swap rename to use DacFx move api (#22051) * swap rename to use DacFx project apis * add support for rename pre/post deploy scripts and add tests * update the enum names too * check instanceof instead of getting and iterating through all the collections --- .../src/common/constants.ts | 8 +-- .../src/controllers/projectController.ts | 20 ++++-- .../src/models/tree/fileFolderTreeItem.ts | 8 +-- .../src/test/projectController.test.ts | 64 +++++++++++++++++++ .../src/test/projectTree.test.ts | 6 +- 5 files changed, 88 insertions(+), 18 deletions(-) diff --git a/extensions/sql-database-projects/src/common/constants.ts b/extensions/sql-database-projects/src/common/constants.ts index 2b5b20c10f..303e0fb5e3 100644 --- a/extensions/sql-database-projects/src/common/constants.ts +++ b/extensions/sql-database-projects/src/common/constants.ts @@ -565,10 +565,10 @@ export enum DatabaseProjectItemType { dataSourceRoot = 'databaseProject.itemType.dataSourceRoot', sqlcmdVariablesRoot = 'databaseProject.itemType.sqlcmdVariablesRoot', sqlcmdVariable = 'databaseProject.itemType.sqlcmdVariable', - preDeploy = 'databaseProject.itemType.file.preDeploymentScript', - postDeploy = 'databaseProject.itemType.file.postDeployScript', - none = 'databaseProject.itemType.file.noneFile', - sqlObjectFile = 'databaseProject.itemType.file.sqlObjectScript', + preDeploymentScript = 'databaseProject.itemType.file.preDeploymentScript', + postDeploymentScript = 'databaseProject.itemType.file.postDeployScript', + noneFile = 'databaseProject.itemType.file.noneFile', + sqlObjectScript = 'databaseProject.itemType.file.sqlObjectScript', publishProfile = 'databaseProject.itemType.file.publishProfile' } diff --git a/extensions/sql-database-projects/src/controllers/projectController.ts b/extensions/sql-database-projects/src/controllers/projectController.ts index c1a2f1f1fd..7754a4a4f1 100644 --- a/extensions/sql-database-projects/src/controllers/projectController.ts +++ b/extensions/sql-database-projects/src/controllers/projectController.ts @@ -20,7 +20,7 @@ import { promises as fs } from 'fs'; import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog'; import { Project, reservedProjectFolders } from '../models/project'; import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider'; -import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem'; +import { FolderNode, FileNode, SqlObjectFileNode, PreDeployNode, PostDeployNode } from '../models/tree/fileFolderTreeItem'; import { BaseProjectTreeItem } from '../models/tree/baseTreeItem'; import { ImportDataModel } from '../models/api/import'; import { NetCoreTool, DotNetError } from '../tools/netcoreTool'; @@ -856,12 +856,18 @@ export class ProjectsController { return; } - // TODO: swap this out and hookup to "Move" file/folder api - // rename the file - const newFilePath = path.join(path.dirname(file?.fsUri.fsPath!), `${newFileName}.sql`); - await fs.rename(file?.fsUri.fsPath!, newFilePath); - await project.exclude(file!); - await project.addExistingItem(newFilePath); + const newFilePath = path.join(path.dirname(utils.getPlatformSafeFileEntryPath(file?.relativePath!)), `${newFileName}.sql`); + const sqlProjectsService = await utils.getSqlProjectsService(); + + if (node instanceof SqlObjectFileNode) { + await sqlProjectsService.moveSqlObjectScript(project.projectFilePath, newFilePath, file!.relativePath) + } else if (node instanceof PreDeployNode) { + await sqlProjectsService.movePreDeploymentScript(project.projectFilePath, newFilePath, file!.relativePath) + } else if (node instanceof PostDeployNode) { + await sqlProjectsService.movePostDeploymentScript(project.projectFilePath, newFilePath, file!.relativePath) + } + // TODO add support for renaming none scripts after those are added in STS + // TODO add support for renaming publish profiles when support is added in DacFx this.refreshProjectsTree(context); } diff --git a/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts b/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts index 11eca5be8c..c7b390a0e7 100644 --- a/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts +++ b/extensions/sql-database-projects/src/models/tree/fileFolderTreeItem.ts @@ -68,7 +68,7 @@ export abstract class FileNode extends BaseProjectTreeItem { export class SqlObjectFileNode extends FileNode { public override get treeItem(): vscode.TreeItem { const treeItem = super.treeItem; - treeItem.contextValue = DatabaseProjectItemType.sqlObjectFile; + treeItem.contextValue = DatabaseProjectItemType.sqlObjectScript; return treeItem; } @@ -95,7 +95,7 @@ export class TableFileNode extends SqlObjectFileNode { export class PreDeployNode extends FileNode { public override get treeItem(): vscode.TreeItem { const treeItem = super.treeItem; - treeItem.contextValue = DatabaseProjectItemType.preDeploy; + treeItem.contextValue = DatabaseProjectItemType.preDeploymentScript; return treeItem; } @@ -104,7 +104,7 @@ export class PreDeployNode extends FileNode { export class PostDeployNode extends FileNode { public override get treeItem(): vscode.TreeItem { const treeItem = super.treeItem; - treeItem.contextValue = DatabaseProjectItemType.postDeploy; + treeItem.contextValue = DatabaseProjectItemType.postDeploymentScript; return treeItem; } @@ -113,7 +113,7 @@ export class PostDeployNode extends FileNode { export class NoneNode extends FileNode { public override get treeItem(): vscode.TreeItem { const treeItem = super.treeItem; - treeItem.contextValue = DatabaseProjectItemType.none; + treeItem.contextValue = DatabaseProjectItemType.noneFile; return treeItem; } diff --git a/extensions/sql-database-projects/src/test/projectController.test.ts b/extensions/sql-database-projects/src/test/projectController.test.ts index e0b3967e9d..d84edacbeb 100644 --- a/extensions/sql-database-projects/src/test/projectController.test.ts +++ b/extensions/sql-database-projects/src/test/projectController.test.ts @@ -923,6 +923,70 @@ describe('ProjectsController', function (): void { }); }); + describe('Rename file', function (): void { + it('Should not do anything if no new name is provided', async function (): Promise { + sinon.stub(vscode.window, 'showInputBox').resolves(''); + let proj = await testUtils.createTestProject(baselines.openSdkStyleSqlProjectBaseline); + const projTreeRoot = await setupMoveTest(proj); + const projController = new ProjectsController(testContext.outputChannel); + + // try to rename a file from the root folder + const sqlFileNode = projTreeRoot.children.find(x => x.friendlyName === 'script1.sql'); + await projController.rename(createWorkspaceTreeItem(sqlFileNode!)); + + // reload project and verify file was not renamed + proj = await Project.openProject(proj.projectFilePath); + should(proj.files.find(f => f.relativePath === 'script1.sql') !== undefined).be.true('The file path should not have been updated'); + should(await utils.exists(path.join(proj.projectFolderPath, 'script1.sql'))).be.true('The moved file should exist'); + }); + + it('Should rename a sql object file', async function (): Promise { + sinon.stub(vscode.window, 'showInputBox').resolves('newName'); + let proj = await testUtils.createTestProject(baselines.openSdkStyleSqlProjectBaseline); + const projTreeRoot = await setupMoveTest(proj); + const projController = new ProjectsController(testContext.outputChannel); + + // try to rename a file from the root folder + const sqlFileNode = projTreeRoot.children.find(x => x.friendlyName === 'script1.sql'); + await projController.rename(createWorkspaceTreeItem(sqlFileNode!)); + + // reload project and verify file was renamed + proj = await Project.openProject(proj.projectFilePath); + should(proj.files.find(f => f.relativePath === 'newName.sql') !== undefined).be.true('The file path should have been updated'); + should(await utils.exists(path.join(proj.projectFolderPath, 'newName.sql'))).be.true('The moved file should exist'); + }); + + it('Should rename a pre and post deploy script', async function (): Promise { + let proj = await testUtils.createTestProject(baselines.newSdkStyleProjectSdkNodeBaseline); + await proj.addScriptItem('Script.PreDeployment1.sql', 'pre-deployment stuff', ItemType.preDeployScript); + await proj.addScriptItem('Script.PostDeployment1.sql', 'post-deployment stuff', ItemType.postDeployScript); + + const projController = new ProjectsController(testContext.outputChannel); + const projTreeRoot = new ProjectRootTreeItem(proj); + + // try to rename a file from the root folder + sinon.stub(vscode.window, 'showInputBox').resolves('predeployNewName'); + const preDeployScriptNode = projTreeRoot.children.find(x => x.friendlyName === 'Script.PreDeployment1.sql'); + await projController.rename(createWorkspaceTreeItem(preDeployScriptNode!)); + + sinon.restore(); + sinon.stub(vscode.window, 'showInputBox').resolves('postdeployNewName'); + const postDeployScriptNode = projTreeRoot.children.find(x => x.friendlyName === 'Script.PostDeployment1.sql'); + await projController.rename(createWorkspaceTreeItem(postDeployScriptNode!)); + + // reload project and verify files were renamed + proj = await Project.openProject(proj.projectFilePath); + should(proj.preDeployScripts.find(f => f.relativePath === 'predeployNewName.sql') !== undefined).be.true('The pre deploy script file path should have been updated'); + should(await utils.exists(path.join(proj.projectFolderPath, 'predeployNewName.sql'))).be.true('The moved pre deploy script file should exist'); + + should(proj.postDeployScripts.find(f => f.relativePath === 'postdeployNewName.sql') !== undefined).be.true('The post deploy script file path should have been updated'); + should(await utils.exists(path.join(proj.projectFolderPath, 'postdeployNewName.sql'))).be.true('The moved post deploy script file should exist'); + }); + + + // TODO: add test for renaming a file in a folder after fix from DacFx for slashes is brought over + }); + describe('SqlCmd Variables', function (): void { it('Should delete sqlcmd variable', async function (): Promise { let project = await testUtils.createTestProject(baselines.openSdkStyleSqlProjectBaseline); diff --git a/extensions/sql-database-projects/src/test/projectTree.test.ts b/extensions/sql-database-projects/src/test/projectTree.test.ts index 44fd5ef5e4..bb3e5cc931 100644 --- a/extensions/sql-database-projects/src/test/projectTree.test.ts +++ b/extensions/sql-database-projects/src/test/projectTree.test.ts @@ -86,13 +86,13 @@ describe('Project Tree tests', function (): void { DatabaseProjectItemType.sqlcmdVariablesRoot, DatabaseProjectItemType.folder, DatabaseProjectItemType.folder, - DatabaseProjectItemType.sqlObjectFile]); + DatabaseProjectItemType.sqlObjectScript]); should(tree.children.find(x => x.relativeProjectUri.path === '/TestProj/someFolder')?.children.map(y => y.treeItem.contextValue)).deepEqual([ DatabaseProjectItemType.folder, DatabaseProjectItemType.folder, - DatabaseProjectItemType.sqlObjectFile, - DatabaseProjectItemType.sqlObjectFile]); + DatabaseProjectItemType.sqlObjectScript, + DatabaseProjectItemType.sqlObjectScript]); }); it('Should be able to parse windows relative path as platform safe path', function (): void {