diff --git a/.github/workflows/bounty-program-commands.yml b/.github/workflows/bounty-program-commands.yml index 433f7d953d3..645e0c90dbc 100644 --- a/.github/workflows/bounty-program-commands.yml +++ b/.github/workflows/bounty-program-commands.yml @@ -14,12 +14,18 @@ on: types: - created +env: + BOUNTY_PROGRAM_LABELS_JSON: | + [ + {"name": "bounty", "color": "0e8a16", "description": "Participation in the Bounty Program"} + ] + jobs: guard-against-unauthorized-use: if: > github.actor != ('aeworxet' || 'thulieblack') && ( - contains(github.event.comment.body, '/bounty' ) + startsWith(github.event.comment.body, '/bounty' ) ) runs-on: ubuntu-latest @@ -46,15 +52,10 @@ jobs: if: > github.actor == ('aeworxet' || 'thulieblack') && ( - contains(github.event.comment.body, '/bounty' ) + startsWith(github.event.comment.body, '/bounty' ) ) runs-on: ubuntu-latest - env: - BOUNTY_PROGRAM_LABELS_JSON: | - [ - {"name": "bounty", "color": "0e8a16", "description": "Participation in the Bounty Program"} - ] steps: - name: Add label `bounty` @@ -88,3 +89,38 @@ jobs: repo: context.repo.repo, labels: [BOUNTY_PROGRAM_LABELS[0].name] }) + + remove-label-bounty: + if: > + github.actor == ('aeworxet' || 'thulieblack') && + ( + startsWith(github.event.comment.body, '/unbounty' ) + ) + + runs-on: ubuntu-latest + + steps: + - name: Remove label `bounty` + uses: actions/github-script@v6 + + with: + github-token: ${{ secrets.GH_TOKEN }} + script: | + const BOUNTY_PROGRAM_LABELS = JSON.parse(process.env.BOUNTY_PROGRAM_LABELS_JSON); + let LIST_OF_LABELS_FOR_ISSUE = await github.rest.issues.listLabelsOnIssue({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }); + + LIST_OF_LABELS_FOR_ISSUE = LIST_OF_LABELS_FOR_ISSUE.data.map(key => key.name); + + if (LIST_OF_LABELS_FOR_ISSUE.includes(BOUNTY_PROGRAM_LABELS[0].name)) { + console.log('Removing label `bounty`...'); + github.rest.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: [BOUNTY_PROGRAM_LABELS[0].name] + }) + } diff --git a/docs/usage.md b/docs/usage.md index 88f8cfc8549..d0f24dc7447 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -27,7 +27,7 @@ $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version) -@asyncapi/cli/1.11.0 linux-x64 node-v18.20.2 +@asyncapi/cli/1.12.2 linux-x64 node-v18.20.2 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND @@ -65,33 +65,38 @@ USAGE ## `asyncapi bundle` -bundle one or multiple asyncapi documents and their references together. +Bundle one or multiple AsyncAPI Documents and their references together. ``` USAGE - $ asyncapi bundle [-h] [-o ] [-r] [-b ] + $ asyncapi bundle [-h] [-o ] [-b ] [-d ] [-x] FLAGS - -b, --base= Path to the file which will act as a base. This is required when some properties are - to needed to be overwritten. - -h, --help Show CLI help. - -o, --output= The output file name. Omitting this flag the result will be printed in the console. - -r, --reference-into-components Bundle the message $refs into components object. + -b, --base= Path to the file which will act as a base. This is required when some properties need to be + overwritten. + -d, --baseDir= One relative/absolute path to directory relative to which paths to AsyncAPI Documents that + should be bundled will be resolved. + -h, --help Show CLI help. + -o, --output= The output file name. Omitting this flag the result will be printed in the console. + -x, --xOrigin Pass this switch to generate properties "x-origin" that will contain historical values of + dereferenced "$ref"s. DESCRIPTION - bundle one or multiple asyncapi documents and their references together. + Bundle one or multiple AsyncAPI Documents and their references together. EXAMPLES - $ asyncapi bundle ./asyncapi.yaml > final-asyncapi.yaml - $ asyncapi bundle ./asyncapi.yaml --output final-asyncapi.yaml - $ asyncapi bundle ./asyncapi.yaml ./features.yaml --reference-into-components + $ asyncapi bundle ./asyncapi.yaml ./features.yaml + + $ asyncapi bundle ./asyncapi.yaml ./features.yaml --base ./main.yaml + + $ asyncapi bundle ./asyncapi.yaml ./features.yaml --base ./main.yaml --xOrigin - $ asyncapi bundle ./asyncapi.yaml ./features.yaml --base ./asyncapi.yaml --reference-into-components + $ asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service ``` -_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/bundle.ts)_ +_See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/bundle.ts)_ ## `asyncapi config` @@ -105,7 +110,7 @@ DESCRIPTION CLI config settings ``` -_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/index.ts)_ +_See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/index.ts)_ ## `asyncapi config analytics` @@ -125,7 +130,7 @@ DESCRIPTION Enable or disable analytics for metrics collection ``` -_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/analytics.ts)_ +_See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/analytics.ts)_ ## `asyncapi config context` @@ -139,7 +144,7 @@ DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` -_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/index.ts)_ +_See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` @@ -161,7 +166,7 @@ DESCRIPTION Add a context to the store ``` -_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/add.ts)_ +_See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/add.ts)_ ## `asyncapi config context current` @@ -178,7 +183,7 @@ DESCRIPTION Shows the current context that is being used ``` -_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/current.ts)_ +_See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` @@ -199,7 +204,7 @@ DESCRIPTION Edit a context in the store ``` -_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/edit.ts)_ +_See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` @@ -222,7 +227,7 @@ DESCRIPTION Initialize context ``` -_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/init.ts)_ +_See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/init.ts)_ ## `asyncapi config context list` @@ -239,7 +244,7 @@ DESCRIPTION List all the stored contexts in the store ``` -_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/list.ts)_ +_See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` @@ -259,7 +264,7 @@ DESCRIPTION Delete a context from the store ``` -_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/remove.ts)_ +_See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` @@ -279,7 +284,7 @@ DESCRIPTION Set a context as current ``` -_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/context/use.ts)_ +_See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/context/use.ts)_ ## `asyncapi config versions` @@ -296,7 +301,7 @@ DESCRIPTION Show versions of AsyncAPI tools used ``` -_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/config/versions.ts)_ +_See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` @@ -318,7 +323,7 @@ DESCRIPTION Convert asyncapi documents older to newer versions ``` -_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/convert.ts)_ +_See code: [src/commands/convert.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/convert.ts)_ ## `asyncapi diff OLD NEW` @@ -373,7 +378,7 @@ DESCRIPTION Find diff between two asyncapi files ``` -_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/diff.ts)_ +_See code: [src/commands/diff.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/diff.ts)_ ## `asyncapi generate` @@ -387,7 +392,7 @@ DESCRIPTION Generate typed models or other things like clients, applications or docs using AsyncAPI Generator templates. ``` -_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/generate/index.ts)_ +_See code: [src/commands/generate/index.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/generate/index.ts)_ ## `asyncapi generate fromTemplate [ASYNCAPI] [TEMPLATE]` @@ -417,6 +422,9 @@ FLAGS unstaged files or not empty dir (defaults to false) --map-base-url= Maps all schema references from base url to local folder --no-interactive Disable interactive mode and run with the provided flags. + --registry-url Specifies the URL of the private registry for fetching templates and dependencies + --registry-auth The registry username and password encoded with base64, formatted as username:password + --registry-token The npm registry authentication token, that can be passed instead of base64 encoded username and password DESCRIPTION Generates whatever you want using templates compatible with AsyncAPI Generator. @@ -425,7 +433,7 @@ EXAMPLES $ asyncapi generate fromTemplate asyncapi.yaml @asyncapi/html-template --param version=1.0.0 singleFile=true --output ./docs --force-write ``` -_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/generate/fromTemplate.ts)_ +_See code: [src/commands/generate/fromTemplate.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/generate/fromTemplate.ts)_ ## `asyncapi generate models [LANGUAGE] [FILE]` @@ -511,7 +519,7 @@ DESCRIPTION Generates typed models ``` -_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/generate/models.ts)_ +_See code: [src/commands/generate/models.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/generate/models.ts)_ ## `asyncapi new` @@ -568,7 +576,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/new/index.ts)_ +_See code: [src/commands/new/index.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/new/index.ts)_ ## `asyncapi new file` @@ -625,7 +633,7 @@ EXAMPLES $ asyncapi new --file-name=my-asyncapi.yml --example=default-example.yml --no-tty - create a new file with a specific name, using one of the examples and without interactive mode ``` -_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/new/file.ts)_ +_See code: [src/commands/new/file.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/new/file.ts)_ ## `asyncapi new glee` @@ -647,7 +655,7 @@ DESCRIPTION Creates a new Glee project ``` -_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/new/glee.ts)_ +_See code: [src/commands/new/glee.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/new/glee.ts)_ ## `asyncapi optimize [SPEC-FILE]` @@ -685,7 +693,7 @@ EXAMPLES $ asyncapi optimize ./asyncapi.yaml --optimization=remove-components --output=terminal --no-tty ``` -_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/optimize.ts)_ +_See code: [src/commands/optimize.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/optimize.ts)_ ## `asyncapi start` @@ -699,7 +707,7 @@ DESCRIPTION Start asyncapi studio ``` -_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/start/index.ts)_ +_See code: [src/commands/start/index.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/start/index.ts)_ ## `asyncapi start studio` @@ -718,7 +726,7 @@ DESCRIPTION starts a new local instance of Studio ``` -_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/start/studio.ts)_ +_See code: [src/commands/start/studio.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/start/studio.ts)_ ## `asyncapi validate [SPEC-FILE]` @@ -745,5 +753,5 @@ DESCRIPTION validate asyncapi file ``` -_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v1.11.0/src/commands/validate.ts)_ +_See code: [src/commands/validate.ts](https://github.com/asyncapi/cli/blob/v1.12.2/src/commands/validate.ts)_ diff --git a/package-lock.json b/package-lock.json index 6d9989e4d08..6b393eb3154 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,20 +1,20 @@ { "name": "@asyncapi/cli", - "version": "1.12.0", + "version": "1.12.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@asyncapi/cli", - "version": "1.12.0", + "version": "1.12.3", "license": "Apache-2.0", "dependencies": { "@asyncapi/avro-schema-parser": "^3.0.22", - "@asyncapi/bundler": "^0.4.0", + "@asyncapi/bundler": "^0.5.0", "@asyncapi/converter": "^1.4.19", "@asyncapi/diff": "^0.4.1", "@asyncapi/generator": "^1.17.25", - "@asyncapi/modelina": "^3.4.9", + "@asyncapi/modelina": "^3.5.0", "@asyncapi/openapi-schema-parser": "^3.0.22", "@asyncapi/optimizer": "^1.0.2", "@asyncapi/parser": "^3.0.14", @@ -29,6 +29,7 @@ "@smoya/multi-parser": "^5.0.7", "@stoplight/spectral-cli": "6.9.0", "ajv": "^8.12.0", + "axios": "^1.6.8", "chalk": "^4.1.0", "chokidar": "^3.5.2", "fast-levenshtein": "^3.0.0", @@ -215,28 +216,18 @@ } }, "node_modules/@asyncapi/bundler": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@asyncapi/bundler/-/bundler-0.4.0.tgz", - "integrity": "sha512-yBOQb5lmUMNt1inMkuNN4iqmV1FBiR+ZRX4asvRHWYzcnLluhjRahoGuijCvLURuB+iavlr5aLUSX1bFDiz6vw==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@asyncapi/bundler/-/bundler-0.5.0.tgz", + "integrity": "sha512-AaqzVPLqBwBYK8lM3GPAvYDD8rqDrRvzpKkLJmBX34HTekjdbqeMfrOCdA3K4g0kxlPeyl05S7qDdygywiwPUA==", "dependencies": { - "@apidevtools/json-schema-ref-parser": "^9.0.9", + "@apidevtools/json-schema-ref-parser": "^11.5.4", + "@asyncapi/parser": "^3.0.14", "@types/json-schema": "^7.0.11", "js-yaml": "^4.1.0", "jsonpath-plus": "^6.0.1", "lodash": "^4.17.21" } }, - "node_modules/@asyncapi/bundler/node_modules/@apidevtools/json-schema-ref-parser": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.1.2.tgz", - "integrity": "sha512-r1w81DpR+KyRWd3f+rk6TNqMgedmAxZP5v5KWlXQWlgMUUtyEJch0DKEci1SorPMiSeM8XPl7MZ3miJ60JIpQg==", - "dependencies": { - "@jsdevtools/ono": "^7.1.3", - "@types/json-schema": "^7.0.6", - "call-me-maybe": "^1.0.1", - "js-yaml": "^4.1.0" - } - }, "node_modules/@asyncapi/converter": { "version": "1.4.19", "resolved": "https://registry.npmjs.org/@asyncapi/converter/-/converter-1.4.19.tgz", @@ -442,9 +433,9 @@ "link": true }, "node_modules/@asyncapi/modelina": { - "version": "3.4.9", - "resolved": "https://registry.npmjs.org/@asyncapi/modelina/-/modelina-3.4.9.tgz", - "integrity": "sha512-BJIahpkXB0WmALKNyNj8ilEVE6L79UBg121NFbiCQ//F5bmurB0DSZSquWlCIvO6I0CFnJ8Bh6UUxx36rQhijw==", + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/@asyncapi/modelina/-/modelina-3.5.0.tgz", + "integrity": "sha512-mrRg0ZYKtJPr/clgWb9n+/rLtlQr3NnMtBpA7YiAh5p4/oVoz691J6nx5A7bZ6pV+04VTPfE2s3nt92FCdVJmw==", "dependencies": { "@apidevtools/json-schema-ref-parser": "^11.1.0", "@apidevtools/swagger-parser": "^10.1.0", @@ -3467,7 +3458,6 @@ }, "node_modules/@clack/prompts/node_modules/is-unicode-supported": { "version": "1.3.0", - "extraneous": true, "inBundle": true, "license": "MIT", "engines": { @@ -38768,6 +38758,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -42707,6 +42707,25 @@ "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -42769,7 +42788,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -65145,6 +65163,11 @@ "undici-types": "~5.26.4" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/psl": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", diff --git a/package.json b/package.json index 2ed78005ac6..f48303df647 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@asyncapi/cli", "description": "All in one CLI for all AsyncAPI tools", - "version": "1.12.0", + "version": "1.12.3", "author": "@asyncapi", "bin": { "asyncapi": "./bin/run_bin" @@ -9,11 +9,11 @@ "bugs": "https://github.com/asyncapi/cli/issues", "dependencies": { "@asyncapi/avro-schema-parser": "^3.0.22", - "@asyncapi/bundler": "^0.4.0", + "@asyncapi/bundler": "^0.5.0", "@asyncapi/converter": "^1.4.19", "@asyncapi/diff": "^0.4.1", "@asyncapi/generator": "^1.17.25", - "@asyncapi/modelina": "^3.4.9", + "@asyncapi/modelina": "^3.5.0", "@asyncapi/openapi-schema-parser": "^3.0.22", "@asyncapi/optimizer": "^1.0.2", "@asyncapi/parser": "^3.0.14", diff --git a/src/commands/bundle.ts b/src/commands/bundle.ts index 481973f935a..4d7291706e7 100644 --- a/src/commands/bundle.ts +++ b/src/commands/bundle.ts @@ -4,49 +4,44 @@ import Command from '../base'; import bundle from '@asyncapi/bundler'; import { promises } from 'fs'; import path from 'path'; -import { Specification, load } from '../models/SpecificationFile'; -import { Parser } from '@asyncapi/parser'; +import { Specification } from '../models/SpecificationFile'; import { Document } from '@asyncapi/bundler/lib/document'; const { writeFile } = promises; export default class Bundle extends Command { - static description = 'bundle one or multiple asyncapi documents and their references together.'; + static readonly description = 'Bundle one or multiple AsyncAPI Documents and their references together.'; static strict = false; static examples: Example[] = [ - 'asyncapi bundle ./asyncapi.yaml > final-asyncapi.yaml', 'asyncapi bundle ./asyncapi.yaml --output final-asyncapi.yaml', - 'asyncapi bundle ./asyncapi.yaml ./features.yaml --reference-into-components', - 'asyncapi bundle ./asyncapi.yaml ./features.yaml --base ./asyncapi.yaml --reference-into-components' + 'asyncapi bundle ./asyncapi.yaml ./features.yaml', + 'asyncapi bundle ./asyncapi.yaml ./features.yaml --base ./main.yaml', + 'asyncapi bundle ./asyncapi.yaml ./features.yaml --base ./main.yaml --xOrigin', + 'asyncapi bundle ./asyncapi.yaml -o final-asyncapi.yaml --base ../public-api/main.yaml --baseDir ./social-media/comments-service', ]; static flags = { help: Flags.help({ char: 'h' }), output: Flags.string({ char: 'o', description: 'The output file name. Omitting this flag the result will be printed in the console.' }), - 'reference-into-components': Flags.boolean({ char: 'r', description: 'Bundle the message $refs into components object.' }), - base: Flags.string({ char: 'b', description: 'Path to the file which will act as a base. This is required when some properties are to needed to be overwritten.' }), + base: Flags.string({ char: 'b', description: 'Path to the file which will act as a base. This is required when some properties need to be overwritten.' }), + baseDir: Flags.string({ char: 'd', description: 'One relative/absolute path to directory relative to which paths to AsyncAPI Documents that should be bundled will be resolved.' }), + xOrigin: Flags.boolean({ char: 'x', description: 'Pass this switch to generate properties "x-origin" that will contain historical values of dereferenced "$ref"s.' }), }; - parser = new Parser(); - async run() { const { argv, flags } = await this.parse(Bundle); const output = flags.output; - let baseFile; const outputFormat = path.extname(argv[0]); - const AsyncAPIFiles = await this.loadFiles(argv); - - this.metricsMetadata.files = AsyncAPIFiles.length; - - if (flags.base) {baseFile = (await load(flags.base)).text();} + const AsyncAPIFiles = argv; - const fileContents = AsyncAPIFiles.map((file) => file.text()); + this.metricsMetadata.files = AsyncAPIFiles.length; - const document = await bundle(fileContents, + const document = await bundle(AsyncAPIFiles, { - referenceIntoComponents: flags['reference-into-components'], - base: baseFile + base: flags.base, + baseDir: flags.baseDir, + xOrigin: flags.xOrigin, } ); @@ -86,13 +81,4 @@ export default class Bundle extends Command { } } } - - async loadFiles(filepaths: string[]): Promise { - const files = []; - for (const filepath of filepaths) { - const file = await load(filepath); - files.push(file); - } - return files; - } } diff --git a/src/commands/generate/fromTemplate.ts b/src/commands/generate/fromTemplate.ts index 3dec4adc200..eb216bcad73 100644 --- a/src/commands/generate/fromTemplate.ts +++ b/src/commands/generate/fromTemplate.ts @@ -15,6 +15,7 @@ import { Parser } from '@asyncapi/parser'; import type { Example } from '@oclif/core/lib/interfaces'; import { intro, isCancel, spinner, text } from '@clack/prompts'; import { inverse, yellow, magenta, green, red } from 'picocolors'; +import fetch from 'node-fetch'; interface IMapBaseUrlToFlag { url: string, @@ -36,8 +37,6 @@ const templatesNotSupportingV3: Record = { '@asyncapi/java-spring-cloud-stream-template': 'https://github.com/asyncapi/java-spring-cloud-stream-template/issues/336', '@asyncapi/go-watermill-template': 'https://github.com/asyncapi/go-watermill-template/issues/243', '@asyncapi/java-spring-template': 'https://github.com/asyncapi/java-spring-template/issues/308', - '@asyncapi/nodejs-template': 'https://github.com/asyncapi/nodejs-template/issues/215', - '@asyncapi/java-template': 'https://github.com/asyncapi/java-template/issues/118', '@asyncapi/php-template': 'https://github.com/asyncapi/php-template/issues/191' }; @@ -102,8 +101,17 @@ export default class Template extends Command { 'map-base-url': Flags.string({ description: 'Maps all schema references from base url to local folder' }), + 'registry-url': Flags.string({ + default: 'https://registry.npmjs.org', + description: 'Specifies the URL of the private registry for fetching templates and dependencies' + }), + 'registry-auth': Flags.string({ + description: 'The registry username and password encoded with base64, formatted as username:password' + }), + 'registry-token': Flags.string({ + description: 'The npm registry authentication token, that can be passed instead of base64 encoded username and password' + }) }; - static args = [ { name: 'asyncapi', description: '- Local path, url or context-name pointing to AsyncAPI file' }, { name: 'template', description: '- Name of the generator template like for example @asyncapi/html-template or https://github.com/asyncapi/html-template' }, @@ -126,7 +134,7 @@ export default class Template extends Command { output = parsedArgs.output; } - const parsedFlags = this.parseFlags(flags['disable-hook'], flags['param'], flags['map-base-url']); + const parsedFlags = this.parseFlags(flags['disable-hook'], flags['param'], flags['map-base-url'],flags['registry.url'],flags['registry.auth'],flags['registry.token']); const options = { forceWrite: flags['force-write'], install: flags.install, @@ -135,6 +143,11 @@ export default class Template extends Command { noOverwriteGlobs: flags['no-overwrite'], mapBaseUrlToFolder: parsedFlags.mapBaseUrlToFolder, disabledHooks: parsedFlags.disableHooks, + registry: { + url: flags['registry-url'], + auth: flags['registry-auth'], + token: flags['registry-token'] + } }; const asyncapiInput = (await load(asyncapi)) || (await load()); @@ -213,14 +226,30 @@ export default class Template extends Command { return { asyncapi, template, output }; } - private parseFlags(disableHooks?: string[], params?: string[], mapBaseUrl?: string): ParsedFlags { + private parseFlags(disableHooks?: string[], params?: string[], mapBaseUrl?: string, registryUrl?: string, registryAuth?:string, registryToken?:string): ParsedFlags { return { params: this.paramParser(params), disableHooks: this.disableHooksParser(disableHooks), mapBaseUrlToFolder: this.mapBaseURLParser(mapBaseUrl), + registryURLValidation: this.registryURLParser(registryUrl), + registryAuthentication: this.registryValidation(registryUrl, registryAuth, registryToken) + } as ParsedFlags; } + private registryURLParser(input?:string) { + if (!input) { return; } + const isURL = /^https?:/; + if (!isURL.test(input.toLowerCase())) { + throw new Error('Invalid --registry-url flag. The param requires a valid http/https url.'); + } + } + private async registryValidation(registryUrl?:string, registryAuth?:string, registryToken?:string) { + const response= await fetch(registryUrl as string); + if (response.status === 401&&!registryAuth&&!registryToken) { + throw new Error('Need to pass either registryAuth in username:password encoded in Base64 or need to pass registryToken'); + } + } private paramParser(inputs?: string[]) { if (!inputs) { return {}; } const params: Record = {}; diff --git a/src/models/SpecificationFile.ts b/src/models/SpecificationFile.ts index 857ac471cf4..d81c84b1a41 100644 --- a/src/models/SpecificationFile.ts +++ b/src/models/SpecificationFile.ts @@ -222,4 +222,3 @@ async function detectSpecFile(): Promise { })); return existingFileNames.find(filename => filename !== undefined); } - diff --git a/test/integration/bundle/bundle.test.ts b/test/integration/bundle/bundle.test.ts index 0cc20e7cb31..f1ac4bf776a 100644 --- a/test/integration/bundle/bundle.test.ts +++ b/test/integration/bundle/bundle.test.ts @@ -45,25 +45,14 @@ describe('bundle', () => { 'bundle', './test/integration/bundle/asyncapi.yml' ]) .it('should throw error message if the file path is wrong', (ctx, done) => { - expect(ctx.stderr).to.contain('error loading AsyncAPI document from file: ./test/integration/bundle/asyncapi.yml file does not exist.\n'); + expect(ctx.stderr).to.contain('Error: ENOENT: no such file or directory'); done(); }); test .stdout() .command([ - 'bundle', './test/integration/bundle/first-asyncapi.yaml', '--reference-into-components', '--output=./test/integration/bundle/final.yaml' - ]) - .it('should be able to refence messages into components', (ctx, done) => { - expect(ctx.stdout).to.contain('Check out your shiny new bundled files at ./test/integration/bundle/final.yaml\n'); - fileCleanup('./test/integration/bundle/final.yaml'); - done(); - }); - - test - .stdout() - .command([ - 'bundle', './test/integration/bundle/first-asyncapi.yaml', './test/integration/bundle/feature.yaml', '--reference-into-components', '--output=test/integration/bundle/final.yaml' + 'bundle', './test/integration/bundle/first-asyncapi.yaml', './test/integration/bundle/feature.yaml', '--output=test/integration/bundle/final.yaml' ]) .it('should be able to bundle multiple specs along with custom reference', (ctx, done) => { expect(ctx.stdout).to.contain('Check out your shiny new bundled files at test/integration/bundle/final.yaml\n'); @@ -75,7 +64,7 @@ describe('bundle', () => { test .stdout() .command([ - 'bundle', './test/integration/bundle/first-asyncapi.yaml', './test/integration/bundle/feature.yaml', '--reference-into-components', '--output=test/integration/bundle/final.yaml', '--base=./test/integration/bundle/first-asyncapi.yaml' + 'bundle', './test/integration/bundle/first-asyncapi.yaml', './test/integration/bundle/feature.yaml', '--output=test/integration/bundle/final.yaml', '--base=./test/integration/bundle/first-asyncapi.yaml' ]) .it('should be able to bundle correctly with overwriting base file', (ctx, done) => { expect(ctx.stdout).to.contain('Check out your shiny new bundled files at test/integration/bundle/final.yaml\n'); diff --git a/test/integration/bundle/channels.yaml b/test/integration/bundle/channels.yaml new file mode 100644 index 00000000000..b1794157960 --- /dev/null +++ b/test/integration/bundle/channels.yaml @@ -0,0 +1,3 @@ +channels: + commentLikedChannel: + address: comment/liked \ No newline at end of file diff --git a/test/integration/bundle/feature.yaml b/test/integration/bundle/feature.yaml index f3b41b9e0b4..1a716520cc9 100644 --- a/test/integration/bundle/feature.yaml +++ b/test/integration/bundle/feature.yaml @@ -1,11 +1,10 @@ -asyncapi: "2.5.0" +asyncapi: "2.6.0" info: title: Account Service version: 1.0.0 description: This service is in charge of processing user logouts channels: user/loggedOut: - subcribe: + unsubcribe: message: $ref: 'test/integration/bundle/messages.yaml#/messages/UserLoggedOut' - diff --git a/test/integration/bundle/final-asyncapi.yaml b/test/integration/bundle/final-asyncapi.yaml index 4624b746503..9de32aa5d81 100644 --- a/test/integration/bundle/final-asyncapi.yaml +++ b/test/integration/bundle/final-asyncapi.yaml @@ -1,4 +1,4 @@ -asyncapi: 2.5.0 +asyncapi: 2.6.0 info: title: Account Service version: 1.0.0 @@ -9,7 +9,7 @@ channels: message: $ref: '#/components/messages/UserSignedUp' user/loggedOut: - subcribe: + unsubcribe: message: $ref: '#/components/messages/UserLoggedOut' components: @@ -38,4 +38,3 @@ components: timestamp: type: number descriptio: Time stamp when the user logged out - diff --git a/test/integration/bundle/first-asyncapi.yaml b/test/integration/bundle/first-asyncapi.yaml index f49894d1d7f..d41ed4a2fec 100644 --- a/test/integration/bundle/first-asyncapi.yaml +++ b/test/integration/bundle/first-asyncapi.yaml @@ -1,4 +1,4 @@ -asyncapi: "2.5.0" +asyncapi: "2.6.0" info: title: Account Service version: 1.0.0 diff --git a/test/integration/bundle/first-asyncapiv3.yaml b/test/integration/bundle/first-asyncapiv3.yaml index 117d7bad68c..d49bb67334c 100644 --- a/test/integration/bundle/first-asyncapiv3.yaml +++ b/test/integration/bundle/first-asyncapiv3.yaml @@ -1,34 +1,8 @@ asyncapi: 3.0.0 info: - title: Account Service + title: Example Service version: 1.0.0 - description: This service is in charge of processing user signupsA + description: Example Service. channels: - userSignedup: - address: 'user/signedup' - messages: - userSignedUpMessage: - $ref: './test/integration/bundle/messages.yaml#/messages/UserSignedUp' - test: - address: '/test' - messages: - testMessage: - $ref: '#/components/messages/TestMessage' -operations: - UserSignedUp: - action: send - channel: - $ref: '#/channels/userSignedup' - messages: - - $ref: './test/integration/bundle/messages.yaml#/messages/UserSignedUp' - TestOpp: - action: send - channel: - $ref: '#/channels/test' - messages: - - $ref: '#/components/messages/TestMessage' -components: - messages: - TestMessage: - payload: - type: string \ No newline at end of file + commentLikedChannel: + $ref: './test/integration/bundle/channels.yaml#/channels/commentLikedChannel'