Support CLI operations against the .insomnia git data directory (#2294)

This commit is contained in:
Opender Singh
2020-06-18 10:58:31 +12:00
committed by GitHub
parent 2586ee5ad7
commit df2bbda240
21 changed files with 537 additions and 57 deletions

View File

@@ -1879,7 +1879,6 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
@@ -2265,6 +2264,11 @@
"unset-value": "^1.0.0"
}
},
"call-me-maybe": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz",
"integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms="
},
"caller-callsite": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz",
@@ -2757,8 +2761,7 @@
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"estraverse": {
"version": "4.3.0",
@@ -5286,7 +5289,6 @@
"version": "3.14.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz",
"integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -5350,6 +5352,16 @@
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=",
"dev": true
},
"json-schema-ref-parser": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/json-schema-ref-parser/-/json-schema-ref-parser-7.1.4.tgz",
"integrity": "sha512-AD7bvav0vak1/63w3jH8F7eHId/4E4EPdMAEZhGxtjktteUv9dnNB/cJy6nVnMyoTPBJnLwFK6tiQPSTeleCtQ==",
"requires": {
"call-me-maybe": "^1.0.1",
"js-yaml": "^3.13.1",
"ono": "^6.0.0"
}
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -5441,6 +5453,16 @@
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
},
"lodash.sortby": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
@@ -5794,6 +5816,32 @@
"mimic-fn": "^2.1.0"
}
},
"ono": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/ono/-/ono-6.0.1.tgz",
"integrity": "sha512-5rdYW/106kHqLeG22GE2MHKq+FlsxMERZev9DCzQX1zwkxnFwBivSn5i17a5O/rDmOJOdf4Wyt80UZljzx9+DA=="
},
"openapi-2-kong": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/openapi-2-kong/-/openapi-2-kong-2.2.6.tgz",
"integrity": "sha512-GggreyB+ZbkjO9MqDIZOm/M9mrSdVdsSyYYx0uglz1S7EhC0YAN+RNIFJWD1aZ9xkEXmzpjaIT12/KjyHb7Svw==",
"requires": {
"slugify": "^1.3.6",
"swagger-parser": "^8.0.3",
"url-join": "^4.0.1",
"yaml": "^1.7.2"
}
},
"openapi-schemas": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/openapi-schemas/-/openapi-schemas-1.0.3.tgz",
"integrity": "sha512-KtMWcK2VtOS+nD8RKSIyScJsj8JrmVWcIX7Kjx4xEHijFYuvMTDON8WfeKOgeSb4uNG6UsqLj5Na7nKbSav9RQ=="
},
"openapi-types": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz",
"integrity": "sha512-11oi4zYorsgvg5yBarZplAqbpev5HkuVNPlZaPTknPDzAynq+lnJdXAmruGWP0s+dNYZS7bjM+xrTpJw7184Fg=="
},
"opencollective-postinstall": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz",
@@ -6652,6 +6700,11 @@
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"dev": true
},
"slugify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.0.tgz",
"integrity": "sha512-FtLNsMGBSRB/0JOE2A0fxlqjI6fJsgHGS13iTuVT28kViI4JjUiNqp/vyis0ZXYcMnpR3fzGNkv+6vRlI2GwdQ=="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -6861,8 +6914,7 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
},
"sshpk": {
"version": "1.16.1",
@@ -7019,6 +7071,25 @@
}
}
},
"swagger-methods": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/swagger-methods/-/swagger-methods-2.0.2.tgz",
"integrity": "sha512-/RNqvBZkH8+3S/FqBPejHxJxZenaYq3MrpeXnzi06aDIS39Mqf5YCUNb/ZBjsvFFt8h9FxfKs8EXPtcYdfLiRg=="
},
"swagger-parser": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/swagger-parser/-/swagger-parser-8.0.4.tgz",
"integrity": "sha512-KGRdAaMJogSEB7sPKI31ptKIWX8lydEDAwWgB4pBMU7zys5cd54XNhoPSVlTxG/A3LphjX47EBn9j0dOGyzWbA==",
"requires": {
"call-me-maybe": "^1.0.1",
"json-schema-ref-parser": "^7.1.3",
"ono": "^6.0.0",
"openapi-schemas": "^1.0.2",
"openapi-types": "^1.3.5",
"swagger-methods": "^2.0.1",
"z-schema": "^4.2.2"
}
},
"symbol-tree": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
@@ -7273,6 +7344,11 @@
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
"dev": true
},
"url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
},
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
@@ -7322,6 +7398,11 @@
"spdx-expression-parse": "^3.0.0"
}
},
"validator": {
"version": "12.2.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-12.2.0.tgz",
"integrity": "sha512-jJfE/DW6tIK1Ek8nCfNFqt8Wb3nzMoAbocBF6/Icgg1ZFSBpObdnwVY2jQj6qUqzhx5jc71fpvBWyLGO7Xl+nQ=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
@@ -7534,6 +7615,25 @@
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
},
"z-schema": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/z-schema/-/z-schema-4.2.3.tgz",
"integrity": "sha512-zkvK/9TC6p38IwcrbnT3ul9in1UX4cm1y/VZSs4GHKIiDCrlafc+YQBgQBUdDXLAoZHf2qvQ7gJJOo6yT1LH6A==",
"requires": {
"commander": "^2.7.1",
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"validator": "^12.0.0"
},
"dependencies": {
"commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"optional": true
}
}
}
}
}

