mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 17:22:45 -05:00
Adding SQL Edge project template (#13558)
* Checkpoint * removing flag for not creating subfolder * Adding Edge template * Removing janky map function * Adding templates for additional objects * Updating tests, fixing bug * Added Edge project icon * Updating strings to Drew-approved text * Cleaning up template scripts and Edge project template names
This commit is contained in:
@@ -23,9 +23,13 @@ export const MicrosoftDatatoolsSchemaSqlSql = 'Microsoft.Data.Tools.Schema.Sql.S
|
||||
export const databaseSchemaProvider = 'DatabaseSchemaProvider';
|
||||
|
||||
// Project Provider
|
||||
export const sqlDatabaseProjectTypeId = 'sqldbproj';
|
||||
export const projectTypeDisplayName = localize('projectTypeDisplayName', "SQL Database");
|
||||
export const projectTypeDescription = localize('projectTypeDescription', "Design, edit, and publish schemas for SQL databases");
|
||||
export const emptySqlDatabaseProjectTypeId = 'EmptySqlDbProj';
|
||||
export const emptyProjectTypeDisplayName = localize('emptyProjectTypeDisplayName', "SQL Database");
|
||||
export const emptyProjectTypeDescription = localize('emptyProjectTypeDescription', "Develop and publish schemas for SQL databases starting from an empty project");
|
||||
|
||||
export const edgeSqlDatabaseProjectTypeId = 'SqlDbEdgeProj';
|
||||
export const edgeProjectTypeDisplayName = localize('edgeProjectTypeDisplayName', "SQL Edge");
|
||||
export const edgeProjectTypeDescription = localize('edgeProjectTypeDescription', "Start with the core pieces to develop and publish schemas for SQL Edge");
|
||||
|
||||
// commands
|
||||
export const revealFileInOsCommand = 'revealFileInOS';
|
||||
@@ -196,6 +200,9 @@ export const scriptFriendlyName = localize('scriptFriendlyName', "Script");
|
||||
export const tableFriendlyName = localize('tableFriendlyName', "Table");
|
||||
export const viewFriendlyName = localize('viewFriendlyName', "View");
|
||||
export const storedProcedureFriendlyName = localize('storedProcedureFriendlyName', "Stored Procedure");
|
||||
export const dataSourceFriendlyName = localize('dataSource', "Data Source");
|
||||
export const fileFormatFriendlyName = localize('fileFormat', "File Format");
|
||||
export const externalStreamFriendlyName = localize('externalStream', "External Stream");
|
||||
export const externalStreamingJobFriendlyName = localize('externalStreamingJobFriendlyName', "External Streaming Job");
|
||||
export const preDeployScriptFriendlyName = localize('preDeployScriptFriendlyName', "Script.PreDeployment");
|
||||
export const postDeployScriptFriendlyName = localize('postDeployScriptFriendlyName', "Script.PostDeployment");
|
||||
|
||||
@@ -14,6 +14,7 @@ export class IconPathHelper {
|
||||
private static extensionContext: vscode.ExtensionContext;
|
||||
public static databaseProject: IconPath;
|
||||
public static colorfulSqlProject: IconPath;
|
||||
public static sqlEdgeProject: IconPath;
|
||||
|
||||
public static dataSourceGroup: IconPath;
|
||||
public static dataSourceSql: IconPath;
|
||||
@@ -33,6 +34,7 @@ export class IconPathHelper {
|
||||
|
||||
IconPathHelper.databaseProject = IconPathHelper.makeIcon('databaseProject');
|
||||
IconPathHelper.colorfulSqlProject = IconPathHelper.makeIcon('colorfulSqlProject', true);
|
||||
IconPathHelper.sqlEdgeProject = IconPathHelper.makeIcon('sqlEdgeProject', true);
|
||||
|
||||
IconPathHelper.dataSourceGroup = IconPathHelper.makeIcon('dataSourceGroup');
|
||||
IconPathHelper.dataSourceSql = IconPathHelper.makeIcon('dataSource-sql');
|
||||
|
||||
@@ -56,40 +56,35 @@ export class ProjectsController {
|
||||
* @param folderUri
|
||||
* @param projectGuid
|
||||
*/
|
||||
public async createNewProject(newProjName: string, folderUri: vscode.Uri, makeOwnFolder: boolean, projectGuid?: string): Promise<string> {
|
||||
if (projectGuid && !UUID.isUUID(projectGuid)) {
|
||||
throw new Error(`Specified GUID is invalid: '${projectGuid}'`);
|
||||
public async createNewProject(creationParams: NewProjectParams): Promise<string> {
|
||||
if (creationParams.projectGuid && !UUID.isUUID(creationParams.projectGuid)) {
|
||||
throw new Error(`Specified GUID is invalid: '${creationParams.projectGuid}'`);
|
||||
}
|
||||
|
||||
const macroDict: Record<string, string> = {
|
||||
'PROJECT_NAME': newProjName,
|
||||
'PROJECT_GUID': projectGuid ?? UUID.generateUuid().toUpperCase()
|
||||
'PROJECT_NAME': creationParams.newProjName,
|
||||
'PROJECT_GUID': creationParams.projectGuid ?? UUID.generateUuid().toUpperCase()
|
||||
};
|
||||
|
||||
let newProjFileContents = this.macroExpansion(templates.newSqlProjectTemplate, macroDict);
|
||||
let newProjFileContents = templates.macroExpansion(templates.newSqlProjectTemplate, macroDict);
|
||||
|
||||
let newProjFileName = newProjName;
|
||||
let newProjFileName = creationParams.newProjName;
|
||||
|
||||
if (!newProjFileName.toLowerCase().endsWith(constants.sqlprojExtension)) {
|
||||
newProjFileName += constants.sqlprojExtension;
|
||||
}
|
||||
|
||||
const newProjFilePath = makeOwnFolder ? path.join(folderUri.fsPath, path.parse(newProjFileName).name, newProjFileName) : path.join(folderUri.fsPath, newProjFileName);
|
||||
const newProjFilePath = path.join(creationParams.folderUri.fsPath, path.parse(newProjFileName).name, newProjFileName);
|
||||
|
||||
let fileExists = false;
|
||||
try {
|
||||
await fs.access(newProjFilePath);
|
||||
fileExists = true;
|
||||
}
|
||||
catch { } // file doesn't already exist
|
||||
|
||||
if (fileExists) {
|
||||
if (await utils.exists(newProjFilePath)) {
|
||||
throw new Error(constants.projectAlreadyExists(newProjFileName, path.parse(newProjFilePath).dir));
|
||||
}
|
||||
|
||||
await fs.mkdir(path.dirname(newProjFilePath), { recursive: true });
|
||||
await fs.writeFile(newProjFilePath, newProjFileContents);
|
||||
|
||||
await this.addTemplateFiles(newProjFilePath, creationParams.projectTypeId);
|
||||
|
||||
return newProjFilePath;
|
||||
}
|
||||
|
||||
@@ -256,7 +251,7 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
const itemType = templates.projectScriptTypeMap()[itemTypeName.toLocaleLowerCase()];
|
||||
const itemType = templates.get(itemTypeName);
|
||||
const absolutePathToParent = path.join(project.projectFolderPath, relativePath);
|
||||
let itemObjectName = await this.promptForNewObjectName(itemType, project, absolutePathToParent, constants.sqlFileExtension);
|
||||
|
||||
@@ -266,18 +261,10 @@ export class ProjectsController {
|
||||
return; // user cancelled
|
||||
}
|
||||
|
||||
const newFileText = this.macroExpansion(itemType.templateScript, { 'OBJECT_NAME': itemObjectName });
|
||||
const newFileText = templates.macroExpansion(itemType.templateScript, { 'OBJECT_NAME': itemObjectName });
|
||||
const relativeFilePath = path.join(relativePath, itemObjectName + constants.sqlFileExtension);
|
||||
|
||||
try {
|
||||
// check if file already exists
|
||||
const absoluteFilePath = path.join(project.projectFolderPath, relativeFilePath);
|
||||
const fileExists = await utils.exists(absoluteFilePath);
|
||||
|
||||
if (fileExists) {
|
||||
throw new Error(constants.fileAlreadyExists(path.parse(absoluteFilePath).name));
|
||||
}
|
||||
|
||||
const newEntry = await project.addScriptItem(relativeFilePath, newFileText, itemType.type);
|
||||
|
||||
await vscode.commands.executeCommand(constants.vscodeOpenCommand, newEntry.fsUri);
|
||||
@@ -460,6 +447,12 @@ export class ProjectsController {
|
||||
return addDatabaseReferenceDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a database reference to a project, after selections have been made in the dialog
|
||||
* @param project project to which to add the database reference
|
||||
* @param settings settings for the database reference
|
||||
* @param context a treeItem in a project's hierarchy, to be used to obtain a Project
|
||||
*/
|
||||
public async addDatabaseReferenceCallback(project: Project, settings: ISystemDatabaseReferenceSettings | IDacpacReferenceSettings | IProjectReferenceSettings, context: dataworkspace.WorkspaceTreeItem): Promise<void> {
|
||||
try {
|
||||
if ((<IProjectReferenceSettings>settings).projectName !== undefined) {
|
||||
@@ -494,6 +487,11 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the contents of an external streaming job's query against the last-built dacpac.
|
||||
* If no dacpac exists at the output path, one will be built first.
|
||||
* @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);
|
||||
|
||||
@@ -547,6 +545,29 @@ export class ProjectsController {
|
||||
}
|
||||
}
|
||||
|
||||
private async addTemplateFiles(newProjFilePath: string, projectTypeId: string): Promise<void> {
|
||||
if (projectTypeId === constants.emptySqlDatabaseProjectTypeId || newProjFilePath === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (projectTypeId === constants.edgeSqlDatabaseProjectTypeId) {
|
||||
const project = await Project.openProject(newProjFilePath);
|
||||
|
||||
await this.createFileFromTemplate(project, templates.get(templates.table), 'DataTable.sql', { 'OBJECT_NAME': 'DataTable' });
|
||||
await this.createFileFromTemplate(project, templates.get(templates.dataSource), 'EdgeHubInputDataSource.sql', { 'OBJECT_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'edgehub://' });
|
||||
await this.createFileFromTemplate(project, templates.get(templates.dataSource), 'SqlOutputDataSource.sql', { 'OBJECT_NAME': 'SqlOutputDataSource', 'LOCATION': 'sqlserver://tcp:.,1433' });
|
||||
await this.createFileFromTemplate(project, templates.get(templates.fileFormat), 'StreamFileFormat.sql', { 'OBJECT_NAME': 'StreamFileFormat' });
|
||||
await this.createFileFromTemplate(project, templates.get(templates.externalStream), 'EdgeHubInputStream.sql', { 'OBJECT_NAME': 'EdgeHubInputStream', 'DATA_SOURCE_NAME': 'EdgeHubInputDataSource', 'LOCATION': 'input', 'OPTIONS': ',\n\tFILE_FORMAT = StreamFileFormat' });
|
||||
await this.createFileFromTemplate(project, templates.get(templates.externalStream), 'SqlOutputStream.sql', { 'OBJECT_NAME': 'SqlOutputStream', 'DATA_SOURCE_NAME': 'SqlOutputDataSource', 'LOCATION': 'TSQLStreaming.dbo.DataTable', 'OPTIONS': '' });
|
||||
await this.createFileFromTemplate(project, templates.get(templates.externalStreamingJob), 'EdgeStreamingJob.sql', { 'OBJECT_NAME': 'EdgeStreamingJob' });
|
||||
}
|
||||
}
|
||||
|
||||
private async createFileFromTemplate(project: Project, itemType: templates.ProjectScriptType, relativePath: string, expansionMacros: Record<string, string>): Promise<void> {
|
||||
const newFileText = templates.macroExpansion(itemType.templateScript, expansionMacros);
|
||||
await project.addScriptItem(relativePath, newFileText, itemType.type);
|
||||
}
|
||||
|
||||
private getProjectFromContext(context: Project | BaseProjectTreeItem | dataworkspace.WorkspaceTreeItem): Project {
|
||||
if ('element' in context) {
|
||||
return context.element.root.project;
|
||||
@@ -570,21 +591,7 @@ export class ProjectsController {
|
||||
return (ext.exports as mssql.IExtension).dacFx;
|
||||
}
|
||||
|
||||
private macroExpansion(template: string, macroDict: Record<string, string>): string {
|
||||
const macroIndicator = '@@';
|
||||
let output = template;
|
||||
|
||||
for (const macro in macroDict) {
|
||||
// check if value contains the macroIndicator, which could break expansion for successive macros
|
||||
if (macroDict[macro].includes(macroIndicator)) {
|
||||
throw new Error(`Macro value ${macroDict[macro]} is invalid because it contains ${macroIndicator}`);
|
||||
}
|
||||
|
||||
output = output.replace(new RegExp(macroIndicator + macro + macroIndicator, 'g'), macroDict[macro]);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private async promptForNewObjectName(itemType: templates.ProjectScriptType, _project: Project, folderPath: string, fileExtension?: string): Promise<string | undefined> {
|
||||
const suggestedName = itemType.friendlyName.replace(/\s+/g, '');
|
||||
@@ -632,7 +639,12 @@ export class ProjectsController {
|
||||
|
||||
const newProjFolderUri = model.filePath;
|
||||
|
||||
const newProjFilePath = await this.createNewProject(model.projName, vscode.Uri.file(newProjFolderUri), true);
|
||||
const newProjFilePath = await this.createNewProject({
|
||||
newProjName: model.projName,
|
||||
folderUri: vscode.Uri.file(newProjFolderUri),
|
||||
projectTypeId: constants.emptySqlDatabaseProjectTypeId
|
||||
});
|
||||
|
||||
model.filePath = path.dirname(newProjFilePath);
|
||||
this.setFilePath(model);
|
||||
|
||||
@@ -718,3 +730,10 @@ export class ProjectsController {
|
||||
|
||||
//#endregion
|
||||
}
|
||||
|
||||
export interface NewProjectParams {
|
||||
newProjName: string;
|
||||
folderUri: vscode.Uri;
|
||||
projectTypeId: string;
|
||||
projectGuid?: string;
|
||||
}
|
||||
|
||||
@@ -282,19 +282,26 @@ export class Project {
|
||||
* @param contents Contents to be written to the new file
|
||||
*/
|
||||
public async addScriptItem(relativeFilePath: string, contents?: string, itemType?: string): Promise<FileProjectEntry> {
|
||||
// check if file already exists
|
||||
const absoluteFilePath = path.join(this.projectFolderPath, relativeFilePath);
|
||||
|
||||
if (contents !== undefined && contents !== '' && await utils.exists(absoluteFilePath)) {
|
||||
throw new Error(constants.fileAlreadyExists(path.parse(absoluteFilePath).name));
|
||||
}
|
||||
|
||||
// create the file
|
||||
if (contents) {
|
||||
await fs.mkdir(path.dirname(absoluteFilePath), { recursive: true });
|
||||
await fs.writeFile(absoluteFilePath, contents);
|
||||
}
|
||||
|
||||
//Check that file actually exists
|
||||
// check that file was successfully created
|
||||
let exists = await utils.exists(absoluteFilePath);
|
||||
if (!exists) {
|
||||
throw new Error(constants.noFileExist(absoluteFilePath));
|
||||
}
|
||||
|
||||
// update sqlproj XML
|
||||
const fileEntry = this.createFileProjectEntry(relativeFilePath, EntryType.File);
|
||||
|
||||
let xmlTag;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import * as dataworkspace from 'dataworkspace';
|
||||
import * as vscode from 'vscode';
|
||||
import { sqlprojExtension, projectTypeDisplayName, projectTypeDescription, sqlDatabaseProjectTypeId } from '../common/constants';
|
||||
import * as constants from '../common/constants';
|
||||
import { IconPathHelper } from '../common/iconHelper';
|
||||
import { SqlDatabaseProjectTreeViewProvider } from '../controllers/databaseProjectTreeViewProvider';
|
||||
import { ProjectsController } from '../controllers/projectController';
|
||||
@@ -44,11 +44,18 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide
|
||||
*/
|
||||
get supportedProjectTypes(): dataworkspace.IProjectType[] {
|
||||
return [{
|
||||
id: sqlDatabaseProjectTypeId,
|
||||
projectFileExtension: sqlprojExtension.replace(/\./g, ''),
|
||||
displayName: projectTypeDisplayName,
|
||||
description: projectTypeDescription,
|
||||
id: constants.emptySqlDatabaseProjectTypeId,
|
||||
projectFileExtension: constants.sqlprojExtension.replace(/\./g, ''),
|
||||
displayName: constants.emptyProjectTypeDisplayName,
|
||||
description: constants.emptyProjectTypeDescription,
|
||||
icon: IconPathHelper.colorfulSqlProject
|
||||
},
|
||||
{
|
||||
id: constants.edgeSqlDatabaseProjectTypeId,
|
||||
projectFileExtension: constants.sqlprojExtension.replace(/\./g, ''),
|
||||
displayName: constants.edgeProjectTypeDisplayName,
|
||||
description: constants.edgeProjectTypeDescription,
|
||||
icon: IconPathHelper.sqlEdgeProject
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -56,10 +63,16 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide
|
||||
* Create a project
|
||||
* @param name name of the project
|
||||
* @param location the parent directory
|
||||
* @param projectTypeId the ID of the project/template
|
||||
* @returns Uri of the newly created project file
|
||||
*/
|
||||
async createProject(name: string, location: vscode.Uri, _: string): Promise<vscode.Uri> {
|
||||
const projectFile = await this.projectController.createNewProject(name, location, true);
|
||||
async createProject(name: string, location: vscode.Uri, projectTypeId: string): Promise<vscode.Uri> {
|
||||
const projectFile = await this.projectController.createNewProject({
|
||||
newProjName: name,
|
||||
folderUri: location,
|
||||
projectTypeId: projectTypeId
|
||||
});
|
||||
|
||||
return vscode.Uri.file(projectFile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,9 @@ export const script: string = 'script';
|
||||
export const table: string = 'table';
|
||||
export const view: string = 'view';
|
||||
export const storedProcedure: string = 'storedProcedure';
|
||||
export const dataSource: string = 'dataSource';
|
||||
export const fileFormat: string = 'fileFormat';
|
||||
export const externalStream: string = 'externalStream';
|
||||
export const externalStreamingJob: string = 'externalStreamingJob';
|
||||
|
||||
export const folder: string = 'folder';
|
||||
@@ -25,12 +28,12 @@ export const postDeployScript: string = 'postDeployScript';
|
||||
|
||||
let scriptTypeMap: Record<string, ProjectScriptType> = {};
|
||||
|
||||
export function projectScriptTypeMap(): Record<string, ProjectScriptType> {
|
||||
export function get(key: string): ProjectScriptType {
|
||||
if (Object.keys(scriptTypeMap).length === 0) {
|
||||
throw new Error('Templates must be loaded from file before attempting to use.');
|
||||
}
|
||||
|
||||
return scriptTypeMap;
|
||||
return scriptTypeMap[key.toLocaleLowerCase()];
|
||||
}
|
||||
|
||||
let scriptTypes: ProjectScriptType[] = [];
|
||||
@@ -44,6 +47,8 @@ export function projectScriptTypes(): ProjectScriptType[] {
|
||||
}
|
||||
|
||||
export async function loadTemplates(templateFolderPath: string) {
|
||||
reset();
|
||||
|
||||
await Promise.all([
|
||||
Promise.resolve(newSqlProjectTemplate = await loadTemplate(templateFolderPath, 'newSqlProjectTemplate.xml')),
|
||||
loadObjectTypeInfo(script, constants.scriptFriendlyName, templateFolderPath, 'newTsqlScriptTemplate.sql'),
|
||||
@@ -52,11 +57,14 @@ export async function loadTemplates(templateFolderPath: string) {
|
||||
loadObjectTypeInfo(storedProcedure, constants.storedProcedureFriendlyName, templateFolderPath, 'newTsqlStoredProcedureTemplate.sql'),
|
||||
loadObjectTypeInfo(preDeployScript, constants.preDeployScriptFriendlyName, templateFolderPath, 'newTsqlPreDeployScriptTemplate.sql'),
|
||||
loadObjectTypeInfo(postDeployScript, constants.postDeployScriptFriendlyName, templateFolderPath, 'newTsqlPostDeployScriptTemplate.sql'),
|
||||
loadObjectTypeInfo(dataSource, constants.dataSourceFriendlyName, templateFolderPath, 'newTsqlDataSourceTemplate.sql'),
|
||||
loadObjectTypeInfo(fileFormat, constants.fileFormatFriendlyName, templateFolderPath, 'newTsqlFileFormatTemplate.sql'),
|
||||
loadObjectTypeInfo(externalStream, constants.externalStreamFriendlyName, templateFolderPath, 'newTsqlExternalStreamTemplate.sql'),
|
||||
loadObjectTypeInfo(externalStreamingJob, constants.externalStreamingJobFriendlyName, templateFolderPath, 'newTsqlExternalStreamingJobTemplate.sql')
|
||||
]);
|
||||
|
||||
for (const scriptType of scriptTypes) {
|
||||
if (Object.keys(projectScriptTypeMap).find(s => s === scriptType.type.toLocaleLowerCase() || s === scriptType.friendlyName.toLocaleLowerCase())) {
|
||||
if (Object.keys(scriptTypeMap).find(s => s === scriptType.type.toLocaleLowerCase() || s === scriptType.friendlyName.toLocaleLowerCase())) {
|
||||
throw new Error(`Script type map already contains ${scriptType.type} or its friendlyName.`);
|
||||
}
|
||||
|
||||
@@ -65,9 +73,27 @@ export async function loadTemplates(templateFolderPath: string) {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadObjectTypeInfo(key: string, friendlyName: string, templateFolderPath: string, fileName: string) {
|
||||
export function macroExpansion(template: string, macroDict: Record<string, string>): string {
|
||||
const macroIndicator = '@@';
|
||||
let output = template;
|
||||
|
||||
for (const macro in macroDict) {
|
||||
// check if value contains the macroIndicator, which could break expansion for successive macros
|
||||
if (macroDict[macro].includes(macroIndicator)) {
|
||||
throw new Error(`Macro value ${macroDict[macro]} is invalid because it contains ${macroIndicator}`);
|
||||
}
|
||||
|
||||
output = output.replace(new RegExp(macroIndicator + macro + macroIndicator, 'g'), macroDict[macro]);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
async function loadObjectTypeInfo(key: string, friendlyName: string, templateFolderPath: string, fileName: string): Promise<string> {
|
||||
const template = await loadTemplate(templateFolderPath, fileName);
|
||||
scriptTypes.push(new ProjectScriptType(key, friendlyName, template));
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
async function loadTemplate(templateFolderPath: string, fileName: string): Promise<string> {
|
||||
|
||||
@@ -16,6 +16,7 @@ import { PublishDatabaseDialog } from '../../dialogs/publishDatabaseDialog';
|
||||
import { Project } from '../../models/project';
|
||||
import { ProjectsController } from '../../controllers/projectController';
|
||||
import { IPublishSettings, IGenerateScriptSettings } from '../../models/IPublishSettings';
|
||||
import { emptySqlDatabaseProjectTypeId } from '../../common/constants';
|
||||
|
||||
describe.skip('Publish Database Dialog', () => {
|
||||
before(async function (): Promise<void> {
|
||||
@@ -27,7 +28,13 @@ describe.skip('Publish Database Dialog', () => {
|
||||
const projController = new ProjectsController();
|
||||
const projFileDir = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`);
|
||||
|
||||
const projFilePath = await projController.createNewProject('TestProjectName', vscode.Uri.file(projFileDir), true, 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575');
|
||||
const projFilePath = await projController.createNewProject({
|
||||
newProjName: 'TestProjectName',
|
||||
folderUri: vscode.Uri.file(projFileDir),
|
||||
projectTypeId: emptySqlDatabaseProjectTypeId,
|
||||
projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'
|
||||
});
|
||||
|
||||
const project = new Project(projFilePath);
|
||||
const publishDatabaseDialog = new PublishDatabaseDialog(project);
|
||||
publishDatabaseDialog.openDialog();
|
||||
@@ -39,7 +46,13 @@ describe.skip('Publish Database Dialog', () => {
|
||||
const projFolder = `TestProject_${new Date().getTime()}`;
|
||||
const projFileDir = path.join(os.tmpdir(), projFolder);
|
||||
|
||||
const projFilePath = await projController.createNewProject('TestProjectName', vscode.Uri.file(projFileDir), true, 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575');
|
||||
const projFilePath = await projController.createNewProject({
|
||||
newProjName: 'TestProjectName',
|
||||
folderUri: vscode.Uri.file(projFileDir),
|
||||
projectTypeId: emptySqlDatabaseProjectTypeId,
|
||||
projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'
|
||||
});
|
||||
|
||||
const project = new Project(projFilePath);
|
||||
|
||||
const publishDatabaseDialog = new PublishDatabaseDialog(project);
|
||||
@@ -55,7 +68,7 @@ describe.skip('Publish Database Dialog', () => {
|
||||
|
||||
let profile: IPublishSettings | IGenerateScriptSettings | undefined;
|
||||
|
||||
const expectedPublish: IPublishSettings = {
|
||||
const expectedPublish: IPublishSettings = {
|
||||
databaseName: 'MockDatabaseName',
|
||||
connectionUri: 'Mock|Connection|Uri',
|
||||
upgradeExisting: true,
|
||||
|
||||
@@ -54,7 +54,12 @@ describe('ProjectsController', function (): void {
|
||||
const projController = new ProjectsController();
|
||||
const projFileDir = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`);
|
||||
|
||||
const projFilePath = await projController.createNewProject('TestProjectName', vscode.Uri.file(projFileDir), false, 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575');
|
||||
const projFilePath = await projController.createNewProject({
|
||||
newProjName: 'TestProjectName',
|
||||
folderUri: vscode.Uri.file(projFileDir),
|
||||
projectTypeId: constants.emptySqlDatabaseProjectTypeId,
|
||||
projectGuid: 'BA5EBA11-C0DE-5EA7-ACED-BABB1E70A575'
|
||||
});
|
||||
|
||||
let projFileText = (await fs.readFile(projFilePath)).toString();
|
||||
|
||||
@@ -152,6 +157,7 @@ describe('ProjectsController', function (): void {
|
||||
|
||||
it('Should delete nested ProjectEntry from node', async function (): Promise<void> {
|
||||
let proj = await testUtils.createTestProject(templates.newSqlProjectTemplate);
|
||||
|
||||
const setupResult = await setupDeleteExcludeTest(proj);
|
||||
const scriptEntry = setupResult[0], projTreeRoot = setupResult[1], preDeployEntry = setupResult[2], postDeployEntry = setupResult[3], noneEntry = setupResult[4];
|
||||
|
||||
@@ -436,7 +442,15 @@ describe('ProjectsController', function (): void {
|
||||
const createProjectFromDatabaseDialog = TypeMoq.Mock.ofType(CreateProjectFromDatabaseDialog, undefined, undefined, undefined);
|
||||
createProjectFromDatabaseDialog.callBase = true;
|
||||
createProjectFromDatabaseDialog.setup(x => x.handleCreateButtonClick()).returns(async () => {
|
||||
await projController.object.createProjectFromDatabaseCallback( { serverId: 'My Id', database: 'My Database', projName: 'testProject', filePath: 'testLocation', version: '1.0.0.0', extractTarget: mssql.ExtractTarget['schemaObjectType'] });
|
||||
await projController.object.createProjectFromDatabaseCallback({
|
||||
serverId: 'My Id',
|
||||
database: 'My Database',
|
||||
projName: 'testProject',
|
||||
filePath: 'testLocation',
|
||||
version: '1.0.0.0',
|
||||
extractTarget: mssql.ExtractTarget['schemaObjectType']
|
||||
});
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
});
|
||||
|
||||
|
||||
@@ -14,8 +14,8 @@ describe('Templates: loading templates from disk', function (): void {
|
||||
});
|
||||
|
||||
it('Should throw error when attempting to use templates before loaded from file', async function (): Promise<void> {
|
||||
await shouldThrowSpecificError(() => templates.projectScriptTypeMap(), 'Templates must be loaded from file before attempting to use.');
|
||||
await shouldThrowSpecificError(() => templates.projectScriptTypes(), 'Templates must be loaded from file before attempting to use.');
|
||||
await shouldThrowSpecificError(() => templates.get('foobar'), 'Templates must be loaded from file before attempting to use.');
|
||||
await shouldThrowSpecificError(() => templates.get('foobar'), 'Templates must be loaded from file before attempting to use.');
|
||||
});
|
||||
|
||||
it('Should load all templates from files', async function (): Promise<void> {
|
||||
@@ -23,7 +23,7 @@ describe('Templates: loading templates from disk', function (): void {
|
||||
|
||||
// check expected counts
|
||||
|
||||
const numScriptObjectTypes = 7;
|
||||
const numScriptObjectTypes = 10;
|
||||
|
||||
should(templates.projectScriptTypes().length).equal(numScriptObjectTypes);
|
||||
should(Object.keys(templates.projectScriptTypes()).length).equal(numScriptObjectTypes);
|
||||
|
||||
@@ -28,6 +28,7 @@ export async function shouldThrowSpecificError(block: Function, expectedMessage:
|
||||
}
|
||||
|
||||
export async function createTestSqlProjFile(contents: string, folderPath?: string): Promise<string> {
|
||||
folderPath = folderPath ?? path.join(await generateTestFolderPath(), 'TestProject');
|
||||
return await createTestFile(contents, 'TestProject.sqlproj', folderPath);
|
||||
}
|
||||
|
||||
@@ -40,7 +41,7 @@ export async function createTestDataSources(contents: string, folderPath?: strin
|
||||
}
|
||||
|
||||
export async function generateTestFolderPath(): Promise<string> {
|
||||
const folderPath = path.join(os.tmpdir(), `TestProject_${new Date().getTime()}`);
|
||||
const folderPath = path.join(os.tmpdir(), `TestRun_${new Date().getTime()}`);
|
||||
await fs.mkdir(folderPath, { recursive: true });
|
||||
|
||||
return folderPath;
|
||||
@@ -55,6 +56,7 @@ export async function createTestFile(contents: string, fileName: string, folderP
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* TestFolder directory structure
|
||||
* - file1.sql
|
||||
|
||||
Reference in New Issue
Block a user