From 9f847e240137e1d5b17e61f7ca861e3dfd08b40c Mon Sep 17 00:00:00 2001 From: Adi Boghawala <114283933+Adi-204@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:46:33 +0530 Subject: [PATCH 1/7] feat: remove -f flag from asyncapi start command (#1638) --- docs/usage.md | 62 ++++++++++++++------------ package-lock.json | 5 ++- src/commands/start/studio.ts | 28 +++++++++--- src/core/flags/start/studio.flags.ts | 1 - src/core/models/Studio.ts | 66 +++++++++++++++++----------- 5 files changed, 100 insertions(+), 62 deletions(-) diff --git a/docs/usage.md b/docs/usage.md index 9e261882a78..62349fbdb7c 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -38,33 +38,35 @@ USAGE # Commands -* [`asyncapi bundle`](#asyncapi-bundle) -* [`asyncapi config`](#asyncapi-config) -* [`asyncapi config analytics`](#asyncapi-config-analytics) -* [`asyncapi config context`](#asyncapi-config-context) -* [`asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH`](#asyncapi-config-context-add-context-name-spec-file-path) -* [`asyncapi config context current`](#asyncapi-config-context-current) -* [`asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#asyncapi-config-context-edit-context-name-new-spec-file-path) -* [`asyncapi config context init [CONTEXT-FILE-PATH]`](#asyncapi-config-context-init-context-file-path) -* [`asyncapi config context list`](#asyncapi-config-context-list) -* [`asyncapi config context remove CONTEXT-NAME`](#asyncapi-config-context-remove-context-name) -* [`asyncapi config context use CONTEXT-NAME`](#asyncapi-config-context-use-context-name) -* [`asyncapi config versions`](#asyncapi-config-versions) -* [`asyncapi convert [SPEC-FILE] [PROXYHOST] [PROXYPORT]`](#asyncapi-convert-spec-file-proxyhost-proxyport) -* [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) -* [`asyncapi format [SPEC-FILE]`](#asyncapi-format-spec-file) -* [`asyncapi generate`](#asyncapi-generate) -* [`asyncapi generate fromTemplate ASYNCAPI TEMPLATE`](#asyncapi-generate-fromtemplate-asyncapi-template) -* [`asyncapi generate models LANGUAGE FILE`](#asyncapi-generate-models-language-file) -* [`asyncapi new`](#asyncapi-new) -* [`asyncapi new file`](#asyncapi-new-file) -* [`asyncapi new glee`](#asyncapi-new-glee) -* [`asyncapi new template`](#asyncapi-new-template) -* [`asyncapi optimize [SPEC-FILE] [PROXYHOST] [PROXYPORT]`](#asyncapi-optimize-spec-file-proxyhost-proxyport) -* [`asyncapi pretty SPEC-FILE`](#asyncapi-pretty-spec-file) -* [`asyncapi start`](#asyncapi-start) -* [`asyncapi start studio`](#asyncapi-start-studio) -* [`asyncapi validate [SPEC-FILE] [PROXYHOST] [PROXYPORT]`](#asyncapi-validate-spec-file-proxyhost-proxyport) +- [Usage](#usage) +- [Commands](#commands) + - [`asyncapi bundle`](#asyncapi-bundle) + - [`asyncapi config`](#asyncapi-config) + - [`asyncapi config analytics`](#asyncapi-config-analytics) + - [`asyncapi config context`](#asyncapi-config-context) + - [`asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH`](#asyncapi-config-context-add-context-name-spec-file-path) + - [`asyncapi config context current`](#asyncapi-config-context-current) + - [`asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH`](#asyncapi-config-context-edit-context-name-new-spec-file-path) + - [`asyncapi config context init [CONTEXT-FILE-PATH]`](#asyncapi-config-context-init-context-file-path) + - [`asyncapi config context list`](#asyncapi-config-context-list) + - [`asyncapi config context remove CONTEXT-NAME`](#asyncapi-config-context-remove-context-name) + - [`asyncapi config context use CONTEXT-NAME`](#asyncapi-config-context-use-context-name) + - [`asyncapi config versions`](#asyncapi-config-versions) + - [`asyncapi convert [SPEC-FILE] [PROXYHOST] [PROXYPORT]`](#asyncapi-convert-spec-file-proxyhost-proxyport) + - [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) + - [`asyncapi format [SPEC-FILE]`](#asyncapi-format-spec-file) + - [`asyncapi generate`](#asyncapi-generate) + - [`asyncapi generate fromTemplate ASYNCAPI TEMPLATE`](#asyncapi-generate-fromtemplate-asyncapi-template) + - [`asyncapi generate models LANGUAGE FILE`](#asyncapi-generate-models-language-file) + - [`asyncapi new`](#asyncapi-new) + - [`asyncapi new file`](#asyncapi-new-file) + - [`asyncapi new glee`](#asyncapi-new-glee) + - [`asyncapi new template`](#asyncapi-new-template) + - [`asyncapi optimize [SPEC-FILE] [PROXYHOST] [PROXYPORT]`](#asyncapi-optimize-spec-file-proxyhost-proxyport) + - [`asyncapi pretty SPEC-FILE`](#asyncapi-pretty-spec-file) + - [`asyncapi start`](#asyncapi-start) + - [`asyncapi start studio`](#asyncapi-start-studio) + - [`asyncapi validate [SPEC-FILE] [PROXYHOST] [PROXYPORT]`](#asyncapi-validate-spec-file-proxyhost-proxyport) ## `asyncapi bundle` @@ -786,10 +788,12 @@ starts a new local instance of Studio ``` USAGE - $ asyncapi start studio [-h] [-f ] [-p ] + $ asyncapi start studio [SPEC_FILE] [-h] [-p ] + +ARGUMENTS + SPEC-FILE spec path, url, or context-name FLAGS - -f, --file= path to the AsyncAPI file to link with Studio -h, --help Show CLI help. -p, --port= port in which to start Studio diff --git a/package-lock.json b/package-lock.json index 30b14fe7b7b..d1e4e2e4196 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@asyncapi/cli", - "version": "2.14.1", + "version": "2.15.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@asyncapi/cli", - "version": "2.14.1", + "version": "2.15.0", "license": "Apache-2.0", "dependencies": { "@asyncapi/avro-schema-parser": "^3.0.23", @@ -3690,6 +3690,7 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", + "extraneous": true, "inBundle": true, "license": "MIT", "engines": { diff --git a/src/commands/start/studio.ts b/src/commands/start/studio.ts index 23bc3e42e28..69e206c3bbd 100644 --- a/src/commands/start/studio.ts +++ b/src/commands/start/studio.ts @@ -2,20 +2,38 @@ import Command from '../../core/base'; import { start as startStudio } from '../../core/models/Studio'; import { load } from '../../core/models/SpecificationFile'; import { studioFlags } from '../../core/flags/start/studio.flags'; +import { Args } from '@oclif/core'; export default class StartStudio extends Command { static description = 'starts a new local instance of Studio'; static flags = studioFlags(); + static readonly args = { + 'spec-file': Args.string({ description: 'spec path, url, or context-name', required: false }), + }; + async run() { - const { flags } = await this.parse(StartStudio); - const filePath = flags.file || (await load()).getFilePath(); + const { args, flags } = await this.parse(StartStudio); + let filePath = args['spec-file']; const port = flags.port; - - this.specFile = await load(filePath); + if (!filePath) { + try { + filePath = ((await load()).getFilePath()); + this.log(`Loaded specification from: ${filePath}`); + } catch (error) { + filePath = ''; + this.log('No file specified.'); + } + } + try { + this.specFile = await load(filePath); + } catch (error) { + if (filePath) { + this.error(error as Error); + } + } this.metricsMetadata.port = port; - startStudio(filePath as string, port); } } diff --git a/src/core/flags/start/studio.flags.ts b/src/core/flags/start/studio.flags.ts index acc4a175713..008907f7994 100644 --- a/src/core/flags/start/studio.flags.ts +++ b/src/core/flags/start/studio.flags.ts @@ -3,7 +3,6 @@ import { Flags } from '@oclif/core'; export const studioFlags = () => { return { help: Flags.help({ char: 'h' }), - file: Flags.string({ char: 'f', description: 'path to the AsyncAPI file to link with Studio' }), port: Flags.integer({ char: 'p', description: 'port in which to start Studio' }), }; }; diff --git a/src/core/models/Studio.ts b/src/core/models/Studio.ts index d2ed51837dc..69b08171686 100644 --- a/src/core/models/Studio.ts +++ b/src/core/models/Studio.ts @@ -21,30 +21,32 @@ function isValidFilePath(filePath: string): boolean { } export function start(filePath: string, port: number = DEFAULT_PORT): void { - if (!isValidFilePath(filePath)) { + if (filePath && !isValidFilePath(filePath)) { throw new SpecificationFileNotFound(filePath); } - chokidar.watch(filePath).on('all', (event, path) => { - switch (event) { - case 'add': - case 'change': - getFileContent(path).then((code:string) => { + if (filePath) { + chokidar.watch(filePath).on('all', (event, path) => { + switch (event) { + case 'add': + case 'change': + getFileContent(path).then((code: string) => { + messageQueue.push(JSON.stringify({ + type: 'file:changed', + code, + })); + sendQueuedMessages(); + }); + break; + case 'unlink': messageQueue.push(JSON.stringify({ - type: 'file:changed', - code, + type: 'file:deleted', + filePath, })); sendQueuedMessages(); - }); - break; - case 'unlink': - messageQueue.push(JSON.stringify({ - type: 'file:deleted', - filePath, - })); - sendQueuedMessages(); - break; - } - }); + break; + } + }); + } const server = createServer((request, response) => { //not all CLI users use npm. Some package managers put dependencies in different weird places @@ -71,18 +73,26 @@ export function start(filePath: string, port: number = DEFAULT_PORT): void { wsServer.on('connection', (socket: any) => { sockets.push(socket); - getFileContent(filePath).then((code: string) => { + if (filePath) { + getFileContent(filePath).then((code: string) => { + messageQueue.push(JSON.stringify({ + type: 'file:loaded', + code, + })); + sendQueuedMessages(); + }); + } else { messageQueue.push(JSON.stringify({ type: 'file:loaded', - code, + code: '', })); sendQueuedMessages(); - }); + } socket.on('message', (event: string) => { try { - const json:any = JSON.parse(event); - if (json.type === 'file:update') { + const json: any = JSON.parse(event); + if (filePath && json.type === 'file:update') { saveFileContent(filePath, json.code); } else { console.warn('Live Server: An unknown event has been received. See details:'); @@ -102,7 +112,13 @@ export function start(filePath: string, port: number = DEFAULT_PORT): void { const url = `http://localhost:${port}?liveServer=${port}&studio-version=${studioVersion}`; console.log(`Studio is now running at ${url}.`); console.log(`You can open this URL in your web browser, and if needed, press ${gray('Ctrl + C')} to stop the process.`); - console.log(`Watching changes on file ${filePath}`); + if (filePath) { + console.log(`Watching changes on file ${filePath}`); + } else { + console.log( + 'Hint : No file was provided, and we couldn\'t find a default file (like "asyncapi.yaml" or "asyncapi.json") in the current folder. Starting Studio with a blank workspace.' + ); + } open(url); }); } From a37e1241f05ad2b923f9d50cc63779092cba8511 Mon Sep 17 00:00:00 2001 From: Ashish Padhy Date: Tue, 21 Jan 2025 23:07:07 +0530 Subject: [PATCH 2/7] fix: deprecate --file and add release (#1639) * chore: deprecate -file flag in studio Signed-off-by: Ashish Padhy <100484401+Shurtu-gal@users.noreply.github.com> * chore: update action-template Signed-off-by: Ashish Padhy <100484401+Shurtu-gal@users.noreply.github.com> * chore: add changeset Signed-off-by: Ashish Padhy <100484401+Shurtu-gal@users.noreply.github.com> --------- Signed-off-by: Ashish Padhy <100484401+Shurtu-gal@users.noreply.github.com> --- .changeset/rude-pets-begin.md | 5 +++++ action-template.yml | 4 ++-- src/commands/start/studio.ts | 10 ++++++++-- src/core/flags/start/studio.flags.ts | 1 + src/core/models/Studio.ts | 4 ++-- 5 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 .changeset/rude-pets-begin.md diff --git a/.changeset/rude-pets-begin.md b/.changeset/rude-pets-begin.md new file mode 100644 index 00000000000..13bd6145284 --- /dev/null +++ b/.changeset/rude-pets-begin.md @@ -0,0 +1,5 @@ +--- +'@asyncapi/cli': minor +--- + +Deprecate the --file flag in `start studio` command diff --git a/action-template.yml b/action-template.yml index 40aba410cbb..7b948e50d69 100644 --- a/action-template.yml +++ b/action-template.yml @@ -1,5 +1,5 @@ -name: 'Generator, Validator, Converter and others - all in one for your AsyncAPI docs' -description: 'Use this action to generate docs or code from your AsyncAPI document. Use default templates or provide your custom ones.' +name: 'AsyncAPI CLI Action' +description: 'One stop solution for all your AsyncAPI Specification needs in github actions.' inputs: cli_version: description: 'Version of AsyncAPI CLI to be used. This is only needed if you want to test with a specific version of AsyncAPI CLI. Default is latest which is also the recommended option.' diff --git a/src/commands/start/studio.ts b/src/commands/start/studio.ts index 69e206c3bbd..0395490336f 100644 --- a/src/commands/start/studio.ts +++ b/src/commands/start/studio.ts @@ -15,7 +15,13 @@ export default class StartStudio extends Command { async run() { const { args, flags } = await this.parse(StartStudio); - let filePath = args['spec-file']; + + if (flags.file) { + this.warn('The file flag has been removed and is being replaced by the argument spec-file. Please pass the filename directly like `asyncapi start studio asyncapi.yml`'); + } + + let filePath = args['spec-file'] ?? flags.file; + const port = flags.port; if (!filePath) { try { @@ -23,7 +29,7 @@ export default class StartStudio extends Command { this.log(`Loaded specification from: ${filePath}`); } catch (error) { filePath = ''; - this.log('No file specified.'); + this.error('No file specified.'); } } try { diff --git a/src/core/flags/start/studio.flags.ts b/src/core/flags/start/studio.flags.ts index 008907f7994..532d40cce40 100644 --- a/src/core/flags/start/studio.flags.ts +++ b/src/core/flags/start/studio.flags.ts @@ -3,6 +3,7 @@ import { Flags } from '@oclif/core'; export const studioFlags = () => { return { help: Flags.help({ char: 'h' }), + file: Flags.string({ char: 'f', description: 'path to the AsyncAPI file to link with Studio', deprecated: true }), port: Flags.integer({ char: 'p', description: 'port in which to start Studio' }), }; }; diff --git a/src/core/models/Studio.ts b/src/core/models/Studio.ts index 69b08171686..21c291c5858 100644 --- a/src/core/models/Studio.ts +++ b/src/core/models/Studio.ts @@ -115,8 +115,8 @@ export function start(filePath: string, port: number = DEFAULT_PORT): void { if (filePath) { console.log(`Watching changes on file ${filePath}`); } else { - console.log( - 'Hint : No file was provided, and we couldn\'t find a default file (like "asyncapi.yaml" or "asyncapi.json") in the current folder. Starting Studio with a blank workspace.' + console.warn( + 'Warning: No file was provided, and we couldn\'t find a default file (like "asyncapi.yaml" or "asyncapi.json") in the current folder. Starting Studio with a blank workspace.' ); } open(url); From 3867411c7cab113771320a62597c308ad9123494 Mon Sep 17 00:00:00 2001 From: asyncapi-bot Date: Tue, 21 Jan 2025 18:48:51 +0100 Subject: [PATCH 3/7] chore(release): release and bump versions of packages (#1640) --- .changeset/rude-pets-begin.md | 5 ----- CHANGELOG.md | 6 ++++++ action.yml | 6 +++--- package.json | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) delete mode 100644 .changeset/rude-pets-begin.md diff --git a/.changeset/rude-pets-begin.md b/.changeset/rude-pets-begin.md deleted file mode 100644 index 13bd6145284..00000000000 --- a/.changeset/rude-pets-begin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@asyncapi/cli': minor ---- - -Deprecate the --file flag in `start studio` command diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b456efc8c2..42247b31c55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # @asyncapi/cli +## 2.16.0 + +### Minor Changes + +- a37e124: Deprecate the --file flag in `start studio` command + ## 2.15.0 ### Minor Changes diff --git a/action.yml b/action.yml index 4af9aeb1dd8..17235ea3c79 100644 --- a/action.yml +++ b/action.yml @@ -1,5 +1,5 @@ -name: 'Generator, Validator, Converter and others - all in one for your AsyncAPI docs' -description: 'Use this action to generate docs or code from your AsyncAPI document. Use default templates or provide your custom ones.' +name: 'AsyncAPI CLI Action' +description: 'One stop solution for all your AsyncAPI Specification needs in github actions.' inputs: cli_version: description: 'Version of AsyncAPI CLI to be used. This is only needed if you want to test with a specific version of AsyncAPI CLI. Default is latest which is also the recommended option.' @@ -38,7 +38,7 @@ runs: using: 'docker' # This is the image that will be used to run the action. # IMPORTANT: The version has to be changed manually in your PRs. - image: 'docker://asyncapi/github-action-for-cli:2.15.0' + image: 'docker://asyncapi/github-action-for-cli:2.16.0' args: - ${{ inputs.cli_version }} - ${{ inputs.command }} diff --git a/package.json b/package.json index 9429d505e87..8fc50abed31 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@asyncapi/cli", "description": "All in one CLI for all AsyncAPI tools", - "version": "2.15.0", + "version": "2.16.0", "author": "@asyncapi", "bin": { "asyncapi": "./bin/run_bin" From 07514e6ce84b7d4fde8bde98911fb512d62df5bf Mon Sep 17 00:00:00 2001 From: Tushar <141230066+neoandmatrix@users.noreply.github.com> Date: Wed, 22 Jan 2025 17:02:13 +0530 Subject: [PATCH 4/7] chore: added UI/UX improvements to start command (#1641) Co-authored-by: Moderator <60972989+AayushSaini101@users.noreply.github.com> --- .changeset/five-moles-care.md | 5 +++++ src/core/models/Studio.ts | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 .changeset/five-moles-care.md diff --git a/.changeset/five-moles-care.md b/.changeset/five-moles-care.md new file mode 100644 index 00000000000..645b03e1a8e --- /dev/null +++ b/.changeset/five-moles-care.md @@ -0,0 +1,5 @@ +--- +"@asyncapi/cli": patch +--- + +Added UI/UX improvements to start command diff --git a/src/core/models/Studio.ts b/src/core/models/Studio.ts index 21c291c5858..a1e56aa0dd2 100644 --- a/src/core/models/Studio.ts +++ b/src/core/models/Studio.ts @@ -7,7 +7,7 @@ import chokidar from 'chokidar'; import open from 'open'; import path from 'path'; import { version as studioVersion } from '@asyncapi/studio/package.json'; -import { gray } from 'picocolors'; +import { blueBright,redBright } from 'picocolors'; const { readFile, writeFile } = fPromises; @@ -110,10 +110,11 @@ export function start(filePath: string, port: number = DEFAULT_PORT): void { server.listen(port, () => { const url = `http://localhost:${port}?liveServer=${port}&studio-version=${studioVersion}`; - console.log(`Studio is now running at ${url}.`); - console.log(`You can open this URL in your web browser, and if needed, press ${gray('Ctrl + C')} to stop the process.`); + console.log(`🎉 Connected to Live Server running at ${blueBright(url)}.`); + console.log(`🌐 Open this URL in your web browser: ${blueBright(url)}`); + console.log(`🛑 If needed, press ${redBright('Ctrl + C')} to stop the process.`); if (filePath) { - console.log(`Watching changes on file ${filePath}`); + console.log(`👁️ Watching changes on file ${blueBright(filePath)}`); } else { console.warn( 'Warning: No file was provided, and we couldn\'t find a default file (like "asyncapi.yaml" or "asyncapi.json") in the current folder. Starting Studio with a blank workspace.' From 9817950854319537dcf2f5ce5ca205ae983ba034 Mon Sep 17 00:00:00 2001 From: Tushar <141230066+neoandmatrix@users.noreply.github.com> Date: Fri, 24 Jan 2025 21:19:06 +0530 Subject: [PATCH 5/7] chore: config command UI/UX improvement. (#1643) --- .changeset/five-moles-care.md | 2 +- src/commands/config/analytics.ts | 11 ++++++----- src/commands/config/context/add.ts | 15 ++++----------- src/commands/config/context/current.ts | 16 +++++----------- src/commands/config/context/edit.ts | 13 ++++--------- src/commands/config/context/init.ts | 10 +++++----- src/commands/config/context/list.ts | 9 ++++----- src/commands/config/context/remove.ts | 11 ++++------- src/commands/config/context/use.ts | 10 ++++------ src/commands/config/versions.ts | 5 +++-- test/integration/config/analytics.test.ts | 2 +- test/integration/context.test.ts | 18 +++++++++--------- 12 files changed, 50 insertions(+), 72 deletions(-) diff --git a/.changeset/five-moles-care.md b/.changeset/five-moles-care.md index 645b03e1a8e..00a0112509f 100644 --- a/.changeset/five-moles-care.md +++ b/.changeset/five-moles-care.md @@ -2,4 +2,4 @@ "@asyncapi/cli": patch --- -Added UI/UX improvements to start command +implemented new UI/UX improvements in config command diff --git a/src/commands/config/analytics.ts b/src/commands/config/analytics.ts index 3cabf71efeb..03b5ca83d0b 100644 --- a/src/commands/config/analytics.ts +++ b/src/commands/config/analytics.ts @@ -3,6 +3,7 @@ import Command from '../../core/base'; import { promises as fPromises } from 'fs'; import { homedir } from 'os'; import { analyticsFlags } from '../../core/flags/config/analytics.flags'; +import { blueBright, redBright } from 'picocolors'; const { readFile, writeFile } = fPromises; @@ -26,7 +27,7 @@ export default class Analytics extends Command { this.log('\nAnalytics enabled.\n'); this.metricsMetadata.analytics_enabled = flags.enable; } else if (!flags.status) { - this.log('\nPlease append the "--disable" flag to the command in case you prefer to disable analytics, or use the "--enable" flag if you want to enable analytics back again. In case you do not know the analytics current status, then you can append the "--status" flag to be aware of it.\n'); + this.log(`\nPlease append the ${blueBright('--disable')} flag to the command if you prefer to disable analytics, or use the ${blueBright('--enable')} flag if you want to enable analytics again. To check the current analytics status, use the ${blueBright('--status')} flag.\n`); return; } await writeFile(analyticsConfigFile, JSON.stringify(analyticsConfigFileContent), { encoding: 'utf8' }); @@ -35,20 +36,20 @@ export default class Analytics extends Command { if (analyticsConfigFileContent.analyticsEnabled === 'true') { this.log('\nAnalytics are enabled.\n'); } else { - this.log('\nAnalytics are disabled. Please append the "--enable" flag to the command in case you prefer to enable analytics.\n'); + this.log(`\n${redBright('Analytics are disabled.')} To enable analytics, use the ${blueBright('--enable')} flag.\n`); } this.metricsMetadata.analytics_status_checked = flags.status; } } catch (e: any) { switch (e.code) { case 'ENOENT': - this.error(`Unable to access the analytics configuration file. We tried to access the ".asyncapi-analytics" file in in the path "${analyticsConfigFile}" but the file could not be found.`); + this.error(`Unable to access the analytics configuration file. We tried to access the ${blueBright('.asyncapi-analytics')} file in the path "${blueBright(analyticsConfigFile)}" but the file could not be found.`); break; case 'EEXIST': - this.error(`Unable to update the analytics configuration file. We tried to update your ".asyncapi-analytics" file in the path "${analyticsConfigFile}" but the file does not exist.`); + this.error(`Unable to update the analytics configuration file. We tried to update your ".asyncapi-analytics" file in the path "${blueBright(analyticsConfigFile)}" but the file does not exist.`); break; default: - this.error(`Unable to change your analytics configuration. Please check the following message for further info about the error:\n\n${e}`); + this.error(`Unable to change your analytics configuration. Please check the following message for further info about the error:\n\n${redBright(e)}`); } } } diff --git a/src/commands/config/context/add.ts b/src/commands/config/context/add.ts index f17e19480fd..616e2b7be38 100644 --- a/src/commands/config/context/add.ts +++ b/src/commands/config/context/add.ts @@ -6,6 +6,7 @@ import { ContextFileWrongFormatError, } from '../../../core/errors/context-error'; import { addFlags } from '../../../core/flags/config/context.flags'; +import { blueBright } from 'picocolors'; export default class ContextAdd extends Command { static description = 'Add a context to the store'; @@ -24,24 +25,16 @@ export default class ContextAdd extends Command { try { await addContext(contextName, specFilePath); - this.log( - `Added context "${contextName}".\n\nYou can set it as your current context: asyncapi config context use ${contextName}\nYou can use this context when needed by passing ${contextName} as a parameter: asyncapi validate ${contextName}` - ); - + this.log(`🎉 Context ${blueBright(contextName)} added successfully!\nYou can set it as your current context:\n ${blueBright('asyncapi')} ${blueBright('config')} ${blueBright('context')} ${blueBright('use')} ${blueBright(contextName)}\nYou can use this context when needed by passing ${blueBright(contextName)} as a parameter:\n ${blueBright('asyncapi')} ${blueBright('validate')} ${blueBright(contextName)}`); if (setAsCurrent) { await setCurrentContext(contextName); - this.log( - `The newly added context "${contextName}", is set as your current context!` - ); + this.log(`\nThe newly added context, ${blueBright(contextName)}, is set as your current context!`); } } catch (e) { if ( e instanceof (MissingContextFileError || ContextFileWrongFormatError) ) { - this.log( - 'You have no context file configured. Run "asyncapi config context init" to initialize it.' - ); - return; + this.error(`Unable to add context. You have no context file configured.\nRun ${blueBright('asyncapi config context init')} to initialize it.`); } throw e; } diff --git a/src/commands/config/context/current.ts b/src/commands/config/context/current.ts index 49067e33dae..45dc1c65fa3 100644 --- a/src/commands/config/context/current.ts +++ b/src/commands/config/context/current.ts @@ -7,6 +7,7 @@ import { ContextNotFoundError, } from '../../../core/errors/context-error'; import { helpFlag } from '../../../core/flags/global.flags'; +import { blueBright } from 'picocolors'; export default class ContextCurrent extends Command { static description = 'Shows the current context that is being used'; @@ -21,27 +22,20 @@ export default class ContextCurrent extends Command { if ( e instanceof (MissingContextFileError || ContextFileWrongFormatError) ) { - this.log( - 'You have no context file configured. Run "asyncapi config context init" to initialize it.' - ); - return; + this.error(`Unable to show current context. You have no context file configured.\nRun ${blueBright('asyncapi config context init')} to initialize it.`); } else if (e instanceof ContextFileEmptyError) { - this.log(`Context file "${CONTEXT_FILE_PATH}" is empty.`); - return; + this.error(`Context file ${blueBright(CONTEXT_FILE_PATH)} is empty.`); } else if ( e instanceof ContextNotFoundError || (fileContent && !fileContent.current) ) { - this.log( - 'No context is set as current. Run "asyncapi config context" to see all available options.' - ); - return; + this.error(`No context is set as current.\nRun ${blueBright('asyncapi config context')} to see all available options.`); } throw e; } if (fileContent) { - this.log(`${fileContent.current}: ${fileContent.context}`); + this.log(`${blueBright(fileContent.current)}: ${fileContent.context}`); } } } diff --git a/src/commands/config/context/edit.ts b/src/commands/config/context/edit.ts index f16409e9141..c08aec7e159 100644 --- a/src/commands/config/context/edit.ts +++ b/src/commands/config/context/edit.ts @@ -7,6 +7,7 @@ import { ContextFileEmptyError, } from '../../../core/errors/context-error'; import { helpFlag } from '../../../core/flags/global.flags'; +import { blueBright } from 'picocolors'; export default class ContextEdit extends Command { static description = 'Edit a context in the store'; @@ -23,20 +24,14 @@ export default class ContextEdit extends Command { try { await editContext(contextName, newSpecFilePath); - this.log( - `Edited context "${contextName}".\n\nYou can set it as your current context: asyncapi config context use ${contextName}\nYou can use this context when needed by passing ${contextName} as a parameter: asyncapi validate ${contextName}` - ); + this.log(`🎉 Context ${blueBright(contextName)} edited successfully!\nYou can set it as your current context:\n ${blueBright('asyncapi')} ${blueBright('config')} ${blueBright('context')} ${blueBright('use')} ${blueBright(contextName)}\nYou can use this context when needed by passing ${blueBright(contextName)} as a parameter:\n ${blueBright('asyncapi')} ${blueBright('validate')} ${blueBright(contextName)}`); } catch (e) { if ( e instanceof (MissingContextFileError || ContextFileWrongFormatError) ) { - this.log( - 'You have no context file configured. Run "asyncapi config context init" to initialize it.' - ); - return; + this.error(`Unable to edit context. You have no context file configured.\nRun ${blueBright('asyncapi config context init')} to initialize it.`); } else if (e instanceof ContextFileEmptyError) { - this.log(`Context file "${CONTEXT_FILE_PATH}" is empty.`); - return; + this.error(`Context file ${blueBright(CONTEXT_FILE_PATH)} is empty.`); } throw e; } diff --git a/src/commands/config/context/init.ts b/src/commands/config/context/init.ts index 40d4dc7ab2c..67c24f3c6ec 100644 --- a/src/commands/config/context/init.ts +++ b/src/commands/config/context/init.ts @@ -2,15 +2,15 @@ import { Args } from '@oclif/core'; import Command from '../../../core/base'; import { initContext } from '../../../core/models/Context'; import { helpFlag } from '../../../core/flags/global.flags'; - +import { blueBright } from 'picocolors'; export default class ContextInit extends Command { static description = 'Initialize context'; static flags = helpFlag(); static contextFilePathMessage = `Specify directory in which context file should be created: - - current directory : asyncapi config context init . (default) - - root of current repository : asyncapi config context init ./ - - user's home directory : asyncapi config context init ~`; + - current directory : ${blueBright('asyncapi config context init .')}(default) + - root of current repository : ${blueBright('asyncapi config context init ./ ')} + - user's home directory : ${blueBright('asyncapi config context init ~`')}`; static args = { 'context-file-path': Args.string({description: `${ContextInit.contextFilePathMessage}`, required: false}) @@ -21,6 +21,6 @@ export default class ContextInit extends Command { const contextFilePath = args['context-file-path']; const contextWritePath = await initContext(contextFilePath as string); - this.log(`Initialized context ${contextWritePath}`); + this.log(`🎉 Context initialized at ${blueBright(contextWritePath)}`); } } diff --git a/src/commands/config/context/list.ts b/src/commands/config/context/list.ts index 2286173c00c..34391a1a0e0 100644 --- a/src/commands/config/context/list.ts +++ b/src/commands/config/context/list.ts @@ -9,6 +9,7 @@ import { ContextFileWrongFormatError, } from '../../../core/errors/context-error'; import { helpFlag } from '../../../core/flags/global.flags'; +import { blueBright } from 'picocolors'; export default class ContextList extends Command { static description = 'List all the stored contexts in the store'; @@ -19,7 +20,7 @@ export default class ContextList extends Command { const fileContent = await loadContextFile(); if (await isContextFileEmpty(fileContent)) { - this.log(`Context file "${CONTEXT_FILE_PATH}" is empty.`); + this.log(`Context file ${blueBright(CONTEXT_FILE_PATH)} is empty.`); return; } @@ -27,16 +28,14 @@ export default class ContextList extends Command { for (const [contextName, filePath] of Object.entries( fileContent.store )) { - this.log(`${contextName}: ${filePath}`); + this.log(`${blueBright(contextName)}: ${filePath}`); } } } catch (e) { if ( e instanceof (MissingContextFileError || ContextFileWrongFormatError) ) { - this.log( - 'You have no context file configured. Run "asyncapi config context init" to initialize it.' - ); + this.log(`Unable to list contexts. You have no context file configured.\nRun ${blueBright('asyncapi config context init')} to initialize it.\n`); return; } throw e; diff --git a/src/commands/config/context/remove.ts b/src/commands/config/context/remove.ts index 9a29cd6770d..c37fcb09b8f 100644 --- a/src/commands/config/context/remove.ts +++ b/src/commands/config/context/remove.ts @@ -7,6 +7,7 @@ import { ContextFileEmptyError, } from '../../../core/errors/context-error'; import { helpFlag } from '../../../core/flags/global.flags'; +import { blueBright } from 'picocolors'; export default class ContextRemove extends Command { static description = 'Delete a context from the store'; @@ -22,18 +23,14 @@ export default class ContextRemove extends Command { try { await removeContext(contextName); - this.log(`${contextName} successfully deleted`); + this.log(`Context ${blueBright(contextName)} removed successfully!\n`); } catch (e) { if ( e instanceof (MissingContextFileError || ContextFileWrongFormatError) ) { - this.log( - 'You have no context file configured. Run "asyncapi config context init" to initialize it.' - ); - return; + this.error(`Unable to remove context. You have no context file configured.\nRun ${blueBright('asyncapi config context init')} to initialize it.`); } else if (e instanceof ContextFileEmptyError) { - this.log(`Context file "${CONTEXT_FILE_PATH}" is empty.`); - return; + this.error(`Context file ${blueBright(CONTEXT_FILE_PATH)} is empty.`); } throw e; } diff --git a/src/commands/config/context/use.ts b/src/commands/config/context/use.ts index 6450d524047..bc4c071f638 100644 --- a/src/commands/config/context/use.ts +++ b/src/commands/config/context/use.ts @@ -7,6 +7,7 @@ import { ContextFileEmptyError, } from '../../../core/errors/context-error'; import { helpFlag } from '../../../core/flags/global.flags'; +import { blueBright } from 'picocolors'; export default class ContextUse extends Command { static description = 'Set a context as current'; @@ -22,17 +23,14 @@ export default class ContextUse extends Command { try { await setCurrentContext(contextName); - this.log(`${contextName} is set as current`); + this.log(`Context ${blueBright(contextName)} is now set as current.`); } catch (e) { if ( e instanceof (MissingContextFileError || ContextFileWrongFormatError) ) { - this.log( - 'You have no context file configured. Run "asyncapi config context init" to initialize it.' - ); - return; + this.error(`Unable to set the current context. You have no context file configured.\nRun ${blueBright('asyncapi config context init')} to initialize it.`); } else if (e instanceof ContextFileEmptyError) { - this.log(`Context file "${CONTEXT_FILE_PATH}" is empty.`); + this.error(`Context file ${blueBright(CONTEXT_FILE_PATH)} is empty.`); return; } throw e; diff --git a/src/commands/config/versions.ts b/src/commands/config/versions.ts index 915f83ccb3f..50052b88d05 100644 --- a/src/commands/config/versions.ts +++ b/src/commands/config/versions.ts @@ -1,5 +1,6 @@ import Command from '../../core/base'; import { helpFlag } from '../../core/flags/global.flags'; +import { blueBright, gray } from 'picocolors'; export default class Versions extends Command { static description = 'Show versions of AsyncAPI tools used'; @@ -30,7 +31,7 @@ export default class Versions extends Command { } // Showing information available with `--version` flag. - this.log(this.config.userAgent); + this.log(gray(`\n${this.config.userAgent}\n`)); // Iteration through the array containing all dependencies '@asyncapi/*' // along with their versions. @@ -49,6 +50,6 @@ export default class Versions extends Command { } } - this.log(`Repository: ${this.config.pjson.homepage}`); + this.log(`Repository: ${blueBright(this.config.pjson.homepage)}`); } } diff --git a/test/integration/config/analytics.test.ts b/test/integration/config/analytics.test.ts index 7ac5d4d04a6..eb1b4b243c7 100644 --- a/test/integration/config/analytics.test.ts +++ b/test/integration/config/analytics.test.ts @@ -42,7 +42,7 @@ describe('config:analytics', () => { .stdout() .command(['config:analytics']) .it('should show informational message when no flags are used', (ctx, done) => { - expect(ctx.stdout).to.equal('\nPlease append the "--disable" flag to the command in case you prefer to disable analytics, or use the "--enable" flag if you want to enable analytics back again. In case you do not know the analytics current status, then you can append the "--status" flag to be aware of it.\n\n'); + expect(ctx.stdout).to.equal('\nPlease append the --disable flag to the command if you prefer to disable analytics, or use the --enable flag if you want to enable analytics again. To check the current analytics status, use the --status flag.\n\n'); expect(ctx.stderr).to.equal(''); done(); }); diff --git a/test/integration/context.test.ts b/test/integration/context.test.ts index 83044c53391..76590b253cb 100644 --- a/test/integration/context.test.ts +++ b/test/integration/context.test.ts @@ -56,7 +56,7 @@ describe('config:context, positive scenario', () => { .command(['config:context:add', 'test', './test/integration/specification.yml']) .it('should add new context called "test"', (ctx, done) => { expect(ctx.stdout).to.equals( - 'Added context "test".\n\nYou can set it as your current context: asyncapi config context use test\nYou can use this context when needed by passing test as a parameter: asyncapi validate test\n' + '🎉 Context test added successfully!\nYou can set it as your current context:\n asyncapi config context use test\nYou can use this context when needed by passing test as a parameter:\n asyncapi validate test\n' ); expect(ctx.stderr).to.equals(''); done(); @@ -86,7 +86,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:edit', 'test', './test/specification2.yml']) .it('should edit existing context "test"', (ctx, done) => { - expect(ctx.stdout).to.contain('Edited context "test".'); + expect(ctx.stdout).to.contain('🎉 Context test edited successfully!'); expect(ctx.stderr).to.equals(''); done(); }); @@ -98,7 +98,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:use', 'code']) .it('should update the current context', (ctx, done) => { - expect(ctx.stdout).to.equals('code is set as current\n'); + expect(ctx.stdout).to.equals('Context code is now set as current.\n'); expect(ctx.stderr).to.equals(''); done(); }); @@ -114,7 +114,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:remove', 'code']) .it('should remove existing context', (ctx, done) => { - expect(ctx.stdout).to.equals('code successfully deleted\n'); + expect(ctx.stdout).to.equals('Context code removed successfully!\n\n'); expect(ctx.stderr).to.equals(''); done(); }); @@ -126,7 +126,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:init']) .it('should initialize new empty context file without a switch', (ctx, done) => { - expect(ctx.stdout).to.contain('Initialized context'); + expect(ctx.stdout).to.contain('🎉 Context initialized at'); expect(ctx.stderr).to.equals(''); done(); }); @@ -138,7 +138,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:init', '.']) .it('should initialize new empty context file with switch "."', (ctx, done) => { - expect(ctx.stdout).to.contain('Initialized context'); + expect(ctx.stdout).to.contain('🎉 Context initialized at'); expect(ctx.stderr).to.equals(''); done(); }); @@ -150,7 +150,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:init', './']) .it('should initialize new empty context file with switch "./"', (ctx, done) => { - expect(ctx.stdout).to.contain('Initialized context'); + expect(ctx.stdout).to.contain('🎉 Context initialized at'); expect(ctx.stderr).to.equals(''); done(); }); @@ -162,7 +162,7 @@ describe('config:context, positive scenario', () => { .stdout() .command(['config:context:init', '~']) .it('should initialize new empty context file with switch "~"', (ctx, done) => { - expect(ctx.stdout).to.contain('Initialized context'); + expect(ctx.stdout).to.contain('🎉 Context initialized at'); expect(ctx.stderr).to.equals(''); done(); }); @@ -279,7 +279,7 @@ describe('config:context, negative scenario', () => { .it( 'should output info message (to stdout, NOT stderr) about absence of context file.', (ctx, done) => { - expect(ctx.stdout).to.contain('You have no context file configured.'); + expect(ctx.stdout).to.contain('Unable to list contexts. You have no context file configured.'); expect(ctx.stderr).to.equals(''); done(); } From b2711afb50625c54786906aaf5f07aa0c271cb2b Mon Sep 17 00:00:00 2001 From: Ashish Padhy Date: Fri, 24 Jan 2025 21:33:49 +0530 Subject: [PATCH 6/7] chore: add github action to web docs (#1644) Signed-off-by: Ashish Padhy <100484401+Shurtu-gal@users.noreply.github.com> --- README.md | 4 + docs/github-action.md | 239 ++++++++++++++++++++++++++++++++++++++++ github-action/README.md | 236 +-------------------------------------- 3 files changed, 244 insertions(+), 235 deletions(-) create mode 100644 docs/github-action.md diff --git a/README.md b/README.md index 15d0f6e9005..eea76fa676d 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ CLI to work with your AsyncAPI files. Currently under development, we are workin - [Installation](#installation) - [Usage](#usage) +- [Github Action](#github-action) - [Contributing](#contributing) * [Set up development environment](#set-up-development-environment) * [Command Structure and Patterns](#command-structure-and-patterns) @@ -25,6 +26,9 @@ Learn how to install the AsyncAPI CLI by following the instructions in the [inst ## Usage The [usage guide](/docs/usage.md) provides information about different ways to use the CLI. +## Github Action + +The AsyncAPI CLI can be used as a GitHub Action. You can find more information in the [GitHub Action guide](https://www.asyncapi.com/docs/tools/cli/github-action). ## Contributing diff --git a/docs/github-action.md b/docs/github-action.md new file mode 100644 index 00000000000..f3bd85d7b32 --- /dev/null +++ b/docs/github-action.md @@ -0,0 +1,239 @@ +--- +title: GitHub Action for CLI +weight: 50 +--- + +This action exposes the [AsyncAPI CLI](https://github.com/asyncapi/cli). It allows you to generate documentation, validate AsyncAPI documents, convert between different AsyncAPI versions and much more. The source code of the action can be found [here](https://github.com/asyncapi/cli/tree/master/github-action) + +## Inputs + +### `cli_version` + +Version of the AsyncAPI CLI you wish to use. You can find all available versions [here](https://github.com/asyncapi/cli/releases). Recommended leave it out of the inputs and use the default value. + +**Default** points to the`latest` version. + +> [!TIP] +> We recommend to default to `latest` version. This way there is no overhead with the script updating the CLI version. As it takes a lot of time to update the CLI version, we recommend to update it only when you need to use another one for compatibility reasons. + +### `command` + +Command that you wish to run. You can find all available commands Available commands are: +- `generate` - generates documentation from AsyncAPI document +- `validate` - validates AsyncAPI document +- `optimize` - optimizes AsyncAPI document +- `convert` - converts AsyncAPI document to another version +- `custom` - allows you to run any command that is available in the AsyncAPI CLI. You can find all available commands [here](https://www.asyncapi.com/docs/tools/cli/usage). + +**Default** points to `generate` command. + +> [!IMPORTANT] +> In case you want to use `custom` command, you need to pass an array of commands to the [`custom_command`](#custom_command) input. Although passing command is not required, it is recommended to pass it to avoid any issues later on. +> For example, if you want to run `asyncapi bundle ./asyncapi.yaml --output final-asyncapi.yaml` you need to pass `"bundle ./asyncapi.yaml --output final-asyncapi.yaml" to the `custom_command` input. + +### `custom_command` + +In case you want to use `custom` command you need to pass the command that you want to run in this input. You can find all available commands [here](https://www.asyncapi.com/docs/tools/cli/usage). + +**Default** points to '' (empty string). + +Sample usage: + +```yaml +- name: Generating HTML from my AsyncAPI document + uses: asyncapi/cli@v2.16.0# You can use any version you want + with: + custom_command: bundle ./asyncapi.yaml --output final-asyncapi.yaml +``` + +> [!CAUTION] +> You have to pass the whole command as a string including the parameters and the command itself. +> It will run like this: `asyncapi ` + + +### `filepath` + +Path to the AsyncAPI document that you want to process. + +**Default** expects the AsyncAPI document to be in the root of the repository and named `asyncapi.yaml`. + +### `template` + +Template for the generator. Official templates are listed here https://github.com/asyncapi/generator#list-of-official-generator-templates. You can pass template as npm package, url to git repository, link to tar file or local template. + +**Default** points to `@asyncapi/markdown-template@0.10.0` template. + +> [!TIP] +> We recommend to always specify the version of the template to not encounter any issues with the action in case of release of the template that is not compatible with given version of the generator. + +### `language` + +Specifies the language to be used for the generated models. The value must be a valid language name supported by [modelina](https://github.com/asyncapi/modelina). + +**Default** is not set. + +> [!WARNING] +> Either `language` or `template` must be set else an error will be thrown. +> The action will return an error if the language is not supported by [modelina](https://github.com/asyncapi/modelina). + +### `output` + +Path to the output directory. Can be used for `generate` and `convert` commands. + +**Default** points to `output` directory in the root of the repository. + +### `parameters` + +The command that you use might support and even require specific parameters to be passed to the CLI for the generation. You can find all available parameters [here](https://www.asyncapi.com/docs/tools/cli/usage). + +**Default** points to '' (empty string). + +> [!NOTE] +> For template parameters, you need to pass them as `-p ` as can be seen in CLI documentation. + + +## Example usage + +> [!WARNING] +> Using `docker://asyncapi/github-action-for-cli` will not work as expected. This is because the GitHub Actions runner does not pass params to the docker image correctly. This is why we recommend to use `asyncapi/cli` instead. +> However, you don't need to worry as it won't build the image every time. It will pull it from Docker Hub as it is already built there. + +### Basic + +In case all defaults are fine for you, just add such step: + +```yaml +- name: Generating Markdown from my AsyncAPI document + uses: asyncapi/cli@v2.16.0 # You can use any version you want +``` + +### Using all possible inputs + +In case you do not want to use defaults, you for example want to use different template: + +```yaml +- name: Generating HTML from my AsyncAPI document + uses: asyncapi/cli@v2.16.0 # You can use any version you want + with: + command: generate + filepath: ./docs/api/asyncapi.yaml + template: "@asyncapi/html-template@0.9.0" #In case of template from npm. Or can use a link. + output: ./generated-html + parameters: "-p baseHref=/test-experiment/ sidebarOrganization=byTags" +``` +> [!IMPORTANT] +> Note the usage of `-p` in `parameters` input. This is required for template parameters, unlike previous versions of this action as the action includes other commands than just `generate`. + +### Example workflow with publishing generated HTML to GitHub Pages + +In case you want to validate your asyncapi file first, and also send generated HTML to GitHub Pages this is how full workflow could look like: + +```yaml +name: AsyncAPI documents processing + +on: + push: + branches: [ master ] + +jobs: + generate: + runs-on: ubuntu-latest + steps: + #"standard step" where repo needs to be checked-out first + - name: Checkout repo + uses: actions/checkout@v2 + + #In case you do not want to use defaults, you for example want to use different template + - name: Generating HTML from my AsyncAPI document + uses: asyncapi/cli@v2.16.0 # You can use any version you want + with: + template: '@asyncapi/html-template@0.9.0' #In case of template from npm, because of @ it must be in quotes + filepath: docs/api/my-asyncapi.yml + parameters: -p baseHref=/test-experiment/ sidebarOrganization=byTags #space separated list of key/values + output: generated-html + + #Using another action that takes generated HTML and pushes it to GH Pages + - name: Deploy GH page + uses: JamesIves/github-pages-deploy-action@3.4.2 + with: + ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: generated-html +``` + +### Example workflow for generating models + +In case you want to use models generated from your AsyncAPI document, you can use this action to generate them and then use them in your workflow. This is how full workflow could look like: + +```yaml + +name: AsyncAPI documents processing + +on: + push: + branches: [ master ] + +jobs: + generate-models: + runs-on: ubuntu-latest + steps: + #"standard step" where repo needs to be checked-out first + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Generating models from my AsyncAPI document + uses: asyncapi/cli@v2.16.0 # You can use any version you want + with: + command: generate + filepath: docs/api/my-asyncapi.yml + language: typescript + output: generated-models +``` + +### Example workflow for validating AsyncAPI document changes + +In case you want to validate your AsyncAPI document changes, you can use this action to validate them and then use them in your workflow. This is how full workflow could look like: + +```yaml +name: Validate AsyncAPI document + +on: + pull_request: + branches: [ master ] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + #"standard step" where repo needs to be checked-out first + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Validating AsyncAPI document + uses: asyncapi/cli@v2.16.0 # You can use any version you want + with: + command: validate + filepath: docs/api/my-asyncapi.yml +``` + +## Local dry run + +Use following commands to run and test github action locally: + +1. Build docker image of github action for cli + + ```bash + npm run action:docker:build + ``` + +2. Execute docker image with proper arguments + + ```bash + docker run -e GITHUB_WORKSPACE="" --workdir /action -v "/home/{user}/path/to/repo":"/action" asyncapi/github-action-for-cli "" "generate" "github-action/test/asyncapi.yml" "@asyncapi/markdown-template@0.10.0" "" "output" "" "" + ``` + +Make sure to change the path of the repo and user in the command. + +## Troubleshooting + +You can enable more log information in GitHub Action by adding `ACTIONS_STEP_DEBUG` secret to repository where you want to use this action. Set the value of this secret to `true` and you''ll notice more debug logs from this action. \ No newline at end of file diff --git a/github-action/README.md b/github-action/README.md index ee8e790cdfa..d2c5b986b79 100644 --- a/github-action/README.md +++ b/github-action/README.md @@ -2,238 +2,4 @@ This action exposes the [AsyncAPI CLI](https://github.com/asyncapi/cli). It allows you to generate documentation, validate AsyncAPI documents, convert between different AsyncAPI versions and much more. -## Inputs - -### `cli_version` - -Version of the AsyncAPI CLI you wish to use. You can find all available versions [here](https://github.com/asyncapi/cli/releases). Recommended leave it out of the inputs and use the default value. - -**Default** points to the`latest` version. - -> [!TIP] -> We recommend to default to `latest` version. This way there is no overhead with the script updating the CLI version. As it takes a lot of time to update the CLI version, we recommend to update it only when you need to use another one for compatibility reasons. - -### `command` - -Command that you wish to run. You can find all available commands Available commands are: -- `generate` - generates documentation from AsyncAPI document -- `validate` - validates AsyncAPI document -- `optimize` - optimizes AsyncAPI document -- `convert` - converts AsyncAPI document to another version -- `custom` - allows you to run any command that is available in the AsyncAPI CLI. You can find all available commands [here](https://www.asyncapi.com/docs/tools/cli/usage). - -**Default** points to `generate` command. - -> [!IMPORTANT] -> In case you want to use `custom` command, you need to pass an array of commands to the [`custom_command`](#custom_command) input. Although passing command is not required, it is recommended to pass it to avoid any issues later on. -> For example, if you want to run `asyncapi bundle ./asyncapi.yaml --output final-asyncapi.yaml` you need to pass `"bundle ./asyncapi.yaml --output final-asyncapi.yaml" to the `custom_command` input. - -### `custom_command` - -In case you want to use `custom` command you need to pass the command that you want to run in this input. You can find all available commands [here](https://www.asyncapi.com/docs/tools/cli/usage). - -**Default** points to '' (empty string). - -Sample usage: - -```yaml -- name: Generating HTML from my AsyncAPI document - uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want - with: - custom_command: bundle ./asyncapi.yaml --output final-asyncapi.yaml -``` - -> [!CAUTION] -> You have to pass the whole command as a string including the parameters and the command itself. -> It will run like this: `asyncapi ` - - -### `filepath` - -Path to the AsyncAPI document that you want to process. - -**Default** expects the AsyncAPI document to be in the root of the repository and named `asyncapi.yaml`. - -### `template` - -Template for the generator. Official templates are listed here https://github.com/asyncapi/generator#list-of-official-generator-templates. You can pass template as npm package, url to git repository, link to tar file or local template. - -**Default** points to `@asyncapi/markdown-template@0.10.0` template. - -> [!TIP] -> We recommend to always specify the version of the template to not encounter any issues with the action in case of release of the template that is not compatible with given version of the generator. - -### `language` - -Specifies the language to be used for the generated models. The value must be a valid language name supported by [modelina](https://github.com/asyncapi/modelina). - -**Default** is not set. - -> [!WARNING] -> Either `language` or `template` must be set else an error will be thrown. -> The action will return an error if the language is not supported by [modelina](https://github.com/asyncapi/modelina). - -### `output` - -Path to the output directory. Can be used for `generate` and `convert` commands. - -**Default** points to `output` directory in the root of the repository. - -### `parameters` - -The command that you use might support and even require specific parameters to be passed to the CLI for the generation. You can find all available parameters [here](https://www.asyncapi.com/docs/tools/cli/usage). - -**Default** points to '' (empty string). - -> [!NOTE] -> For template parameters, you need to pass them as `-p ` as can be seen in CLI documentation. - - -## Example usage - -> [!WARNING] -> Using `docker://asyncapi/github-action-for-cli` will not work as expected. This is because the GitHub Actions runner does not pass params to the docker image correctly. This is why we recommend to use `asyncapi/github-action-for-cli` instead. -> However, you don't need to worry as it won't build the image every time. It will pull it from Docker Hub as it is already built there. - -### Basic - -In case all defaults are fine for you, just add such step: - -```yaml -- name: Generating Markdown from my AsyncAPI document - uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want -``` - -### Using all possible inputs - -In case you do not want to use defaults, you for example want to use different template: - -```yaml -- name: Generating HTML from my AsyncAPI document - uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want - with: - command: generate - filepath: ./docs/api/asyncapi.yaml - template: "@asyncapi/html-template@0.9.0" #In case of template from npm. Or can use a link. - output: ./generated-html - parameters: "-p baseHref=/test-experiment/ sidebarOrganization=byTags" -``` -> [!IMPORTANT] -> Note the usage of `-p` in `parameters` input. This is required for template parameters, unlike previous versions of this action as the action includes other commands than just `generate`. - -### Example workflow with publishing generated HTML to GitHub Pages - -In case you want to validate your asyncapi file first, and also send generated HTML to GitHub Pages this is how full workflow could look like: - -```yaml -name: AsyncAPI documents processing - -on: - push: - branches: [ master ] - -jobs: - generate: - runs-on: ubuntu-latest - steps: - #"standard step" where repo needs to be checked-out first - - name: Checkout repo - uses: actions/checkout@v2 - - #In case you do not want to use defaults, you for example want to use different template - - name: Generating HTML from my AsyncAPI document - uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want - with: - template: '@asyncapi/html-template@0.9.0' #In case of template from npm, because of @ it must be in quotes - filepath: docs/api/my-asyncapi.yml - parameters: -p baseHref=/test-experiment/ sidebarOrganization=byTags #space separated list of key/values - output: generated-html - - #Using another action that takes generated HTML and pushes it to GH Pages - - name: Deploy GH page - uses: JamesIves/github-pages-deploy-action@3.4.2 - with: - ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BRANCH: gh-pages - FOLDER: generated-html -``` - -### Example workflow for generating models - -In case you want to use models generated from your AsyncAPI document, you can use this action to generate them and then use them in your workflow. This is how full workflow could look like: - -```yaml - -name: AsyncAPI documents processing - -on: - push: - branches: [ master ] - -jobs: - generate-models: - runs-on: ubuntu-latest - steps: - #"standard step" where repo needs to be checked-out first - - name: Checkout repo - uses: actions/checkout@v2 - - - name: Generating models from my AsyncAPI document - uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want - with: - command: generate - filepath: docs/api/my-asyncapi.yml - language: typescript - output: generated-models -``` - -### Example workflow for validating AsyncAPI document changes - -In case you want to validate your AsyncAPI document changes, you can use this action to validate them and then use them in your workflow. This is how full workflow could look like: - -```yaml -name: Validate AsyncAPI document - -on: - pull_request: - branches: [ master ] - -jobs: - validate: - runs-on: ubuntu-latest - steps: - #"standard step" where repo needs to be checked-out first - - name: Checkout repo - uses: actions/checkout@v2 - - - name: Validating AsyncAPI document - uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want - with: - command: validate - filepath: docs/api/my-asyncapi.yml -``` - -## Local dry run - -Use following commands to run and test github action locally: - -1. Build docker image of github action for cli - - ```bash - npm run action:docker:build - ``` - -2. Execute docker image with proper arguments - - ```bash - docker run -e GITHUB_WORKSPACE="" --workdir /action -v "/home/{user}/path/to/repo":"/action" asyncapi/github-action-for-cli "" "generate" "github-action/test/asyncapi.yml" "@asyncapi/markdown-template@0.10.0" "" "output" "" "" - ``` - -Make sure to change the path of the repo and user in the command. - -## Troubleshooting - -You can enable more log information in GitHub Action by adding `ACTIONS_STEP_DEBUG` secret to repository where you want to use this action. Set the value of this secret to `true` and you''ll notice more debug logs from this action. - - -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +The detailed docs can be found [here](../docs/github-action.md). \ No newline at end of file From 80d4da014cf701934c17af59dd0968ba36a8a6ab Mon Sep 17 00:00:00 2001 From: Gaurav Saini Date: Sat, 18 Jan 2025 15:05:20 +0530 Subject: [PATCH 7/7] fix error in asyncapi optimize Signed-off-by: Gourav --- src/commands/optimize.ts | 24 ++++++++++++++++-------- src/core/errors/validation-error.ts | 5 ++++- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/commands/optimize.ts b/src/commands/optimize.ts index 435971c6427..4fe57becf31 100644 --- a/src/commands/optimize.ts +++ b/src/commands/optimize.ts @@ -71,12 +71,20 @@ export default class Optimize extends Command { if (err.message.includes('Failed to download')) { throw new Error('Proxy Connection Error: Unable to establish a connection to the proxy check hostName or PortNumber.'); } else { - this.error( - new ValidationError({ - type: 'invalid-file', - filepath: filePath, - }) - ); + if(filePath){ + this.error( + new ValidationError({ + type: 'invalid-file', + filepath: filePath, + }) + ); + }else{ + this.error( + new ValidationError({ + type: 'no-spec-found' + }) + ); + } } } @@ -88,8 +96,8 @@ export default class Optimize extends Command { } catch (err) { this.error( new ValidationError({ - type: 'invalid-file', - filepath: filePath, + type: 'invalid-syntax-file', + filepath: this.specFile.getFilePath(), }) ); } diff --git a/src/core/errors/validation-error.ts b/src/core/errors/validation-error.ts index c8386082f59..44c4164bae8 100644 --- a/src/core/errors/validation-error.ts +++ b/src/core/errors/validation-error.ts @@ -1,4 +1,4 @@ -type ErrorType = 'parser-error' | 'invalid-file' | 'no-spec-found'; +type ErrorType = 'parser-error' | 'invalid-file' | 'no-spec-found' | 'invalid-syntax-file'; interface IValidationErrorInput { type: ErrorType; @@ -15,6 +15,9 @@ export class ValidationError extends Error { if (error.type === 'invalid-file') { this.message = `There is no file or context with name "${error.filepath}".`; } + if (error.type === 'invalid-syntax-file') { + this.message = `Syntax Error in "${error.filepath}"`; + } if (error.type === 'no-spec-found') { this.message = 'Unable to perform validation. Specify what AsyncAPI file should be validated.\n\nThese are your options to specify in the CLI what AsyncAPI file should be used:\n- You can provide a path to the AsyncAPI file: asyncapi validate path/to/file/asyncapi.yml\n- You can also pass a saved context that points to your AsyncAPI file: asyncapi validate mycontext\n- In case you did not specify a context that you want to use, the CLI checks if there is a default context and uses it. To set default context run: asyncapi context use mycontext\n- In case you did not provide any reference to AsyncAPI file and there is no default context, the CLI detects if in your current working directory you have files like asyncapi.json, asyncapi.yaml, asyncapi.yml. Just rename your file accordingly.'; }