View File

@@ -6,12 +6,13 @@ exports[`Snapshot for "inso --help" 1`] = `
A CLI for Insomnia!
Options:
-v, --version output the version number
-h, --help display help for command
-v, --version output the version number
--workingDir <dir> Working directory
-h, --help display help for command
Commands:
generate Code generation utilities
help [command] display help for command"
generate Code generation utilities
help [command] display help for command"
`;
exports[`Snapshot for "inso -h" 1`] = `
@@ -20,12 +21,13 @@ exports[`Snapshot for "inso -h" 1`] = `
A CLI for Insomnia!
Options:
-v, --version output the version number
-h, --help display help for command
-v, --version output the version number
--workingDir <dir> Working directory
-h, --help display help for command
Commands:
generate Code generation utilities
help [command] display help for command"
generate Code generation utilities
help [command] display help for command"
`;
exports[`Snapshot for "inso generate -h" 1`] = `
@@ -34,15 +36,15 @@ exports[`Snapshot for "inso generate -h" 1`] = `
Code generation utilities
Options:
-h, --help display help for command
-h, --help display help for command
Commands:
config [options] <filePath> Generate configuration from an api spec
help [command] display help for command"
config [options] <identifier> Generate configuration from an api spec
help [command] display help for command"
`;
exports[`Snapshot for "inso generate config -h" 1`] = `
"Usage: inso generate config [options] <filePath>
"Usage: inso generate config [options] <identifier>
Generate configuration from an api spec
@@ -59,10 +61,11 @@ exports[`Snapshot for "inso help" 1`] = `
A CLI for Insomnia!
Options:
-v, --version output the version number
-h, --help display help for command
-v, --version output the version number
--workingDir <dir> Working directory
-h, --help display help for command
Commands:
generate Code generation utilities
help [command] display help for command"
generate Code generation utilities
help [command] display help for command"
`;

View File

@@ -36,19 +36,30 @@ describe('cli', () => {
it('should call generateConfig with undefined output argument', () => {
inso('generate config -t declarative file.yaml');
expect(generateConfig).toHaveBeenCalledWith({
filePath: 'file.yaml',
expect(generateConfig).toHaveBeenCalledWith('file.yaml', {
type: 'declarative',
output: undefined,
});
});
it('should call generateConfig with all expected arguments', () => {
inso('generate config -t kubernetes -o output.yaml file.yaml');
expect(generateConfig).toHaveBeenCalledWith({
filePath: 'file.yaml',
type: 'kubernetes',
output: 'output.yaml',
});
expect(generateConfig).toHaveBeenCalledWith(
'file.yaml',
expect.objectContaining({
type: 'kubernetes',
output: 'output.yaml',
}),
);
});
it('should call generateConfig with global option', () => {
inso('generate config -t kubernetes --workingDir testing/dir file.yaml');
expect(generateConfig).toHaveBeenCalledWith(
'file.yaml',
expect.objectContaining({
type: 'kubernetes',
workingDir: 'testing/dir',
}),
);
});
});

View File

@@ -0,0 +1,23 @@
// @flow
import commander from 'commander';
import { getAllOptions } from '../util';
describe('getAllOptions()', () => {
it('should combine options from all commands into one object', () => {
const command = new commander.Command('command');
command
.command('subCommand')
.option('-s, --subCmd')
.action(cmd => {
expect(getAllOptions(cmd)).toEqual({
global: true,
subCmd: true,
});
});
const parent = new commander.Command().option('-g, --global').addCommand(command);
parent.parse('node test command subCommand --global --subCmd'.split(' '));
});
});

View File

@@ -1,6 +1,6 @@
// @flow
import { ConversionTypeMap, generateConfig } from './commands/generate';
import { getVersion, createCommand } from './util';
import { getVersion, createCommand, getAllOptions } from './util';
function makeGenerateCommand(exitOverride: boolean) {
// inso generate
@@ -10,14 +10,14 @@ function makeGenerateCommand(exitOverride: boolean) {
// inso generate config -t kubernetes config.yaml
generate
.command('config <filePath>')
.command('config <identifier>')
.description('Generate configuration from an api spec')
.requiredOption(
'-t, --type <value>',
`the type of configuration to generate, options are [${conversionTypes}]`,
)
.option('-o, --output <path>', 'the output path')
.action((filePath, opts) => generateConfig({ filePath, ...opts }));
.action((identifier, cmd) => generateConfig(identifier, getAllOptions(cmd)));
return generate;
}
@@ -31,6 +31,8 @@ export function go(args?: Array<string>, exitOverride?: boolean): void {
createCommand(!!exitOverride)
.version(getVersion(), '-v, --version')
.description('A CLI for Insomnia!')
.option('--workingDir <dir>', 'Working directory')
.addCommand(makeGenerateCommand(!!exitOverride))
.parse(args);
.parseAsync(args)
.catch(err => console.log('An error occurred', err));
}

View File

@@ -6,13 +6,6 @@ import fs from 'fs';
import path from 'path';
jest.mock('openapi-2-kong');
jest.mock('fs');
const base: GenerateConfigOptions = {
filePath: 'file.yaml',
type: 'kubernetes',
output: undefined,
};
describe('generateConfig()', () => {
// make flow happy
@@ -20,10 +13,18 @@ describe('generateConfig()', () => {
afterEach(() => {
jest.restoreAllMocks();
});
const base: GenerateConfigOptions = {
type: 'kubernetes',
output: undefined,
};
const filePath = 'file.yaml';
it('should should not generate if type arg is invalid', async () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
await generateConfig({ ...base, type: 'invalid' });
await generateConfig(filePath, { ...base, type: 'invalid' });
expect(o2k.generate).not.toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith(
@@ -35,20 +36,34 @@ describe('generateConfig()', () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
mock(o2k.generate).mockResolvedValue({ documents: ['a', 'b'] });
await generateConfig(base);
await generateConfig(filePath, base);
expect(o2k.generate).toHaveBeenCalledWith(base.filePath, ConversionTypeMap[base.type]);
expect(o2k.generate).toHaveBeenCalledWith(filePath, ConversionTypeMap[base.type]);
expect(consoleSpy).toHaveBeenCalledWith('a\n---\nb\n');
});
it('should load identifier from database', async () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
mock(o2k.generateFromString).mockResolvedValue({ documents: ['a', 'b'] });
await generateConfig('spc_46c5a4a40e83445a9bd9d9758b86c16c', {
...base,
workingDir: 'src/db/__fixtures__/git-repo',
});
expect(o2k.generateFromString).toHaveBeenCalled();
expect(consoleSpy).toHaveBeenCalledWith('a\n---\nb\n');
});
it('should write converted documents to file system', async () => {
const consoleSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
const writeFileSpy = jest.spyOn(fs, 'writeFileSync').mockImplementation(() => {});
mock(o2k.generate).mockResolvedValue({ documents: ['a', 'b'] });
await generateConfig({ ...base, output: 'output.yaml' });
await generateConfig(filePath, { ...base, output: 'output.yaml' });
expect(o2k.generate).toHaveBeenCalledWith(base.filePath, ConversionTypeMap[base.type]);
expect(fs.writeFileSync).toHaveBeenCalledWith(path.resolve('output.yaml'), 'a\n---\nb\n');
expect(o2k.generate).toHaveBeenCalledWith(filePath, ConversionTypeMap[base.type]);
expect(writeFileSpy).toHaveBeenCalledWith(path.resolve('output.yaml'), 'a\n---\nb\n');
expect(consoleSpy).not.toHaveBeenCalled();
});
});

View File

@@ -1,19 +1,20 @@
// @flow
import o2k from 'openapi-2-kong';
import * as o2k from 'openapi-2-kong';
import YAML from 'yaml';
import path from 'path';
import fs from 'fs';
import type { GlobalOptions } from '../util';
import { gitDataDirDb } from '../db/mem-db';
export const ConversionTypeMap: { [string]: ConversionResultType } = {
kubernetes: 'kong-for-kubernetes',
declarative: 'kong-declarative-config',
};
export type GenerateConfigOptions = {|
filePath: string,
export type GenerateConfigOptions = GlobalOptions<{|
type: $Keys<typeof ConversionTypeMap>,
output?: string,
|};
|}>;
function validateOptions({ type }: GenerateConfigOptions): boolean {
if (!ConversionTypeMap[type]) {
@@ -25,14 +26,31 @@ function validateOptions({ type }: GenerateConfigOptions): boolean {
return true;
}
export async function generateConfig(options: GenerateConfigOptions): Promise<void> {
export async function generateConfig(
identifier: string,
options: GenerateConfigOptions,
): Promise<void> {
if (!validateOptions(options)) {
return;
}
const { type, output, filePath } = options;
const { type, output, workingDir } = options;
const result = await o2k.generate(filePath, ConversionTypeMap[type]);
const db = await gitDataDirDb({ dir: workingDir, filterTypes: ['ApiSpec'] });
let result: ConversionResult;
const specFromDb = db.ApiSpec.get(identifier);
try {
if (specFromDb?.contents) {
result = await o2k.generateFromString(specFromDb.contents, ConversionTypeMap[type]);
} else {
result = await o2k.generate(identifier, ConversionTypeMap[type]);
}
} catch (err) {
console.log('Config failed to generate', err);
return;
}
const yamlDocs = result.documents.map(d => YAML.stringify(d));

View File

@@ -0,0 +1,32 @@
_id: spc_46c5a4a40e83445a9bd9d9758b86c16c
contentType: yaml
contents: |
openapi: '3.0.2'
info:
title: Global Security
version: '1.2'
servers:
- url: https://api.server.test/v1
tags:
- name: Folder
paths:
/global:
get:
tags:
- Folder
responses:
'200':
description: OK
/override:
get:
security:
- Key-Query: []
responses:
'200':
description: OK
created: 1589851906273
fileName: Global Security
modified: 1592254074772
parentId: wrk_012d4860c7da418a85ffea7406e1292a
type: ApiSpec

View File

@@ -0,0 +1,8 @@
_id: wrk_012d4860c7da418a85ffea7406e1292a
created: 1589851906270
description: ""
modified: 1592254074771
name: Global Security 1.2
parentId: null
scope: spec
type: Workspace

View File

@@ -0,0 +1,32 @@
_id: spc_46c5a4a40e83445a9bd9d9758b86c16c
contentType: yaml
contents: |
openapi: '3.0.2'
info:
title: Global Security
version: '1.2'
servers:
- url: https://api.server.test/v1
tags:
- name: Folder
paths:
/global:
get:
tags:
- Folder
responses:
'200':
description: OK
/override:
get:
security:
- Key-Query: []
responses:
'200':
description: OK
created: 1589851906273
fileName: Global Security
modified: 1592254074772
parentId: wrk_012d4860c7da418a85ffea7406e1292a
type: ApiSpec

View File

@@ -0,0 +1,14 @@
_id: env_ca046a738f001eb3090261a537b1b78f86c2094c
color: null
created: 1589851906358
data:
base_url: "{{ scheme }}://{{ host }}{{ base_path }}"
dataPropertyOrder:
"&":
- base_url
isPrivate: false
metaSortKey: 1589851906358
modified: 1592254074769
name: Base environment
parentId: wrk_012d4860c7da418a85ffea7406e1292a
type: Environment

View File

@@ -0,0 +1,14 @@
_id: env_env_ca046a738f001eb3090261a537b1b78f86c2094c_sub
color: null
created: 1592252904087
data:
base_path: /v1
host: api.server.test
scheme: https
dataPropertyOrder: null
isPrivate: false
metaSortKey: 1592252904087
modified: 1592254074767
name: OpenAPI env
parentId: env_ca046a738f001eb3090261a537b1b78f86c2094c
type: Environment

View File

@@ -0,0 +1,21 @@
_id: req_wrk_012d4860c7da418a85ffea7406e1292a21946b60
authentication: {}
body: {}
created: 1592254074764
description: ""
headers: []
isPrivate: false
metaSortKey: -1592254074764
method: GET
modified: 1592254074764
name: /global
parameters: []
parentId: fld_wrk_012d4860c7da418a85ffea7406e1292a30baa249
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingFollowRedirects: global
settingRebuildPath: true
settingSendCookies: true
settingStoreCookies: true
type: Request
url: "{{ base_url }}/global"

View File

@@ -0,0 +1,21 @@
_id: req_wrk_012d4860c7da418a85ffea7406e1292ab410454b
authentication: {}
body: {}
created: 1592254074762
description: ""
headers: []
isPrivate: false
metaSortKey: -1592254074762
method: GET
modified: 1592254074762
name: /override
parameters: []
parentId: wrk_012d4860c7da418a85ffea7406e1292a
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingFollowRedirects: global
settingRebuildPath: true
settingSendCookies: true
settingStoreCookies: true
type: Request
url: "{{ base_url }}/override"

View File

@@ -0,0 +1,10 @@
_id: fld_wrk_012d4860c7da418a85ffea7406e1292a30baa249
created: 1592254074765
description: ""
environment: {}
environmentPropertyOrder: null
metaSortKey: -1592254074765
modified: 1592254074765
name: Folder
parentId: wrk_012d4860c7da418a85ffea7406e1292a
type: RequestGroup

View File

@@ -0,0 +1,8 @@
_id: wrk_012d4860c7da418a85ffea7406e1292a
created: 1589851906270
description: ""
modified: 1592254074771
name: Global Security 1.2
parentId: null
scope: spec
type: Workspace

View File

@@ -0,0 +1,44 @@
// @flow
import path from 'path';
import { gitDataDirDb } from '../mem-db';
describe('mem-db', () => {
describe('seedGitDataDir()', () => {
const fixturesPath = 'src/db/__fixtures__';
it('should seed with git-repo directory', async () => {
const dir = path.join(fixturesPath, 'git-repo');
const db = await gitDataDirDb({ dir });
expect(db.ApiSpec.size).toBe(1);
expect(db.Environment.size).toBe(2);
expect(db.Request.size).toBe(2);
expect(db.RequestGroup.size).toBe(1);
expect(db.Workspace.size).toBe(1);
});
it('should seed with git-repo directory with filter', async () => {
const dir = path.join(fixturesPath, 'git-repo');
const db = await gitDataDirDb({ dir, filterTypes: ['Environment'] });
expect(db.ApiSpec.size).toBe(0);
expect(db.Environment.size).toBe(2);
expect(db.Request.size).toBe(0);
expect(db.RequestGroup.size).toBe(0);
expect(db.Workspace.size).toBe(0);
});
it('should safely continue if data directory not found', async () => {
const dir = path.join(fixturesPath, 'git-repo-without-insomnia');
const db = await gitDataDirDb({ dir });
expect(db.ApiSpec.size).toBe(0);
});
it('should ignore unexpected type directories', async () => {
const dir = path.join(fixturesPath, 'git-repo-malformed-insomnia');
const db = await gitDataDirDb({ dir });
expect(db.Workspace.size).toBe(1);
});
});
});

View File

@@ -0,0 +1,65 @@
// @flow
import fs from 'fs';
import path from 'path';
import YAML from 'yaml';
import type { ApiSpec } from './types';
type Database = {|
ApiSpec: Map<string, ApiSpec>,
Environment: Map<string, Object>,
Request: Map<string, Object>,
RequestGroup: Map<string, Object>,
Workspace: Map<string, Object>,
|};
export const emptyDb = (): Database => ({
ApiSpec: new Map(),
Environment: new Map(),
Request: new Map(),
RequestGroup: new Map(),
Workspace: new Map(),
});
type Options = {
dir?: string,
filterTypes?: Array<$Keys<Database>>,
};
export const gitDataDirDb = async ({ dir, filterTypes }: Options): Promise<Database> => {
const db = emptyDb();
const insomniaDir = path.normalize(path.join(dir || '.', '.insomnia'));
if (!fs.existsSync(insomniaDir)) {
// TODO: control logging with verbose flag
// console.log(`Directory not found: ${insomniaDir}`);
return db;
}
const readAndInsertDoc = async (type: $Keys<Database>, fileName: string): Promise<void> => {
// Get contents of each file in type dir and insert into data
const contents = await fs.promises.readFile(fileName);
const obj = YAML.parse(contents.toString());
db[type].set(obj._id, obj);
};
const types = filterTypes?.length ? filterTypes : Object.keys(db);
await Promise.all(
types.map(async type => {
// Get all files in type dir
const typeDir = path.join(insomniaDir, type);
if (!fs.existsSync(typeDir)) {
return;
}
const files = await fs.promises.readdir(typeDir);
return Promise.all(
// Insert each file from each type
files.map(file => readAndInsertDoc(type, path.join(insomniaDir, type, file))),
);
}),
);
return db;
};

View File

@@ -0,0 +1,23 @@
// @flow
// These types should come from a shared location (maybe insomnia-importers?)
// They represent the models that are read from an Insomnia data source
// eg. git data directory, insomnia export format, etc
export type BaseModel = {
_id: string,
type: string,
parentId: string,
modified: number,
created: number,
};
type BaseApiSpec = {
fileName: string,
contentType: 'json' | 'yaml',
contents: string,
};
export const SpecName = 'ApiSpec';
export type ApiSpec = BaseModel & BaseApiSpec;

View File

@@ -2,10 +2,13 @@
import commander from 'commander';
import * as packageJson from '../package.json';
export type GlobalOptions<T> = {|
workingDir?: string,
...T,
|};
export function createCommand(exitOverride: boolean, cmd?: string) {
const command = new commander.Command(cmd)
.storeOptionsAsProperties(false)
.passCommandToAction(false);
const command = new commander.Command(cmd).storeOptionsAsProperties(false);
if (exitOverride) {
return command.exitOverride();
@@ -17,3 +20,16 @@ export function createCommand(exitOverride: boolean, cmd?: string) {
export function getVersion() {
return packageJson.version;
}
export function getAllOptions<T>(cmd: Object): T {
let opts = {};
let command = cmd;
do {
// overwrite options with more specific ones
opts = { ...command.opts(), ...opts };
command = command.parent;
} while (command);
return opts;
}