Repository: asyncapi/cli Branch: master Commit: b53337377884 Files: 299 Total size: 911.1 KB Directory structure: gitextract_blnuhiyp/ ├── .all-contributorsrc ├── .asyncapi-tool ├── .changeset/ │ └── config.json ├── .dockerignore ├── .editorconfig ├── .gitattributes ├── .github/ │ └── workflows/ │ ├── add-good-first-issue-labels.yml │ ├── automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml │ ├── automerge-for-humans-merging.yml │ ├── automerge-for-humans-remove-ready-to-merge-label-on-edit.yml │ ├── automerge-orphans.yml │ ├── automerge.yml │ ├── autoupdate.yml │ ├── bounty-program-commands.yml │ ├── bump-homebrew-formula.yml │ ├── bump.yml │ ├── deploy/ │ │ └── chocolatey/ │ │ ├── asyncapi-cli.nuspec │ │ ├── replace.ps1 │ │ └── tools/ │ │ └── chocolateyinstall.ps1 │ ├── help-command.yml │ ├── if-docker-pr-testing.yml │ ├── if-nodejs-pr-testing.yml │ ├── issues-prs-notifications.yml │ ├── lint-pr-title.yml │ ├── notify-tsc-members-mention.yml │ ├── please-take-a-look-command.yml │ ├── release-announcements.yml │ ├── release-chocolatey.yml │ ├── release-docker.yml │ ├── release-server-api.yml │ ├── release-with-changesets.yml │ ├── scripts/ │ │ ├── README.md │ │ ├── kit/ │ │ │ ├── htmlContent.js │ │ │ ├── index.js │ │ │ └── package.json │ │ └── mailchimp/ │ │ └── htmlContent.js │ ├── stale-issues-prs.yml │ ├── test-action.yml │ ├── update-docs-in-website.yml │ ├── update-docs-on-docs-commits.yml │ ├── update-maintainers-trigger.yaml │ ├── update-pr.yml │ ├── upload-release-assets.yml │ └── welcome-first-time-contrib.yml ├── .gitignore ├── .prettierrc ├── .sonarcloud.properties ├── CHANGELOG.md ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPMENT.md ├── Dockerfile ├── LICENSE ├── NOTICE ├── README.md ├── action-template.yml ├── action.yml ├── assets/ │ ├── create-template/ │ │ └── templates/ │ │ └── default/ │ │ ├── asyncapi.yaml │ │ ├── package.json │ │ ├── readme.md │ │ └── template/ │ │ └── index.js │ └── examples/ │ ├── default-example.json │ └── default-example.yaml ├── bin/ │ ├── dev │ ├── dev.cmd │ ├── run │ ├── run.cmd │ ├── run_bin │ └── run_bin.cmd ├── docs/ │ ├── architecture.md │ ├── autocompleteEnabled.md │ ├── context.md │ ├── contributing-prs.md │ ├── debugging-testing.md │ ├── github-action.md │ ├── index.md │ ├── installation.md │ ├── metrics_collection.md │ └── usage.md ├── eslint.config.mjs ├── github-action/ │ ├── .asyncapi-tool │ ├── Dockerfile │ ├── Makefile │ ├── README.md │ ├── bump-test.sh │ ├── entrypoint.sh │ ├── lib/ │ │ └── bump-action-version.js │ └── test/ │ ├── asyncapi.yml │ ├── bundle/ │ │ ├── asyncapi.yaml │ │ ├── features.yaml │ │ └── messages.yaml │ ├── dummy.yml │ ├── specification-invalid.yml │ ├── unoptimized.yml │ └── unoptimized_optimized.yml ├── jest.config.ts ├── nodemon.json ├── openapi.yaml ├── package.json ├── scripts/ │ ├── enableAutoComplete.js │ ├── fetch-asyncapi-example.js │ ├── generateTypesForGenerateCommand.js │ ├── releasePackagesRename.js │ └── updateUsageDocs.js ├── src/ │ ├── apps/ │ │ ├── api/ │ │ │ ├── .do/ │ │ │ │ ├── app.yaml │ │ │ │ └── apps/ │ │ │ │ ├── .gitignore │ │ │ │ ├── .terraform.lock.hcl │ │ │ │ └── main.tf │ │ │ ├── Dockerfile │ │ │ ├── README.md │ │ │ ├── app.ts │ │ │ ├── configs/ │ │ │ │ ├── development.json │ │ │ │ ├── production.json │ │ │ │ └── test.json │ │ │ ├── constants.ts │ │ │ ├── controllers/ │ │ │ │ ├── bundle.controller.ts │ │ │ │ ├── convert.controller.ts │ │ │ │ ├── diff.controller.ts │ │ │ │ ├── docs.controller.ts │ │ │ │ ├── generate.controller.ts │ │ │ │ ├── help.controller.ts │ │ │ │ ├── parse.controller.ts │ │ │ │ ├── validate.controller.ts │ │ │ │ └── version.controller.ts │ │ │ ├── exceptions/ │ │ │ │ └── problem.exception.ts │ │ │ ├── index.ts │ │ │ ├── middlewares/ │ │ │ │ ├── logger.middleware.ts │ │ │ │ ├── problem.middleware.ts │ │ │ │ └── validation.middleware.ts │ │ │ ├── server-api.d.ts │ │ │ ├── server.ts │ │ │ └── templates.json │ │ └── cli/ │ │ ├── commands/ │ │ │ ├── bundle.ts │ │ │ ├── config/ │ │ │ │ ├── analytics.ts │ │ │ │ ├── auth/ │ │ │ │ │ └── add.ts │ │ │ │ ├── context/ │ │ │ │ │ ├── add.ts │ │ │ │ │ ├── current.ts │ │ │ │ │ ├── edit.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── init.ts │ │ │ │ │ ├── list.ts │ │ │ │ │ ├── remove.ts │ │ │ │ │ └── use.ts │ │ │ │ ├── index.ts │ │ │ │ └── versions.ts │ │ │ ├── convert.ts │ │ │ ├── diff.ts │ │ │ ├── format.ts │ │ │ ├── generate/ │ │ │ │ ├── client.ts │ │ │ │ ├── fromTemplate.ts │ │ │ │ ├── index.ts │ │ │ │ └── models.ts │ │ │ ├── new/ │ │ │ │ ├── file.ts │ │ │ │ ├── index.ts │ │ │ │ └── template.ts │ │ │ ├── optimize.ts │ │ │ ├── pretty.ts │ │ │ ├── start/ │ │ │ │ ├── api.ts │ │ │ │ ├── index.ts │ │ │ │ ├── preview.ts │ │ │ │ └── studio.ts │ │ │ └── validate.ts │ │ └── internal/ │ │ ├── args/ │ │ │ └── generate.args.ts │ │ ├── base/ │ │ │ └── BaseGeneratorCommand.ts │ │ ├── base.ts │ │ ├── flags/ │ │ │ ├── bundle.flags.ts │ │ │ ├── config/ │ │ │ │ ├── analytics.flags.ts │ │ │ │ └── context.flags.ts │ │ │ ├── convert.flags.ts │ │ │ ├── diff.flags.ts │ │ │ ├── format.flags.ts │ │ │ ├── generate/ │ │ │ │ ├── clients.flags.ts │ │ │ │ ├── fromTemplate.flags.ts │ │ │ │ ├── models.flags.ts │ │ │ │ └── sharedFlags.ts │ │ │ ├── global.flags.ts │ │ │ ├── new/ │ │ │ │ ├── file.flags.ts │ │ │ │ └── template.flags.ts │ │ │ ├── optimize.flags.ts │ │ │ ├── parser.flags.ts │ │ │ ├── pretty.flags.ts │ │ │ ├── proxy.flags.ts │ │ │ ├── start/ │ │ │ │ ├── api.flags.ts │ │ │ │ ├── preview.flags.ts │ │ │ │ └── studio.flags.ts │ │ │ └── validate.flags.ts │ │ ├── global.d.ts │ │ ├── globals.ts │ │ └── hooks/ │ │ └── command_not_found/ │ │ └── myhook.ts │ ├── domains/ │ │ ├── models/ │ │ │ ├── Context.ts │ │ │ ├── Preview.ts │ │ │ ├── SpecificationFile.ts │ │ │ ├── Studio.ts │ │ │ └── generate/ │ │ │ └── Flags.ts │ │ └── services/ │ │ ├── archiver.service.ts │ │ ├── base.service.ts │ │ ├── config.service.ts │ │ ├── convert.service.ts │ │ ├── generator.service.ts │ │ ├── module.d.ts │ │ └── validation.service.ts │ ├── errors/ │ │ ├── context-error.ts │ │ ├── diff-error.ts │ │ ├── generator-error.ts │ │ ├── specification-file.ts │ │ └── validation-error.ts │ ├── index.ts │ ├── interfaces/ │ │ └── index.ts │ └── utils/ │ ├── ajv.ts │ ├── app-openapi.ts │ ├── error-handler.ts │ ├── generate/ │ │ ├── flags.ts │ │ ├── mapBaseUrl.ts │ │ ├── parseParams.ts │ │ ├── prompts.ts │ │ ├── registry.ts │ │ └── watcher.ts │ ├── logger.ts │ ├── proxy.ts │ ├── retrieve-language.ts │ ├── scoreCalculator.ts │ ├── temp-dir.ts │ └── validation.ts ├── test/ │ ├── fixtures/ │ │ ├── asyncapiTestingScore.yml │ │ ├── asyncapiValid_v1.yml │ │ ├── asyncapi_v1.yml │ │ ├── asyncapi_v2.yml │ │ ├── badFormatAsyncapi.json │ │ ├── dummyspec/ │ │ │ ├── apiwithref.json │ │ │ ├── dummySpec.yml │ │ │ ├── dummySpecWithoutSecurity.yml │ │ │ ├── shared.json │ │ │ ├── unoptimizedSpec.json │ │ │ └── unoptimizedSpec.yml │ │ ├── external-refs/ │ │ │ ├── main.yaml │ │ │ └── schemas.yaml │ │ ├── generate-same-dir-ref/ │ │ │ ├── asyncapi.yaml │ │ │ └── messages.yaml │ │ ├── invalid-overrides.json │ │ ├── minimaltemplate/ │ │ │ ├── hooks/ │ │ │ │ └── generateAsyncapiFile.js │ │ │ ├── package.json │ │ │ └── template/ │ │ │ └── index.js │ │ ├── newtemplate/ │ │ │ ├── hooks/ │ │ │ │ └── generateAsyncapiFile.js │ │ │ ├── package.json │ │ │ └── template/ │ │ │ └── index.js │ │ ├── openapi.yml │ │ ├── overrides.json │ │ ├── specification-avro.yml │ │ ├── specification-invalid.yml │ │ ├── specification-v3-diff.yml │ │ ├── specification-v3.yml │ │ ├── specification.json │ │ ├── specification.yml │ │ ├── valid-specification-latest.yml │ │ └── valid-specification.yml │ ├── helpers/ │ │ ├── index.ts │ │ └── init.js │ ├── hooks/ │ │ └── command_not_found/ │ │ └── myhook.spec.ts │ ├── integration/ │ │ ├── bundle/ │ │ │ ├── bundle.test.ts │ │ │ ├── channels.yaml │ │ │ ├── feature.yaml │ │ │ ├── final-asyncapi.yaml │ │ │ ├── first-asyncapi.yaml │ │ │ ├── first-asyncapiv3.yaml │ │ │ └── messages.yaml │ │ ├── config/ │ │ │ ├── analytics.test.ts │ │ │ └── versions.test.ts │ │ ├── context.test.ts │ │ ├── convert.test.ts │ │ ├── diff.test.ts │ │ ├── format.test.ts │ │ ├── generate/ │ │ │ ├── __snapshots__/ │ │ │ │ └── models.test.ts.snap │ │ │ ├── client.test.ts │ │ │ ├── fromTemplate.test.ts │ │ │ └── models.test.ts │ │ ├── new/ │ │ │ ├── file.test.ts │ │ │ └── template.test.ts │ │ ├── optimize.test.ts │ │ ├── pretty.test.ts │ │ ├── studio.test.ts │ │ └── validate.test.ts │ ├── jest.setup.ts │ ├── system/ │ │ └── .gitkeep │ ├── tsconfig.json │ └── unit/ │ ├── controllers/ │ │ ├── convert.controller.test.ts │ │ ├── diff.controller.test.ts │ │ ├── parse.controller.test.ts │ │ ├── setup.test.ts │ │ └── validate.controller.test.ts │ ├── services/ │ │ ├── archiver.service.test.ts │ │ ├── convert.service.test.ts │ │ └── validation.service.test.ts │ └── utils/ │ ├── ajv.test.ts │ ├── app-openapi.test.ts │ ├── registry.test.ts │ ├── retrieve-language.test.ts │ └── temp-dir.test.ts └── tsconfig.json ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "files": [ "README.md" ], "imageSize": 100, "commit": false, "contributors": [ { "login": "jotamusik", "name": "Jorge Aguiar Martín", "avatar_url": "https://avatars.githubusercontent.com/u/14940638?v=4", "profile": "https://github.com/jotamusik", "contributions": [ "code", "ideas", "test", "doc" ] }, { "login": "derberg", "name": "Lukasz Gornicki", "avatar_url": "https://avatars.githubusercontent.com/u/6995927?v=4", "profile": "https://www.brainfart.dev/", "contributions": [ "ideas", "code", "review", "maintenance" ] }, { "login": "Souvikns", "name": "souvik", "avatar_url": "https://avatars.githubusercontent.com/u/41781438?v=4", "profile": "https://souvik.vercel.app/", "contributions": [ "code", "ideas", "test", "review", "maintenance", "doc" ] }, { "login": "boyney123", "name": "David Boyne", "avatar_url": "https://avatars.githubusercontent.com/u/3268013?v=4", "profile": "https://boyney.io/", "contributions": [ "code", "ideas", "maintenance" ] }, { "login": "fmvilas", "name": "Fran Méndez", "avatar_url": "https://avatars.githubusercontent.com/u/242119?v=4", "profile": "http://www.fmvilas.com/", "contributions": [ "code", "ideas", "review" ] }, { "login": "magicmatatjahu", "name": "Maciej Urbańczyk", "avatar_url": "https://avatars.githubusercontent.com/u/20404945?v=4", "profile": "https://github.com/magicmatatjahu", "contributions": [ "review", "maintenance", "ideas" ] }, { "login": "aayushmau5", "name": "Aayush Kumar Sahu", "avatar_url": "https://avatars.githubusercontent.com/u/54525741?v=4", "profile": "https://aayushsahu.com/", "contributions": [ "code", "test" ] }, { "login": "mihirterna", "name": "Mihir Kulkarni", "avatar_url": "https://avatars.githubusercontent.com/u/31316452?v=4", "profile": "https://github.com/mihirterna", "contributions": [ "code" ] }, { "login": "imabp", "name": "Abir", "avatar_url": "https://avatars.githubusercontent.com/u/53480076?v=4", "profile": "https://imabp.github.io/resume/", "contributions": [ "test", "code" ] }, { "login": "peter-rr", "name": "Peter Ramos", "avatar_url": "https://avatars.githubusercontent.com/u/81691177?v=4", "profile": "https://github.com/peter-rr", "contributions": [ "code" ] }, { "login": "Samridhi-98", "name": "Samriddhi", "avatar_url": "https://avatars.githubusercontent.com/u/54466041?v=4", "profile": "https://samridhi-98.github.io/Portfolio", "contributions": [ "test" ] }, { "login": "pranay202", "name": "Pranay Kharabe", "avatar_url": "https://avatars.githubusercontent.com/u/68046838?v=4", "profile": "https://linktr.ee/KharabePranay", "contributions": [ "code" ] }, { "login": "activus-d", "name": "Damilola Oladele", "avatar_url": "https://avatars.githubusercontent.com/u/98895460?v=4", "profile": "https://d-m-oladele.netlify.app/", "contributions": [ "doc" ] }, { "login": "prayutsu", "name": "Abhay Garg", "avatar_url": "https://avatars.githubusercontent.com/u/54636525?v=4", "profile": "https://github.com/prayutsu", "contributions": [ "code", "test" ] }, { "login": "sambhavgupta0705", "name": "Sambhav Gupta", "avatar_url": "https://avatars.githubusercontent.com/u/81870866?v=4", "profile": "https://github.com/sambhavgupta0705", "contributions": [ "code", "test" ] }, { "login": "CyberHippo", "name": "Hippolyte Vergnol", "avatar_url": "https://avatars.githubusercontent.com/u/18269437?v=4", "profile": "https://github.com/CyberHippo", "contributions": [ "code", "infra" ] }, { "login": "Vetsoo", "name": "Jente Vets", "avatar_url": "https://avatars.githubusercontent.com/u/22449126?v=4", "profile": "https://www.jentevets.com", "contributions": [ "code" ] }, { "login": "kaushik-rishi", "name": "Rishi", "avatar_url": "https://avatars.githubusercontent.com/u/52498617?v=4", "profile": "https://github.com/kaushik-rishi", "contributions": [ "code" ] }, { "login": "Shurtu-gal", "name": "Ashish Padhy", "avatar_url": "https://avatars.githubusercontent.com/u/100484401?v=4", "profile": "http://ashishpadhy.live", "contributions": [ "code" ] }, { "login": "meetagrawal09", "name": "Meet Agrawal", "avatar_url": "https://avatars.githubusercontent.com/u/73902874?v=4", "profile": "https://github.com/meetagrawal09", "contributions": [ "infra" ] }, { "login": "chinma-yyy", "name": "Chinmay Shewale", "avatar_url": "https://avatars.githubusercontent.com/u/112387862?v=4", "profile": "https://www.chinmayyy.tech", "contributions": [ "code", "test" ] }, { "login": "mhmohona", "name": "Mahfuza Humayra Mohona", "avatar_url": "https://avatars.githubusercontent.com/u/14244685?v=4", "profile": "https://github.com/mhmohona", "contributions": [ "doc" ] }, { "login": "GreenRover", "name": "Heiko Henning", "avatar_url": "https://avatars.githubusercontent.com/u/512850?v=4", "profile": "https://github.com/GreenRover", "contributions": [ "code" ] }, { "login": "AayushSaini101", "name": "Zack_Aayush", "avatar_url": "https://avatars.githubusercontent.com/u/60972989?v=4", "profile": "https://www.linkedin.com/in/aayush-saini-0a25931b1/", "contributions": [ "code" ] }, { "login": "ayushnau", "name": "Ayush Nautiyal", "avatar_url": "https://avatars.githubusercontent.com/u/78146753?v=4", "profile": "https://github.com/ayushnau", "contributions": [ "code" ] }, { "login": "Anish Kacham", "name": "AnishKacham", "avatar_url": "https://avatars.githubusercontent.com/u/79566582?v=4", "profile": "https://github.com/AnishKacham", "contributions": [ "code" ] }, { "login": "aeworxet", "name": "Viacheslav Turovskyi", "avatar_url": "https://avatars.githubusercontent.com/u/16149591?v=4", "profile": "https://github.com/aeworxet", "contributions": [ "code" ] }, { "login": "amanbedi1", "name": "Amanpreet Singh Bedi ", "avatar_url": "https://avatars.githubusercontent.com/u/82234871?v=4", "profile": "https://github.com/amanbedi1", "contributions": [ "code" ] }, { "login": "ron-debajyoti", "name": "Debajyoti Halder", "avatar_url": "https://avatars.githubusercontent.com/u/22571664?v=4", "profile": "https://github.com/ron-debajyoti", "contributions": [ "code" ] }, { "login": "Savio629", "name": "Savio Dias", "avatar_url": "https://avatars.githubusercontent.com/u/91362589?v=4", "profile": "https://github.com/Savio629", "contributions": [ "code" ] }, { "login": "jonaslagoni", "name": "Jonas Lagoni", "avatar_url": "https://avatars.githubusercontent.com/u/13396189?v=4", "profile": "https://github.com/jonaslagoni", "contributions": [ "code", "ideas", "review", "test" ] }, { "login": "KhudaDad414", "name": "Khuda Dad Nomani", "avatar_url": "https://avatars.githubusercontent.com/u/32505158?v=4", "profile": "https://github.com/KhudaDad414", "contributions": [ "code", "doc" ] }, { "login": "smoya", "name": "Sergio Moya ", "avatar_url": "https://avatars.githubusercontent.com/u/1083296?v=4", "profile": "https://github.com/smoya", "contributions": [ "code" ] }, { "login": "Vishal2002", "name": "Vishal Sharma", "avatar_url": "https://avatars.githubusercontent.com/u/35897449?v=4", "profile": "https://github.com/Vishal2002", "contributions": [ "code" ] } ], "contributorsPerLine": 7, "projectName": "cli", "projectOwner": "asyncapi", "repoType": "github", "repoHost": "https://github.com", "skipCi": false, "commitConvention": "angular", "commitType": "docs" } ================================================ FILE: .asyncapi-tool ================================================ title: AsyncAPI CLI description: | One CLI to rule them all. This is a CLI that aims to integrate all AsyncAPI tools that you need while AsyncAPI document development and maintainance. You can use it to generate docs or code, validate AsyncAPI document and event create new documents. links: websiteUrl: https://www.asyncapi.com/tools/cli filters: technology: - TypeScript categories: - others - cli hasCommercial: false ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json", "changelog": ["@changesets/changelog-git", { "repo": "asyncapi/cli" }], "commit": false, "fixed": [], "linked": [], "access": "public", "baseBranch": "master", "updateInternalDependencies": "patch", "privatePackages": { "version": true, "tag": true } } ================================================ FILE: .dockerignore ================================================ node_modules npm-debug.log Dockerfile .dockerignore .git ================================================ FILE: .editorconfig ================================================ root = true [*] indent_style = space indent_size = 2 charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true [*.md] trim_trailing_whitespace = false ================================================ FILE: .gitattributes ================================================ * text=auto eol=lf ================================================ FILE: .github/workflows/add-good-first-issue-labels.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # Purpose of this workflow is to enable anyone to label issue with 'Good First Issue' and 'area/*' with a single command. name: Add 'Good First Issue' and 'area/*' labels # if proper comment added on: issue_comment: types: - created permissions: {} jobs: add-labels: name: Add 'Good First Issue' and 'area/*' labels if: ${{(!github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot') && (contains(github.event.comment.body, '/good-first-issue') || contains(github.event.comment.body, '/gfi' ))}} runs-on: ubuntu-latest permissions: issues: write # This is needed to add labels to issues. steps: - name: Add label uses: actions/github-script@v7 with: github-token: ${{ github.token }} script: | const areas = ['javascript', 'typescript', 'java' , 'go', 'docs', 'ci-cd', 'design']; const words = context.payload.comment.body.trim().split(" "); const areaIndex = words.findIndex((word)=> word === '/gfi' || word === '/good-first-issue') + 1 let area = words[areaIndex]; switch(area){ case 'ts': area = 'typescript'; break; case 'js': area = 'javascript'; break; case 'markdown': area = 'docs'; break; } if(!areas.includes(area)){ const message = `Hey @${context.payload.sender.login}, your message doesn't follow the requirements, you can try \`/help\`.` await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: message }) } else { // remove area if there is any before adding new labels. const currentLabels = (await github.rest.issues.listLabelsOnIssue({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, })).data.map(label => label.name); const shouldBeRemoved = currentLabels.filter(label => (label.startsWith('area/') && !label.endsWith(area))); shouldBeRemoved.forEach(label => { github.rest.issues.deleteLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, }); }); // Add new labels. github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: ['good first issue', `area/${area}`] }); } ================================================ FILE: .github/workflows/automerge-for-humans-add-ready-to-merge-or-do-not-merge-label.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # Purpose of this workflow is to enable anyone to label PR with the following labels: # `ready-to-merge` and `do-not-merge` labels to get stuff merged or blocked from merging # `autoupdate` to keep a branch up-to-date with the target branch name: Label PRs # if proper comment added on: issue_comment: types: - created permissions: {} jobs: add-ready-to-merge-label: name: Add ready-to-merge label permissions: issues: write # required to add labels and post comments on PR issues pull-requests: write # required to read PR metadata from the issue pull_request URL contents: read # required to compare PR branch commits against base if: > github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot' && ( contains(github.event.comment.body, '/ready-to-merge') || contains(github.event.comment.body, '/rtm' ) ) runs-on: ubuntu-latest steps: - name: Add ready-to-merge label uses: actions/github-script@v7 env: GITHUB_ACTOR: ${{ github.actor }} with: github-token: ${{ github.token }} script: | const prDetailsUrl = context.payload.issue.pull_request.url; const { data: pull } = await github.request(prDetailsUrl); const { draft: isDraft} = pull; if(!isDraft) { console.log('adding ready-to-merge label...'); github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: ['ready-to-merge'] }) } const { data: comparison } = await github.rest.repos.compareCommitsWithBasehead({ owner: pull.head.repo.owner.login, repo: pull.head.repo.name, basehead: `${pull.base.label}...${pull.head.label}`, }); if (comparison.behind_by !== 0 && pull.mergeable_state === 'behind') { console.log(`This branch is behind the target by ${comparison.behind_by} commits`) console.log('adding out-of-date comment...'); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `Hello, @${process.env.GITHUB_ACTOR}! 👋🏼 This PR is not up to date with the base branch and can't be merged. Please update your branch manually with the latest version of the base branch. PRO-TIP: To request an update from the upstream branch, simply comment \`/u\` or \`/update\` and our bot will handle the update operation promptly. The only requirement for this to work is to enable [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option in your PR. Also the update will not work if your fork is located in an organization, not under your personal profile. Thanks 😄` }) } add-do-not-merge-label: name: Add do-not-merge label permissions: issues: write # required to add labels on PR issues pull-requests: write # required to read PR metadata from the issue pull_request URL if: > github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot' && ( contains(github.event.comment.body, '/do-not-merge') || contains(github.event.comment.body, '/dnm' ) ) runs-on: ubuntu-latest steps: - name: Add do-not-merge label uses: actions/github-script@v7 with: github-token: ${{ github.token }} script: | github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: ['do-not-merge'] }) add-autoupdate-label: name: Add autoupdate label permissions: issues: write # required to add labels on PR issues pull-requests: write # required to read PR metadata from the issue pull_request URL if: > github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot' && ( contains(github.event.comment.body, '/autoupdate') || contains(github.event.comment.body, '/au' ) ) runs-on: ubuntu-latest steps: - name: Add autoupdate label uses: actions/github-script@v7 with: github-token: ${{ github.token }} script: | github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: ['autoupdate'] }) ================================================ FILE: .github/workflows/automerge-for-humans-merging.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # Purpose of this workflow is to allow people to merge PR without a need of maintainer doing it. If all checks are in place (including maintainers approval) - JUST MERGE IT! name: Automerge For Humans on: pull_request_target: types: - labeled - unlabeled - synchronize - opened - edited - ready_for_review - reopened - unlocked # zizmor: ignore[dangerous-triggers] needed if we want author to be our bot permissions: {} jobs: automerge-for-humans: name: Automerge PRs labeled with ready-to-merge permissions: contents: read # required for PR commit metadata reads pull-requests: read # required to read pull request details in github-script steps # it runs only if PR actor is not a bot, at least not a bot that we know if: | github.event.pull_request.draft == false && !contains(fromJSON('["asyncapi-bot","dependabot[bot]","dependabot-preview[bot]"]'), github.event.pull_request.user.login) runs-on: ubuntu-latest steps: - name: Get PR authors id: authors uses: actions/github-script@v7 with: script: | // Get paginated list of all commits in the PR try { const commitOpts = github.rest.pulls.listCommits.endpoint.merge({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number }); const commits = await github.paginate(commitOpts); if (commits.length === 0) { core.setFailed('No commits found in the PR'); return ''; } // Get unique authors from the commits list const authors = commits.reduce((acc, commit) => { const username = commit.author?.login || commit.commit.author?.name; if (username && !acc[username]) { acc[username] = { name: commit.commit.author?.name, email: commit.commit.author?.email, } } return acc; }, {}); return authors; } catch (error) { core.setFailed(error.message); return []; } - name: Create commit message id: create-commit-message uses: actions/github-script@v7 env: AUTHORS_JSON: ${{ steps.authors.outputs.result }} with: script: | const authors = JSON.parse(process.env.AUTHORS_JSON); if (Object.keys(authors).length === 0) { core.setFailed('No authors found in the PR'); return ''; } // Create a string of the form "Co-authored-by: Name " // ref: https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors const coAuthors = Object.values(authors).map(author => { return `Co-authored-by: ${author.name} <${author.email}>`; }).join('\n'); core.debug(coAuthors);; return coAuthors; - name: Automerge PR uses: pascalgn/automerge-action@22948e0bc22f0aa673800da838595a3e7347e584 #v0.15.6 https://github.com/pascalgn/automerge-action/releases/tag/v0.15.6 env: GITHUB_TOKEN: "${{ secrets.GH_TOKEN }}" MERGE_LABELS: "!do-not-merge,ready-to-merge" MERGE_METHOD: "squash" # Using the output of the previous step (`Co-authored-by: ...` lines) as commit description. # Important to keep 2 empty lines as https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors#creating-co-authored-commits-on-the-command-line mentions MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})\n\n\n${{ fromJSON(steps.create-commit-message.outputs.result) }}" MERGE_RETRIES: "20" MERGE_RETRY_SLEEP: "30000" ================================================ FILE: .github/workflows/automerge-for-humans-remove-ready-to-merge-label-on-edit.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # Defence from evil contributor that after adding `ready-to-merge` all suddenly makes evil commit or evil change in PR title # Label is removed once above action is detected name: Remove ready-to-merge label on: pull_request: types: - synchronize - edited permissions: {} jobs: remove-ready-label: name: Remove ready-to-merge label runs-on: ubuntu-latest permissions: pull-requests: write # required to remove labels and post comments on PR issues steps: - name: Remove label uses: actions/github-script@v7 with: github-token: ${{ github.token }} script: | const labelToRemove = 'ready-to-merge'; const labels = context.payload.pull_request.labels; const isLabelPresent = labels.some(label => label.name === labelToRemove) if(!isLabelPresent) return; github.rest.issues.removeLabel({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, name: labelToRemove }) ================================================ FILE: .github/workflows/automerge-orphans.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: 'Notify on failing automerge' on: schedule: - cron: "0 0 * * *" permissions: {} jobs: identify-orphans: if: startsWith(github.repository, 'asyncapi/') name: Find orphans and notify permissions: contents: read # required by checkout and repository metadata reads pull-requests: read # required to list open pull requests runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Get list of orphans uses: actions/github-script@v7 id: orphans with: github-token: ${{ github.token }} script: | const query = `query($owner:String!, $name:String!) { repository(owner:$owner, name:$name){ pullRequests(first: 100, states: OPEN){ nodes{ title url author { resourcePath } } } } }`; const variables = { owner: context.repo.owner, name: context.repo.repo }; const { repository: { pullRequests: { nodes } } } = await github.graphql(query, variables); let orphans = nodes.filter( (pr) => pr.author.resourcePath === '/asyncapi-bot' || pr.author.resourcePath === '/apps/dependabot') if (orphans.length) { core.setOutput('found', 'true'); //Yes, this is very naive approach to assume there is just one PR causing issues, there can be a case that more PRs are affected the same day //The thing is that handling multiple PRs will increase a complexity in this PR that in my opinion we should avoid //The other PRs will be reported the next day the action runs, or person that checks first url will notice the other ones core.setOutput('url', orphans[0].url); core.setOutput('title', orphans[0].title); } - if: steps.orphans.outputs.found == 'true' name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: issuemarkdown with: markdown: "-> [${{steps.orphans.outputs.title}}](${{steps.orphans.outputs.url}})" - if: steps.orphans.outputs.found == 'true' name: Send info about orphan to slack uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_CI_FAIL_NOTIFY}} SLACK_TITLE: 🚨 Not merged PR that should be automerged 🚨 SLACK_MESSAGE: ${{steps.issuemarkdown.outputs.text}} MSG_MINIMAL: true ================================================ FILE: .github/workflows/automerge.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo. name: Automerge PRs from bots on: pull_request_target: # Needed as GH_TOKEN_BOT_EVE needed for approval. types: - opened - synchronize # zizmor: ignore[dangerous-triggers] permissions: {} jobs: autoapprove-for-bot: name: Autoapprove PR comming from a bot if: > contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]"]'), github.event.pull_request.user.login) && contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]"]'), github.actor) && !contains(github.event.pull_request.labels.*.name, 'released') runs-on: ubuntu-latest steps: - name: Autoapproving uses: hmarr/auto-approve-action@44888193675f29a83e04faf4002fa8c0b537b1e4 # v3.2.1 is used https://github.com/hmarr/auto-approve-action/releases/tag/v3.2.1 with: github-token: "${{ secrets.GH_TOKEN_BOT_EVE }}" - name: Label autoapproved uses: actions/github-script@v7 with: github-token: ${{ secrets.GH_TOKEN }} script: | github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: ['autoapproved', 'autoupdate'] }) automerge-for-bot: name: Automerge PR autoapproved by a bot needs: [autoapprove-for-bot] runs-on: ubuntu-latest steps: - name: Automerging uses: pascalgn/automerge-action@22948e0bc22f0aa673800da838595a3e7347e584 #v0.15.6 https://github.com/pascalgn/automerge-action/releases/tag/v0.15.6 env: GITHUB_TOKEN: "${{ secrets.GH_TOKEN }}" GITHUB_LOGIN: asyncapi-bot MERGE_LABELS: "!do-not-merge" MERGE_METHOD: "squash" MERGE_COMMIT_MESSAGE: "{pullRequest.title} (#{pullRequest.number})" MERGE_RETRIES: "20" MERGE_RETRY_SLEEP: "30000" ================================================ FILE: .github/workflows/autoupdate.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # This workflow is designed to work with: # - autoapprove and automerge workflows for dependabot and asyncapibot. # - special release branches that we from time to time create in upstream repos. If we open up PRs for them from the very beginning of the release, the release branch will constantly update with new things from the destination branch they are opened against # It uses GitHub Action that auto-updates pull requests branches, whenever changes are pushed to their destination branch. # Autoupdating to latest destination branch works only in the context of upstream repo and not forks name: autoupdate on: push: branches-ignore: - 'version-bump/**' - 'dependabot/**' - 'bot/**' - 'all-contributors/**' permissions: {} jobs: autoupdate-for-bot: if: startsWith(github.repository, 'asyncapi/') name: Autoupdate autoapproved PR created in the upstream runs-on: ubuntu-latest steps: - name: Autoupdating uses: chinthakagodawita/autoupdate@0707656cd062a3b0cf8fa9b2cda1d1404d74437e env: GITHUB_TOKEN: '${{ secrets.GH_TOKEN_BOT_EVE }}' PR_FILTER: "labelled" PR_LABELS: "autoupdate" PR_READY_STATE: "ready_for_review" MERGE_CONFLICT_ACTION: "ignore" ================================================ FILE: .github/workflows/bounty-program-commands.yml ================================================ # This workflow is centrally managed at https://github.com/asyncapi/.github/ # Don't make changes to this file in this repository, as they will be overwritten with # changes made to the same file in the abovementioned repository. # The purpose of this workflow is to allow Bounty Team members # (https://github.com/orgs/asyncapi/teams/bounty_team) to issue commands to the # organization's global AsyncAPI bot related to the Bounty Program, while at the # same time preventing unauthorized users from misusing them. name: Bounty Program commands on: issue_comment: types: - created env: BOUNTY_PROGRAM_LABELS_JSON: | [ {"name": "bounty", "color": "0e8a16", "description": "Participation in the Bounty Program"} ] permissions: {} jobs: guard-against-unauthorized-use: name: Guard against unauthorized use permissions: issues: write # required to post a comment on the issue/PR pull-requests: write # required to post a comment on the issue/PR if it's a PR if: > !contains(fromJSON('["aeworxet","thulieblack"]'), github.actor) && ( startsWith(github.event.comment.body, '/bounty' ) ) runs-on: ubuntu-latest steps: - name: ❌ @${{github.actor}} made an unauthorized attempt to use a Bounty Program's command uses: actions/github-script@v7 env: ACTOR: ${{ github.actor }} with: github-token: ${{ github.token }} script: | const commentText = `❌ @${process.env.ACTOR} is not authorized to use the Bounty Program's commands. These commands can only be used by members of the [Bounty Team](https://github.com/orgs/asyncapi/teams/bounty_team).`; console.log(`❌ @${process.env.ACTOR} made an unauthorized attempt to use a Bounty Program's command.`); github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: commentText }) add-label-bounty: name: Add bounty label permissions: issues: write # required to read/create labels and add labels on the issue/PR pull-requests: write # required to read/create labels and add labels on the issue/PR if: > contains(fromJSON('["aeworxet","thulieblack"]'), github.actor) && ( startsWith(github.event.comment.body, '/bounty' ) ) runs-on: ubuntu-latest steps: - name: Add label `bounty` uses: actions/github-script@v7 with: github-token: ${{ github.token }} script: | const BOUNTY_PROGRAM_LABELS = JSON.parse(process.env.BOUNTY_PROGRAM_LABELS_JSON); let LIST_OF_LABELS_FOR_REPO = await github.rest.issues.listLabelsForRepo({ owner: context.repo.owner, repo: context.repo.repo, }); LIST_OF_LABELS_FOR_REPO = LIST_OF_LABELS_FOR_REPO.data.map(key => key.name); if (!LIST_OF_LABELS_FOR_REPO.includes(BOUNTY_PROGRAM_LABELS[0].name)) { await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: BOUNTY_PROGRAM_LABELS[0].name, color: BOUNTY_PROGRAM_LABELS[0].color, description: BOUNTY_PROGRAM_LABELS[0].description }); } console.log('Adding label `bounty`...'); github.rest.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: [BOUNTY_PROGRAM_LABELS[0].name] }) remove-label-bounty: name: Remove bounty label permissions: issues: write # required to read/remove labels on the issue/PR pull-requests: write # required to read/remove labels on the issue/PR if it's a PR if: > contains(fromJSON('["aeworxet","thulieblack"]'), github.actor) && ( startsWith(github.event.comment.body, '/unbounty' ) ) runs-on: ubuntu-latest steps: - name: Remove label `bounty` uses: actions/github-script@v7 with: github-token: ${{ github.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] }) } ================================================ FILE: .github/workflows/bump-homebrew-formula.yml ================================================ name: Bump Homebrew formula for CLI on: # Since now release depends on schedule, might be that there is a situation we cannot wait for schedule and trigger release manually workflow_dispatch: # We cannot run brew release continusly every time we release something as sometimes we release a couple of times a day and overload brew pipelines # More details https://github.com/asyncapi/cli/issues/503 schedule: - cron: "0 23 * * *" jobs: bump-formula-in-homebrew: if: github.repository == 'asyncapi/cli' name: Bump the formula in homebrew-core repo runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 - name: Get version from package.json id: extractver run: | VERSION=$(npm run get-version --silent) echo "version=$VERSION" >> $GITHUB_OUTPUT - uses: mislav/bump-homebrew-formula-action@9d4d820e1d00b99927bd36e67d41fff1cfc8bd07 # v2 with: # A PR will be sent to github.com/Homebrew/homebrew-core to update AsyncAPI CLI formula: formula-name: asyncapi # https://github.com/mislav/bump-homebrew-formula-action/issues/58 formula-path: Formula/a/asyncapi.rb tag-name: ${{ steps.extractver.outputs.version }} download-url: https://registry.npmjs.org/@asyncapi/cli/-/cli-${{ steps.extractver.outputs.version }}.tgz #we need to point to npm not github as there is a dist that is not on github env: COMMITTER_TOKEN: ${{ secrets.GH_TOKEN_BOT_EVE }} - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel name: Report workflow run status to Slack uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 # v3.15.1 with: status: ${{ job.status }} fields: repo,action,workflow text: 'AsyncAPI CLI release to BREW failed' env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} ================================================ FILE: .github/workflows/bump.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # Purpose of this action is to update npm package in libraries that use it. It is like dependabot for asyncapi npm modules only. # It runs in a repo after merge of release commit and searches for other packages that use released package. Every found package gets updated with lates version name: Bump package version in dependent repos - if Node project on: # It cannot run on release event as when release is created then version is not yet bumped in package.json # This means we cannot extract easily latest version and have a risk that package is not yet on npm push: branches: - master jobs: bump-in-dependent-projects: name: Bump this package in repositories that depend on it if: startsWith(github.event.commits[0].message, 'chore(release):') runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v3 - name: Check if Node.js project and has package.json id: packagejson run: test -e ./package.json && echo "exists=true" >> $GITHUB_OUTPUT || echo "exists=false" >> $GITHUB_OUTPUT - if: steps.packagejson.outputs.exists == 'true' name: Bumping latest version of this package in other repositories uses: derberg/npm-dependency-manager-for-your-github-org@1eafd3bf3974f21d395c1abac855cb04b295d570 # using v6.-.- https://github.com/derberg/npm-dependency-manager-for-your-github-org/releases/tag/v6 with: github_token: ${{ secrets.GH_TOKEN }} committer_username: asyncapi-bot committer_email: info@asyncapi.io repos_to_ignore: spec,bindings,saunter,server-api custom_id: "dependency update from asyncapi bot" ================================================ FILE: .github/workflows/deploy/chocolatey/asyncapi-cli.nuspec ================================================ asyncapi {{version}} https://github.com/asyncapi/cli/releases/v{{version}} AsyncAPI_Initiative asyncapi-cli AsyncAPI_Initiative https://www.asyncapi.com/ https://avatars.githubusercontent.com/u/16401334?s=200 2023 AsyncAPI Initiative https://github.com/asyncapi/cli/blob/master/LICENSE false https://github.com/asyncapi/cli/releases/v{{version}} https://github.com/asyncapi/cli https://www.asyncapi.com/docs/tools/cli https://github.com/asyncapi/cli/issues/new/choose asyncapi-cli cli nodejs api asyncapi CLI to work with your AsyncAPI files. You can validate them and in the future use a generator and even bootstrap a new file. Contributions are welcomed! CLI to work with your AsyncAPI files. You can validate them and in the future use a generator and even bootstrap a new file. Contributions are welcomed! ================================================ FILE: .github/workflows/deploy/chocolatey/replace.ps1 ================================================ param ( [Parameter(Mandatory=$true)] [string]$version, [string]$checksum, [string]$checksum64 ) $filePaths = @( './tools/chocolateyinstall.ps1' './asyncapi-cli.nuspec' ) foreach ($filePath in $filePaths) { $fileContents = Get-Content $filePath $fileContents = $fileContents -replace '{{version}}', $version $fileContents = $fileContents -replace '{{checksum}}', $checksum $fileContents = $fileContents -replace '{{checksum64}}', $checksum64 Set-Content $filePath $fileContents } ================================================ FILE: .github/workflows/deploy/chocolatey/tools/chocolateyinstall.ps1 ================================================ $ErrorActionPreference = 'Stop' # stop on all errors $toolsDir = "$(Split-Path -parent $MyInvocation.MyCommand.Definition)" $url = 'https://github.com/asyncapi/cli/releases/download/v{{version}}/asyncapi.x86.exe' $url64 = 'https://github.com/asyncapi/cli/releases/download/v{{version}}/asyncapi.x64.exe' $packageArgs = @{ packageName = $env:ChocolateyPackageName unzipLocation = $toolsDir fileType = 'EXE' url = $url url64bit = $url64 #file = $fileLocation NOTE: Commented out because we are using url instead softwareName = 'asyncapi-cli*' checksum = '{{checksum}}' checksumType = 'sha256' #default is md5, can also be sha1, sha256 or sha512 checksum64 = '{{checksum64}}' checksumType64= 'sha256' #default is checksumType validExitCodes= @(0, 3010, 1641) silentArgs = '/S' # NSIS } Install-ChocolateyPackage @packageArgs # https://docs.chocolatey.org/en-us/create/functions/install-chocolateypackage ================================================ FILE: .github/workflows/help-command.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: Create help comment on: issue_comment: types: - created permissions: {} jobs: create_help_comment_pr: name: Help Comment in PR if: ${{ github.event.issue.pull_request && startsWith(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot' }} runs-on: ubuntu-latest permissions: pull-requests: write # To comment on Pull requests steps: - name: Add comment to PR uses: actions/github-script@v7 env: ACTOR: ${{ github.actor }} with: github-token: ${{ github.token }} script: | //Yes to add comment to PR the same endpoint is use that we use to create a comment in issue //For more details http://developer.github.com/v3/issues/comments/ //Also proved by this action https://github.com/actions-ecosystem/action-create-comment/blob/main/src/main.ts github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `Hello, @${process.env.ACTOR}! 👋🏼 I'm 🧞🧞🧞 Genie 🧞🧞🧞 from the magic lamp. Looks like somebody needs a hand! At the moment the following comments are supported in pull requests: - \`/please-take-a-look\` or \`/ptal\` - This comment will add a comment to the PR asking for attention from the reviewrs who have not reviewed the PR yet. - \`/ready-to-merge\` or \`/rtm\` - This comment will trigger automerge of PR in case all required checks are green, approvals in place and do-not-merge label is not added - \`/do-not-merge\` or \`/dnm\` - This comment will block automerging even if all conditions are met and ready-to-merge label is added - \`/autoupdate\` or \`/au\` - This comment will add \`autoupdate\` label to the PR and keeps your PR up-to-date to the target branch's future changes. Unless there is a merge conflict or it is a draft PR. (Currently only works for upstream branches.) - \`/update\` or \`/u\` - This comment will update the PR with the latest changes from the target branch. Unless there is a merge conflict or it is a draft PR. NOTE: this only updates the PR once, so if you need to update again, you need to call the command again.` }) create_help_comment_issue: name: Help Comment in Issue if: ${{ !github.event.issue.pull_request && startsWith(github.event.comment.body, '/help') && github.actor != 'asyncapi-bot' }} runs-on: ubuntu-latest permissions: issues: write # To comment on Issues steps: - name: Add comment to Issue uses: actions/github-script@v7 env: ACTOR: ${{ github.actor }} with: github-token: ${{ github.token }} script: | github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `Hello, @${process.env.ACTOR}! 👋🏼 I'm 🧞🧞🧞 Genie 🧞🧞🧞 from the magic lamp. Looks like somebody needs a hand! At the moment the following comments are supported in issues: - \`/good-first-issue {js | ts | java | go | docs | design | ci-cd}\` or \`/gfi {js | ts | java | go | docs | design | ci-cd}\` - label an issue as a \`good first issue\`. example: \`/gfi js\` or \`/good-first-issue ci-cd\` - \`/transfer-issue {repo-name}\` or \`/ti {repo-name}\` - transfer issue from the source repository to the other repository passed by the user. example: \`/ti cli\` or \`/transfer-issue cli\`.` }) ================================================ FILE: .github/workflows/if-docker-pr-testing.yml ================================================ #This action is centrally managed in https://github.com/asyncapi/.github/ #Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo #It does magic only if there is a Dockerfile in the root of the project name: PR testing - if Docker on: pull_request: types: [opened, reopened, synchronize, ready_for_review] env: IMAGE_NAME: ${{ github.repository }} permissions: contents: read jobs: test-docker-pr: name: Test Docker build runs-on: ubuntu-latest steps: - if: > !github.event.pull_request.draft && !( (github.event.pull_request.user.login == 'asyncapi-bot' && ( startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') || startsWith(github.event.pull_request.title, 'chore(release):') )) || (github.event.pull_request.user.login == 'asyncapi-bot-eve' && ( startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') || startsWith(github.event.pull_request.title, 'chore(release):') )) || (github.event.pull_request.user.login == 'allcontributors[bot]' && startsWith(github.event.pull_request.title, 'docs: add') ) ) id: should_run name: Should Run run: echo "shouldrun=true" >> "$GITHUB_OUTPUT" - if: steps.should_run.outputs.shouldrun == 'true' name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - if: steps.should_run.outputs.shouldrun == 'true' name: Check if project has a Dockerfile id: docker run: test -e ./Dockerfile && echo "exists=true" >> "$GITHUB_OUTPUT" || echo "exists=false" >> "$GITHUB_OUTPUT" shell: bash - if: steps.docker.outputs.exists == 'true' name: Set up Docker Buildx uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # use 3.10.0 https://github.com/docker/setup-buildx-action/releases/tag/v2.5.0 - if: steps.docker.outputs.exists == 'true' name: Extract metadata for Docker id: meta uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # use 5.7.0 https://github.com/docker/metadata-action/releases/tag/v4.3.0 with: images: ${{ env.IMAGE_NAME }} - if: steps.docker.outputs.exists == 'true' name: Build Docker image uses: docker/build-push-action@471d1dc4e07e5cdedd4c2171150001c434f0b7a4 # use 6.15.0 https://github.com/docker/build-push-action/releases/tag/v4.0.0 with: context: . push: false tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max ================================================ FILE: .github/workflows/if-nodejs-pr-testing.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # It does magic only if there is package.json file in the root of the project name: PR testing - if Node project on: pull_request: types: [opened, reopened, synchronize, ready_for_review] permissions: contents: read jobs: test-nodejs-pr: name: Test NodeJS PR - ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - if: > !github.event.pull_request.draft && !( (github.event.pull_request.user.login == 'asyncapi-bot' && ( startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') || startsWith(github.event.pull_request.title, 'chore(release):') )) || (github.event.pull_request.user.login == 'asyncapi-bot-eve' && ( startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') || startsWith(github.event.pull_request.title, 'chore(release):') )) || (github.event.pull_request.user.login == 'allcontributors[bot]' && startsWith(github.event.pull_request.title, 'docs: add') ) ) id: should_run name: Should Run run: echo "shouldrun=true" >> "$GITHUB_OUTPUT" shell: bash - if: steps.should_run.outputs.shouldrun == 'true' name: Set git to use LF #to once and for all finish neverending fight between Unix and Windows run: | git config --global core.autocrlf false git config --global core.eol lf shell: bash - if: steps.should_run.outputs.shouldrun == 'true' name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - if: steps.should_run.outputs.shouldrun == 'true' name: Check if Node.js project and has package.json id: packagejson run: test -e ./package.json && echo "exists=true" >> "$GITHUB_OUTPUT" || echo "exists=false" >> "$GITHUB_OUTPUT" shell: bash - if: steps.packagejson.outputs.exists == 'true' name: Determine what node version to use # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master # //NOSONAR with: node-version: ${{ vars.NODE_VERSION }} id: lockversion - if: steps.packagejson.outputs.exists == 'true' name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "${{ steps.lockversion.outputs.version }}" - if: steps.lockversion.outputs.version == '18' && matrix.os == 'windows-latest' #npm cli 10 is buggy because of some cache issue name: Install npm cli 8 shell: bash run: npm install -g npm@8.19.4 - if: steps.packagejson.outputs.exists == 'true' name: Install dependencies shell: bash run: npm ci - if: steps.packagejson.outputs.exists == 'true' name: Test run: npm test --if-present - if: steps.packagejson.outputs.exists == 'true' && matrix.os == 'ubuntu-latest' #linting should run just one and not on all possible operating systems name: Run linter run: npm run lint --if-present - if: steps.packagejson.outputs.exists == 'true' name: Run release assets generation to make sure PR does not break it shell: bash run: npm run generate:assets --if-present ================================================ FILE: .github/workflows/issues-prs-notifications.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # This action notifies community on slack whenever there is a new issue, PR or discussion started in given repository name: Notify slack on: issues: types: [opened, reopened] pull_request_target: types: [opened, reopened, ready_for_review] # zizmor: ignore[dangerous-triggers] discussion: types: [created] permissions: {} jobs: issue: if: github.event_name == 'issues' && github.actor != 'asyncapi-bot' && github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]' name: Notify slack on every new issue runs-on: ubuntu-latest steps: - name: Convert markdown to slack markdown for issue # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: issuemarkdown env: ISSUE_TITLE: ${{github.event.issue.title}} ISSUE_URL: ${{github.event.issue.html_url}} ISSUE_BODY: ${{github.event.issue.body}} with: markdown: "[${{ env.ISSUE_TITLE }}](${{ env.ISSUE_URL }}) \n ${{ env.ISSUE_BODY }}" - name: Send info about issue uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_GITHUB_NEWISSUEPR}} SLACK_TITLE: 🐛 New Issue in ${{github.repository}} 🐛 SLACK_MESSAGE: ${{steps.issuemarkdown.outputs.text}} MSG_MINIMAL: true pull_request: if: github.event_name == 'pull_request_target' && github.actor != 'asyncapi-bot' && github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]' name: Notify slack on every new pull request runs-on: ubuntu-latest steps: - name: Convert markdown to slack markdown for pull request # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: prmarkdown env: PR_TITLE: ${{github.event.pull_request.title}} PR_URL: ${{github.event.pull_request.html_url}} PR_BODY: ${{github.event.pull_request.body}} with: markdown: "[${{ env.PR_TITLE }}](${{ env.PR_URL }}) \n ${{ env.PR_BODY }}" - name: Send info about pull request uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_GITHUB_NEWISSUEPR}} SLACK_TITLE: 💪 New Pull Request in ${{github.repository}} 💪 SLACK_MESSAGE: ${{steps.prmarkdown.outputs.text}} MSG_MINIMAL: true discussion: if: github.event_name == 'discussion' && github.actor != 'asyncapi-bot' && github.actor != 'dependabot[bot]' && github.actor != 'dependabot-preview[bot]' name: Notify slack on every new pull request runs-on: ubuntu-latest steps: - name: Convert markdown to slack markdown for pull request # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: discussionmarkdown env: DISCUSSION_TITLE: ${{github.event.discussion.title}} DISCUSSION_URL: ${{github.event.discussion.html_url}} DISCUSSION_BODY: ${{github.event.discussion.body}} with: markdown: "[${{ env.DISCUSSION_TITLE }}](${{ env.DISCUSSION_URL }}) \n ${{ env.DISCUSSION_BODY }}" - name: Send info about pull request uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_GITHUB_NEWISSUEPR}} SLACK_TITLE: 💬 New Discussion in ${{github.repository}} 💬 SLACK_MESSAGE: ${{steps.discussionmarkdown.outputs.text}} MSG_MINIMAL: true ================================================ FILE: .github/workflows/lint-pr-title.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: Lint PR title on: pull_request: types: [opened, reopened, synchronize, edited, ready_for_review] permissions: {} jobs: lint-pr-title: name: Lint PR title runs-on: ubuntu-latest permissions: contents: read # To checkout code and read PR information pull-requests: write # To comment on PR if the title is not valid steps: # Since this workflow is REQUIRED for a PR to be mergable, we have to have this 'if' statement in step level instead of job level. - if: ${{ !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor) }} # zizmor: ignore[obfuscation] uses: amannn/action-semantic-pull-request@c3cd5d1ea3580753008872425915e343e351ab54 #version 5.2.0 https://github.com/amannn/action-semantic-pull-request/releases/tag/v5.2.0 id: lint_pr_title env: GITHUB_TOKEN: ${{ github.token }} with: subjectPattern: ^(?![A-Z]).+$ subjectPatternError: | The subject "{subject}" found in the pull request title "{title}" should start with a lowercase character. # Comments the error message from the above lint_pr_title action - if: ${{ always() && steps.lint_pr_title.outputs.error_message != null && !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor)}} # zizmor: ignore[obfuscation] name: Comment on PR uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd #use 2.5.0 https://github.com/marocchino/sticky-pull-request-comment/releases/tag/v2.5.0 with: header: pr-title-lint-error GITHUB_TOKEN: ${{ github.token }} message: | We require all PRs to follow [Conventional Commits specification](https://www.conventionalcommits.org/en/v1.0.0/). More details 👇🏼 ``` ${{ steps.lint_pr_title.outputs.error_message}} ``` # deletes the error comment if the title is correct - if: ${{ steps.lint_pr_title.outputs.error_message == null }} name: delete the comment uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd #use 2.5.0 https://github.com/marocchino/sticky-pull-request-comment/releases/tag/v2.5.0 with: header: pr-title-lint-error delete: true GITHUB_TOKEN: ${{ github.token }} ================================================ FILE: .github/workflows/notify-tsc-members-mention.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # This action notifies community on slack whenever there is a new issue, PR or discussion started in given repository name: Notify slack and email subscribers whenever TSC members are mentioned in GitHub on: issue_comment: types: - created discussion_comment: types: - created issues: types: - opened pull_request_target: # Needed to access secrets. The checkout is done on base branch so script cannot be malicious. types: - opened # zizmor: ignore[dangerous-triggers] discussion: types: - created permissions: contents: read # To checkout repository jobs: issue: if: github.event_name == 'issues' && contains(github.event.issue.body, '@asyncapi/tsc_members') name: TSC notification on every new issue runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' cache-dependency-path: '**/package-lock.json' ######### # Handling Slack notifications ######### - name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: issuemarkdown with: markdown: "[${{github.event.issue.title}}](${{github.event.issue.html_url}}) \n ${{github.event.issue.body}}" - name: Send info about issue uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} SLACK_TITLE: 🆘 New issue that requires TSC Members attention 🆘 SLACK_MESSAGE: ${{steps.issuemarkdown.outputs.text}} MSG_MINIMAL: true ######### # Handling Kit.com notifications ######### - name: Install deps run: npm install working-directory: ./.github/workflows/scripts/kit - name: Send email with Kit.com uses: actions/github-script@v7 env: KIT_API_KEY: ${{ secrets.KIT_API_KEY }} KIT_TSC_TAG_ID: ${{ secrets.KIT_TSC_TAG_ID }} TITLE: ${{ github.event.issue.title }} HTML_URL: ${{ github.event.issue.html_url }} with: script: | const sendEmail = require('./.github/workflows/scripts/kit/index.js'); return sendEmail(process.env.HTML_URL, process.env.TITLE); pull_request: if: github.event_name == 'pull_request_target' && contains(github.event.pull_request.body, '@asyncapi/tsc_members') name: TSC notification on every new pull request runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' cache-dependency-path: '**/package-lock.json' ######### # Handling Slack notifications ######### - name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: prmarkdown with: markdown: "[${{github.event.pull_request.title}}](${{github.event.pull_request.html_url}}) \n ${{github.event.pull_request.body}}" - name: Send info about pull request uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} SLACK_TITLE: 🆘 New PR that requires TSC Members attention 🆘 SLACK_MESSAGE: ${{steps.prmarkdown.outputs.text}} MSG_MINIMAL: true ######### # Handling Kit.com notifications ######### - name: Install deps run: npm install working-directory: ./.github/workflows/scripts/kit - name: Send email with Kit.com uses: actions/github-script@v7 env: KIT_API_KEY: ${{ secrets.KIT_API_KEY }} KIT_TSC_TAG_ID: ${{ secrets.KIT_TSC_TAG_ID }} TITLE: ${{ github.event.pull_request.title }} HTML_URL: ${{ github.event.pull_request.html_url }} with: script: | const sendEmail = require('./.github/workflows/scripts/kit/index.js'); return sendEmail(process.env.HTML_URL, process.env.TITLE); discussion: if: github.event_name == 'discussion' && contains(github.event.discussion.body, '@asyncapi/tsc_members') name: TSC notification on every new discussion runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' cache-dependency-path: '**/package-lock.json' ######### # Handling Slack notifications ######### - name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: discussionmarkdown with: markdown: "[${{github.event.discussion.title}}](${{github.event.discussion.html_url}}) \n ${{github.event.discussion.body}}" - name: Send info about discussion uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} SLACK_TITLE: 🆘 New discussion that requires TSC Members attention 🆘 SLACK_MESSAGE: ${{steps.discussionmarkdown.outputs.text}} MSG_MINIMAL: true ######### # Handling Kit.com notifications ######### - name: Install deps run: npm install working-directory: ./.github/workflows/scripts/kit - name: Send email with Kit.com uses: actions/github-script@v7 env: KIT_API_KEY: ${{ secrets.KIT_API_KEY }} KIT_TSC_TAG_ID: ${{ secrets.KIT_TSC_TAG_ID }} TITLE: ${{ github.event.discussion.title }} HTML_URL: ${{ github.event.discussion.html_url }} with: script: | const sendEmail = require('./.github/workflows/scripts/kit/index.js'); return sendEmail(process.env.HTML_URL, process.env.TITLE); issue_comment: if: ${{ github.event_name == 'issue_comment' && !github.event.issue.pull_request && contains(github.event.comment.body, '@asyncapi/tsc_members') }} name: TSC notification on every new comment in issue runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' cache-dependency-path: '**/package-lock.json' ######### # Handling Slack notifications ######### - name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: issuemarkdown with: markdown: "[${{github.event.issue.title}}](${{github.event.comment.html_url}}) \n ${{github.event.comment.body}}" - name: Send info about issue comment uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} SLACK_TITLE: 🆘 New comment under existing issue that requires TSC Members attention 🆘 SLACK_MESSAGE: ${{steps.issuemarkdown.outputs.text}} MSG_MINIMAL: true ######### # Handling Kit.com notifications ######### - name: Install deps run: npm install working-directory: ./.github/workflows/scripts/kit - name: Send email with Kit.com uses: actions/github-script@v7 env: KIT_API_KEY: ${{ secrets.KIT_API_KEY }} KIT_TSC_TAG_ID: ${{ secrets.KIT_TSC_TAG_ID }} TITLE: ${{ github.event.issue.title }} HTML_URL: ${{ github.event.comment.html_url }} with: script: | const sendEmail = require('./.github/workflows/scripts/kit/index.js'); return sendEmail(process.env.HTML_URL, process.env.TITLE); pr_comment: if: github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '@asyncapi/tsc_members') name: TSC notification on every new comment in pr runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' cache-dependency-path: '**/package-lock.json' ######### # Handling Slack notifications ######### - name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: prmarkdown with: markdown: "[${{github.event.issue.title}}](${{github.event.comment.html_url}}) \n ${{github.event.comment.body}}" - name: Send info about PR comment uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} SLACK_TITLE: 🆘 New comment under existing PR that requires TSC Members attention 🆘 SLACK_MESSAGE: ${{steps.prmarkdown.outputs.text}} MSG_MINIMAL: true ######### # Handling Kit.com notifications ######### - name: Install deps run: npm install working-directory: ./.github/workflows/scripts/kit - name: Send email with Kit.com uses: actions/github-script@v7 env: KIT_API_KEY: ${{ secrets.KIT_API_KEY }} KIT_TSC_TAG_ID: ${{ secrets.KIT_TSC_TAG_ID }} TITLE: ${{ github.event.issue.title }} HTML_URL: ${{ github.event.comment.html_url }} with: script: | const sendEmail = require('./.github/workflows/scripts/kit/index.js'); return sendEmail(process.env.HTML_URL, process.env.TITLE); discussion_comment: if: github.event_name == 'discussion_comment' && contains(github.event.comment.body, '@asyncapi/tsc_members') name: TSC notification on every new comment in discussion runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: 20 cache: 'npm' cache-dependency-path: '**/package-lock.json' ######### # Handling Slack notifications ######### - name: Convert markdown to slack markdown # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: discussionmarkdown with: markdown: "[${{github.event.discussion.title}}](${{github.event.comment.html_url}}) \n ${{github.event.comment.body}}" - name: Send info about discussion comment uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{secrets.SLACK_TSC_MEMBERS_NOTIFY}} SLACK_TITLE: 🆘 New comment under existing discussion that requires TSC Members attention 🆘 SLACK_MESSAGE: ${{steps.discussionmarkdown.outputs.text}} MSG_MINIMAL: true ######### # Handling Kit.com notifications ######### - name: Install deps run: npm install working-directory: ./.github/workflows/scripts/kit - name: Send email with Kit.com uses: actions/github-script@v7 env: KIT_API_KEY: ${{ secrets.KIT_API_KEY }} KIT_TSC_TAG_ID: ${{ secrets.KIT_TSC_TAG_ID }} TITLE: ${{ github.event.discussion.title }} HTML_URL: ${{ github.event.comment.html_url }} with: script: | const sendEmail = require('./.github/workflows/scripts/kit/index.js'); return sendEmail(process.env.HTML_URL, process.env.TITLE); ================================================ FILE: .github/workflows/please-take-a-look-command.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # It uses Github actions to listen for comments on issues and pull requests and # if the comment contains /please-take-a-look or /ptal it will add a comment pinging # the code-owners who are reviewers for PR name: Please take a Look on: issue_comment: types: [created] permissions: {} jobs: ping-for-attention: if: > github.event.issue.pull_request && github.event.issue.state != 'closed' && github.actor != 'asyncapi-bot' && ( contains(github.event.comment.body, '/please-take-a-look') || contains(github.event.comment.body, '/ptal') || contains(github.event.comment.body, '/PTAL') ) name: Ping code owners for attention runs-on: ubuntu-latest steps: - name: Check for Please Take a Look Command uses: actions/github-script@v7 with: github-token: ${{ secrets.GH_TOKEN }} script: | const prDetailsUrl = context.payload.issue.pull_request.url; const { data: pull } = await github.request(prDetailsUrl); const reviewers = (pull.requested_reviewers || []).map(reviewer => reviewer.login); const { data: reviews } = await github.rest.pulls.listReviews({ owner: context.repo.owner, repo: context.repo.repo, pull_number: context.issue.number }); const reviewersWhoHaveReviewed = reviews.map(review => review.user.login); const reviewersWhoHaveNotReviewed = reviewers.filter(reviewer => !reviewersWhoHaveReviewed.includes(reviewer)); if (reviewersWhoHaveNotReviewed.length > 0) { const comment = reviewersWhoHaveNotReviewed.filter(reviewer => reviewer !== 'asyncapi-bot-eve' ).map(reviewer => `@${reviewer}`).join(' '); await github.rest.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: `${comment} Please take a look at this PR. Thanks! :wave:` }); } ================================================ FILE: .github/workflows/release-announcements.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: 'Announce releases in different channels' on: release: types: - published permissions: contents: read # To checkout code and read release information jobs: slack-announce: name: Slack - notify on every release runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: persist-credentials: false - name: Convert markdown to slack markdown for issue # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/slackify-markdown@master # //NOSONAR id: markdown env: RELEASE_TAG: ${{github.event.release.tag_name}} RELEASE_URL: ${{github.event.release.html_url}} RELEASE_BODY: ${{ github.event.release.body }} with: markdown: "[${{ env.RELEASE_TAG }}](${{ env.RELEASE_URL }}) \n ${{ env.RELEASE_BODY }}" - name: Send info about release to Slack uses: rtCamp/action-slack-notify@c33737706dea87cd7784c687dadc9adf1be59990 # Using v2.3.2 env: SLACK_WEBHOOK: ${{ secrets.SLACK_RELEASES }} SLACK_TITLE: Release ${{ env.RELEASE_TAG }} for ${{ env.REPO_NAME }} is out in the wild 😱💪🍾🎂 SLACK_MESSAGE: ${{steps.markdown.outputs.text}} MSG_MINIMAL: true RELEASE_TAG: ${{github.event.release.tag_name}} REPO_NAME: ${{github.repository}} twitter-announce: name: Twitter - notify on minor and major releases runs-on: ubuntu-latest steps: - name: Checkout repo uses: actions/checkout@v4 with: persist-credentials: false - name: Get version of last and previous release uses: actions/github-script@v7 id: versions with: github-token: ${{ github.token }} script: | const query = `query($owner:String!, $name:String!) { repository(owner:$owner, name:$name){ releases(first: 2, orderBy: {field: CREATED_AT, direction: DESC}) { nodes { name } } } }`; const variables = { owner: context.repo.owner, name: context.repo.repo }; const { repository: { releases: { nodes } } } = await github.graphql(query, variables); core.setOutput('lastver', nodes[0].name); // In case of first release in the package, there is no such thing as previous error, so we set info about previous version only once we have it // We should tweet about the release no matter of the type as it is initial release if (nodes.length != 1) core.setOutput('previousver', nodes[1].name); - name: Identify release type id: releasetype # if previousver is not provided then this steps just logs information about missing version, no errors env: PREV_VERSION: ${{steps.versions.outputs.previousver}} LAST_VERSION: ${{steps.versions.outputs.lastver}} run: echo "type=$(npx -q -p semver-diff-cli semver-diff "$PREV_VERSION" "$LAST_VERSION")" >> "$GITHUB_OUTPUT" - name: Get name of the person that is behind the newly released version id: author run: | AUTHOR_NAME=$(git log -1 --pretty=format:'%an') printf 'name=%s\n' "$AUTHOR_NAME" >> "$GITHUB_OUTPUT" - name: Publish information about the release to Twitter # tweet only if detected version change is not a patch # tweet goes out even if the type is not major or minor but "You need provide version number to compare." # it is ok, it just means we did not identify previous version as we are tweeting out information about the release for the first time if: steps.releasetype.outputs.type != 'null' && steps.releasetype.outputs.type != 'patch' # null means that versions are the same uses: m1ner79/Github-Twittction@d1e508b6c2170145127138f93c49b7c46c6ff3a7 # using 2.0.0 https://github.com/m1ner79/Github-Twittction/releases/tag/v2.0.0 env: RELEASE_TAG: ${{github.event.release.tag_name}} REPO_NAME: ${{github.repository}} AUTHOR_NAME: ${{ steps.author.outputs.name }} RELEASE_URL: ${{github.event.release.html_url}} with: twitter_status: "Release ${{ env.RELEASE_TAG }} for ${{ env.REPO_NAME }} is out in the wild 😱💪🍾🎂\n\nThank you for the contribution ${{ env.AUTHOR_NAME }} ${{ env.RELEASE_URL }}" twitter_consumer_key: ${{ secrets.TWITTER_CONSUMER_KEY }} twitter_consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }} twitter_access_token_key: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }} twitter_access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} ================================================ FILE: .github/workflows/release-chocolatey.yml ================================================ name: Release Chocolatey Package on: # We cannot run chocolatey release continusly every time we release something as sometimes we release a couple of times a day and overload chocolatey pipelines # More details https://github.com/asyncapi/cli/issues/503 schedule: - cron: '0 23 * * *' # Run every day at 23:00 UTC # Since now release depends on schedule, might be that there is a situation we cannot wait for schedule and trigger release manually workflow_dispatch: inputs: version: description: 'Version to release (optional)' required: false jobs: release: name: Publish to Chocolatey Community runs-on: windows-latest steps: - name: Checkout uses: actions/checkout@v3 - name: Set Version id: release_version run: | if ( "${{ github.event_name }}" -eq "workflow_dispatch" -and "${{ github.event.inputs.version }}" -ne "" ) { $version = "${{ github.event.inputs.version }}" } else { $version = $(npm pkg get version) } $version = $version.Replace("`"", "") echo "Setting version to $version" echo "version=$version" >> $env:GITHUB_OUTPUT - name: Check if this is a new version to release id: check_new_version run: | $output = choco search asyncapi-cli --version=${{ steps.release_version.outputs.version }} # Output is of the form: # Chocolatey v2.2.2 # asyncapi-cli 0.0.1 [Approved] # 1 packages found. # If the version is not found, the output will of the form: # Chocolatey v2.2.2 # 0 packages found. if ($output -match "0 packages found.") { echo "This is a new version to release" echo "new_version=true" >> $env:GITHUB_OUTPUT } else { echo "This is not a new version to release" echo "new_version=false" >> $env:GITHUB_OUTPUT } - name: Download release if: steps.check_new_version.outputs.new_version == 'true' run: | echo "Downloading release assets for version ${{ steps.release_version.outputs.version }}" mkdir -p ./dist/win32 curl -L "https://github.com/asyncapi/cli/releases/download/v${{ steps.release_version.outputs.version }}/asyncapi.x64.exe" -o "./dist/win32/asyncapi.x64.exe" curl -L "https://github.com/asyncapi/cli/releases/download/v${{ steps.release_version.outputs.version }}/asyncapi.x86.exe" -o "./dist/win32/asyncapi.x86.exe" - name: Get Checksum of the release if: steps.check_new_version.outputs.new_version == 'true' id: release_checksum run: | $checksum = (Get-FileHash -Path "./dist/win32/asyncapi.x86.exe" -Algorithm SHA256).Hash $checksum64 = (Get-FileHash -Path "./dist/win32/asyncapi.x64.exe" -Algorithm SHA256).Hash echo "Setting checksum to $checksum" echo "checksum=$checksum" >> $env:GITHUB_OUTPUT echo "Setting checksum64 to $checksum64" echo "checksum64=$checksum64" >> $env:GITHUB_OUTPUT - name: Make nuspec from the template if: steps.check_new_version.outputs.new_version == 'true' run: | cd ./.github/workflows/deploy/chocolatey pwsh -File ./replace.ps1 -version ${{ steps.release_version.outputs.version }} -checksum ${{ steps.release_checksum.outputs.checksum }} -checksum64 ${{ steps.release_checksum.outputs.checksum64 }} - name: Run Chocolatey Pack if: steps.check_new_version.outputs.new_version == 'true' run: | cd ./.github/workflows/deploy/chocolatey choco pack ./asyncapi-cli.nuspec choco apikey add --source "'https://push.chocolatey.org/'" --key ${{ secrets.CHOCOLATEY_API_KEY }} choco push ./asyncapi.${{ steps.release_version.outputs.version }}.nupkg --source "'https://push.chocolatey.org/'" - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel name: Report workflow run status to Slack uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 with: status: ${{ job.status }} fields: repo,action,workflow text: 'AsyncAPI CLI release to Chocolatey failed' env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} ================================================ FILE: .github/workflows/release-docker.yml ================================================ name: Release Docker Image on: release: types: - published jobs: publish-docker: name: Generating Docker runs-on: ubuntu-latest steps: - name: Get version without v character id: version env: TAG_NAME: ${{ github.event.release.tag_name }} run: | VERSION_WITHOUT_V=${TAG_NAME:1} echo "value=${VERSION_WITHOUT_V}" >> $GITHUB_OUTPUT - name : Checkout repository uses: actions/checkout@v4 with: ref: ${{ github.event.release.tag_name }} - name: Set Up QEMU uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - name: Set Up Docker Buildx uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - name: login to Docker Hub uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build Image uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: push: true load: false build-args: | ASYNCAPI_CLI_VERSION=${{ steps.version.outputs.value }} tags: | asyncapi/cli:${{ steps.version.outputs.value }} asyncapi/cli:latest platforms: linux/amd64,linux/arm64 cache-from: type=gha cache-to: type=gha - name: Sync README.md and Description to Docker Hub uses: actions/checkout@v4 - uses: meeDamian/sync-readme@82715041300710d9be7c726c9d6c683b70451087 # v1.0.6 with: user: ${{ secrets.DOCKER_USERNAME }} pass: ${{ secrets.DOCKER_PASSWORD }} slug: asyncapi/cli description: CLI to work with your AsyncAPI files publish-action-docker: name: Release github action for cli and update version in action.yml runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 with: ref: ${{ github.event.release.tag_name }} - name: Get version without v character id: version env: TAG_NAME: ${{ github.event.release.tag_name }} run: | VERSION_WITHOUT_V=${TAG_NAME:1} echo "value=${VERSION_WITHOUT_V}" >> $GITHUB_OUTPUT - name: Set Up QEMU uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3 # v3.0.0 - name: Set Up Docker Buildx uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - name: Login to Docker Hub uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: context: . file: ./github-action/Dockerfile push: true tags: | asyncapi/github-action-for-cli:${{ steps.version.outputs.value }} asyncapi/github-action-for-cli:latest platforms: linux/amd64,linux/arm64 - name: Change directory to github-action run: | cd github-action/ ls -la - uses: meeDamian/sync-readme@82715041300710d9be7c726c9d6c683b70451087 # v1.0.6 with: user: ${{ secrets.DOCKER_USERNAME }} pass: ${{ secrets.DOCKER_PASSWORD }} slug: asyncapi/github-action-for-cli description: Github action for AsyncAPI CLI ================================================ FILE: .github/workflows/release-server-api.yml ================================================ name: Release Server API Image on: release: types: - published workflow_dispatch: inputs: version: description: 'Version to release' required: true jobs: publish-docker: name: Generating Docker runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Get version without v character id: version run: | VERSION=${{github.event.release.tag_name || github.event.inputs.version}} VERSION_WITHOUT_V=${VERSION:1} echo "value=${VERSION_WITHOUT_V}" >> $GITHUB_OUTPUT - name: Set Up QEMU uses: docker/setup-qemu-action@v3 - name: Set Up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and Push Docker Image uses: docker/build-push-action@v6 id: push with: context: . file: ./src/apps/api/Dockerfile push: true tags: | asyncapi/server-api:${{ steps.version.outputs.value }} asyncapi/server-api:latest platforms: linux/amd64,linux/arm64 - uses: meeDamian/sync-readme@82715041300710d9be7c726c9d6c683b70451087 #version 1.0.6 https://github.com/meeDamian/sync-readme/releases/tag/v1.0.6 with: user: ${{secrets.DOCKER_USERNAME}} pass: ${{ secrets.DOCKER_PASSWORD }} slug: asyncapi/server-api readme: ./src/apps/api/README.md description: Server API providing official AsyncAPI tools outputs: digest: ${{ steps.push.outputs.digest }} deploy-app: name: Deploy to DigitalOcean App needs: publish-docker runs-on: ubuntu-latest steps: - name: Checkout repository uses: actions/checkout@v4 - name: Deploy to DigitalOcean App uses: digitalocean/app_action/deploy@190f99be3ce4cbbe5d1ca0a63a8ac9d0add205d0 env: DOCKER_DIGEST: ${{ needs.publish-docker.outputs.digest }} with: token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} app_spec_location: ./src/apps/api/.do/app.yaml print_deploy_logs: true ================================================ FILE: .github/workflows/release-with-changesets.yml ================================================ # It does magic only if there is a package.json file in the root of the project name: Release on: push: branches: - master # The below lines are not enough to have release supported for these branches - next-spec - next-major - next-major-spec - beta - alpha - next jobs: test-nodejs: # We just check the message of the first commit as there is always just one commit because we squash into one before merging # "commits" contains an array of objects where one of the properties is the commit "message" # Release workflow will be skipped if release conventional commits are not used if: | (startsWith( github.event.commits[0].message , 'fix:' ) || startsWith( github.event.commits[0].message, 'fix!:' ) || startsWith( github.event.commits[0].message, 'feat:' ) || startsWith( github.event.commits[0].message, 'chore(release):' ) || startsWith( github.event.commits[0].message, 'feat!:' )) name: Test NodeJS release on ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - name: Set git to use LF # To once and for all finish the never-ending fight between Unix and Windows run: | git config --global core.autocrlf false git config --global core.eol lf shell: bash - name: Checkout repository uses: actions/checkout@v4 - name: Check if Node.js project and has package.json id: packagejson run: test -e ./package.json && echo "exists=true" >> $GITHUB_OUTPUT || echo "exists=false" >> $GITHUB_OUTPUT shell: bash - if: steps.packagejson.outputs.exists == 'true' name: Check package-lock version uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master id: lockversion - if: steps.packagejson.outputs.exists == 'true' name: Setup Node.js uses: actions/setup-node@v4 with: node-version: "${{ steps.lockversion.outputs.version }}" registry-url: "https://registry.npmjs.org" - if: steps.lockversion.outputs.version == '18' && matrix.os == 'windows-latest' name: Install npm cli 8 shell: bash # npm cli 10 is buggy because of some cache issues run: npm install -g npm@8.19.4 - if: steps.packagejson.outputs.exists == 'true' name: Install dependencies shell: bash run: npm ci - if: steps.packagejson.outputs.exists == 'true' name: Run test run: npm test --if-present - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel name: Report workflow run status to Slack uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 # v3.15.1 with: status: ${{ job.status }} fields: repo,action,workflow text: "Release workflow failed in testing job" env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} release: needs: [test-nodejs] name: Publish to any of NPM, GitHub, or Docker Hub runs-on: ubuntu-latest permissions: contents: write id-token: write pull-requests: write steps: - name: Set git to use LF # To once and for all finish the never-ending fight between Unix and Windows run: | git config --global core.autocrlf false git config --global core.eol lf - name: Checkout repository uses: actions/checkout@v6 - name: Check if Node.js project and has package.json id: packagejson run: test -e ./package.json && echo "exists=true" >> $GITHUB_OUTPUT || echo "exists=false" >> $GITHUB_OUTPUT shell: bash - if: steps.packagejson.outputs.exists == 'true' name: Check package-lock version uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master id: lockversion with: node-version: ${{ vars.NODE_VERSION }} - if: steps.packagejson.outputs.exists == 'true' name: Setup Node.js uses: actions/setup-node@v6 with: node-version: "${{ steps.lockversion.outputs.version }}" - if: steps.packagejson.outputs.exists == 'true' name: Install dependencies shell: bash run: npm ci - if: steps.packagejson.outputs.exists == 'true' name: Install changelog shell: bash # This step can be removed once the issue is fixed in the changeset package. run: npm install @changesets/changelog-git@0.2.0 - if: steps.packagejson.outputs.exists == 'true' name: Publish to any of NPM, Github, and Docker Hub #this step has 2 goals, it is either identifying that there is changeset file created and then this action creates a PR with version bump that will trigger release - or if it sees there is no changeset, and there are versions changes in package.json files, it publish new versions to NPM is they are not there yet # However, as currently changeset's publish isn't working well with OIDC next step will directly publish to NPM if there are version changes but no changesets uses: changesets/action@e0145edc7d9d8679003495b11f87bd8ef63c0cba # v1.5.3 id: release with: version: npm run bump:version commit: "chore(release): release and bump versions of packages" title: "chore(release): release and bump versions of packages" # Working around changesets action not supporting OIDC yet. Need to pass successful release output for triggering github release publish: npm run publish:trusted setupGitUser: false env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} GIT_AUTHOR_NAME: asyncapi-bot GIT_AUTHOR_EMAIL: info@asyncapi.io GIT_COMMITTER_NAME: asyncapi-bot GIT_COMMITTER_EMAIL: info@asyncapi.io - name: Publish to NPM directly (skip if version already published) if: steps.packagejson.outputs.exists == 'true' && steps.release.outputs.hasChangesets == 'false' shell: bash run: | # Check if the version in package.json is already published VERSION=$(node -p "require('./package.json').version") PACKAGE_NAME=$(node -p "require('./package.json').name") if npm view "$PACKAGE_NAME@$VERSION" > /dev/null 2>&1; then echo "Version $VERSION of package $PACKAGE_NAME is already published. Skipping publish." else echo "Publishing version $VERSION of package $PACKAGE_NAME to NPM." npm publish --provenance fi - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci Slack channel name: Report workflow run status to Slack uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 # v3.15.1 with: status: ${{ job.status }} fields: repo,action,workflow text: "Release workflow failed in release job" env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} ================================================ FILE: .github/workflows/scripts/README.md ================================================ The entire `scripts` directory is centrally managed in [.github](https://github.com/asyncapi/.github/) repository. Any changes in this folder should be done in central repository. ================================================ FILE: .github/workflows/scripts/kit/htmlContent.js ================================================ /** * This code is centrally managed in https://github.com/asyncapi/.github/ * Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo * * Kit.com version — greeting uses Kit Liquid (subscriber.first_name). Unsubscribe is provided by the Kit email template/footer. */ /** * Escape HTML special characters to prevent XSS */ function escapeHtml(text) { if (!text) return ''; return text .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } module.exports = (link, title) => { // Sanitize inputs to prevent XSS const safeLink = escapeHtml(link); const safeTitle = escapeHtml(title); return ` ${safeTitle}
Hey {{ subscriber.first_name | strip | default: "TSC member" }},

