mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-14 01:25:37 -05:00
Auto increment new db project name (#11882)
* auto increment db proj name * auto increment on import project from db * adding separate message if workspace setting is invalid * updating based on feedback * adding do not ask again functionality * moving constants * making newprojecttool only top level functions * adding tests * updating to address merge conflicts * fixing tests * fixing tests
This commit is contained in:
@@ -35,6 +35,15 @@
|
||||
"sqlDatabaseProjects.netCoreSDKLocation": {
|
||||
"type": "string",
|
||||
"description": "%sqlDatabaseProjects.netCoreInstallLocation%"
|
||||
},
|
||||
"sqlDatabaseProjects.defaultProjectSaveLocation": {
|
||||
"type": "string",
|
||||
"description": "%sqlDatabaseProjects.defaultProjectSaveLocation%"
|
||||
},
|
||||
"sqlDatabaseProjects.showUpdateSaveLocationPrompt": {
|
||||
"type": "boolean",
|
||||
"description": "%sqlDatabaseProjects.showUpdateSaveLocationPrompt%",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
"sqlDatabaseProjects.openContainingFolder": "Open Containing Folder",
|
||||
|
||||
"sqlDatabaseProjects.Settings": "Database Projects",
|
||||
"sqlDatabaseProjects.netCoreInstallLocation": "Full Path to .Net Core SDK on the machine.",
|
||||
"sqlDatabaseProjects.netCoreInstallLocation": "Full path to .Net Core SDK on the machine.",
|
||||
"sqlDatabaseProjects.defaultProjectSaveLocation": "Full path to folder where new database projects are saved by default.",
|
||||
"sqlDatabaseProjects.showUpdateSaveLocationPrompt": "After creating a new database project, always prompt to update the location where new projects are saved by default.",
|
||||
"sqlDatabaseProjects.welcome": "No database projects currently open.\n[New Project](command:sqlDatabaseProjects.new)\n[Open Project](command:sqlDatabaseProjects.open)\n[Create Project From Database](command:sqlDatabaseProjects.importDatabase)"
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ export const flat = localize('flat', "Flat");
|
||||
export const objectType = localize('objectType', "Object Type");
|
||||
export const schema = localize('schema', "Schema");
|
||||
export const schemaObjectType = localize('schemaObjectType', "Schema/Object Type");
|
||||
export const defaultProjectNameStarter = localize('defaultProjectNameStarter', "DatabaseProject");
|
||||
export const newDefaultProjectSaveLocation = localize('newDefaultProjectSaveLocation', "Would you like to update the default location to save new database projects?");
|
||||
export const invalidDefaultProjectSaveLocation = localize('invalidDefaultProjectSaveLocation', "Default location to save new database projects is invalid. Would you like to update it?");
|
||||
export const openWorkspaceSettings = localize('openWorkspaceSettings', "Yes, open Settings");
|
||||
export const doNotPromptAgain = localize('doNotPromptAgain', "Don't ask again");
|
||||
export function newObjectNamePrompt(objectType: string) { return localize('newObjectNamePrompt', 'New {0} name:', objectType); }
|
||||
export function deleteConfirmation(toDelete: string) { return localize('deleteConfirmation', "Are you sure you want to delete {0}?", toDelete); }
|
||||
export function deleteConfirmationContents(toDelete: string) { return localize('deleteConfirmationContents', "Are you sure you want to delete {0} and all of its contents?", toDelete); }
|
||||
@@ -207,6 +212,11 @@ export const activeDirectoryInteractive = 'active directory interactive';
|
||||
export const userIdSetting = 'User ID';
|
||||
export const passwordSetting = 'Password';
|
||||
|
||||
// Workspace settings for saving new database projects
|
||||
export const dbProjectConfigurationKey = 'sqlDatabaseProjects';
|
||||
export const projectSaveLocationKey = 'defaultProjectSaveLocation';
|
||||
export const showUpdatePromptKey = 'showUpdateSaveLocationPrompt';
|
||||
|
||||
// Authentication types
|
||||
export const integratedAuth = 'Integrated';
|
||||
export const azureMfaAuth = 'AzureMFA';
|
||||
|
||||
@@ -9,6 +9,7 @@ import * as templates from '../templates/templates';
|
||||
import * as constants from '../common/constants';
|
||||
import * as path from 'path';
|
||||
import * as glob from 'fast-glob';
|
||||
import * as newProjectTool from '../tools/newProjectTool';
|
||||
|
||||
import { SqlDatabaseProjectTreeViewProvider } from './databaseProjectTreeViewProvider';
|
||||
import { getErrorMessage } from '../common/utils';
|
||||
@@ -89,6 +90,9 @@ export default class MainController implements vscode.Disposable {
|
||||
// ensure .net core is installed
|
||||
await this.netcoreTool.findOrInstallNetCore();
|
||||
|
||||
// set the user settings around saving new projects to default value
|
||||
await newProjectTool.initializeSaveLocationSetting();
|
||||
|
||||
// load any sql projects that are open in workspace folder
|
||||
await this.loadProjectsInWorkspace();
|
||||
}
|
||||
@@ -144,8 +148,7 @@ export default class MainController implements vscode.Disposable {
|
||||
try {
|
||||
let newProjName = await vscode.window.showInputBox({
|
||||
prompt: constants.newDatabaseProjectName,
|
||||
value: `DatabaseProject${this.projectsController.projects.length + 1}`
|
||||
// TODO: Smarter way to suggest a name. Easy if we prompt for location first, but that feels odd...
|
||||
value: newProjectTool.defaultProjectNameNewProj()
|
||||
});
|
||||
|
||||
newProjName = newProjName?.trim();
|
||||
@@ -160,7 +163,7 @@ export default class MainController implements vscode.Disposable {
|
||||
canSelectFiles: false,
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
defaultUri: vscode.workspace.workspaceFolders ? (vscode.workspace.workspaceFolders as vscode.WorkspaceFolder[])[0].uri : undefined
|
||||
defaultUri: newProjectTool.defaultProjectSaveLocation()
|
||||
});
|
||||
|
||||
if (!selectionResult) {
|
||||
@@ -174,6 +177,8 @@ export default class MainController implements vscode.Disposable {
|
||||
const newProjFilePath = await this.projectsController.createNewProject(<string>newProjName, newProjFolderUri, true);
|
||||
const proj = await this.projectsController.openProject(vscode.Uri.file(newProjFilePath));
|
||||
|
||||
newProjectTool.updateSaveLocationSetting();
|
||||
|
||||
return proj;
|
||||
}
|
||||
catch (err) {
|
||||
|
||||
@@ -11,9 +11,10 @@ import * as path from 'path';
|
||||
import * as utils from '../common/utils';
|
||||
import * as UUID from 'vscode-languageclient/lib/utils/uuid';
|
||||
import * as templates from '../templates/templates';
|
||||
|
||||
import * as newProjectTool from '../tools/newProjectTool';
|
||||
import * as vscode from 'vscode';
|
||||
import * as azdata from 'azdata';
|
||||
|
||||
import { promises as fs } from 'fs';
|
||||
import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog';
|
||||
import { Project, DatabaseReferenceLocation, SystemDatabase, TargetPlatform, ProjectEntry, reservedProjectFolders, SqlProjectReferenceProjectEntry } from '../models/project';
|
||||
@@ -661,6 +662,8 @@ export class ProjectsController {
|
||||
model.extractTarget = await this.getExtractTarget();
|
||||
model.version = '1.0.0.0';
|
||||
|
||||
newProjectTool.updateSaveLocationSetting();
|
||||
|
||||
const newProjFilePath = await this.createNewProject(model.projName, vscode.Uri.file(newProjFolderUri), true);
|
||||
model.filePath = path.dirname(newProjFilePath);
|
||||
|
||||
@@ -739,7 +742,7 @@ export class ProjectsController {
|
||||
private async getProjectName(dbName: string): Promise<string> {
|
||||
let projName = await vscode.window.showInputBox({
|
||||
prompt: constants.newDatabaseProjectName,
|
||||
value: `DatabaseProject${dbName}`
|
||||
value: newProjectTool.defaultProjectNameFromDb(dbName)
|
||||
});
|
||||
|
||||
projName = projName?.trim();
|
||||
@@ -797,7 +800,7 @@ export class ProjectsController {
|
||||
canSelectFolders: true,
|
||||
canSelectMany: false,
|
||||
openLabel: constants.selectString,
|
||||
defaultUri: vscode.workspace.workspaceFolders ? (vscode.workspace.workspaceFolders as vscode.WorkspaceFolder[])[0].uri : undefined
|
||||
defaultUri: newProjectTool.defaultProjectSaveLocation()
|
||||
});
|
||||
|
||||
if (selectionResult) {
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as should from 'should';
|
||||
import * as newProjectTool from '../tools/newProjectTool';
|
||||
import * as constants from '../common/constants';
|
||||
import { generateTestFolderPath, createTestFile } from './testUtils';
|
||||
|
||||
let previousSetting : string;
|
||||
let testFolderPath : string;
|
||||
|
||||
describe('NewProjectTool: New project tool tests', function (): void {
|
||||
beforeEach(async function () {
|
||||
previousSetting = await vscode.workspace.getConfiguration(constants.dbProjectConfigurationKey)[constants.projectSaveLocationKey];
|
||||
testFolderPath = await generateTestFolderPath();
|
||||
});
|
||||
|
||||
afterEach(async function () {
|
||||
await vscode.workspace.getConfiguration(constants.dbProjectConfigurationKey).update(constants.projectSaveLocationKey, previousSetting, true);
|
||||
});
|
||||
|
||||
it('Should generate correct default project names', async function (): Promise<void> {
|
||||
await vscode.workspace.getConfiguration(constants.dbProjectConfigurationKey).update(constants.projectSaveLocationKey, testFolderPath, true);
|
||||
should(newProjectTool.defaultProjectNameNewProj()).equal('DatabaseProject1');
|
||||
should(newProjectTool.defaultProjectNameFromDb('master')).equal('DatabaseProjectmaster');
|
||||
});
|
||||
|
||||
it('Should auto-increment default project names for new projects', async function (): Promise<void> {
|
||||
await vscode.workspace.getConfiguration(constants.dbProjectConfigurationKey).update(constants.projectSaveLocationKey, testFolderPath, true);
|
||||
should(newProjectTool.defaultProjectNameNewProj()).equal('DatabaseProject1');
|
||||
|
||||
await createTestFile('', 'DatabaseProject1', testFolderPath);
|
||||
should(newProjectTool.defaultProjectNameNewProj()).equal('DatabaseProject2');
|
||||
|
||||
await createTestFile('', 'DatabaseProject2', testFolderPath);
|
||||
should(newProjectTool.defaultProjectNameNewProj()).equal('DatabaseProject3');
|
||||
});
|
||||
|
||||
it('Should auto-increment default project names for import projects', async function (): Promise<void> {
|
||||
await vscode.workspace.getConfiguration(constants.dbProjectConfigurationKey).update(constants.projectSaveLocationKey, testFolderPath, true);
|
||||
should(newProjectTool.defaultProjectNameFromDb("master")).equal('DatabaseProjectmaster');
|
||||
|
||||
await createTestFile('', 'DatabaseProjectmaster', testFolderPath);
|
||||
should(newProjectTool.defaultProjectNameFromDb("master")).equal('DatabaseProjectmaster2');
|
||||
|
||||
await createTestFile('', 'DatabaseProjectmaster2', testFolderPath);
|
||||
should(newProjectTool.defaultProjectNameFromDb("master")).equal('DatabaseProjectmaster3');
|
||||
});
|
||||
});
|
||||
122
extensions/sql-database-projects/src/tools/newProjectTool.ts
Normal file
122
extensions/sql-database-projects/src/tools/newProjectTool.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import * as path from 'path';
|
||||
import * as constants from '../common/constants';
|
||||
|
||||
/**
|
||||
* Sets workspace setting on the default save location to the user's home directory
|
||||
*/
|
||||
export async function initializeSaveLocationSetting() {
|
||||
if (!projectSaveLocationSettingExists()) {
|
||||
await config().update(constants.projectSaveLocationKey, os.homedir(), true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default location to save a new database project
|
||||
*/
|
||||
export function defaultProjectSaveLocation(): vscode.Uri {
|
||||
return projectSaveLocationSettingIsValid() ? vscode.Uri.file(projectSaveLocationSetting()) : vscode.Uri.file(os.homedir());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default project name for a fresh new project, such as 'DatabaseProject1'. Auto-increments
|
||||
* the suggestion if a project of that name already exists in the default save location
|
||||
*/
|
||||
export function defaultProjectNameNewProj(): string {
|
||||
return defaultProjectName(constants.defaultProjectNameStarter, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns default project name for a new project based on given dbName. Auto-increments
|
||||
* the suggestion if a project of that name already exists in the default save location
|
||||
*
|
||||
* @param dbName the database name to base the default project name off of
|
||||
*/
|
||||
export function defaultProjectNameFromDb(dbName: string): string {
|
||||
const projectNameStarter = constants.defaultProjectNameStarter + dbName;
|
||||
const projectPath: string = path.join(defaultProjectSaveLocation().fsPath, projectNameStarter);
|
||||
if (!fs.existsSync(projectPath)) {
|
||||
return projectNameStarter;
|
||||
}
|
||||
|
||||
return defaultProjectName(projectNameStarter, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts user to update workspace settings
|
||||
*/
|
||||
export async function updateSaveLocationSetting(): Promise<void> {
|
||||
const showPrompt: boolean = config()[constants.showUpdatePromptKey];
|
||||
if (showPrompt) {
|
||||
const openSettingsMessage = projectSaveLocationSettingIsValid() ?
|
||||
constants.newDefaultProjectSaveLocation : constants.invalidDefaultProjectSaveLocation;
|
||||
const result = await vscode.window.showInformationMessage(openSettingsMessage, constants.openWorkspaceSettings,
|
||||
constants.doNotPromptAgain);
|
||||
|
||||
if (result === constants.openWorkspaceSettings || result === constants.doNotPromptAgain) {
|
||||
// if user either opens settings or clicks "don't ask again", do not prompt for save location again
|
||||
await config().update(constants.showUpdatePromptKey, false, true);
|
||||
|
||||
if (result === constants.openWorkspaceSettings) {
|
||||
await vscode.commands.executeCommand('workbench.action.openGlobalSettings'); //open settings
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get workspace configurations for this extension
|
||||
*/
|
||||
function config(): vscode.WorkspaceConfiguration {
|
||||
return vscode.workspace.getConfiguration(constants.dbProjectConfigurationKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the workspace setting on the default location to save new database projects
|
||||
*/
|
||||
function projectSaveLocationSetting(): string {
|
||||
return config()[constants.projectSaveLocationKey];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the default save location for new database projects workspace setting exists and is
|
||||
* a valid path
|
||||
*/
|
||||
function projectSaveLocationSettingIsValid(): boolean {
|
||||
return projectSaveLocationSettingExists() && fs.existsSync(projectSaveLocationSetting());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a value for the default save location for new database projects exists
|
||||
*/
|
||||
function projectSaveLocationSettingExists(): boolean {
|
||||
return projectSaveLocationSetting() !== undefined && projectSaveLocationSetting() !== null
|
||||
&& projectSaveLocationSetting().trim() !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a project name that begins with the given nameStarter, and ends in a number, such as
|
||||
* 'DatabaseProject1'. Number begins at the given counter, but auto-increments if a project of
|
||||
* that name already exists in the default save location.
|
||||
*
|
||||
* @param nameStarter the beginning of the default project name, such as 'DatabaseProject'
|
||||
* @param counter the starting value of of the number appended to the nameStarter
|
||||
*/
|
||||
function defaultProjectName(nameStarter: string, counter: number): string {
|
||||
while (counter < Number.MAX_SAFE_INTEGER) {
|
||||
const name: string = nameStarter + counter;
|
||||
const projectPath: string = path.join(defaultProjectSaveLocation().fsPath, name);
|
||||
if (!fs.existsSync(projectPath)) {
|
||||
return name;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return constants.defaultProjectNameStarter + counter;
|
||||
}
|
||||
Reference in New Issue
Block a user