Adds autorest-based SQL Project generation to SQL Database Projects extension (#17078)

* Initial changes

* checkpoint

* Constructing project with post deployment script

* Correcting to intentionally read from cached list of projects

* Adding activation event, fixing fresh workspace bug

* Convert netcoreTool and autorestHelper to share a helper class for streamed command

* Include npm package version to force update

* test checkpoint

* Unit tests

* Added contextual quickpicks for autorest dialogs

* Adding projectController test

* Added projectController test, some refactoring for testability

* Merge branch 'main' into benjin/autorest

* Fixing 'which' import

* PR feedback

* Fixing tests

* Adding additional information for when project provider tests fail

* Hopefully fixing failing tests (unable to repro locally)

* Adding Generate Project item to workspace menu

* PR feedback
This commit is contained in:
Benjin Dubishar
2021-09-16 20:38:40 -07:00
committed by GitHub
parent 0cf1abc7c2
commit 08e15bce99
18 changed files with 586 additions and 85 deletions

View File

@@ -21,7 +21,7 @@ import { SqlDatabaseProjectTreeViewProvider } from '../controllers/databaseProje
import { ProjectsController } from '../controllers/projectController';
import { promises as fs } from 'fs';
import { createContext, TestContext, mockDacFxResult, mockConnectionProfile } from './testContext';
import { Project, reservedProjectFolders, SystemDatabase, FileProjectEntry, SystemDatabaseReferenceProjectEntry } from '../models/project';
import { Project, reservedProjectFolders, SystemDatabase, FileProjectEntry, SystemDatabaseReferenceProjectEntry, EntryType } from '../models/project';
import { PublishDatabaseDialog } from '../dialogs/publishDatabaseDialog';
import { ProjectRootTreeItem } from '../models/tree/projectTreeItem';
import { FolderNode, FileNode } from '../models/tree/fileFolderTreeItem';
@@ -429,7 +429,7 @@ describe('ProjectsController', function (): void {
const proj = await testUtils.createTestProject(baselines.openProjectFileBaseline);
await projController.object.publishOrScriptProject(proj, { connectionUri: '', databaseName: '' , serverName: ''}, false);
await projController.object.publishOrScriptProject(proj, { connectionUri: '', databaseName: '', serverName: '' }, false);
should(builtDacpacPath).not.equal('', 'built dacpac path should be set');
should(publishedDacpacPath).not.equal('', 'published dacpac path should be set');
@@ -665,7 +665,7 @@ describe('ProjectsController', function (): void {
// add dacpac reference to something in the a folder outside of the project
await projController.addDatabaseReferenceCallback(project1, {
databaseName: <string>this.databaseNameTextbox?.value,
dacpacFileLocation: vscode.Uri.file(path.join(path.dirname(projFilePath), '..','someFolder', 'outsideFolderTest.dacpac')),
dacpacFileLocation: vscode.Uri.file(path.join(path.dirname(projFilePath), '..', 'someFolder', 'outsideFolderTest.dacpac')),
suppressMissingDependenciesErrors: false
},
{ treeDataProvider: new SqlDatabaseProjectTreeViewProvider(), element: undefined });
@@ -678,6 +678,49 @@ describe('ProjectsController', function (): void {
should(projFileText).containEql('..\\someFolder\\outsideFolderTest.dacpac');
});
});
describe('AutoRest generation', function (): void {
it('Should create project from autorest-generated files', async function (): Promise<void> {
const parentFolder = await testUtils.generateTestFolderPath();
await testUtils.createDummyFileStructure();
const specName = 'DummySpec.yaml';
const newProjFolder = path.join(parentFolder, path.basename(specName, '.yaml'));
let fileList: vscode.Uri[] = [];
const projController = TypeMoq.Mock.ofType(ProjectsController);
projController.callBase = true;
projController.setup(x => x.selectAutorestSpecFile()).returns(async () => specName);
projController.setup(x => x.selectAutorestProjectLocation(TypeMoq.It.isAny())).returns(async () => {
await fs.mkdir(newProjFolder);
return {
newProjectFolder: newProjFolder,
outputFolder: parentFolder,
projectName: path.basename(specName, '.yaml')
};
});
projController.setup(x => x.generateAutorestFiles(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => {
await testUtils.createDummyFileStructure(true, fileList, newProjFolder);
await testUtils.createTestFile('SELECT \'This is a post-deployment script\'', constants.autorestPostDeploymentScriptName, newProjFolder);
});
projController.setup(x => x.openProjectInWorkspace(TypeMoq.It.isAny())).returns(async () => { });
const project = (await projController.object.generateProjectFromOpenApiSpec())!;
should(project.postDeployScripts.length).equal(1, `Expected 1 post-deployment script, got ${project?.postDeployScripts.length}`);
const actual = path.basename(project.postDeployScripts[0].fsUri.fsPath);
should(actual).equal(constants.autorestPostDeploymentScriptName, `Unexpected post-deployment script name: ${actual}, expected ${constants.autorestPostDeploymentScriptName}`);
const expectedScripts = fileList.filter(f => path.extname(f.fsPath) === '.sql');
should(project.files.filter(f => f.type === EntryType.File).length).equal(expectedScripts.length, 'Unexpected number of scripts in project');
const expectedFolders = fileList.filter(f => path.extname(f.fsPath) === '' && f.fsPath.toUpperCase() !== newProjFolder.toUpperCase());
should(project.files.filter(f => f.type === EntryType.Folder).length).equal(expectedFolders.length, 'Unexpected number of folders in project');
});
});
});
async function setupDeleteExcludeTest(proj: Project): Promise<[FileProjectEntry, ProjectRootTreeItem, FileProjectEntry, FileProjectEntry, FileProjectEntry]> {