There is a new topic at AsyncAPI Initiative that requires Technical Steering Committee attention.
Please have a look if it is just something you need to be aware of, or maybe your vote is needed.
Topic: ${ safeTitle }.
Cheers,
AsyncAPI Initiative
You are receiving this email because you are subscribed to TSC Voting notifications.
 
` } ================================================ FILE: .github/workflows/scripts/kit/index.js ================================================ /** * This code is centrally managed in https://github.com/asyncapi/.github/ * Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo */ const core = require('@actions/core'); const htmlContent = require('./htmlContent.js'); const sanitizeLinkAndTitle = (link, title) => { // Validate inputs to prevent injection attacks if (!link || typeof link !== 'string' || link.length > 2000) { return core.setFailed('Invalid link parameter'); } if (!title || typeof title !== 'string' || title.length > 500) { return core.setFailed('Invalid title parameter'); } let parsedLink; try { parsedLink = new URL(link); } catch (error) { return core.setFailed('Invalid link parameter'); } if (parsedLink.protocol !== 'https:') { return core.setFailed('Link must use https protocol'); } // Sanitize title by removing control characters and limiting length const sanitizedTitle = title.replace(/[\x00-\x1F\x7F]/g, '').substring(0, 250); return { sanitizedLink: parsedLink.toString(), sanitizedTitle }; }; module.exports = async (link, title) => { const KIT_BASE = 'https://api.kit.com/v4'; const TSC_TAG_ID = Number(process.env.KIT_TSC_TAG_ID); // Schedule 1 minute ahead const sendAt = new Date(Date.now() + 60 * 1000); const { sanitizedLink, sanitizedTitle } = sanitizeLinkAndTitle(link, title); const res = await fetch(`${KIT_BASE}/broadcasts`, { method: 'POST', headers: { 'X-Kit-Api-Key': process.env.KIT_API_KEY, 'Content-Type': 'application/json' }, body: JSON.stringify({ subject: `TSC attention required: ${sanitizedTitle}`, preview_text: 'Check out the latest topic that TSC members have to be aware of', content: htmlContent(sanitizedLink, sanitizedTitle), description: `TSC notification - ${new Date().toUTCString()}`, public: false, published_at: null, send_at: sendAt.toISOString(), subscriber_filter: [{ all: [{ type: 'tag', ids: [TSC_TAG_ID] }] }] }) }); if (!res.ok) return core.setFailed(`Failed creating broadcast: ${await res.text()}`); core.info(`Kit.com TSC broadcast scheduled for ${sendAt.toISOString()}`); }; ================================================ FILE: .github/workflows/scripts/kit/package.json ================================================ { "name": "schedule-email", "description": "Kit.com email broadcast script for TSC notifications. This file is centrally managed in https://github.com/asyncapi/.github/", "license": "Apache 2.0", "dependencies": { "@actions/core": "1.6.0" } } ================================================ FILE: .github/workflows/scripts/mailchimp/htmlContent.js ================================================ /** * This code is centrally managed in https://github.com/asyncapi/.github/ * Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo */ /** * Escape HTML special characters to prevent XSS */ function escapeHtml(text) { if (!text) return ''; return text .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } module.exports = (link, title) => { // Sanitize inputs to prevent XSS const safeLink = escapeHtml(link); const safeTitle = escapeHtml(title); return ` *|MC:SUBJECT|*
Hey *|FNAME|*,

