Add database configuration store (#1691)
This "config store" creates a `dbconfig.json` file (if it doesn't yet exist), and reads the file to load the database panel state. Only the database config store should be able to modify the config — the config cannot be modified externally.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
**/* @github/codeql-vscode-reviewers
|
**/* @github/codeql-vscode-reviewers
|
||||||
**/remote-queries/ @github/code-scanning-secexp-reviewers
|
**/remote-queries/ @github/code-scanning-secexp-reviewers
|
||||||
**/variant-analysis/ @github/code-scanning-secexp-reviewers
|
**/variant-analysis/ @github/code-scanning-secexp-reviewers
|
||||||
|
**/databases/ @github/code-scanning-secexp-reviewers
|
||||||
|
|||||||
3
extensions/ql-vscode/src/databases/README.md
Normal file
3
extensions/ql-vscode/src/databases/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
### Databases
|
||||||
|
|
||||||
|
This folder contains code for the new experimental databases panel and new query run experience.
|
||||||
46
extensions/ql-vscode/src/databases/db-config-store.ts
Normal file
46
extensions/ql-vscode/src/databases/db-config-store.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { cloneDbConfig, DbConfig } from './db-config';
|
||||||
|
|
||||||
|
export class DbConfigStore {
|
||||||
|
private readonly configPath: string;
|
||||||
|
|
||||||
|
private config: DbConfig;
|
||||||
|
|
||||||
|
public constructor(workspaceStoragePath: string) {
|
||||||
|
this.configPath = path.join(workspaceStoragePath, 'dbconfig.json');
|
||||||
|
|
||||||
|
this.config = this.createEmptyConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async initialize(): Promise<void> {
|
||||||
|
await this.loadConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
public getConfig(): DbConfig {
|
||||||
|
// Clone the config so that it's not modified outside of this class.
|
||||||
|
return cloneDbConfig(this.config);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async loadConfig(): Promise<void> {
|
||||||
|
if (!await fs.pathExists(this.configPath)) {
|
||||||
|
await fs.writeJSON(this.configPath, this.createEmptyConfig(), { spaces: 2 });
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.readConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async readConfig(): Promise<void> {
|
||||||
|
this.config = await fs.readJSON(this.configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private createEmptyConfig(): DbConfig {
|
||||||
|
return {
|
||||||
|
remote: {
|
||||||
|
repositoryLists: [],
|
||||||
|
owners: [],
|
||||||
|
repositories: [],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
29
extensions/ql-vscode/src/databases/db-config.ts
Normal file
29
extensions/ql-vscode/src/databases/db-config.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
// Contains models for the data we want to store in the database config
|
||||||
|
|
||||||
|
export interface DbConfig {
|
||||||
|
remote: RemoteDbConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RemoteDbConfig {
|
||||||
|
repositoryLists: RemoteRepositoryList[];
|
||||||
|
owners: string[];
|
||||||
|
repositories: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RemoteRepositoryList {
|
||||||
|
name: string;
|
||||||
|
repositories: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cloneDbConfig(config: DbConfig): DbConfig {
|
||||||
|
return {
|
||||||
|
remote: {
|
||||||
|
repositoryLists: config.remote.repositoryLists.map((list) => ({
|
||||||
|
name: list.name,
|
||||||
|
repositories: [...list.repositories],
|
||||||
|
})),
|
||||||
|
owners: [...config.remote.owners],
|
||||||
|
repositories: [...config.remote.repositories],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"remote": {
|
||||||
|
"repositoryLists": [
|
||||||
|
{
|
||||||
|
"name": "repoList1",
|
||||||
|
"repositories": ["foo/bar", "foo/baz"]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"owners": [],
|
||||||
|
"repositories": ["owner/repo1", "owner/repo2", "owner/repo3"]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
import * as fs from 'fs-extra';
|
||||||
|
import * as path from 'path';
|
||||||
|
import { DbConfigStore } from '../../../src/databases/db-config-store';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
|
||||||
|
|
||||||
|
describe('db config store', async () => {
|
||||||
|
const workspaceStoragePath = path.join(__dirname, 'test-workspace');
|
||||||
|
const testStoragePath = path.join(__dirname, 'data');
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await fs.ensureDir(workspaceStoragePath);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await fs.remove(workspaceStoragePath);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create a new config if one does not exist', async () => {
|
||||||
|
const configPath = path.join(workspaceStoragePath, 'dbconfig.json');
|
||||||
|
|
||||||
|
const configStore = new DbConfigStore(workspaceStoragePath);
|
||||||
|
await configStore.initialize();
|
||||||
|
|
||||||
|
expect(await fs.pathExists(configPath)).to.be.true;
|
||||||
|
const config = configStore.getConfig();
|
||||||
|
expect(config.remote.repositoryLists).to.be.empty;
|
||||||
|
expect(config.remote.owners).to.be.empty;
|
||||||
|
expect(config.remote.repositories).to.be.empty;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load an existing config', async () => {
|
||||||
|
const configStore = new DbConfigStore(testStoragePath);
|
||||||
|
await configStore.initialize();
|
||||||
|
|
||||||
|
const config = configStore.getConfig();
|
||||||
|
expect(config.remote.repositoryLists).to.have.length(1);
|
||||||
|
expect(config.remote.repositoryLists[0]).to.deep.equal({
|
||||||
|
'name': 'repoList1',
|
||||||
|
'repositories': ['foo/bar', 'foo/baz']
|
||||||
|
});
|
||||||
|
expect(config.remote.owners).to.be.empty;
|
||||||
|
expect(config.remote.repositories).to.have.length(3);
|
||||||
|
expect(config.remote.repositories).to.deep.equal(['owner/repo1', 'owner/repo2', 'owner/repo3']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow modification of the config', async () => {
|
||||||
|
const configStore = new DbConfigStore(testStoragePath);
|
||||||
|
await configStore.initialize();
|
||||||
|
|
||||||
|
const config = configStore.getConfig();
|
||||||
|
config.remote.repositoryLists = [];
|
||||||
|
|
||||||
|
const reRetrievedConfig = configStore.getConfig();
|
||||||
|
expect(reRetrievedConfig.remote.repositoryLists).to.have.length(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user