From e110c3a33bb1856e31c44fdb7041c7ab16f4e79e Mon Sep 17 00:00:00 2001 From: Viacheslav Turovskyi Date: Tue, 4 Jul 2023 23:16:01 +0000 Subject: [PATCH] feat: support context file location in repository --- docs/context.md | 13 ++-- src/commands/config/context/init.ts | 8 +- src/models/Context.ts | 20 ++--- test/commands/context.test.ts | 111 +++++++++++++++++++++------- 4 files changed, 99 insertions(+), 53 deletions(-) diff --git a/docs/context.md b/docs/context.md index 2542ffdb215..fdf4359f576 100644 --- a/docs/context.md +++ b/docs/context.md @@ -19,23 +19,26 @@ If your use case is that you work with multiple repositories, you might want to ### How to add context to a project -##### Using previously created context file: +##### Manually: - Create file `.asyncapi-cli` containing [minimal empty context file](#minimalEmptyContextFile) in: - current directory - root of current repository - user's home directory - - Make use of this file by executing command `asyncapi config context add [CONTEXT-NAME] [SPEC-FILE-PATH]` ##### Using CLI's `init` command: `asyncapi config context init [CONTEXT-FILE-PATH]` -Where `[CONTEXT-FILE-PATH]` instructs CLI what directory should the context file be created in: - - current directory: `asyncapi config context init . (default)` +Where `[CONTEXT-FILE-PATH]` instructs CLI what directory should the file `.asyncapi-cli` containing [minimal empty context file](#minimalEmptyContextFile) be created in: + - current directory: `asyncapi config context init .` (default) - root of current repository: `asyncapi config context init ./` - user's home directory: `asyncapi config context init ~` + +(if `[CONTEXT-FILE-PATH]` is omitted, empty context file is created in current directory) -If `[CONTEXT-FILE-PATH]` is omitted, the context file is created in current directory. +Make use of newly created `.asyncapi-cli` by executing command: + +`asyncapi config context add [CONTEXT-NAME] [SPEC-FILE-PATH]` ### Context File structure diff --git a/src/commands/config/context/init.ts b/src/commands/config/context/init.ts index fb53bb8a895..0b8d5172d0b 100644 --- a/src/commands/config/context/init.ts +++ b/src/commands/config/context/init.ts @@ -24,14 +24,8 @@ export default class ContextInit extends Command { async run() { const { args } = await this.parse(ContextInit); const contextFilePath = args['context-file-path']; - const contextName = args['context-name']; - const specFilePath = args['spec-file-path']; - const contextWritePath = await initContext( - contextFilePath, - contextName, - specFilePath - ); + const contextWritePath = await initContext(contextFilePath); this.log(`Initialized context ${contextWritePath}`); } } diff --git a/src/models/Context.ts b/src/models/Context.ts index e20674922ae..28661102595 100644 --- a/src/models/Context.ts +++ b/src/models/Context.ts @@ -69,12 +69,8 @@ export interface ICurrentContext { readonly context: string; } -export async function initContext( - contextFilePath: string, - contextName: string, - specFilePath: string -) { - let fileContent: IContextFile = { +export async function initContext(contextFilePath: string) { + const fileContent: IContextFile = { store: {}, }; let contextWritePath = ''; @@ -88,6 +84,10 @@ export async function initContext( case './': contextWritePath = repoRoot.path + path.sep + CONTEXT_FILENAME; break; + // There are two variants of `~` case because tilde expansion in UNIX + // systems is not a guaranteed feature - sometimes `~` can return just `~` + // instead of home directory path. + // https://stackoverflow.com/questions/491877/how-to-find-a-users-home-directory-on-linux-or-unix#comment17161699_492669 case os.homedir(): contextWritePath = os.homedir() + path.sep + CONTEXT_FILENAME; break; @@ -98,14 +98,6 @@ export async function initContext( contextWritePath = process.cwd() + path.sep + CONTEXT_FILENAME; } - if (contextName && specFilePath) { - fileContent = { - store: { - [String(contextName)]: String(specFilePath), - }, - }; - } - try { await writeFile(contextWritePath, JSON.stringify(fileContent), { encoding: 'utf8', diff --git a/test/commands/context.test.ts b/test/commands/context.test.ts index 70547a68703..5ff6c8c0356 100644 --- a/test/commands/context.test.ts +++ b/test/commands/context.test.ts @@ -28,24 +28,32 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:current']) .it('should show current context', (ctx, done) => { - expect(ctx.stdout).toEqual(`${testHelper.context.current}: ${testHelper.context.store['home']}\n`); + expect(ctx.stdout).toEqual( + `${testHelper.context.current}: ${testHelper.context.store['home']}\n` + ); expect(ctx.stderr).toEqual(''); done(); }); }); - + describe('config:context:list', () => { test .stderr() .stdout() .command(['config:context:list']) - .it('should list contexts prints list if context file is present', (ctx, done) => { - expect(ctx.stdout).toEqual( - `home: ${path.resolve(__dirname, '../specification.yml')}\ncode: ${path.resolve(__dirname, '../specification.yml')}\n` - ); - expect(ctx.stderr).toEqual(''); - done(); - }); + .it( + 'should list contexts prints list if context file is present', + (ctx, done) => { + expect(ctx.stdout).toEqual( + `home: ${path.resolve( + __dirname, + '../specification.yml' + )}\ncode: ${path.resolve(__dirname, '../specification.yml')}\n` + ); + expect(ctx.stderr).toEqual(''); + done(); + } + ); }); describe('config:context:add', () => { @@ -67,15 +75,18 @@ describe('config:context, positive scenario', () => { .stderr() .stdout() .command(['config:context:add', 'test', './test/specification.yml']) - .it('should NOT add new context with already existing in context file name "test"', (ctx, done) => { - expect(ctx.stdout).toEqual( - '' - ); - expect(ctx.stderr).toEqual(`ContextError: Context with name "test" already exists in context file "${CONTEXT_FILE_PATH}".\n`); - done(); - }); + .it( + 'should NOT add new context with already existing in context file name "test"', + (ctx, done) => { + expect(ctx.stdout).toEqual(''); + expect(ctx.stderr).toEqual( + `ContextError: Context with name "test" already exists in context file "${CONTEXT_FILE_PATH}".\n` + ); + done(); + } + ); }); - + describe('config:context:edit', () => { test .stderr() @@ -94,9 +105,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:use', 'code']) .it('should update the current context', (ctx, done) => { - expect(ctx.stdout).toEqual( - 'code is set as current\n' - ); + expect(ctx.stdout).toEqual('code is set as current\n'); expect(ctx.stderr).toEqual(''); done(); }); @@ -112,16 +121,62 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:remove', 'code']) .it('should remove existing context', (ctx, done) => { - expect(ctx.stdout).toEqual( - 'code successfully deleted\n' - ); + expect(ctx.stdout).toEqual('code successfully deleted\n'); + expect(ctx.stderr).toEqual(''); + done(); + }); + }); + + describe('config:context:init', () => { + test + .stderr() + .stdout() + .command(['config:context:init']) + .it('should initialize new empty context file without a switch', (ctx, done) => { + expect(ctx.stdout).toContain('Initialized context'); + expect(ctx.stderr).toEqual(''); + done(); + }); + }); + + describe('config:context:init', () => { + test + .stderr() + .stdout() + .command(['config:context:init', '.']) + .it('should initialize new empty context file with switch "."', (ctx, done) => { + expect(ctx.stdout).toContain('Initialized context'); + expect(ctx.stderr).toEqual(''); + done(); + }); + }); + + describe('config:context:init', () => { + test + .stderr() + .stdout() + .command(['config:context:init', './']) + .it('should initialize new empty context file with switch "./"', (ctx, done) => { + expect(ctx.stdout).toContain('Initialized context'); + expect(ctx.stderr).toEqual(''); + done(); + }); + }); + + describe('config:context:init', () => { + test + .stderr() + .stdout() + .command(['config:context:init', '~']) + .it('should initialize new empty context file with switch "~"', (ctx, done) => { + expect(ctx.stdout).toContain('Initialized context'); expect(ctx.stderr).toEqual(''); done(); }); }); }); -describe('config:context, negative scenario', () => { +describe('config:context, negative scenario', () => { beforeAll(() => { // Any context file needs to be created before starting test suite, // otherwise a totally legitimate context file will be created automatically @@ -141,7 +196,7 @@ describe('config:context, negative scenario', () => { .stdout() .command(['config:context:add', 'home', './test/specification.yml']) .it( - 'should throw error on empty file saying that context file has wrong format.', + 'should throw error on zero-sized file saying that context file has wrong format.', (ctx, done) => { expect(ctx.stdout).toEqual(''); expect(ctx.stderr).toContain( @@ -189,7 +244,7 @@ describe('config:context, negative scenario', () => { } ); }); - + // Totally correct (and considered correct by `@oclif/core`) format of the // context file // `{"current":"home","store":{"home":"homeSpecFile","code":"codeSpecFile"}}` @@ -197,7 +252,9 @@ describe('config:context, negative scenario', () => { // scenarios coding. describe('config:context:add', () => { testHelper.deleteDummyContextFile(); - testHelper.createDummyContextFileWrong('{"current":"home","current2":"test","store":{"home":"homeSpecFile","code":"codeSpecFile"}}'); + testHelper.createDummyContextFileWrong( + '{"current":"home","current2":"test","store":{"home":"homeSpecFile","code":"codeSpecFile"}}' + ); test .stderr() .stdout()