There is a new topic at AsyncAPI Initiative that requires Technical Steering Committee attention.
Please have a look if it is just something you need to be aware of, or maybe your vote is needed.
Topic: ${ safeTitle }.
Cheers,
AsyncAPI Initiative
Want to change how you receive these emails?
You can update your preferences or unsubscribe from this list.
 
` } ================================================ FILE: .github/workflows/stale-issues-prs.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: Manage stale issues and PRs on: schedule: - cron: "0 0 * * *" permissions: {} jobs: stale: if: startsWith(github.repository, 'asyncapi/') name: Mark issue or PR as stale runs-on: ubuntu-latest permissions: contents: read # As delete-branch is not being used issues: write # To add comments and labels to issues pull-requests: write # To add comments and labels to PRs steps: - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 #v9.1.0 but pointing to commit for security reasons with: repo-token: ${{ github.token }} stale-issue-message: | This issue has been automatically marked as stale because it has not had recent activity :sleeping: It will be closed in 120 days if no further activity occurs. To unstale this issue, add a comment with a detailed explanation. There can be many reasons why some specific issue has no activity. The most probable cause is lack of time, not lack of interest. AsyncAPI Initiative is a Linux Foundation project not owned by a single for-profit company. It is a community-driven initiative ruled under [open governance model](https://github.com/asyncapi/community/blob/master/CHARTER.md). Let us figure out together how to push this issue forward. Connect with us through [one of many communication channels](https://github.com/asyncapi/community/issues/1) we established here. Thank you for your patience :heart: stale-pr-message: | This pull request has been automatically marked as stale because it has not had recent activity :sleeping: It will be closed in 120 days if no further activity occurs. To unstale this pull request, add a comment with detailed explanation. There can be many reasons why some specific pull request has no activity. The most probable cause is lack of time, not lack of interest. AsyncAPI Initiative is a Linux Foundation project not owned by a single for-profit company. It is a community-driven initiative ruled under [open governance model](https://github.com/asyncapi/community/blob/master/CHARTER.md). Let us figure out together how to push this pull request forward. Connect with us through [one of many communication channels](https://github.com/asyncapi/community/issues/1) we established here. Thank you for your patience :heart: days-before-stale: 120 days-before-close: 120 stale-issue-label: stale stale-pr-label: stale exempt-issue-labels: keep-open exempt-pr-labels: keep-open close-issue-reason: not_planned ================================================ FILE: .github/workflows/test-action.yml ================================================ name: PR testing of CLI action on: pull_request: types: [ opened, synchronize, reopened, ready_for_review ] jobs: should-workflow-run: runs-on: ubuntu-latest steps: - if: > !github.event.pull_request.draft && !( (github.actor == 'asyncapi-bot' && ( startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') || startsWith(github.event.pull_request.title, 'chore(release):') )) || (github.actor == 'asyncapi-bot-eve' && ( startsWith(github.event.pull_request.title, 'ci: update of files from global .github repo') || startsWith(github.event.pull_request.title, 'chore(release):') )) || (github.actor == 'allcontributors[bot]' && startsWith(github.event.pull_request.title, 'docs: add') ) ) id: should_run name: Should Run run: echo "shouldrun=true" >> $GITHUB_OUTPUT outputs: shouldrun: ${{ steps.should_run.outputs.shouldrun }} build-docker: needs: should-workflow-run name: Build Docker image if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Get docker version id: docker_version run: > ls -la; action=$(cat action.yml); regex='docker:\/\/asyncapi\/github-action-for-cli:([0-9.]+)'; [[ $action =~ $regex ]]; action_version=${BASH_REMATCH[1]}; echo "action_version=$action_version" >> $GITHUB_OUTPUT - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build Docker image and export uses: docker/build-push-action@v5 with: context: . file: ./github-action/Dockerfile tags: asyncapi/github-action-for-cli:${{ steps.docker_version.outputs.action_version }} outputs: type=docker,dest=/tmp/asyncapi.tar - name: Upload artifact uses: actions/upload-artifact@v4 with: name: asyncapi path: /tmp/asyncapi.tar test-defaults: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action uses: ./ with: filepath: ./github-action/test/asyncapi.yml - name: Assert GitHub Action run: | echo "Listing all files" ls -R echo "Asserting GitHub Action" if [ -f "./output/asyncapi.md" ]; then echo "Files exist" else echo "Files do not exist:- ./output/asyncapi.md" echo "Action failed" exit 1 fi test-validate-success: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action uses: ./ with: filepath: ./github-action/test/asyncapi.yml command: validate test-custom-command: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action uses: ./ with: # Custom command to generate models # Note: You can use command itself to generate models, but this is just an example for testing custom commands custom_command: "generate models typescript ./github-action/test/asyncapi.yml -o ./output" - name: Assert GitHub Action run: | echo "Listing all files" ls -R echo "Asserting GitHub Action" if [ -f "./output/AnonymousSchema_1.ts" ]; then echo "Models have been generated" else echo "Models have not been generated" echo "Action failed" exit 1 fi test-custom-output: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action uses: ./ with: filepath: ./github-action/test/asyncapi.yml output: custom-output - name: Assert GitHub Action run: | echo "Listing all files" ls -R echo "Asserting GitHub Action" if [ -f "./custom-output/asyncapi.md" ]; then echo "Files exist" else echo "Files do not exist:- ./custom-output/asyncapi.md" echo "Action failed" exit 1 fi test-file-not-found: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action id: test uses: ./ with: filepath: non_existent_file.yml continue-on-error: true - name: Check for failure run: | if [ "${{ steps.test.outcome }}" == "success" ]; then echo "Test Failure: non_existent_file.yml should throw an error but did not" exit 1 else echo "Test Success: non_existent_file.yml threw an error as expected" fi test-invalid-input: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action id: test uses: ./ with: filepath: github-action/test/asyncapi.yml command: generate # No template or language specified template: '' # Empty string continue-on-error: true - name: Check for failure run: | if [ "${{ steps.test.outcome }}" == "success" ]; then echo "Test Failure: generate command should throw an error as no template or language specified but did not" exit 1 else echo "Test Success: generate command threw an error as expected" fi test-optimize: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action uses: ./ with: filepath: github-action/test/unoptimized.yml command: optimize parameters: '-o new-file --no-tty' - name: Assert GitHub Action run: | echo "Listing all files" ls -R echo "Asserting GitHub Action" if [ -f "./github-action/test/unoptimized_optimized.yml" ]; then echo "The specified file has been optimized" else echo "The specified file has not been optimized" echo "Action failed" exit 1 fi test-bundle: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Make output directory run: mkdir -p ./output/bundle - name: Test GitHub Action uses: ./ with: custom_command: 'bundle ./github-action/test/bundle/asyncapi.yaml ./github-action/test/bundle/features.yaml --base ./github-action/test/bundle/asyncapi.yaml -o ./output/bundle/asyncapi.yaml' - name: Assert GitHub Action run: | echo "Listing all files" ls -R echo "Asserting GitHub Action" if [ -f "./output/bundle/asyncapi.yaml" ]; then echo "The specified files have been bundled" else echo "The specified files have not been bundled" echo "Action failed" exit 1 fi test-convert: if: ${{ needs.should-workflow-run.outputs.shouldrun == 'true' }} runs-on: ubuntu-latest needs: [should-workflow-run, build-docker] steps: - name: Download artifact uses: actions/download-artifact@v4 with: name: asyncapi path: /tmp - name: Load Docker image run: | docker load --input /tmp/asyncapi.tar docker image ls -a - uses: actions/checkout@v4 - name: Remove bin directory to disable developer mode run: rm -rf ./bin - name: Test GitHub Action uses: ./ with: command: convert filepath: github-action/test/asyncapi.yml output: output/convert/asyncapi.yaml - name: Assert GitHub Action run: | echo "Listing all files" ls -R echo "Asserting GitHub Action" if [ -f "./output/convert/asyncapi.yaml" ]; then echo "The specified file has been converted" else echo "The specified file has not been converted" echo "Action failed" exit 1 fi ================================================ FILE: .github/workflows/update-docs-in-website.yml ================================================ name: Update latest CLI documentation in the website on: push: branches: - 'master' paths: - 'docs/*.md' workflow_dispatch: jobs: Make-PR: name: Make PR on website repository with updated latest CLI documentation runs-on: ubuntu-latest env: GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} steps: - name: Checkout Current repository uses: actions/checkout@v3 with: path: cli - name: Checkout Another repository uses: actions/checkout@v3 with: repository: asyncapi/website path: website token: ${{ env.GITHUB_TOKEN }} - name: Config git run: | git config --global user.name asyncapi-bot git config --global user.email info@asyncapi.io - name: Create branch working-directory: ./website run: | git checkout -b update-cli-docs-${{ github.sha }} - name: Copy cli folder from Current Repo to Another working-directory: ./website run: | mkdir -p ./markdown/docs/tools/cli printf "%s\ntitle: CLI\nweight: 10\n%s" "---" "---"> ../cli/docs/_section.md mv ../cli/docs/*.md ./markdown/docs/tools/cli - name: Commit and push working-directory: ./website run: | git add . git commit -m "docs(cli): update latest cli docs" git push https://${{ env.GITHUB_TOKEN }}@github.com/asyncapi/website - name: Create PR working-directory: ./website run: | gh pr create --title "docs(cli): update latest cli documentation" --body "Updated cli documentation is available and this PR introduces update to cli folder on the website" --head "update-cli-docs-${{ github.sha }}" ================================================ FILE: .github/workflows/update-docs-on-docs-commits.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # The given workflow is responsible for generating docs and creating PR with them when there is a commit with docs: prefix # This workflow will be updated in all repos with the topic get-global-docs-autoupdate name: 'Update generated parts of documentation on docs: commits' on: push: branches: - master jobs: docs-gen: name: 'Generate docs and create PR' runs-on: ubuntu-latest # PR should be created within this GH action only if it is a docs: commit # Otherwise it will conflict with release workflow if: startsWith(github.event.commits[0].message, 'docs:') steps: - name: Checkout repo uses: actions/checkout@v4 - name: Determine what node version to use # This workflow is from our own org repo and safe to reference by 'master'. uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master # //NOSONAR with: node-version: ${{ vars.NODE_VERSION }} id: lockversion - name: Use Node.js uses: actions/setup-node@v4 with: node-version: "${{ steps.lockversion.outputs.version }}" cache: 'npm' cache-dependency-path: '**/package-lock.json' - name: Install dependencies run: npm ci - name: Regenerate docs run: npm run generate:assets --if-present - name: Create Pull Request with updated docs uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # uses 7.0.8 https://github.com/peter-evans/create-pull-request/releases/tag/v7.0.8 with: token: ${{ secrets.GH_TOKEN }} commit-message: 'chore: update generated docs' committer: asyncapi-bot author: asyncapi-bot title: 'chore: update generated docs' body: 'Update of docs that are generated and were forgotten on PR level.' branch: gen-docs-update/${{ github.job }} - name: Report workflow status to Slack if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel uses: 8398a7/action-slack@28ba43ae48961b90635b50953d216767a6bea486 #using https://github.com/8398a7/action-slack/releases/tag/v3.16.2 with: status: ${{ job.status }} fields: repo,action,workflow text: 'AsyncAPI docs generation workflow failed' author_name: asyncapi-bot env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} ================================================ FILE: .github/workflows/update-maintainers-trigger.yaml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: Trigger MAINTAINERS.yaml file update on: push: branches: [ master ] paths: # Check all valid CODEOWNERS locations: # https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners#codeowners-file-location - 'CODEOWNERS' - '.github/CODEOWNERS' - '.docs/CODEOWNERS' permissions: contents: read # Just to limit GITHUB_TOKEN as we use GH_TOKEN only jobs: trigger-maintainers-update: name: Trigger updating MAINTAINERS.yaml because of CODEOWNERS change runs-on: ubuntu-latest steps: - name: Repository Dispatch uses: peter-evans/repository-dispatch@ff45666b9427631e3450c54a1bcbee4d9ff4d7c0 # https://github.com/peter-evans/repository-dispatch/releases/tag/v3.0.0 with: # The PAT with the 'public_repo' scope is required token: ${{ secrets.GH_TOKEN }} repository: ${{ github.repository_owner }}/community event-type: trigger-maintainers-update ================================================ FILE: .github/workflows/update-pr.yml ================================================ # This workflow is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo # This workflow will run on every comment with /update or /u. And will create merge-commits for the PR. # This also works with forks, not only with branches in the same repository/organization. # Currently, does not work with forks in different organizations. # This workflow will be distributed to all repositories in the AsyncAPI organization name: Update PR branches from fork permissions: contents: read on: issue_comment: types: [created] jobs: update-pr: name: Update the fork PR with upstream changes if: > startsWith(github.repository, 'asyncapi/') && github.event.issue.pull_request && github.event.issue.state != 'closed' && ( contains(github.event.comment.body, '/update') || contains(github.event.comment.body, '/u') ) runs-on: ubuntu-latest permissions: issues: write # Required to read PR details and post comments on the PR pull-requests: write # Required to update the PR branch contents: read steps: - name: Get Pull Request Details id: pr uses: actions/github-script@v7 with: github-token: ${{ secrets.GH_TOKEN || github.token }} previews: 'merge-info-preview' # https://docs.github.com/en/graphql/overview/schema-previews#merge-info-preview-more-detailed-information-about-a-pull-requests-merge-state-preview script: | const prNumber = context.payload.issue.number; core.debug(`PR Number: ${prNumber}`); const { data: pr } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, pull_number: prNumber }); // If the PR has conflicts, we don't want to update it const updateable = ['behind', 'blocked', 'unknown', 'draft', 'clean', 'unstable'].includes(pr.mergeable_state); console.log(`PR #${prNumber} is ${pr.mergeable_state} and is ${updateable ? 'updateable' : 'not updateable'}`); core.setOutput('updateable', updateable); core.debug(`Updating PR #${prNumber} with head ${pr.head.sha}`); return { id: pr.node_id, number: prNumber, head: pr.head.sha, } - name: Update the Pull Request if: steps.pr.outputs.updateable == 'true' uses: actions/github-script@v7 env: PR_DETAILS: ${{ steps.pr.outputs.result }} with: github-token: ${{ secrets.GH_TOKEN || github.token }} script: | const mutation = `mutation update($input: UpdatePullRequestBranchInput!) { updatePullRequestBranch(input: $input) { pullRequest { mergeable } } }`; const pr_details = JSON.parse(process.env.PR_DETAILS); try { const { data } = await github.graphql(mutation, { input: { pullRequestId: pr_details.id, expectedHeadOid: pr_details.head, } }); } catch (GraphQLError) { core.debug(GraphQLError); if ( GraphQLError.name === 'GraphqlResponseError' && GraphQLError.errors.some( error => error.type === 'FORBIDDEN' || error.type === 'UNAUTHORIZED' ) ) { // Add comment to PR if the bot doesn't have permissions to update the PR const comment = `Hi @${context.actor}. Update of PR has failed. It can be due to one of the following reasons: - I don't have permissions to update this PR. To update your fork with upstream using bot you need to enable [Allow edits from maintainers](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/allowing-changes-to-a-pull-request-branch-created-from-a-fork) option in the PR. - The fork is located in an organization, not under your personal profile. No solution for that. You are on your own with manual update. - There may be a conflict in the PR. Please resolve the conflict and try again.`; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: comment }); core.setFailed('Bot does not have permissions to update the PR'); } else { core.setFailed(GraphQLError.message); } } ================================================ FILE: .github/workflows/upload-release-assets.yml ================================================ name: Upload custom assets to GitHub release on: release: types: - published env: CI: true jobs: upload-assets: name: Generate and upload assets runs-on: ${{ matrix.os }} continue-on-error: true strategy: matrix: include: - os: ubuntu-latest npm_script: pack:linux dist_folder: deb extension: deb - os: ubuntu-latest npm_script: pack:tarballs dist_folder: tar extension: tar.gz - os: ubuntu-latest npm_script: pack:tarballs:alpine dist_folder: tar extension: alpine.tar.gz container: 'node:20-alpine' alpine: true - os: ubuntu-latest npm_script: pack:windows dist_folder: win32 extension: x64.exe - os: ubuntu-latest npm_script: pack:windows dist_folder: win32 extension: x86.exe - os: macos-latest npm_script: pack:macos dist_folder: macos extension: arm64.pkg - os: macos-latest npm_script: pack:macos dist_folder: macos extension: x64.pkg container: ${{ matrix.container }} steps: - name: Install base tools for alpine container if: matrix.container == 'node:20-alpine' run: | apk add --no-cache bash git python3 make g++ perl-utils xz - name: Checkout repository uses: actions/checkout@v4 # Needed to avoid "fatal: detected dubious ownership in repository" error when using alpine container - name: Mark GitHub workspace as safe if: matrix.container == 'node:20-alpine' run: | git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Check package-lock version if: matrix.container == '' uses: asyncapi/.github/.github/actions/get-node-version-from-package-lock@master id: lockversion with: node-version: ${{ vars.NODE_VERSION }} - name: Setup Node.js if: matrix.container == '' uses: actions/setup-node@v6 with: node-version: "${{ steps.lockversion.outputs.version }}" - name: Get version from package.json uses: actions/github-script@v6 id: extractver with: script: | const packageJson = require('./package.json'); const packageJsonVersion = packageJson.version; core.setOutput('version', packageJsonVersion); - if: matrix.npm_script == 'pack:windows' #fix for windows build issue #1433 name: Install p7zip-full nsis run: sudo apt-get install -y p7zip-full nsis - if: matrix.npm_script == 'pack:windows' #npm cli 10 is buggy because of some cache issue name: Install npm cli 10 shell: bash run: npm install -g npm@latest - name: Install dependencies run: npm ci - name: Build project shell: bash run: npm run prepublishOnly - name: Assets generation shell: bash run: | npm run ${{ matrix.npm_script }} if [[ "${{ matrix.alpine }}" == "true" ]]; then npm run pack:rename alpine else npm run pack:rename fi - name: Update release uses: softprops/action-gh-release@v1 with: files: dist/${{ matrix.dist_folder }}/asyncapi.${{ matrix.extension }} tag_name: v${{ steps.extractver.outputs.version }} token: ${{ secrets.GH_TOKEN }} - if: failure() # Only, on failure, send a message on the 94_bot-failing-ci slack channel name: Report workflow run status to Slack uses: 8398a7/action-slack@fbd6aa58ba854a740e11a35d0df80cb5d12101d8 #using https://github.com/8398a7/action-slack/releases/tag/v3.15.1 with: status: ${{ job.status }} fields: repo,action,workflow text: 'AsyncAPI CLI release build artifacts failed' env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_CI_FAIL_NOTIFY }} ================================================ FILE: .github/workflows/welcome-first-time-contrib.yml ================================================ # This action is centrally managed in https://github.com/asyncapi/.github/ # Don't make changes to this file in this repo as they will be overwritten with changes made to the same file in above mentioned repo name: Welcome first time contributors on: pull_request: types: - opened issues: types: - opened permissions: issues: read # Required to check if the issue is the user's first contribution pull-requests: read # Required to check if the pull request is the user's first contribution jobs: welcome: name: Post welcome message if: ${{ !contains(fromJson('["asyncapi-bot", "dependabot[bot]", "dependabot-preview[bot]", "allcontributors[bot]"]'), github.actor) }} # zizmor: ignore[obfuscation] runs-on: ubuntu-latest permissions: contents: read # Required to read repository data for checking if it's the user's first contribution issues: write # Required to post welcome message on issues pull-requests: write # Required to post welcome message on pull requests steps: - uses: actions/github-script@v7 with: github-token: ${{ github.token }} script: | const issueMessage = `Welcome to AsyncAPI. Thanks a lot for reporting your first issue. Please check out our [contributors guide](https://github.com/asyncapi/community/blob/master/CONTRIBUTING.md) and the instructions about a [basic recommended setup](https://github.com/asyncapi/community/blob/master/git-workflow.md) useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).`; const prMessage = `Welcome to AsyncAPI. Thanks a lot for creating your first pull request. Please check out our [contributors guide](https://github.com/asyncapi/community/blob/master/CONTRIBUTING.md) useful for opening a pull request.
Keep in mind there are also other channels you can use to interact with AsyncAPI community. For more details check out [this issue](https://github.com/asyncapi/asyncapi/issues/115).`; if (!issueMessage && !prMessage) { throw new Error('Action must have at least one of issue-message or pr-message set'); } const isIssue = !!context.payload.issue; let isFirstContribution; if (isIssue) { const query = `query($owner:String!, $name:String!, $contributer:String!) { repository(owner:$owner, name:$name){ issues(first: 1, filterBy: {createdBy:$contributer}){ totalCount } } }`; const variables = { owner: context.repo.owner, name: context.repo.repo, contributer: context.payload.sender.login }; const { repository: { issues: { totalCount } } } = await github.graphql(query, variables); isFirstContribution = totalCount === 1; } else { const query = `query($qstr: String!) { search(query: $qstr, type: ISSUE, first: 1) { issueCount } }`; const variables = { "qstr": `repo:${context.repo.owner}/${context.repo.repo} type:pr author:${context.payload.sender.login}`, }; const { search: { issueCount } } = await github.graphql(query, variables); isFirstContribution = issueCount === 1; } if (!isFirstContribution) { console.log(`Not the users first contribution.`); return; } const message = isIssue ? issueMessage : prMessage; // Add a comment to the appropriate place if (isIssue) { const issueNumber = context.payload.issue.number; console.log(`Adding message: ${message} to issue #${issueNumber}`); await github.rest.issues.createComment({ owner: context.payload.repository.owner.login, repo: context.payload.repository.name, issue_number: issueNumber, body: message }); } else { const pullNumber = context.payload.pull_request.number; console.log(`Adding message: ${message} to pull request #${pullNumber}`); await github.rest.pulls.createReview({ owner: context.payload.repository.owner.login, repo: context.payload.repository.name, pull_number: pullNumber, body: message, event: 'COMMENT' }); } ================================================ FILE: .gitignore ================================================ *-debug.log *-error.log .DS_Store .idea /.nyc_output /dist /dist/ /lib /node_modules/ /tmp /yarn.lock /assets/examples/** !assets/examples/default-example.yaml !assets/examples/tutorial.yml' !assets/examples/default-example.json node_modules /test/integration/generate/models/ test.asyncapi-cli asyncapi.json test/fixtures/minimaltemplate/__transpiled test/fixtures/newtemplate/__transpiled test/fixtures/specification-conv.yml test/fixtures/specification-conv.yaml test/fixtures/specification-conv.json .vscode src/domains/models/generate/ClientLanguages.ts /action/ /github-action/output/ oclif.manifest.json spec-examples.zip # Coverage for testing coverage .asyncapi-analytics # Analytics .asyncapi-analytics # Modelina test/fixtures/generate/models ================================================ FILE: .prettierrc ================================================ { "singleQuote": true } ================================================ FILE: .sonarcloud.properties ================================================ sonar.exclusions=test/**/*,Dockerfile,github-action/Dockerfile sonar.issue.ignore.multicriteria=e1,e2 # Exclude copy recursively and root user issue in Dockerfile sonar.issue.ignore.multicriteria.e1.ruleKey=docker:S6470 sonar.issue.ignore.multicriteria.e1.resourceKey=**/Dockerfile sonar.issue.ignore.multicriteria.e2.ruleKey=docker:S6471 sonar.issue.ignore.multicriteria.e2.resourceKey=**/Dockerfile ================================================ FILE: CHANGELOG.md ================================================ # @asyncapi/cli ## 6.0.0 ### Major Changes - 7580cee: Removal of postman -> asyncapi conversion functionality ## ⚠ BREAKING CHANGES Remove postman conversion utilities due to unmaintained dependencies and compatibility issues. **Why this change?** - The `postman2openapi` dependency causes multiple issues due to its WASM involvement - WASM file loading causes browser compatibility issues after webpack updates - Alternative libraries like `postman-to-openapi` did not provide adequate functionality - The underlying dependencies are unmaintained and pose long-term maintenance risks **Impact:** - The `convert` command no longer supports postman format conversion - Users relying on postman conversion will need to find alternative solutions **Future:** We can consider re-adding this feature after community discussion and establishing a sustainable maintenance plan with actively maintained dependencies. Related: https://github.com/asyncapi/converter-js/pull/311 ## 5.0.7 ### Patch Changes - 72fd21f: Bump @asyncapi/generator from v3.1.0 → v3.1.1 ## 5.0.6 ### Patch Changes - a414293: - Updated `@asyncapi/generator` from `3.0.1` → `3.1.0` ## 5.0.5 ### Patch Changes - be7c41d: chore: bump Node.js version to 24 in remaining Dockerfiles ## 5.0.4 ### Patch Changes - cacf566: Update server-api image to use Node 24. ## 5.0.3 ### Patch Changes - 125e907: Update dependencies to the latest feasible ones thus eliminating vulnerabilities. ## 5.0.2 ### Patch Changes - 4073175: - Alpine Releases have been fixed now. - Smaller docker image sizes and pruned dependencies. ## 5.0.1 ### Patch Changes - 394967f: fix: remove unnecessary await from startPreview call The startPreview function returns void, not a Promise, so awaiting it was incorrect and triggered a linter error. This matches the pattern used in the studio command. ## 5.0.0 ### Major Changes - dac7bb4: Removed support for AsyncAPI Generator v1 and v2. The CLI now exclusively uses Generator v3. The `--use-new-generator` flag has been removed from the `generate fromTemplate` command. - b90a9b7: ## Major release with important security updates - Keeping in mind the recent Shai-Hulud attack, we have adopted trusted publishing with NPM. - This requires us to use node >= 24 and npm >= 11 - Next.js version is in sync with Studio, and is currently 14.2.35 deemed safe by CVE. [For more details](https://nextjs.org/blog/CVE-2025-66478) ### Breaking Changes - Node.js version 24 or higher is now required. - NPM version 11 or higher is now required. - Next.js version is now 14.2.35 or higher. - The CLI now exclusively uses Generator v3 only. - The `--use-new-generator` flag has been removed from the `generate fromTemplate` command. - Default template in action has been upgraded to `@asyncapi/markdown-template@2.0.0` Please make sure to update your environment accordingly before upgrading to this version. ### Minor Changes - c648614: Studio updated to 1.1.0 with Next.js 14.2.35 in https://github.com/asyncapi/cli/pull/1922/changes ## 4.1.3 ### Patch Changes - a77940f: fix: show the correct path to the newly created optimized file - e16ebf5: fix: show the correct path to the newly created optimized file ## 4.1.2 ### Patch Changes - df62a63: fix: generate optimized output corresponding to the input format - c756765: fix: generate optimized output corresponding to the input format ## 4.1.1 ### Patch Changes - 8eca9ed: fix: update redoc - adde5d4: chore: update redoc Signed-off-by: Shurtu-gal ## 4.1.0 ### Minor Changes - 70761f0: feat: add new custom resolver to fetch the reference from private repo - 88ceb3d: add new custom resolver to fetch the reference from private repo - 4974358: Update src/domains/services/validation.service.ts Co-authored-by: Fran Méndez - c764ee6: update instruction in the test case for the validation success - 2b9457f: fix test-cases - 86bbfc4: fix lint issue across the project - 6813ef0: Update 1875.md ## 4.0.1 ### Patch Changes - 9b479fc: fix: lockfile fixed - 92bb81b: fix:lockfile fixed Signed-off-by: Tushar Anand ## 4.0.0 ### Major Changes - 9d05d49: feat!: tests, flags and glee command code removed - 7df684f: chore: major tests flags and glee command code removed Signed-off-by: Tushar Anand - 4a94f51: chore:glee removal complete Signed-off-by: Tushar Anand ## 3.6.0 ### Minor Changes - ca8101f: feat: output flag renamed and writing to file functionality added to diff command - 8c2e940: fix:parse flag output renamed to save-output and saving diff output to file functionality added to diff command Signed-off-by: Tushar Anand - 59e1df9: chore:tests added for flags save-output in validate and diff command Signed-off-by: Tushar Anand - 7228a36: chore:cleanup Signed-off-by: Tushar Anand - ccb5388: chore:cleanup Signed-off-by: Tushar Anand ## 3.5.2 ### Patch Changes - bbc9451: fix: server-api deploy - 837be8a: fix: server-api release and deployment Signed-off-by: Shurtu-gal - 09af23e: chore: add app platform spec Signed-off-by: Shurtu-gal - a5eef9f: chore: install generator templates globally Signed-off-by: Shurtu-gal ## 3.5.1 ### Patch Changes - 5a99f6f: fix: modify api:build script to generate languages - 9488a1b: fix: modify script to generate languages Updated the 'api:build' script to include language generation. ## 3.5.0 ### Minor Changes - 129f531: Introduced a new `asyncapi generate client` command to the CLI. This command allows you to generate client libraries using the new **AsyncAPI Generator** baked-in templates. Read more about [baked-in templates in official documentation](https://www.asyncapi.com/docs/tools/generator/baked-in-templates). This feature is based on a new concept introduced in [AsyncAPI Generator version 2.8.3](https://github.com/asyncapi/generator/releases/tag/%40asyncapi%2Fgenerator%402.8.3). The number of templates is limited and the solution is still in the experimental phase. It is not recommended to use them in production. Instead, join us in the [Generator project](https://github.com/asyncapi/generator) to help improve templates with your use cases and your AsyncAPI documents. ## 3.4.2 ### Patch Changes - d832abc: Fixes the dependencies and package-lock.json ## 3.4.2 ### Patch Changes - 80dcadd: fix: get server-api release ready - 35248ba: chore: fix server-api release Signed-off-by: Shurtu-gal - 4dcdd02: fix: get server-api release ready Signed-off-by: Shurtu-gal ## 3.4.1 ### Patch Changes - e2a3583: fix: made studio start on different port if one is already in use - 43a8cb8: fix: made studio start on differnt port if one is already in use Signed-off-by: Tushar Anand - ce4b061: Merge remote-tracking branch 'remote/master' into fix-studio-multiple-instance - 122812a: chore: new approach for port allocation done Signed-off-by: Tushar Anand - 5946001: fix: removed comment and fix linting errors Signed-off-by: Tushar Anand ## 3.4.0 ### Minor Changes - 6b00166: feat: asyncapi release for alpine distros - 54ba750: feat: asyncapi on alpine distros - 44d72c3: fix: rename the scripts to use rename instead of tarballs ## 3.3.0 ### Minor Changes - c944268: feat: refactor CLI to be service based and initial migration of server-api - ac95777: feat: refactor cli to be service based and migrate server-api Signed-off-by: Shurtu-gal - 6b925f4: chore: fix diff test Signed-off-by: Shurtu-gal - cfe6e8d: feat: add generator controller Signed-off-by: Shurtu-gal - b2d7bcc: chore: don't need to install everytime Signed-off-by: Shurtu-gal - dd71d22: Merge remote-tracking branch 'origin/master' into refactor - 1fd1216: fix: linting Signed-off-by: Ashish Padhy - 6bd3e73: chore: run prettier Signed-off-by: Ashish Padhy - ca3fdee: chore: run linter Signed-off-by: Ashish Padhy - 1d03d79: chore: quick startup of server-api Signed-off-by: Shurtu-gal - 13729bb: chore: rename to apps Signed-off-by: Ashish Padhy - cdd2a43: chore: rename npm commands Signed-off-by: Ashish Padhy - 90aca02: Merge remote-tracking branch 'remote/master' into refactor ## 3.2.0 ### Minor Changes - 0754d1d: feat: add new feature to supress the warnings - ab94c15: Add a new flag that is --x-suppress-warnings to supress the warning in the validate command - 55819cd: Allow to pass multiple warnings to supress and add check to verify the warning is correct or not - 885fc71: Update src/core/parser.ts Co-authored-by: Souvik De - 16b22de: Update src/core/flags/validate.flags.ts Co-authored-by: Souvik De - de1caad: Add another flag to supressallwarnings and update test case ## 3.1.1 ### Patch Changes - 152c272: feat: made the start studio command interactive along with addition of… - 0e8e3c1: feat: made the start studio command inteactive along with addition of a flag to disable prompt. ## 3.1.0 ### Minor Changes - d17aa54: feat: new command `asyncapi start preview` has been added ## 3.0.1 ### Patch Changes - 1b62a66: - Fixes script detection issue in version 3.0.0 - Fixes testing by testing the github action with local CLI ## 3.0.0 ### Major Changes - b6f8b82: feat: add autocomplete feature in cli ## 2.17.0 ### Minor Changes - f0268d4: Remove `--renderer` flag and make `React` as the de-facto renderer, deprecating `Nunjucks` ## 2.16.10 ### Patch Changes - e11fe05: fix: Wrong Error message in -h command #1725 ## 2.16.9 ### Patch Changes - 819b585: [Fix]: Json file supported in asyncapi new file command - 830fe82: Fix studio not opening in CLI studio command - 830fe82: fix: studio command not working ## 2.16.8 ### Patch Changes - 460c99a: feat: use next.js version of studio - 460c99a: Upgrade studio to latest and allow use of next server ## 2.16.7 ### Patch Changes - 6ca17b3: fix: update packages to latest stable version ## 2.16.6 ### Patch Changes - 82b441f: fix: resolve error in AsyncAPI optimize ## 2.16.5 ### Patch Changes - f873423: docs: update docs regarding asyncapi new command - 2deeb36: fix: print in cli asyncapi generate models without -o flag ## 2.16.4 ### Patch Changes - 67d7e8f: fix: proxy implementation for optimize validate and convert fixed ## 2.16.3 ### Patch Changes - cec8081: feat: added Proxy support for the generate commands. ## 2.16.2 ### Patch Changes - 755339a: feat: change the implementation of new command ## 2.16.1 ### Patch Changes - 3ab019f: chore(deps): bump jsonpath-plus and @stoplight/spectral-core - 07514e6: implemented new UI/UX improvements in config command - a774ae2: fix: starting of studio fixed when using example with new file ## 2.16.0 ### Minor Changes - a37e124: Deprecate the --file flag in `start studio` command ## 2.15.0 ### Minor Changes - dcfb8c7: fix: Remove unused package lodash.template ## 2.14.1 ### Patch Changes - 08afb45: Prepare github action for release - da64c63: ci: bump artifact actions to v4 ## 2.14.0 ### Minor Changes - 6839c8f: - Changed docker build to a source code based build - Changed name of github action to avoid clash - Fixed Docker and Release Pipeline ## 2.13.1 ### Patch Changes - 8ae33c4: Handle AsyncAPI v3 in diff command ## 2.13.0 ### Minor Changes - a76b0fb: Add github-action to monorepo and set up changesets ### Patch Changes - 81b925e: Updated README with Development.md file ================================================ FILE: CODEOWNERS ================================================ # This file provides an overview of code owners in this repository. # Each line is a file pattern followed by one or more owners. # The last matching pattern has the most precedence. # For more details, read the following article on GitHub: https://help.github.com/articles/about-codeowners/. # The default owners are automatically added as reviewers when you open a pull request unless different owners are specified in the file. * @Souvikns @Amzani @Shurtu-gal @asyncapi-bot-eve @AayushSaini101 ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant 3.0 Code of Conduct ## Our Pledge We pledge to make our community welcoming, safe, and equitable for all. We are committed to fostering an environment that respects and promotes the dignity, rights, and contributions of all individuals, regardless of characteristics including race, ethnicity, caste, color, age, physical characteristics, neurodiversity, disability, sex or gender, gender identity or expression, sexual orientation, language, philosophy or religion, national or social origin, socio-economic position, level of education, or other status. The same privileges of participation are extended to everyone who participates in good faith and in accordance with this Covenant. ## Encouraged Behaviors While acknowledging differences in social norms, we all strive to meet our community's expectations for positive behavior. We also understand that our words and actions may be interpreted differently than we intend based on culture, background, or native language. With these considerations in mind, we agree to behave mindfully toward each other and act in ways that center our shared values, including: 1. Respecting the **purpose of our community**, our activities, and our ways of gathering. 2. Engaging **kindly and honestly** with others. 3. Respecting **different viewpoints** and experiences. 4. **Taking responsibility** for our actions and contributions. 5. Gracefully giving and accepting **constructive feedback**. 6. Committing to **repairing harm** when it occurs. 7. Behaving in other ways that promote and sustain the **well-being of our community**. ## Restricted Behaviors We agree to restrict the following behaviors in our community. Instances, threats, and promotion of these behaviors are violations of this Code of Conduct. 1. **Harassment.** Violating explicitly expressed boundaries or engaging in unnecessary personal attention after any clear request to stop. 2. **Character attacks.** Making insulting, demeaning, or pejorative comments directed at a community member or group of people. 3. **Stereotyping or discrimination.** Characterizing anyone’s personality or behavior on the basis of immutable identities or traits. 4. **Sexualization.** Behaving in a way that would generally be considered inappropriately intimate in the context or purpose of the community. 5. **Violating confidentiality**. Sharing or acting on someone's personal or private information without their permission. 6. **Endangerment.** Causing, encouraging, or threatening violence or other harm toward any person or group. 7. Behaving in other ways that **threaten the well-being** of our community. ### Other Restrictions 1. **Misleading identity.** Impersonating someone else for any reason, or pretending to be someone else to evade enforcement actions. 2. **Failing to credit sources.** Not properly crediting the sources of content you contribute. 3. **Promotional materials**. Sharing marketing or other commercial content in a way that is outside the norms of the community. 4. **Irresponsible communication.** Failing to responsibly present content which includes, links or describes any other restricted behaviors. ## Reporting an Issue Tensions can occur between community members even when they are trying their best to collaborate. Not every conflict represents a code of conduct violation, and this Code of Conduct reinforces encouraged behaviors and norms that can help avoid conflicts and minimize harm. When an incident does occur, it is important to report it promptly. To report a possible violation, here are a few simple ways to do it: - Join our [AsyncAPI Slack](https://asyncapi.com/slack-invite) and share your report in the `#coc` channel. - Reach out directly to any member of the [Code of Conduct Committee](https://github.com/orgs/asyncapi/teams/code_of_conduct). - Or, if you’d prefer, just send us an email at **conduct@asyncapi.com**. Community Moderators take reports of violations seriously and will make every effort to respond in a timely manner. They will investigate all reports of code of conduct violations, reviewing messages, logs, and recordings, or interviewing witnesses and other participants. Community Moderators will keep investigation and enforcement actions as transparent as possible while prioritizing safety and confidentiality. In order to honor these values, enforcement actions are carried out in private with the involved parties, but communicating to the whole community may be part of a mutually agreed upon resolution. ## Addressing and Repairing Harm **** If an investigation by the Community Moderators finds that this Code of Conduct has been violated, the following enforcement ladder may be used to determine how best to repair harm, based on the incident's impact on the individuals involved and the community as a whole. Depending on the severity of a violation, lower rungs on the ladder may be skipped. 1) Warning 1) Event: A violation involving a single incident or series of incidents. 2) Consequence: A private, written warning from the Community Moderators. 3) Repair: Examples of repair include a private written apology, acknowledgement of responsibility, and seeking clarification on expectations. 2) Temporarily Limited Activities 1) Event: A repeated incidence of a violation that previously resulted in a warning, or the first incidence of a more serious violation. 2) Consequence: A private, written warning with a time-limited cooldown period designed to underscore the seriousness of the situation and give the community members involved time to process the incident. The cooldown period may be limited to particular communication channels or interactions with particular community members. 3) Repair: Examples of repair may include making an apology, using the cooldown period to reflect on actions and impact, and being thoughtful about re-entering community spaces after the period is over. 3) Temporary Suspension 1) Event: A pattern of repeated violation which the Community Moderators have tried to address with warnings, or a single serious violation. 2) Consequence: A private written warning with conditions for return from suspension. In general, temporary suspensions give the person being suspended time to reflect upon their behavior and possible corrective actions. 3) Repair: Examples of repair include respecting the spirit of the suspension, meeting the specified conditions for return, and being thoughtful about how to reintegrate with the community when the suspension is lifted. 4) Permanent Ban 1) Event: A pattern of repeated code of conduct violations that other steps on the ladder have failed to resolve, or a violation so serious that the Community Moderators determine there is no way to keep the community safe with this person as a member. 2) Consequence: Access to all community spaces, tools, and communication channels is removed. In general, permanent bans should be rarely used, should have strong reasoning behind them, and should only be resorted to if working through other remedies has failed to change the behavior. 3) Repair: There is no possible repair in cases of this severity. This enforcement ladder is intended as a guideline. It does not limit the ability of Community Managers to use their discretion and judgment, in keeping with the best interests of our community. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public or other spaces. Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Attribution This Code of Conduct is adapted from the Contributor Covenant, version 3.0, permanently available at [https://www.contributor-covenant.org/version/3/0/](https://www.contributor-covenant.org/version/3/0/). Contributor Covenant is stewarded by the Organization for Ethical Source and licensed under CC BY-SA 4.0. To view a copy of this license, visit [https://creativecommons.org/licenses/by-sa/4.0/](https://creativecommons.org/licenses/by-sa/4.0/) For answers to common questions about Contributor Covenant, see the FAQ at [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq). Translations are provided at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations). Additional enforcement and community guideline resources can be found at [https://www.contributor-covenant.org/resources](https://www.contributor-covenant.org/resources). The enforcement ladder was inspired by the work of [Mozilla’s code of conduct team](https://github.com/mozilla/inclusion). ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to AsyncAPI We love your input! We want to make contributing to this project as easy and transparent as possible. ## Contribution recogniton We use [All Contributors](https://allcontributors.org/docs/en/specification) specification to handle recognitions. For more details read [this](https://www.asyncapi.com/docs/community/010-contribution-guidelines/recognize-contributors#main-content) document. ## Summary of the contribution flow The following is a summary of the ideal contribution flow. Please, note that Pull Requests can also be rejected by the maintainers when appropriate. ``` ┌───────────────────────┐ │ │ │ Open an issue │ │ (a bug report or a │ │ feature request) │ │ │ └───────────────────────┘ ⇩ ┌───────────────────────┐ │ │ │ Open a Pull Request │ │ (only after issue │ │ is approved) │ │ │ └───────────────────────┘ ⇩ ┌───────────────────────┐ │ │ │ Your changes will │ │ be merged and │ │ published on the next │ │ release │ │ │ └───────────────────────┘ ``` ## Code of Conduct AsyncAPI has adopted a [Code of Conduct](./CODE_OF_CONDUCT.md) that we expect project participants to adhere to. Please read it carefully to understand what sort of behaviour is expected. ## Our Development Process We use Github to host code, to track issues and feature requests, as well as accept pull requests. ## Issues [Open an issue](https://github.com/asyncapi/asyncapi/issues/new) **only** if you want to report a bug or a feature. Don't open issues for questions or support, instead join our [Slack workspace](https://www.asyncapi.com/slack-invite) and ask there. Don't forget to follow our [Slack Etiquette](https://www.asyncapi.com/docs/community/060-meetings-and-communication/slack-etiquette) while interacting with community members! It's more likely you'll get help, and much faster! ## Bug Reports and Feature Requests Please use our issues templates that provide you with hints on what information we need from you to help you out. ## Pull Requests **Please, make sure you open an issue before starting with a Pull Request, unless it's a typo or a really obvious error.** Pull requests are the best way to propose changes to the specification. Get familiar with our document that explains [Git workflow](https://www.asyncapi.com/docs/community/010-contribution-guidelines/git-workflow) used in our repositories. ## Conventional commits Our repositories follow [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/#summary) specification. Releasing to GitHub and NPM is done with the support of [semantic-release](https://semantic-release.gitbook.io/semantic-release/). Pull requests should have a title that follows the specification, otherwise, merging is blocked. If you are not familiar with the specification simply ask maintainers to modify. You can also use this cheatsheet if you want: - `fix: ` prefix in the title indicates that PR is a bug fix and PATCH release must be triggered. - `feat: ` prefix in the title indicates that PR is a feature and MINOR release must be triggered. - `docs: ` prefix in the title indicates that PR is only related to the documentation and there is no need to trigger release. - `chore: ` prefix in the title indicates that PR is only related to cleanup in the project and there is no need to trigger release. - `test: ` prefix in the title indicates that PR is only related to tests and there is no need to trigger release. - `refactor: ` prefix in the title indicates that PR is only related to refactoring and there is no need to trigger release. What about MAJOR release? just add `!` to the prefix, like `fix!: ` or `refactor!: ` Prefix that follows specification is not enough though. Remember that the title must be clear and descriptive with usage of [imperative mood](https://chris.beams.io/posts/git-commit/#imperative). Happy contributing :heart: ## License When you submit changes, your submissions are understood to be under the same [Apache 2.0 License](https://github.com/asyncapi/asyncapi/blob/master/LICENSE) that covers the project. Feel free to [contact the maintainers](https://www.asyncapi.com/slack-invite) if that's a concern. ## References This document was adapted from the open-source contribution guidelines for [Facebook's Draft](https://github.com/facebook/draft-js/blob/master/CONTRIBUTING.md). ================================================ FILE: DEVELOPMENT.md ================================================ # Development guide This guide will help you set up the `cli` locally, run tests, and use Docker for isolated testing. ## Getting started 1. Fork & Clone the repository: First fork the repository from github and then clone it, ```bash git clone https://github.com/{your_username}/cli.git cd cli ``` After cloning the repository, you should setup the fork properly and configure the `remote` repository as described [here](https://github.com/asyncapi/community/blob/master/git-workflow.md) 2. Install dependencies: ```bash npm install ``` ## Running tests ### Local testing To run all tests locally: - CLI tests: `npm run cli:test` - Unit tests: `npm run unit:test` - Github action tests: `npm run action:test` - Single test file: `npm run test:one -- ` ### Adding tests 1. Create new test files in the appropriate directory under `test/`: - Unit tests: `test/unit//.test.ts` - Integration tests: `test/integration/.test.ts` 2. Follow the existing test patterns. 3. Run your new tests using the commands mentioned above. > 📘 **For detailed debugging and testing guidelines**, see the [Debugging & Testing Guide](/docs/debugging-testing.md). ## Release process To release a major/minor/patch: ### Conventional Commits: To maintain a clear git history of commits and easily identify what each commit changed and whether it triggered a release, we use conventional commits. The feat and fix prefixes are particularly important as they are needed to trigger changesets. Using these prefixes ensures that the changes are correctly categorized and the versioning system functions as expected. For Example: ``` feat: add new feature ``` #### Manual 1. Create a new release markdown file in the `.changeset` directory. The filename should indicate what the change is about. 2. Add the following content to the file in this particular format: ```markdown --- "@package-name-1": [type] (major/minor/patch) "@package-name-2": [type] --- [Provide a brief description of the changes. For example: Added a new Release GitHub Flow to the Turborepo. No new features or bugfixes were introduced.] ``` For Example: ```markdown --- "@asyncapi/cli": minor --- Adding new Release Github Flow to the Turborepo. No new features or bugfixes were introduced. ``` 3. Include the file in your pull request. #### Using CLI 1. Create a new release markdown file using changeset CLI. Below command will trigger an interactive prompt that you can use to specify release type and affected packages. ```cli npx -p @changesets/cli@2.27.7 changeset ``` 2. Include the file in your pull request. > [!TIP] > For more detailed instructions, you can refer to the official documentation for creating a changeset: [Adding a changeset](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md) ### Release Flow: 1. **Add a Changeset**: - When you make changes that need to be released, create a markdown file in the `.changeset` directory stating the package name and level of change (major/minor/patch). 2. **Open a Pull Request**: - Push your changes and open a Pull Request (PR). After the PR is merged the changeset file helps communicate the type of changes (major, minor, patch). 3. **CI Processes Changeset**: - After PR is merged, a dedicated GitHub Actions release workflow runs using changeset action, - This action reads the markdown files in the `.changeset` folder and creates a PR with the updated version of the package and removes the markdown file. For example: Before: ```json "name": "@asyncapi/cli", "version": "2.0.1", ``` After: ```json "name": "@asyncapi/cli", "version": "3.0.1", ``` - The new PR will also contain the description from the markdown files, - AsyncAPI bot automatically merge such release PR. 4. **Release the Package**: - After the PR is merged, the CI/CD pipeline triggers again. The `changesets/action` step identifies that the PR was created by itself. It then verifies if the current version of the package is greater than the previously released version. If a difference is detected, it executes the publish command to release the updated package. ## Additional commands - Lint the code: `npm run lint` - Build Docker image: `npm run docker:build` ## Troubleshooting If you encounter any issues during development or testing, please check the following: 1. Ensure you're using the correct Node.js version (24.0.0 or higher) and npm version (8.19.0 or higher). 2. Clear the `node_modules` directory and reinstall dependencies if you encounter unexpected behavior. 3. For Docker-related issues, make sure Docker is running and you have sufficient permissions. 4. For permission errors, try: `sudo chown -R $(whoami) ./lib ./node_modules` 5. For path alias issues, rebuild the project: `npm run build` > 📘 **For comprehensive debugging help**, see the [Debugging & Testing Guide](/docs/debugging-testing.md). If problems persist, please open an issue on the GitHub repository. ================================================ FILE: Dockerfile ================================================ FROM node:24-alpine AS build # Copy the source code COPY ./ /tmp/source_code # Install dependencies RUN cd /tmp/source_code && npm install --ignore-scripts # Build the source code RUN cd /tmp/source_code && npm run build # create libraries directory RUN mkdir -p /libraries # Copy the lib, bin, node_modules, and package.json files to the /libraries directory RUN cp -r /tmp/source_code/lib /libraries RUN cp -r /tmp/source_code/assets /libraries RUN cp /tmp/source_code/package.json /libraries RUN cp /tmp/source_code/package-lock.json /libraries RUN cp /tmp/source_code/oclif.manifest.json /libraries # Copy the bin directory to the /libraries directory RUN cp -r /tmp/source_code/bin /libraries # Remove everything inside /tmp RUN rm -rf /tmp/* FROM node:24-alpine # Set ARG to explicit value to build chosen version. Default is "latest" ARG ASYNCAPI_CLI_VERSION= # Create a non-root user RUN addgroup -S myuser && adduser -S myuser -G myuser WORKDIR /app # Since 0.14.0 release of html-template chromium is needed for pdf generation ENV PUPPETEER_EXECUTABLE_PATH /usr/bin/chromium-browser ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD true # Since 0.30.0 release Git is supported and required as a dependency # Since 0.14.0 release of html-template chromium is needed for pdf generation. # More custom packages for specific template should not be added to this dockerfile. Instead, we should come up with some extensibility solution. RUN apk --update add git chromium && \ apk add --no-cache --virtual .gyp python3 make g++ && \ rm -rf /var/lib/apt/lists/* && \ rm /var/cache/apk/* # Copy the libraries directory from the build stage COPY --from=build /libraries /libraries # Install the dependencies RUN cd /libraries && npm install --omit=dev --ignore-scripts # Create a script that runs the desired command RUN ln -s /libraries/bin/run_bin /usr/local/bin/asyncapi # Make the script executable RUN chmod +x /usr/local/bin/asyncapi # Change ownership to non-root user RUN chown -R myuser:myuser /libraries /usr/local/bin/asyncapi || echo "Failed to change ownership" RUN chown -R myuser:myuser /usr/local/lib/node_modules && \ chown -R myuser:myuser /usr/local/bin # Switch to the non-root user USER myuser ENTRYPOINT [ "asyncapi" ] ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ================================================ FILE: NOTICE ================================================ Copyright 2016-2025 AsyncAPI Initiative This product includes software developed at AsyncAPI Initiative (http://www.asyncapi.com/). ================================================ FILE: README.md ================================================ [![AsyncAPI CLI](./assets/logo.png)](https://www.asyncapi.com/tools/cli) CLI to work with your AsyncAPI files. Currently under development, we are working to bring more features. [![GitHub license](https://img.shields.io/github/license/asyncapi/cli)](https://github.com/asyncapi/cli/blob/master/LICENSE) [![PR testing - if Node project](https://github.com/asyncapi/cli/actions/workflows/if-nodejs-pr-testing.yml/badge.svg)](https://github.com/asyncapi/cli/actions/workflows/if-nodejs-pr-testing.yml) [![npm](https://img.shields.io/npm/dw/@asyncapi/cli)](https://www.npmjs.com/package/@asyncapi/cli) ## Table of contents - [Installation](#installation) - [Usage](#usage) - [Architecture](#architecture) - [Debugging & Testing](#debugging--testing) - [Github Action](#github-action) - [Contributing](#contributing) * [Set up development environment](#set-up-development-environment) * [Command Structure and Patterns](#command-structure-and-patterns) - [Contributors](#contributors) ## Installation Learn how to install the AsyncAPI CLI by following the instructions in the [installation guide](/docs/installation.md). ## Usage The [usage guide](/docs/usage.md) provides information about different ways to use the CLI. ## Architecture The [architecture guide](/docs/architecture.md) provides information about the architecture. ## Debugging & Testing The [debugging & testing guide](/docs/debugging-testing.md) provides step-by-step instructions for debugging CLI commands, API endpoints, and services, along with comprehensive testing guidelines. ## 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 Read [CONTRIBUTING](https://github.com/asyncapi/.github/blob/master/CONTRIBUTING.md) guide. ### Set up development environment Read [DEVELOPMENT.md](/DEVELOPMENT.md) file for development setup. Additional steps: - Run `npm run test` to make sure everything is properly set up - Run `npm run build` and then `bin/run` to try new CLI locally The UX developed for the CLI should comply with the [Command Line Interface Guideline](https://clig.dev/) ### Command Structure and Patterns We are following `verb + noun` and `namespace + noun + [verb]` pattern for making our commands and arguments. For example `asyncapi validate ` and `asyncapi config context add `. ## Contributors Thanks go to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
Jorge Aguiar Martín
Jorge Aguiar Martín

💻 🤔 ⚠️ 📖
Lukasz Gornicki
Lukasz Gornicki

🤔 💻 👀 🚧
souvik
souvik

💻 🤔 ⚠️ 👀 🚧 📖
David Boyne
David Boyne

💻 🤔 🚧
Fran Méndez
Fran Méndez

💻 🤔 👀
Maciej Urbańczyk
Maciej Urbańczyk

👀 🚧 🤔
Aayush Kumar Sahu
Aayush Kumar Sahu

💻 ⚠️
Mihir Kulkarni
Mihir Kulkarni

💻
Abir
Abir

⚠️ 💻
Peter Ramos
Peter Ramos

💻
Samriddhi
Samriddhi

⚠️
Pranay Kharabe
Pranay Kharabe

💻
Damilola Oladele
Damilola Oladele

📖
Abhay Garg
Abhay Garg

💻 ⚠️
Sambhav Gupta
Sambhav Gupta

💻 ⚠️
Hippolyte Vergnol
Hippolyte Vergnol

💻 🚇
Jente Vets
Jente Vets

💻
Rishi
Rishi

💻
Ashish Padhy
Ashish Padhy

💻
Meet Agrawal
Meet Agrawal

🚇
Chinmay Shewale
Chinmay Shewale

💻 ⚠️
Mahfuza Humayra Mohona
Mahfuza Humayra Mohona

📖
Heiko Henning
Heiko Henning

💻
Zack_Aayush
Zack_Aayush

💻
Ayush Nautiyal
Ayush Nautiyal

💻
AnishKacham
AnishKacham

💻
Viacheslav Turovskyi
Viacheslav Turovskyi

💻
Amanpreet Singh Bedi
Amanpreet Singh Bedi

💻
Debajyoti Halder
Debajyoti Halder

💻
Savio Dias
Savio Dias

💻
Jonas Lagoni
Jonas Lagoni

💻 🤔 👀 ⚠️
Khuda Dad Nomani
Khuda Dad Nomani

💻 📖
Sergio Moya
Sergio Moya

💻
Vishal Sharma
Vishal Sharma

💻
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! ================================================ FILE: action-template.yml ================================================ 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.' required: false default: '' command: description: 'Command to run. Available commands in action :- generate, validate, convert, optimize and custom. Default is generate. For custom command, provide the whole command as input. List of available commands can be found in https://www.asyncapi.com/docs/tools/cli/usage.' required: false default: 'generate' filepath: description: 'Path to AsyncAPI document. This input is required if command is set to generate, validate, convert or optimize. Default is ./asyncapi.yaml' required: false default: 'asyncapi.yml' template: description: 'Template for the generator. Official templates are listed here https://github.com/search?q=topic%3Aasyncapi+topic%3Agenerator+topic%3Atemplate. You can pass template as npm package, url to git repository, link to tar file or local template.' default: '@asyncapi/markdown-template@2.0.0' required: false language: description: 'Language of the generated code. This input is required if you want to generate models. List of available languages can be found in https://www.asyncapi.com/docs/tools/cli/usage#asyncapi-generate-models-language-file' required: false default: '' output: description: 'Directory where to put the generated files. Can be used only with generate or convert commands. Default is output.' required: false default: 'output' parameters: description: 'The command that you use might support and even require specific parameters to be passed to the CLI for the generation. Template parameters should be preceded by -p' required: false default: '' custom_command: description: 'Custom command to be run. This input is required if command is set to custom.' required: false default: '' 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:${ version }' args: - ${{ inputs.cli_version }} - ${{ inputs.command }} - ${{ inputs.filepath }} - ${{ inputs.template }} - ${{ inputs.language }} - ${{ inputs.output }} - ${{ inputs.parameters }} - ${{ inputs.custom_command }} branding: icon: 'file-text' color: purple ================================================ FILE: action.yml ================================================ 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.' required: false default: '' command: description: 'Command to run. Available commands in action :- generate, validate, convert, optimize and custom. Default is generate. For custom command, provide the whole command as input. List of available commands can be found in https://www.asyncapi.com/docs/tools/cli/usage.' required: false default: 'generate' filepath: description: 'Path to AsyncAPI document. This input is required if command is set to generate, validate, convert or optimize. Default is ./asyncapi.yaml' required: false default: 'asyncapi.yml' template: description: 'Template for the generator. Official templates are listed here https://github.com/search?q=topic%3Aasyncapi+topic%3Agenerator+topic%3Atemplate. You can pass template as npm package, url to git repository, link to tar file or local template.' default: '@asyncapi/markdown-template@2.0.0' required: false language: description: 'Language of the generated code. This input is required if you want to generate models. List of available languages can be found in https://www.asyncapi.com/docs/tools/cli/usage#asyncapi-generate-models-language-file' required: false default: '' output: description: 'Directory where to put the generated files. Can be used only with generate or convert commands. Default is output.' required: false default: 'output' parameters: description: 'The command that you use might support and even require specific parameters to be passed to the CLI for the generation. Template parameters should be preceded by -p' required: false default: '' custom_command: description: 'Custom command to be run. This input is required if command is set to custom.' required: false default: '' 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:6.0.0' args: - ${{ inputs.cli_version }} - ${{ inputs.command }} - ${{ inputs.filepath }} - ${{ inputs.template }} - ${{ inputs.language }} - ${{ inputs.output }} - ${{ inputs.parameters }} - ${{ inputs.custom_command }} branding: icon: 'file-text' color: purple ================================================ FILE: assets/create-template/templates/default/asyncapi.yaml ================================================ asyncapi: 3.1.0 info: title: Temperature Service version: 1.0.0 description: This service is in charge of processing all the events related to temperature. servers: dev: url: test.mosquitto.org protocol: mqtt channels: temperature/changed: description: Updates the bedroom temperature in the database when the temperature drops or goes up. publish: operationId: temperatureChange message: description: Message that is being sent when the temperature in the bedroom changes. contentType: application/json payload: type: object additionalProperties: false properties: temperatureId: type: string components: schemas: temperatureId: type: object additionalProperties: false properties: temperatureId: type: string ================================================ FILE: assets/create-template/templates/default/package.json ================================================ { "name": "myTemplate", "generator": { "renderer": "react", "supportedProtocols": [] }, "dependencies": { "@asyncapi/generator-react-sdk": "^1.1.2" } } ================================================ FILE: assets/create-template/templates/default/readme.md ================================================ ### First install all the dependencies for template using below command: npm install ### Run the template using for a specific asyncapi document asyncapi generate fromTemplate ../asyncapi-template ================================================ FILE: assets/create-template/templates/default/template/index.js ================================================ import { File, Text } from '@asyncapi/generator-react-sdk'; // Pass the others parameters to get the specificatin of the asyncapi document export default function ({ asyncapi }) { return ( My application's markdown file. App name: **{asyncapi.info().title()}** ); } ================================================ FILE: assets/examples/default-example.json ================================================ { "asyncapi": "3.1.0", "info": { "title": "Account Service", "version": "1.0.0", "description": "This service is in charge of processing user signups" }, "channels": { "userSignedUp": { "address": "user/signedup", "messages": { "UserSignedUp": { "$ref": "#/components/messages/UserSignedUp" } } } }, "operations": { "onUserSignUp": { "action": "receive", "channel": { "$ref": "#/channels/userSignedUp" }, "messages": [ { "$ref": "#/channels/userSignedUp/messages/UserSignedUp" } ] } }, "components": { "messages": { "UserSignedUp": { "payload": { "type": "object", "properties": { "displayName": { "type": "string", "description": "Name of the user" }, "email": { "type": "string", "format": "email", "description": "Email of the user" } } } } } } } ================================================ FILE: assets/examples/default-example.yaml ================================================ asyncapi: 3.1.0 info: title: Account Service version: 1.0.0 description: This service is in charge of processing user signups channels: userSignedUp: address: user/signedup messages: UserSignedUp: $ref: '#/components/messages/UserSignedUp' operations: onUserSignUp: action: receive channel: $ref: '#/channels/userSignedUp' messages: - $ref: '#/channels/userSignedUp/messages/UserSignedUp' components: messages: UserSignedUp: payload: type: object properties: displayName: type: string description: Name of the user email: type: string format: email description: Email of the user ================================================ FILE: bin/dev ================================================ #!/usr/bin/env node const oclif = require('@oclif/core') const path = require('path') const project = path.join(__dirname, '..', 'tsconfig.json') // In dev mode -> use ts-node and dev plugins process.env.NODE_ENV = 'development' require('ts-node').register({project}) // In dev mode, always show stack traces oclif.settings.debug = true; // Start the CLI oclif.run().then(oclif.flush).catch(oclif.Errors.handle) ================================================ FILE: bin/dev.cmd ================================================ @echo off node "%~dp0\dev" %* ================================================ FILE: bin/run ================================================ #!/usr/bin/env node process.env.NODE_ENV = 'development'; const oclif = require('@oclif/core'); oclif.run() .then(require('@oclif/core/flush')) .catch((err) => { const { handle } = require('@oclif/core/handle'); return handle(err); }); ================================================ FILE: bin/run.cmd ================================================ @echo off node "%~dp0\run" %* ================================================ FILE: bin/run_bin ================================================ #!/usr/bin/env node // Only the binary installed through NPM is considered production environment. See "bin" in package.json. process.env.NODE_ENV = 'production'; const oclif = require('@oclif/core'); oclif.run() .then(require('@oclif/core/flush')) .catch((err) => { const { handle } = require('@oclif/core/handle'); return handle(err); }); ================================================ FILE: bin/run_bin.cmd ================================================ @echo off node "%~dp0\run_bin" %* ================================================ FILE: docs/architecture.md ================================================ --- title: 'CLI Architecture' weight: 40 --- # CLI Architecture ## Overview The AsyncAPI CLI is built with [oclif](https://oclif.io/) and provides both command-line operations and a REST API server for working with AsyncAPI specifications. --- ## Architecture Diagram ``` ┌─────────────────────────────────────────────────┐ │ Entry Points │ │ ┌──────────┐ ┌──────────┐ │ │ │ CLI │ │ API │ │ │ │ (oclif) │ │ (Express)│ │ │ └────┬─────┘ └────┬─────┘ │ └───────┼─────────────────────────┼───────────────┘ └───────────┬─────────────┘ ▼ ┌───────────────────────┐ │ Domain Services │ │ Validation, Generator│ │ Convert, Config │ └───────────┬───────────┘ ▼ ┌───────────────────────┐ │ Domain Models │ │ Specification,Context│ └───────────┬───────────┘ ▼ ┌───────────────────────┐ │ Utilities │ │ Logger, Helpers │ └───────────────────────┘ ``` --- ## Directory Structure ``` src/ ├── apps/ │ ├── cli/ # CLI commands & internals │ └── api/ # REST API (Express) ├── domains/ │ ├── models/ # Specification, Context │ └── services/ # Business logic ├── errors/ # Custom errors ├── interfaces/ # TypeScript types └── utils/ # Utilities ``` --- ## Core Components ### CLI Application | Component | Description | |-----------|-------------| | **Entry Points** | `bin/run` (dev), `bin/run_bin` (prod) | | **Base Command** | Metrics, parser integration, error handling | **Commands:** - **Core:** `validate`, `convert`, `format`, `optimize`, `diff`, `bundle` - **Generation:** `generate client`, `generate models`, `generate fromTemplate` - **Config:** `config context`, `config analytics`, `config versions` - **Utility:** `new file`, `new template`, `start api|studio|preview`, `pretty` ### API Server **Endpoints:** `/v1/validate`, `/v1/parse`, `/v1/generate`, `/v1/convert`, `/v1/bundle`, `/v1/diff`, `/v1/docs`, `/v1/help`, `/v1/version` **Features:** Express with Helmet security, CORS, compression, RFC 7807 error responses ### Domain Services All services extend `BaseService` and return `ServiceResult`: | Service | Purpose | |---------|---------| | `ValidationService` | Validates specs with Spectral, calculates scores | | `GeneratorService` | Generates code/models | | `ConvertService` | Converts between AsyncAPI/OpenAPI formats | | `ConfigService` | Manages CLI config and contexts | | `ArchiverService` | Creates ZIP archives | ### Domain Models | Model | Purpose | |-------|---------| | **Specification** | Loads from file, URL, or context; auto-detects `asyncapi.json\|yml\|yaml` | | **Context** | Manages multiple AsyncAPI contexts; stored in `~/.asyncapi/` | ### Error Classes `ContextError`, `SpecificationFileError`, `ValidationError`, `GeneratorError`, `DiffError` --- ## Execution Flow **CLI Command:** ``` User Command → oclif → Base Command → Domain Service → ServiceResult ``` **API Request:** ``` HTTP Request → Express → Controller → Domain Service → HTTP Response ``` --- ## Extension Points | Add | Steps | |-----|-------| | **New Command** | Create in `src/apps/cli/commands/`, extend `Command`, implement `run()` | | **New API Endpoint** | Create controller in `src/apps/api/controllers/`, register in `index.ts` | | **New Service** | Create in `src/domains/services/`, extend `BaseService`, return `ServiceResult` | --- ## Configuration | Config | Location | |--------|----------| | CLI Context | `~/.asyncapi/contexts.json`, `~/.asyncapi/.current` | | Analytics | `~/.asyncapi-analytics` | **Environment Variables:** - `NODE_ENV` — `development` | `production` | `test` - `PORT` — API server port (default: 3000) - `ASYNCAPI_METRICS_*` — Metrics configuration --- ## Technology Stack | Category | Technologies | |----------|--------------| | **Core** | oclif, TypeScript, Express | | **AsyncAPI** | @asyncapi/parser, generator, converter, bundler, diff, optimizer | | **Supporting** | winston, ajv, chalk, @clack/prompts | ================================================ FILE: docs/autocompleteEnabled.md ================================================ --- title: 'Auto-complete setup' weight: 30 --- # AsyncAPI CLI Autocomplete Setup This guide provides steps to enable autocomplete for the AsyncAPI CLI. The setup supports `zsh`, `bash`, and `PowerShell` (manual setup only). ## Automatic Setup (Post-Install Script) The AsyncAPI CLI includes a post-install script that automatically configures autocomplete for supported shells (`zsh` and `bash`). No additional steps are required. ### Steps: 1. Ensure that AsyncAPI CLI is installed. You can verify by running: ```sh asyncapi --version ``` If the command fails, install it using: ```sh npm install -g @asyncapi/cli ``` 2. Apply the changes by running: ```sh source ~/.bashrc # For bash source ~/.zshrc # For zsh ``` 3. Verify autocomplete by typing: ```sh asyncapi ``` You should see command suggestions. ## Manual Setup (For PowerShell and Troubleshooting) If the automatic setup does not work or if you need to enable autocomplete manually (especially for PowerShell), follow these steps. ### Steps: 1. **Build the AsyncAPI CLI manually:** If you are working with the CLI project locally, you need to build it first: ```sh npm install npm run build ``` 2. **Run the autocomplete command manually:** ```sh ./bin/run autocomplete # Run this from the project root folder ``` 3. **Locate the AsyncAPI CLI executable:** Run the following command to find the executable path: ```sh which asyncapi # For bash/zsh Get-Command asyncapi | Select-Object -ExpandProperty Definition # For PowerShell ``` If the command does not return a path, ensure AsyncAPI CLI is installed. 4. **Generate and apply the autocomplete script:** Run the following command based on your shell: ```sh printf "$(./bin/run autocomplete script bash)" >> ~/.bashrc; source ~/.bashrc # For bash printf "$(./bin/run autocomplete script zsh)" >> ~/.zshrc; source ~/.zshrc # For zsh printf "$(./bin/run autocomplete script powershell)" >> $PROFILE; . $PROFILE # For PowerShell ``` 5. **Test autocomplete:** ```sh asyncapi ``` If it works, autocomplete is successfully enabled! --- If you encounter any issues, ensure that your shell configuration file is correctly updated and sourced. Restart your terminal if necessary. ================================================ FILE: docs/context.md ================================================ --- title: 'Context concept' weight: 60 --- ## Overview AsyncAPI CLI provides functionality called `context`. It's purpose is to help to work with AsyncAPI CLI in large projects where you do not have just one service exposing AsyncAPI document, but multiple. Event driven architecture involves multiple actors, subscribers and publishers. One time you want to validate document **A** and the other time you want to generate models from document **B**. Every time you do it, you need to provide to AsyncAPI CLI the location of the AsyncAPI document, which might be time consuming. You can workaround it with aliases in bash profiles or with other solutions but it is better to use `context` feature, as you can then store it in your repository and share with other team members. In short it means that for example instead of writing `asyncapi validate /some/folder/my-asyncapi.yml` you can create a context called `myasync` that will be an alias for and point to `/some/folder/my-asyncapi.yml`. This way next time you use the CLI you can do `asyncapi validate myasync`. ## Context File location You can have a global context for your workstation, and a project specific context. If your use case is that you work with multiple repositories, you might want to use a global context. The `.asyncapi-cli` context file is then located in your home directory. You can also store your custom `.asyncapi-cli` file in your project with custom configuration. This way when you run `asyncapi config context add` inside your project, the new context is added to the context file under your project. ## How to add context to a project ### Manually - Create file `.asyncapi-cli` containing [minimal empty context file](#minimalEmptyContextFile) in: - current directory - root of current repository - user's home directory ### Using CLI's `init` command `asyncapi config context init [CONTEXT-FILE-PATH]` Where `[CONTEXT-FILE-PATH]` instructs CLI what directory should the file `.asyncapi-cli` containing [minimal empty context file](#minimalEmptyContextFile) be created in: - current directory: `asyncapi config context init .` (default) - root of current repository: `asyncapi config context init ./` - user's home directory: `asyncapi config context init ~` (if `[CONTEXT-FILE-PATH]` is omitted, empty context file is created in current directory) Make use of newly created `.asyncapi-cli` by executing command: `asyncapi config context add [CONTEXT-NAME] [SPEC-FILE-PATH]` ### Setup example in a real project Below you can see an example of context setup for [Event Driven Flight status notification service](https://github.com/amadeus4dev-examples/amadeus-async-flight-status/tree/ff433b6d320a3a6a2499976cbf0782353bc57c16) of the [Amadeus Airline Platform](https://amadeus.com/en/industries/airlines/airline-platform), with multiple microservices and their AsyncAPI documents. ```bash # One-time initialization of '.asyncapi-cli' file (main)$ asyncapi config context init Initialized context /amadeus-async-flight-status/.asyncapi-cli # Adding first context (main)$ asyncapi config context add subscriber subscriber/asyncapi.yaml Added context "subscriber". You can set it as your current context: asyncapi config context use subscriber You can use this context when needed by passing subscriber as a parameter: asyncapi validate subscriber # Adding more contexts (main)$ asyncapi config context add notifier notifier/asyncapi.yaml Added context "notifier". You can set it as your current context: asyncapi config context use notifier You can use this context when needed by passing notifier as a parameter: asyncapi validate notifier (main)$ asyncapi config context add monitor monitor/asyncapi.yaml Added context "monitor". You can set it as your current context: asyncapi config context use monitor You can use this context when needed by passing monitor as a parameter: asyncapi validate monitor # Setting monitor as default context (main)$ asyncapi config context use monitor monitor is set as current # Now you do not even have to remember the context name, and default 'monitor/asyncapi.yaml' will be validated (main)$ asyncapi validate File monitor/asyncapi.yaml is valid but has (itself and/or referenced documents) governance issues. monitor/asyncapi.yaml 1:1 warning asyncapi-defaultContentType AsyncAPI document should have "defaultContentType" field. 1:1 warning asyncapi-id AsyncAPI document should have "id" field. 1:1 warning asyncapi2-tags AsyncAPI object should have non-empty "tags" array. 1:11 information asyncapi-latest-version The latest version of AsyncAPi is not used. It is recommended update to the "2.6.0" version. asyncapi 2:6 warning asyncapi-info-contact Info object should have "contact" object. info 19:15 warning asyncapi2-operation-operationId Operation should have an "operationId" field defined. channels.flight/update.subscribe 26:13 warning asyncapi2-operation-operationId Operation should have an "operationId" field defined. channels.flight/queue.publish ✖ 7 problems (0 errors, 6 warnings, 1 info, 0 hints) # You can now use context name when running AsyncAPI commands, no need to remember file location like 'notifier/asyncapi.yaml' (main)$ asyncapi validate notifier File notifier/asyncapi.yaml is valid but has (itself and/or referenced documents) governance issues. notifier/asyncapi.yaml 1:1 warning asyncapi-defaultContentType AsyncAPI document should have "defaultContentType" field. 1:1 warning asyncapi-id AsyncAPI document should have "id" field. 1:1 warning asyncapi2-tags AsyncAPI object should have non-empty "tags" array. 1:11 information asyncapi-latest-version The latest version of AsyncAPi is not used. It is recommended update to the "2.6.0" version. asyncapi 2:6 warning asyncapi-info-contact Info object should have "contact" object. info 18:13 warning asyncapi2-operation-operationId Operation should have an "operationId" field defined. channels.flight/update.publish ✖ 6 problems (0 errors, 5 warnings, 1 info, 0 hints) # Switch default context (main)$ asyncapi config context use notifier notifier is set as current # List all contexts (main)$ asyncapi config context list monitor: monitor/asyncapi.yaml notifier: notifier/asyncapi.yaml subscriber: subscriber/asyncapi.yaml ``` ## Context File structure ### Fixed Fields Field Name | Type | Description ---|:---:|--- current | `string` | An optional string value representing one of context names, which is used as default in CLI. Default means you can run CLI commands without providing context name, like `asyncapi validate`, and it will run against the default - `current` - context. store | [Store Object](#storeObject) | **REQUIRED**. Map of filesystem paths to target AsyncAPI documents. ### Store Object Map of filesystem paths to target AsyncAPI documents. **Patterned Fields** Field Pattern | Type | Description ---|:---:|--- \{contextName\} | `string` | An optional string value representing filesystem path to the target AsyncAPI document. ### Minimal Empty Context File Raw JSON: ``` { "store": {} } ``` Stringified JSON: ``` {"store":{}} ``` ### Context File Example Example of a context file for [Event Driven Flight status notification service](https://github.com/amadeus4dev-examples/amadeus-async-flight-status/tree/ff433b6d320a3a6a2499976cbf0782353bc57c16) of the [Amadeus Airline Platform](https://amadeus.com/en/industries/airlines/airline-platform), with multiple microservices and their AsyncAPI documents: ``` { "current": "monitor", "store": { "monitor": "monitor/asyncapi.yaml", "notifier": "notifier/asyncapi.yaml", "subscriber": "subscriber/asyncapi.yaml" } } ``` ## More context related CLI options All commands for managing contexts are available under `asyncapi config context` [CLI commands group](usage#asyncapi-config-context). ================================================ FILE: docs/contributing-prs.md ================================================ --- title: 'Contributing via Pull Requests' weight: 50 --- # Contributing via Pull Requests ## Getting Started 1. **Open an issue first** (unless it's a trivial fix) 2. **Set up environment** — Follow [DEVELOPMENT.md](../DEVELOPMENT.md) 3. **Create a branch** — Use prefixes: `feat/`, `fix/`, `docs/`, `refactor/`, `test/`, `chore/` --- ## PR Title Format Follow [Conventional Commits](https://www.conventionalcommits.org/): | Type | Description | Release | |------|-------------|---------| | `feat:` | New feature | MINOR | | `fix:` | Bug fix | PATCH | | `docs:` | Documentation | None | | `chore:` | Maintenance | None | | `test:` | Tests only | None | | `refactor:` | Code refactoring | None | **Breaking changes:** Add `!` → `feat!:`, `fix!:` **Examples:** - ✅ `feat: add AsyncAPI 3.0 validation support` - ✅ `fix: resolve context loading with special characters` - ❌ `Added new feature` - ❌ `fix bug` --- ## PR Checklist **Before submitting:** - [ ] Branch synced with `main` - [ ] `npm run build` passes - [ ] `npm run cli:test` passes - [ ] `npm run lint` passes (max 5 warnings) - [ ] Documentation updated (if needed) **Code quality:** - [ ] Follows existing code patterns - [ ] TypeScript types used (avoid `any`) - [ ] Error handling implemented - [ ] Tests added for new functionality - [ ] No `console.log` or commented code --- ## Code Standards | Area | Guideline | |------|-----------| | **TypeScript** | Explicit types, interfaces for objects, prefer `const` | | **Organization** | Follow existing structure, use path aliases (`@/`, `@cli/`, `@domains/`) | | **Errors** | Use custom errors from `src/errors/`, return `ServiceResult` from services | | **Commands** | Extend base `Command`, use domain services for business logic | --- ## Testing **Add tests for:** - New commands or API endpoints - Bug fixes (regression tests) - New domain services - Complex business logic ```bash npm run cli:test # All tests npm run unit:test # Unit tests only ``` --- ## Best Practices | ❌ Avoid | ✅ Do | |----------|-------| | Large PRs (>500 lines) | Small, focused PRs | | Multiple concerns in one PR | One issue per PR | | Skipping tests | Comprehensive tests | | Hardcoded values | Externalize configuration | | Force push to main | Rebase instead of merge | --- ## Review Process 1. CI runs automated checks 2. Maintainers review code 3. Address feedback promptly 4. PR merged when approved --- ## Quick Reference ```bash # Setup npm install && npx lefthook install # Before PR npm run build && npm run lint && npm run cli:test ``` **Quality over speed** — Write good code, tests, and documentation. ================================================ FILE: docs/debugging-testing.md ================================================ --- title: 'Debugging & Testing Guide' weight: 60 --- # Debugging & Testing Guide This guide provides step-by-step instructions for debugging and testing the AsyncAPI CLI. Whether you're fixing a bug, adding a new feature, or understanding existing code, this document will help you navigate the debugging process effectively. ## Table of Contents - [Project Structure Overview](#project-structure-overview) - [Setting Up Your Environment](#setting-up-your-environment) - [Debugging CLI Commands](#debugging-cli-commands) - [Debugging the API Server](#debugging-the-api-server) - [Debugging Services](#debugging-services) - [Writing Tests](#writing-tests) - [Running Tests](#running-tests) - [Common Issues & Solutions](#common-issues--solutions) - [Debugging Tools & Tips](#debugging-tools--tips) --- ## Project Structure Overview Understanding the codebase structure is essential for effective debugging: ``` src/ ├── apps/ │ ├── api/ # REST API server (Express.js) │ │ ├── controllers/ # API endpoint handlers │ │ ├── middlewares/ # Request/response middleware │ │ └── exceptions/ # API error types │ └── cli/ # CLI application (oclif) │ ├── commands/ # CLI command implementations │ └── internal/ # Shared CLI utilities, flags, base classes ├── domains/ │ ├── models/ # Domain models (SpecificationFile, Context, etc.) │ └── services/ # Business logic services ├── errors/ # Custom error classes ├── utils/ # Utility functions └── interfaces/ # TypeScript interfaces test/ ├── fixtures/ # Test data files (AsyncAPI specs, etc.) ├── helpers/ # Test utilities ├── integration/ # Integration tests for CLI commands └── unit/ # Unit tests for services and controllers ├── controllers/ # API controller tests ├── services/ # Service layer tests └── utils/ # Utility function tests ``` --- ## Setting Up Your Environment ### 1. Install Dependencies ```bash npm install ``` ### 2. Build the Project ```bash npm run build ``` ### 3. Set Up Environment Variables for Debugging Create a `.env` file or export variables: ```bash # Enable development mode (verbose logging) export NODE_ENV=development # Disable analytics during testing export TEST=1 # Set custom context file for testing export CUSTOM_CONTEXT_FILENAME="test.asyncapi-cli" export CUSTOM_CONTEXT_FILE_LOCATION="" ``` --- ## Debugging CLI Commands ### Method 1: Using `bin/run` (Development Mode) The `bin/run` script runs the CLI in development mode with TypeScript directly: ```bash # Run any command with debugging ./bin/run validate ./path/to/asyncapi.yml # With verbose output DEBUG=* ./bin/run validate ./path/to/asyncapi.yml ``` ### Method 2: Using Node.js Inspector ```bash # Start with Node inspector node --inspect-brk ./bin/run validate ./path/to/asyncapi.yml # Then open Chrome DevTools at: chrome://inspect ``` ### Method 3: VS Code Debugging Create `.vscode/launch.json`: ```json { "version": "0.2.0", "configurations": [ { "type": "node", "request": "launch", "name": "Debug CLI Command", "program": "${workspaceFolder}/bin/run", "args": ["validate", "./test/fixtures/specification.yml"], "env": { "NODE_ENV": "development", "TEST": "1" }, "sourceMaps": true, "outFiles": ["${workspaceFolder}/lib/**/*.js"] }, { "type": "node", "request": "launch", "name": "Debug Current Test File", "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", "args": [ "--require", "ts-node/register", "--require", "tsconfig-paths/register", "--timeout", "100000", "${file}" ], "env": { "NODE_ENV": "development", "TEST": "1", "CUSTOM_CONTEXT_FILENAME": "test.asyncapi-cli" }, "sourceMaps": true } ] } ``` ### Method 4: Adding Console Logs For quick debugging, add logs in command files: ```typescript // In src/apps/cli/commands/validate.ts async run() { const { args, flags } = await this.parse(Validate); // Debug: Log parsed arguments console.log('DEBUG - Args:', JSON.stringify(args, null, 2)); console.log('DEBUG - Flags:', JSON.stringify(flags, null, 2)); // ... rest of the command } ``` --- ## Debugging the API Server ### Starting the API in Development Mode ```bash # Start with hot-reload npm run api:dev # Or manually with debugging NODE_ENV=development DEBUG=* node ./lib/apps/api/server.js ``` ### Testing API Endpoints ```bash # Validate endpoint curl -X POST http://localhost:3000/v1/validate \ -H "Content-Type: application/json" \ -d '{"asyncapi": "asyncapi: 3.1.0\ninfo:\n title: Test\n version: 1.0.0\nchannels: {}"}' # Parse endpoint curl -X POST http://localhost:3000/v1/parse \ -H "Content-Type: application/json" \ -d '{"asyncapi": "..."}' ``` ### Debugging API Controllers Add middleware logging: ```typescript // In src/apps/api/middlewares/logger.middleware.ts // Logs are automatically enabled in development mode ``` --- ## Debugging Services ### ValidationService The `ValidationService` handles document validation. To debug: ```typescript // Test the service directly import { ValidationService } from '@services/validation.service'; import { load } from '@models/SpecificationFile'; async function debugValidation() { const service = new ValidationService(); const specFile = await load('./path/to/spec.yml'); const result = await service.validateDocument(specFile, { 'fail-severity': 'error', 'log-diagnostics': true, }); console.log('Validation Result:', JSON.stringify(result, null, 2)); } ``` ### ConversionService ```typescript import { ConversionService } from '@services/convert.service'; import { load } from '@models/SpecificationFile'; async function debugConversion() { const service = new ConversionService(); const specFile = await load('./path/to/spec.yml'); const result = await service.convertDocument(specFile, { format: 'asyncapi', 'target-version': '3.0.0', perspective: 'server', }); console.log('Conversion Result:', JSON.stringify(result, null, 2)); } ``` ### GeneratorService ```typescript import { GeneratorService } from '@services/generator.service'; async function debugGenerator() { const service = new GeneratorService(); // Add your debugging logic } ``` --- ## Writing Tests ### Test File Naming Convention - Unit tests: `test/unit//.test.ts` - Integration tests: `test/integration/.test.ts` ### Unit Test Structure ```typescript // test/unit/services/my-service.test.ts import { expect } from 'chai'; import { MyService } from '../../../src/domains/services/my.service'; describe('MyService', () => { let service: MyService; beforeEach(() => { service = new MyService(); }); describe('methodName', () => { it('should do something when given valid input', async () => { // Arrange const input = { /* test data */ }; // Act const result = await service.methodName(input); // Assert expect(result.success).to.be.true; expect(result.data).to.exist; }); it('should handle errors gracefully', async () => { // Arrange const invalidInput = null; // Act const result = await service.methodName(invalidInput); // Assert expect(result.success).to.be.false; expect(result.error).to.include('error message'); }); }); }); ``` ### Integration Test Structure (CLI Commands) ```typescript // test/integration/mycommand.test.ts import { expect, test } from '@oclif/test'; import path from 'path'; const validSpec = path.resolve(__dirname, '../fixtures/specification.yml'); const invalidSpec = path.resolve(__dirname, '../fixtures/specification-invalid.yml'); describe('mycommand', () => { describe('with valid input', () => { test .stdout() .command(['mycommand', validSpec]) .it('should succeed with valid specification', (ctx) => { expect(ctx.stdout).to.contain('Success'); }); }); describe('with invalid input', () => { test .stderr() .command(['mycommand', invalidSpec]) .exit(1) .it('should fail with invalid specification', (ctx) => { expect(ctx.stderr).to.contain('Error'); }); }); describe('with flags', () => { test .stdout() .command(['mycommand', validSpec, '--output', 'result.json']) .it('should handle output flag', (ctx) => { expect(ctx.stdout).to.contain('saved'); }); }); }); ``` ### API Controller Test Structure ```typescript // test/unit/controllers/my.controller.test.ts import request from 'supertest'; import { App } from '../../../src/apps/api/app'; import { MyController } from '../../../src/apps/api/controllers/my.controller'; describe('MyController', () => { let app: App; beforeEach(async () => { app = new App([new MyController()]); await app.init(); }); describe('[POST] /v1/myendpoint', () => { it('should return 200 with valid input', async () => { return request(app.getServer()) .post('/v1/myendpoint') .send({ data: 'valid' }) .expect(200) .then((response) => { expect(response.body).to.have.property('result'); }); }); it('should return 422 with invalid input', async () => { return request(app.getServer()) .post('/v1/myendpoint') .send({}) .expect(422); }); }); }); ``` ### Using Test Fixtures ```typescript import path from 'path'; import { load } from '@models/SpecificationFile'; // Load test fixtures const fixturesPath = path.resolve(__dirname, '../../fixtures'); async function loadTestSpec(filename: string) { return load(path.join(fixturesPath, filename)); } // Usage in tests describe('MyTest', () => { it('should handle v3 spec', async () => { const spec = await loadTestSpec('specification-v3.yml'); // ... test logic }); }); ``` --- ## Running Tests ### Run All Tests ```bash npm test ``` ### Run Only CLI Tests ```bash npm run cli:test ``` ### Run Only Unit Tests ```bash npm run unit:test ``` ### Run a Single Test File ```bash npm run test:one -- test/integration/validate.test.ts ``` ### Run Tests with Coverage ```bash npm run cli:test # Coverage report is generated in ./coverage/ ``` ### Run Tests in Watch Mode (Development) ```bash # Using nodemon for file watching npm run dev # Then run tests manually when needed npm run unit:test ``` --- ## Common Issues & Solutions ### Issue 1: "Cannot find module '@utils/proxy'" **Cause:** TypeScript path aliases not resolved. **Solution:** ```bash # Rebuild the project npm run build ``` ### Issue 2: Permission Denied Errors **Cause:** Files created by root or different user. **Solution:** ```bash # Fix permissions sudo chown -R $(whoami) ./lib ./node_modules ./.nyc_output ``` ### Issue 3: Test Context File Conflicts **Cause:** Tests using the same context file as development. **Solution:** ```bash # Set test-specific context file export CUSTOM_CONTEXT_FILENAME="test.asyncapi-cli" export CUSTOM_CONTEXT_FILE_LOCATION="" ``` ### Issue 4: "ECONNREFUSED" in API Tests **Cause:** API server not started or wrong port. **Solution:** ```bash # Ensure the app is initialized in tests const app = new App([new MyController()]); await app.init(); // Don't forget this! ``` ### Issue 5: Async Test Timeouts **Cause:** Default timeout too short for async operations. **Solution:** ```typescript // Increase timeout for specific tests it('should handle slow operation', async function() { this.timeout(30000); // 30 seconds // ... test logic }); ``` ### Issue 6: ESLint Errors in Tests **Cause:** Using testing patterns that trigger lint rules. **Solution:** ```typescript // Add eslint disable for specific patterns /* eslint-disable @typescript-eslint/no-unused-expressions */ expect(result).to.be.true; // Chai assertions ``` --- ## Debugging Tools & Tips ### 1. Enable Verbose Logging ```bash DEBUG=* ./bin/run validate spec.yml ``` ### 2. Use Node.js Inspector ```bash node --inspect-brk ./bin/run validate spec.yml # Open chrome://inspect in Chrome ``` ### 3. Print Stack Traces ```typescript try { // risky operation } catch (error) { console.error('Stack trace:', error.stack); throw error; } ``` ### 4. Use TypeScript Source Maps Ensure `tsconfig.json` has: ```json { "compilerOptions": { "sourceMap": true } } ``` ### 5. Debug Parser Output ```typescript import { Parser } from '@asyncapi/parser'; const parser = new Parser(); const { document, diagnostics } = await parser.parse(specContent); console.log('Parsed document:', JSON.stringify(document?.json(), null, 2)); console.log('Diagnostics:', JSON.stringify(diagnostics, null, 2)); ``` ### 6. Inspect Service Results All services return a `ServiceResult` type: ```typescript interface ServiceResult { success: boolean; data?: T; error?: string; } // Always check both success and data if (result.success && result.data) { console.log('Success:', result.data); } else { console.log('Error:', result.error); } ``` ### 7. Test Commands Interactively ```bash # Build and run immediately npm run build && ./bin/run validate ./test/fixtures/specification.yml ``` --- ## Quick Reference | Task | Command | |------|---------| | Build project | `npm run build` | | Run all tests | `npm test` | | Run CLI tests | `npm run cli:test` | | Run unit tests | `npm run unit:test` | | Run single test | `npm run test:one -- ` | | Lint code | `npm run lint` | | Fix lint issues | `npm run lint:fix` | | Start API dev server | `npm run api:dev` | | Debug CLI command | `./bin/run ` | | Debug with inspector | `node --inspect-brk ./bin/run ` | --- ## Getting Help If you're still stuck: 1. Check existing tests for similar functionality 2. Look at the error messages and stack traces 3. Search for similar issues in the [GitHub Issues](https://github.com/asyncapi/cli/issues) 4. Ask in the [AsyncAPI Slack](https://asyncapi.com/slack-invite) `#tooling` channel ================================================ FILE: docs/github-action.md ================================================ --- 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@2.0.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@2.0.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. ================================================ FILE: docs/index.md ================================================ --- title: 'Introduction' weight: 20 --- The AsyncAPI CLI is a command-line tool that provides a set of commands for working with AsyncAPI documents. AsyncAPI is a specification for describing asynchronous APIs, which allows developers to define the structure of messages exchanged between different parts of their applications. The AsyncAPI CLI simplifies creating, validating, bundling, and manipulating AsyncAPI documents, making it easier to work with asynchronous APIs. ## Features The AsyncAPI CLI offers the following key features: * Creation: New AsyncAPI documents can be created from scratch using the CLI, which is useful when starting a new project or creating a new version of an existing API. * Validation: AsyncAPI documents can be quickly and easily validated using the [AsyncAPI Parser](https://github.com/asyncapi/parser-js), which ensures that the documents conform to the AsyncAPI specification and catches errors early in the development process. * Conversion: The AsyncAPI CLI can convert AsyncAPI documents from one version to another, which is helpful for migrating APIs to a newer version of the AsyncAPI specification. * Difference: The AsyncAPI CLI can be used to find the differences between two AsyncAPI documents, which helps compare different versions of an API or identify changes made to an API. * Generation: The AsyncAPI CLI leverages AsyncAPI libraries like [Generator](https://github.com/asyncapi/generator) and [Modelina](https://github.com/asyncapi/modelina), which allow you to generate various types of documentation, applications, and models in different programming languages. This feature can save significant time and effort when creating new APIs. * Optimize: Using [Optimizer](https://github.com/asyncapi/optimizer/), the AsyncAPI CLI can be used to optimize an AsyncAPI specification file which can optimize the structure of the AsyncAPI document to make it smaller and without repetition. * Start: The AsyncAPI CLI can be used to start [AsyncAPI Studio](https://studio.asyncapi.com/) locally, which the user can use to view, edit, and test AsyncAPI documents. To summarize, the AsyncAPI CLI offers the following features and process flow, as shown in the diagram below: ```mermaid graph TD; A[AsyncAPI Document] B[Creation] J[Studio - Editor] I[Optimization] D[Validation] C[Generation] F[Apps/Docs] G[Models] H[Diff] K[Bundling] E[Conversion] A-->B; A-->D; A-->C; C-->F C-->G A-->H; A-->I; A-->J; A-->E; A-->K; ``` ## CLI flow The following flowchart illustrates the process flow of the AsyncAPI CLI: ```mermaid graph TD; A[Start] --> B[User runs the AsyncAPI CLI] B --> C[User issues a command] C --> D[CLI processes the command and runs the corresponding operation] D --> |Is the operation successful?| E{Yes} D --> |Is the operation recoverable?| F{Yes} E --> G[CLI returns the results of the operation to the user] F --> |Operation Error| H[CLI displays an error message and suggests possible next steps] G --> J[User receives the results] H --> I[User follows suggested steps to recover] I --> C[User reissues the corrected command] J[User terminates the AsyncAPI CLI] --> K[End] ``` This flowchart shows the high-level process that occurs when using the AsyncAPI CLI. The user starts by running a command (such as `validate`, `generate`, or `start`), which the CLI processes. The CLI then performs the corresponding operation (such as validating or generating an AsyncAPI document) and returns the results to the user. If an error occurs, the CLI displays an error message and suggests possible next steps for the user. ================================================ FILE: docs/installation.md ================================================ --- title: 'Installation guide' weight: 20 --- ## Node and npm To use the AsyncAPI CLI tool, you must install NPM and Node.js version 16 or higher. To check if you already have both installed, run the following commands in your terminal: ```sh # check if node is installed node -v # or node --version # check if NPM is installed npm -v # or npm --version ``` If you don’t have Node.js or NPM installed, you can install both with this [Node.js package manager](https://nodejs.org/en/download/package-manager/). After installing Node.js and NPM, run the following command to install the AsyncAPI ClI globally: ```sh npm install -g @asyncapi/cli ``` To enable the autocomplete feature in the CLI for the shells **bash and zshrc**, there is a script that will run automatically and autocomplete is only support for **bash and zshrc** for the **powershell** refer to manually enabling [autocomplete](https://www.asyncapi.com/docs/tools/cli/autocompleteEnabled) guide in ClI: After the ClI installation : if the configuration is not present logs will be: ```sh ✅ Autocomplete configuration added to .zshrc. ``` If the configuration is present for autocomplete logs: ```sh ✅ Autocomplete is already configured. Skipping addition. ``` To refresh the variables: ```sh source ~/.bashrc # For bash source ~/.zshrc # For zsh ``` ## Docker Install [Docker](https://docs.docker.com/get-docker/) first, then use docker to build the image using the following command : ``` docker build -t asyncapi/cli:latest . ``` and run the image using the following command : ```bash docker run --rm -it \ --user=root \ -v [ASYNCAPI SPEC FILE LOCATION]:/app/asyncapi.yml \ -v [GENERATED FILES LOCATION]:/app/output \ asyncapi/cli [COMMAND HERE] # Example that you can run inside the cli directory after cloning this repository. First, you specify the mount in the location of your AsyncAPI specification file and then you mount it in the directory where the generation result should be saved. docker run --rm -it \ --user=root \ -v ${PWD}/test/integration/fixtures/asyncapi_v1.yml:/app/asyncapi.yml \ -v ${PWD}/output:/app/output \ asyncapi/cli generate fromTemplate -o /app/output /app/asyncapi.yml @asyncapi/html-template --force-write ``` Note: Use ``` ` ``` instead of `\` for Windows. ## Mac There are two ways to install the AsyncAPI CLI on your macOS: using the `brew` package manager or `pkg` files. ### brew To install the AsyncAPI CLI using the `brew` package manager, run the following commands in your terminal: ```sh # Install brew /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" # Install AsyncAPI CLI brew install asyncapi ``` ### pkg Every release of the AsyncAPI CLI has two macOS dedicated `pkg` file that enables you to install the CLI tool as a macOS application for x64 as well as arm64 architecture. To download the latest CLI release, run this command in your terminal: ```sh # For x64 curl -OL https://github.com/asyncapi/cli/releases/latest/download/asyncapi.x64.pkg # For arm64 curl -OL https://github.com/asyncapi/cli/releases/latest/download/asyncapi.arm64.pkg ``` To download a specific CLI release, run this command in your terminal: ```sh curl -OL https://github.com/asyncapi/cli/releases/download//asyncapi.pkg ``` Follow this link for all AsyncAPI CLI releases. After downloading the AsyncAPI CLI, install it via the following command: ```sh sudo installer -pkg asyncapi.pkg -target / ``` ## Windows There are two ways to install the AsyncAPI CLI on your Windows operating system: using the `chocolatey` package manager or executable files. ### Chocolatey Prerequisites: [Chocolatey](https://chocolatey.org/install) must be installed on your Windows operating system. The installation instructions can be found [here](https://docs.chocolatey.org/en-us/choco/setup#installing-chocolatey-cli). To install the AsyncAPI CLI using the `chocolatey` package manager, run the following command in your terminal with administrator privileges: ```sh # Install AsyncAPI CLI choco install asyncapi ``` To upgrade run this command:- ```sh # Upgrade AsyncAPI CLI choco upgrade asyncapi ``` To install a specific version run this command: ```sh # Install AsyncAPI CLI version xx.xx.xx choco install asyncapi --version xx.xx.xx ``` All the AsyncAPI CLI versions can be found [here](https://chocolatey.org/packages/asyncapi). ### Executable files Just install the appropriate installer and simply follow the default installation steps to complete the installation process. Download [asyncapi.x64.exe](https://github.com/asyncapi/cli/releases/latest/download/asyncapi.x64.exe) for 64-bit Windows and download [asyncapi.x86.exe](https://github.com/asyncapi/cli/releases/latest/download/asyncapi.x86.exe) for 32-bit Windows. ## Linux Selecting the appropriate AsyncAPI CLI installation method on a Linux operating system depends on your Linux distro. ### Debian based distros For Debian based distros, you can install the AsycAPI CLI using the `dpkg` package manager for Debian. ```sh curl -OL https://github.com/asyncapi/cli/releases/latest/download/asyncapi.deb ``` To download a specific release of the CLI, run this command in your terminal: ```sh curl -OL https://github.com/asyncapi/cli/releases/download//asyncapi.deb ``` ### Other distros You can install the AsyncAPI CLI for other Linux distros using the archive `tar.gz` file. #### For Alpine Linux / musl-based systems: To download the latest Alpine-compatible release, run this command in your terminal: ```sh curl -OL https://github.com/asyncapi/cli/releases/latest/download/asyncapi-alpine.tar.gz ``` To download a specific Alpine-compatible release, run this command in your terminal: ```sh curl -OL https://github.com/asyncapi/cli/releases/download//asyncapi-alpine.tar.gz ``` Once downloaded, untar the file: ```sh tar -xzf asyncapi-alpine.tar.gz ``` #### For other Linux distributions (glibc-based): To download the latest release of the CLI, run this command in your terminal: ```sh curl -OL https://github.com/asyncapi/cli/releases/latest/download/asyncapi.tar.gz ``` To download a specific release of the CLI, run this command in your terminal: ```sh curl -OL https://github.com/asyncapi/cli/releases/download//asyncapi.tar.gz ``` Once you have downloaded the archived file, untar it by running this command in your terminal: ```sh tar -xzf asyncapi.tar.gz ``` ### Setting up the symlink (for both Alpine and glibc versions): The step above will create an `AsyncAPI` directory in the current path. To run the CLI from anywhere, you must create a `symlink`. If the current path you are on is `/user/local/bin`, for example, you must create the `symlink` in the `/user/local/bin` directory by following these steps: ```sh # cd into the unarchived directory cd asyncapi # get the absolute path pwd # Create a symlink ln -s /bin/asyncapi /user/local/bin/asyncapi # The "asyncapi" command should be available to be used asyncapi ``` > [!NOTE] > If youare using Alpine Linux or any musl-based distribution, make sure to download the `-alpine.tar.gz` version to avoid glibc compatibility issues. The regular `asyncapi.tar.gz` file is compiled for glibc-based systems and will not work on Alpine. ================================================ FILE: docs/metrics_collection.md ================================================ --- title: 'Metrics Collection' weight: 70 --- # Metrics collection guideline AsyncAPI **anonymously** tracks command executions to improve the specification and tools, ensuring no sensitive data reaches our servers. It aids in comprehending how AsyncAPI tools are used and adopted, facilitating ongoing improvements to our specifications and tools. Even though metrics collection is enabled by default, you can always [disable tracking](#how-to-disable-tracking) if you want to. ## What we collect We are collecting the following metrics: - `asyncapi_adoption.action.invoked`: With this metric we are tracking the command executed on the CLI as soon as the command is invoked, so it has already been executed but not finished yet. We just want to know which commands are used, regardless they have failed or succeeded. Example of the data collected by this metric when the `validate` command has been executed: ``` asyncapi_adoption.action.invoked COUNTER { action: 'validate' } 1 ``` - `asyncapi_adoption.action.finished`: This metric tracks the command executed once it has already finished, carrying the result of the execution and some metadata based on the AsyncAPI document in place. Example for `validate` command successfully executed and finished: ``` asyncapi_adoption.action.finished COUNTER { validation_result: 'valid', success: true, asyncapi_version: '2.6.0', asyncapi_servers: 2, asyncapi_channels: 4, asyncapi_messages: 3, asyncapi_operations_send: 3, asyncapi_operations_receive: 1, asyncapi_schemas: 52, action: 'validate' } 1 ``` ## Where the data is stored We are making use of [New Relic API](https://docs.newrelic.com/docs/apis/intro-apis/introduction-new-relic-apis/#rest-api) to send the metrics collected to _New Relic_ servers, where they are stored, and finally visualized on the AsyncAPI website. Metrics won't be collected in CI environments, or when the "CI" env variable is set up to "true". The analytics config file will be store by default at your home directory. In case you prefer to change the file path then you should set the `ASYNCAPI_METRICS_CONFIG_PATH` env var to any specific path value when running any command. For instance: ```` ASYNCAPI_METRICS_CONFIG_PATH=/tmp/.asyncapi-analytics asyncapi config analytics --status ```` ## How to disable tracking To disable tracking, please run the following command: `asyncapi config analytics --disable` Once disabled, if you want to enable tracking back again then run: `asyncapi config analytics --enable` In case you do not know the current status of analytics, then you can append the "--status" flag to be aware of it: `asyncapi config analytics --status` Remember that keeping this tracking enabled will help AsyncAPI community to provide better specifications and tools in the future. ================================================ FILE: docs/usage.md ================================================ --- title: 'Usage' weight: 40 --- The AsyncAPI CLI makes it easier to work with AsyncAPI documents. # Usage ```sh-session $ npm install -g @asyncapi/cli $ asyncapi COMMAND running command... $ asyncapi (--version|--v) @asyncapi/cli/5.0.7 darwin-arm64 node-v24.7.0 $ asyncapi --help [COMMAND] USAGE $ asyncapi COMMAND ... ``` # Commands * [`asyncapi autocomplete [SHELL]`](#asyncapi-autocomplete-shell) * [`asyncapi bundle`](#asyncapi-bundle) * [`asyncapi config`](#asyncapi-config) * [`asyncapi config analytics`](#asyncapi-config-analytics) * [`asyncapi config auth add PATTERN TOKEN`](#asyncapi-config-auth-add-pattern-token) * [`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]`](#asyncapi-convert-spec-file) * [`asyncapi diff OLD NEW`](#asyncapi-diff-old-new) * [`asyncapi format [SPEC-FILE]`](#asyncapi-format-spec-file) * [`asyncapi generate`](#asyncapi-generate) * [`asyncapi generate client LANGUAGE [ASYNCAPI]`](#asyncapi-generate-client-language-asyncapi) * [`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 template`](#asyncapi-new-template) * [`asyncapi optimize [SPEC-FILE]`](#asyncapi-optimize-spec-file) * [`asyncapi pretty SPEC-FILE`](#asyncapi-pretty-spec-file) * [`asyncapi start`](#asyncapi-start) * [`asyncapi start api`](#asyncapi-start-api) * [`asyncapi start preview SPEC-FILE`](#asyncapi-start-preview-spec-file) * [`asyncapi start studio [SPEC-FILE]`](#asyncapi-start-studio-spec-file) * [`asyncapi validate [SPEC-FILE]`](#asyncapi-validate-spec-file) ## `asyncapi autocomplete [SHELL]` Display autocomplete installation instructions. ``` USAGE $ asyncapi autocomplete [SHELL] [-r] ARGUMENTS [SHELL] (zsh|bash|powershell) Shell type FLAGS -r, --refresh-cache Refresh cache (ignores displaying instructions) DESCRIPTION Display autocomplete installation instructions. EXAMPLES $ asyncapi autocomplete $ asyncapi autocomplete bash $ asyncapi autocomplete zsh $ asyncapi autocomplete powershell $ asyncapi autocomplete --refresh-cache ``` _See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.40/src/commands/autocomplete/index.ts)_ ## `asyncapi bundle` Bundle one or multiple AsyncAPI Documents and their references together. ``` USAGE $ 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 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. EXAMPLES $ asyncapi bundle ./asyncapi.yaml > final-asyncapi.yaml $ asyncapi bundle ./asyncapi.yaml --output final-asyncapi.yaml $ 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 ``` _See code: [src/commands/bundle.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/bundle.ts)_ ## `asyncapi config` CLI config settings ``` USAGE $ asyncapi config DESCRIPTION CLI config settings ``` _See code: [src/commands/config/index.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/index.ts)_ ## `asyncapi config analytics` Enable or disable analytics for metrics collection ``` USAGE $ asyncapi config analytics [-h] [-d] [-e] [-s] FLAGS -d, --disable disable analytics -e, --enable enable analytics -h, --help Show CLI help. -s, --status show current status of analytics DESCRIPTION Enable or disable analytics for metrics collection ``` _See code: [src/commands/config/analytics.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/analytics.ts)_ ## `asyncapi config auth add PATTERN TOKEN` Add an authentication config for resolving $ref files requiring HTTP Authorization. ``` USAGE $ asyncapi config auth add PATTERN TOKEN [-a ] [-h ...] ARGUMENTS PATTERN Glob pattern for matching protected URLs (e.g. github.com/org/repo/**/*.*) TOKEN Authentication token or environment variable reference (prefix with $, e.g. $GITHUB_TOKEN) FLAGS -a, --auth-type= Authentication type (default is "Bearer") -h, --header=... Additional header in key=value format; can be used multiple times DESCRIPTION Add an authentication config for resolving $ref files requiring HTTP Authorization. ``` _See code: [src/commands/config/auth/add.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/auth/add.ts)_ ## `asyncapi config context` Manage short aliases for full paths to AsyncAPI documents ``` USAGE $ asyncapi config context DESCRIPTION Manage short aliases for full paths to AsyncAPI documents ``` _See code: [src/commands/config/context/index.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/index.ts)_ ## `asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH` Add a context to the store ``` USAGE $ asyncapi config context add CONTEXT-NAME SPEC-FILE-PATH [-h] [-s] ARGUMENTS CONTEXT-NAME context name SPEC-FILE-PATH file path of the spec file FLAGS -h, --help Show CLI help. -s, --set-current Set context being added as the current context DESCRIPTION Add a context to the store ``` _See code: [src/commands/config/context/add.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/add.ts)_ ## `asyncapi config context current` Shows the current context that is being used ``` USAGE $ asyncapi config context current [-h] FLAGS -h, --help Show CLI help. DESCRIPTION Shows the current context that is being used ``` _See code: [src/commands/config/context/current.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/current.ts)_ ## `asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH` Edit a context in the store ``` USAGE $ asyncapi config context edit CONTEXT-NAME NEW-SPEC-FILE-PATH [-h] ARGUMENTS CONTEXT-NAME context name NEW-SPEC-FILE-PATH file path of the spec file FLAGS -h, --help Show CLI help. DESCRIPTION Edit a context in the store ``` _See code: [src/commands/config/context/edit.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/edit.ts)_ ## `asyncapi config context init [CONTEXT-FILE-PATH]` Initialize context ``` USAGE $ asyncapi config context init [CONTEXT-FILE-PATH] [-h] ARGUMENTS [CONTEXT-FILE-PATH] 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 ~` FLAGS -h, --help Show CLI help. DESCRIPTION Initialize context ``` _See code: [src/commands/config/context/init.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/init.ts)_ ## `asyncapi config context list` List all the stored contexts in the store ``` USAGE $ asyncapi config context list [-h] FLAGS -h, --help Show CLI help. DESCRIPTION List all the stored contexts in the store ``` _See code: [src/commands/config/context/list.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/list.ts)_ ## `asyncapi config context remove CONTEXT-NAME` Delete a context from the store ``` USAGE $ asyncapi config context remove CONTEXT-NAME [-h] ARGUMENTS CONTEXT-NAME Name of the context to delete FLAGS -h, --help Show CLI help. DESCRIPTION Delete a context from the store ``` _See code: [src/commands/config/context/remove.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/remove.ts)_ ## `asyncapi config context use CONTEXT-NAME` Set a context as current ``` USAGE $ asyncapi config context use CONTEXT-NAME [-h] ARGUMENTS CONTEXT-NAME name of the saved context FLAGS -h, --help Show CLI help. DESCRIPTION Set a context as current ``` _See code: [src/commands/config/context/use.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/context/use.ts)_ ## `asyncapi config versions` Show versions of AsyncAPI tools used ``` USAGE $ asyncapi config versions [-h] FLAGS -h, --help Show CLI help. DESCRIPTION Show versions of AsyncAPI tools used ``` _See code: [src/commands/config/versions.ts](https://github.com/asyncapi/cli/blob/v5.0.7/src/commands/config/versions.ts)_ ## `asyncapi convert [SPEC-FILE]` Convert asyncapi documents older to newer versions or OpenAPI documents to AsyncAPI ``` USAGE $ asyncapi convert [SPEC-FILE] -f openapi|asyncapi [-h] [-o ] [-t ] [-p client|server] [--proxyHost ] [--proxyPort ] ARGUMENTS [SPEC-FILE] spec path, url, or context-name FLAGS -f, --format=