diff --git a/.github/workflows/test-action.yml b/.github/workflows/test-action.yml new file mode 100644 index 00000000000..49960223be7 --- /dev/null +++ b/.github/workflows/test-action.yml @@ -0,0 +1,345 @@ +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@v3 + 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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@v3 + 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: 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 diff --git a/.gitignore b/.gitignore index b50ab0c5d88..5b8a7c8b336 100644 --- a/.gitignore +++ b/.gitignore @@ -16,10 +16,12 @@ node_modules /test/integration/generate/models/ test.asyncapi-cli asyncapi.json -asyncapi.yml test/fixtures/minimaltemplate/__transpiled .vscode +/action/ +/github-action/output/ + oclif.manifest.json spec-examples.zip diff --git a/action.yml b/action.yml new file mode 100644 index 00000000000..5366e43d079 --- /dev/null +++ b/action.yml @@ -0,0 +1,54 @@ +name: 'Generator, Validator, Converter and others - all in one for your AsyncAPI docs' +description: 'Use this action to generate docs or code from your AsyncAPI document. Use default templates or provide your custom ones.' +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@0.10.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:3.1.2' + 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 diff --git a/github-action/.asyncapi-tool b/github-action/.asyncapi-tool new file mode 100644 index 00000000000..7023eba6eb9 --- /dev/null +++ b/github-action/.asyncapi-tool @@ -0,0 +1,6 @@ +title: GitHub Action for Generator +filters: + technology: + - AsyncAPI Generator + categories: + - github-actions diff --git a/github-action/Dockerfile b/github-action/Dockerfile new file mode 100644 index 00000000000..28e5d48cf4f --- /dev/null +++ b/github-action/Dockerfile @@ -0,0 +1,58 @@ +# Stage 1: Build stage with Node setup +FROM node:18-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:18-alpine + +# Install necessary packages +RUN apk add --no-cache bash git + +# Copy the libraries directory from the build stage +COPY --from=build /libraries /libraries + +RUN cd /libraries && npm install --production --ignore-scripts + +# Create a non-root user +# RUN addgroup -S myuser && adduser -S myuser -G myuser + +# 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" + +# Copy the entrypoint script +COPY github-action/entrypoint.sh /entrypoint.sh + +# Make the entrypoint script executable +RUN chmod +x /entrypoint.sh + +# Set the entrypoint +ENTRYPOINT ["/entrypoint.sh"] diff --git a/github-action/Makefile b/github-action/Makefile new file mode 100644 index 00000000000..7b7fe5f7e09 --- /dev/null +++ b/github-action/Makefile @@ -0,0 +1,61 @@ +DEFAULT_VERSION = 'latest' +DEFAULT_COMMAND = 'generate' +TEST_FILEPATH = 'test/asyncapi.yml' +DEFAULT_TEMPLATE = '@asyncapi/markdown-template@0.10.0' +DEFAULT_LANGUAGE = '' +DEFAULT_OUTPUT = 'output' +DEFAULT_PARAMETERS = '' +DEFAULT_CUSTOM_COMMANDS = '' +CUSTOM_COMMANDS = 'validate test/asyncapi.yml' + +# Add env variables to the shell +export GITHUB_WORKSPACE = $(shell pwd) + +run: + @bash ./entrypoint.sh $(DEFAULT_VERSION) $(DEFAULT_COMMAND) $(TEST_FILEPATH) $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) $(DEFAULT_PARAMETERS) $(DEFAULT_CUSTOM_COMMANDS) + +test: test-default test-validate-success test-custom-output test-custom-commands test-optimize test-bundle test-convert + +# Test cases + +# Tests if the action has been bumped greater than the latest release +test-action-bump: + @bash bump-test.sh + +# Tests the default configuration without any inputs +test-default: + @bash ./entrypoint.sh $(DEFAULT_VERSION) $(DEFAULT_COMMAND) $(TEST_FILEPATH) $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) $(DEFAULT_PARAMETERS) $(DEFAULT_CUSTOM_COMMANDS) + +# Tests the validate command with a valid specification +test-validate-success: + @bash ./entrypoint.sh $(DEFAULT_VERSION) 'validate' $(TEST_FILEPATH) $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) $(DEFAULT_PARAMETERS) $(DEFAULT_CUSTOM_COMMANDS) + +# Tests the validate command with an invalid specification +test-validate-fail: + @bash ./entrypoint.sh $(DEFAULT_VERSION) 'validate' './test/specification-invalid.yml' $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) $(DEFAULT_PARAMETERS) $(DEFAULT_CUSTOM_COMMANDS) + +# Tests if the generator can output to a custom directory +test-custom-output: + @bash ./entrypoint.sh $(DEFAULT_VERSION) $(DEFAULT_COMMAND) $(TEST_FILEPATH) $(DEFAULT_TEMPLATE) 'typescript' './output/custom-output' $(DEFAULT_PARAMETERS) $(DEFAULT_CUSTOM_COMMANDS) + +# Tests if the action prefers custom commands over the default command +test-custom-commands: + @bash ./entrypoint.sh $(DEFAULT_VERSION) $(DEFAULT_COMMAND) $(TEST_FILEPATH) $(DEFAULT_TEMPLATE) 'typescript' './output/custom-output' $(DEFAULT_PARAMETERS) $(CUSTOM_COMMANDS) + +# Tests if the action fails when the input is invalid (e.g. invalid template as is the case here) +fail-test: + @bash ./entrypoint.sh $(DEFAULT_VERSION) $(DEFAULT_COMMAND) $(TEST_FILEPATH) '' $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) $(DEFAULT_PARAMETERS) $(DEFAULT_CUSTOM_COMMANDS) + +# Tests if the action optimizes the specification +test-optimize: + @bash ./entrypoint.sh $(DEFAULT_VERSION) 'optimize' 'test/unoptimized.yml' $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) '-o new-file --no-tty' $(DEFAULT_CUSTOM_COMMANDS) + +# Tests if the action can bundle the specification with custom commands +BUNDLE_COMMAND='bundle ./test/bundle/asyncapi.yaml ./test/bundle/features.yaml --base ./test/bundle/asyncapi.yaml -o ./output/bundle/asyncapi.yaml' +test-bundle: + mkdir -p ./output/bundle + @bash ./entrypoint.sh $(DEFAULT_VERSION) 'bundle' 'test/bundle/asyncapi.yaml' $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) $(DEFAULT_OUTPUT) '-o output/bundle/asyncapi.yaml' $(BUNDLE_COMMAND) + +# Tests if the action can convert the specification with custom commands +test-convert: + @bash ./entrypoint.sh $(DEFAULT_VERSION) 'convert' 'test/asyncapi.yml' $(DEFAULT_TEMPLATE) $(DEFAULT_LANGUAGE) 'output/convert/asyncapi.yaml' '' $(DEFAULT_CUSTOM_COMMANDS) diff --git a/github-action/README.md b/github-action/README.md new file mode 100644 index 00000000000..ee8e790cdfa --- /dev/null +++ b/github-action/README.md @@ -0,0 +1,239 @@ +# GitHub Action for CLI + +This action exposes the [AsyncAPI CLI](https://github.com/asyncapi/cli). It allows you to generate documentation, validate AsyncAPI documents, convert between different AsyncAPI versions and much more. + +## Inputs + +### `cli_version` + +Version of the AsyncAPI CLI you wish to use. You can find all available versions [here](https://github.com/asyncapi/cli/releases). Recommended leave it out of the inputs and use the default value. + +**Default** points to the`latest` version. + +> [!TIP] +> We recommend to default to `latest` version. This way there is no overhead with the script updating the CLI version. As it takes a lot of time to update the CLI version, we recommend to update it only when you need to use another one for compatibility reasons. + +### `command` + +Command that you wish to run. You can find all available commands Available commands are: +- `generate` - generates documentation from AsyncAPI document +- `validate` - validates AsyncAPI document +- `optimize` - optimizes AsyncAPI document +- `convert` - converts AsyncAPI document to another version +- `custom` - allows you to run any command that is available in the AsyncAPI CLI. You can find all available commands [here](https://www.asyncapi.com/docs/tools/cli/usage). + +**Default** points to `generate` command. + +> [!IMPORTANT] +> In case you want to use `custom` command, you need to pass an array of commands to the [`custom_command`](#custom_command) input. Although passing command is not required, it is recommended to pass it to avoid any issues later on. +> For example, if you want to run `asyncapi bundle ./asyncapi.yaml --output final-asyncapi.yaml` you need to pass `"bundle ./asyncapi.yaml --output final-asyncapi.yaml" to the `custom_command` input. + +### `custom_command` + +In case you want to use `custom` command you need to pass the command that you want to run in this input. You can find all available commands [here](https://www.asyncapi.com/docs/tools/cli/usage). + +**Default** points to '' (empty string). + +Sample usage: + +```yaml +- name: Generating HTML from my AsyncAPI document + uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want + with: + custom_command: bundle ./asyncapi.yaml --output final-asyncapi.yaml +``` + +> [!CAUTION] +> You have to pass the whole command as a string including the parameters and the command itself. +> It will run like this: `asyncapi ` + + +### `filepath` + +Path to the AsyncAPI document that you want to process. + +**Default** expects the AsyncAPI document to be in the root of the repository and named `asyncapi.yaml`. + +### `template` + +Template for the generator. Official templates are listed here https://github.com/asyncapi/generator#list-of-official-generator-templates. You can pass template as npm package, url to git repository, link to tar file or local template. + +**Default** points to `@asyncapi/markdown-template@0.10.0` template. + +> [!TIP] +> We recommend to always specify the version of the template to not encounter any issues with the action in case of release of the template that is not compatible with given version of the generator. + +### `language` + +Specifies the language to be used for the generated models. The value must be a valid language name supported by [modelina](https://github.com/asyncapi/modelina). + +**Default** is not set. + +> [!WARNING] +> Either `language` or `template` must be set else an error will be thrown. +> The action will return an error if the language is not supported by [modelina](https://github.com/asyncapi/modelina). + +### `output` + +Path to the output directory. Can be used for `generate` and `convert` commands. + +**Default** points to `output` directory in the root of the repository. + +### `parameters` + +The command that you use might support and even require specific parameters to be passed to the CLI for the generation. You can find all available parameters [here](https://www.asyncapi.com/docs/tools/cli/usage). + +**Default** points to '' (empty string). + +> [!NOTE] +> For template parameters, you need to pass them as `-p ` as can be seen in CLI documentation. + + +## Example usage + +> [!WARNING] +> Using `docker://asyncapi/github-action-for-cli` will not work as expected. This is because the GitHub Actions runner does not pass params to the docker image correctly. This is why we recommend to use `asyncapi/github-action-for-cli` instead. +> However, you don't need to worry as it won't build the image every time. It will pull it from Docker Hub as it is already built there. + +### Basic + +In case all defaults are fine for you, just add such step: + +```yaml +- name: Generating Markdown from my AsyncAPI document + uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want +``` + +### Using all possible inputs + +In case you do not want to use defaults, you for example want to use different template: + +```yaml +- name: Generating HTML from my AsyncAPI document + uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want + with: + command: generate + filepath: ./docs/api/asyncapi.yaml + template: "@asyncapi/html-template@0.9.0" #In case of template from npm. Or can use a link. + output: ./generated-html + parameters: "-p baseHref=/test-experiment/ sidebarOrganization=byTags" +``` +> [!IMPORTANT] +> Note the usage of `-p` in `parameters` input. This is required for template parameters, unlike previous versions of this action as the action includes other commands than just `generate`. + +### Example workflow with publishing generated HTML to GitHub Pages + +In case you want to validate your asyncapi file first, and also send generated HTML to GitHub Pages this is how full workflow could look like: + +```yaml +name: AsyncAPI documents processing + +on: + push: + branches: [ master ] + +jobs: + generate: + runs-on: ubuntu-latest + steps: + #"standard step" where repo needs to be checked-out first + - name: Checkout repo + uses: actions/checkout@v2 + + #In case you do not want to use defaults, you for example want to use different template + - name: Generating HTML from my AsyncAPI document + uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want + with: + template: '@asyncapi/html-template@0.9.0' #In case of template from npm, because of @ it must be in quotes + filepath: docs/api/my-asyncapi.yml + parameters: -p baseHref=/test-experiment/ sidebarOrganization=byTags #space separated list of key/values + output: generated-html + + #Using another action that takes generated HTML and pushes it to GH Pages + - name: Deploy GH page + uses: JamesIves/github-pages-deploy-action@3.4.2 + with: + ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRANCH: gh-pages + FOLDER: generated-html +``` + +### Example workflow for generating models + +In case you want to use models generated from your AsyncAPI document, you can use this action to generate them and then use them in your workflow. This is how full workflow could look like: + +```yaml + +name: AsyncAPI documents processing + +on: + push: + branches: [ master ] + +jobs: + generate-models: + runs-on: ubuntu-latest + steps: + #"standard step" where repo needs to be checked-out first + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Generating models from my AsyncAPI document + uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want + with: + command: generate + filepath: docs/api/my-asyncapi.yml + language: typescript + output: generated-models +``` + +### Example workflow for validating AsyncAPI document changes + +In case you want to validate your AsyncAPI document changes, you can use this action to validate them and then use them in your workflow. This is how full workflow could look like: + +```yaml +name: Validate AsyncAPI document + +on: + pull_request: + branches: [ master ] + +jobs: + validate: + runs-on: ubuntu-latest + steps: + #"standard step" where repo needs to be checked-out first + - name: Checkout repo + uses: actions/checkout@v2 + + - name: Validating AsyncAPI document + uses: asyncapi/github-action-for-cli@v3.1.1 # You can use any version you want + with: + command: validate + filepath: docs/api/my-asyncapi.yml +``` + +## Local dry run + +Use following commands to run and test github action locally: + +1. Build docker image of github action for cli + + ```bash + npm run action:docker:build + ``` + +2. Execute docker image with proper arguments + + ```bash + docker run -e GITHUB_WORKSPACE="" --workdir /action -v "/home/{user}/path/to/repo":"/action" asyncapi/github-action-for-cli "" "generate" "github-action/test/asyncapi.yml" "@asyncapi/markdown-template@0.10.0" "" "output" "" "" + ``` + +Make sure to change the path of the repo and user in the command. + +## Troubleshooting + +You can enable more log information in GitHub Action by adding `ACTIONS_STEP_DEBUG` secret to repository where you want to use this action. Set the value of this secret to `true` and you''ll notice more debug logs from this action. + + +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/github-action/bump-test.sh b/github-action/bump-test.sh new file mode 100755 index 00000000000..bda3dc112b0 --- /dev/null +++ b/github-action/bump-test.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +version=$(cat package.json | jq -r '.version'); +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"; +echo "Package version: $version"; + +if [[ $action_version > $version ]]; then + echo "Action version is greater than package version"; +else \ + echo "Action version has not been bumped. Please bump the action version to the semantically correct version after $version"; \ + exit 1; \ +fi \ No newline at end of file diff --git a/github-action/entrypoint.sh b/github-action/entrypoint.sh new file mode 100755 index 00000000000..eec3e47cd60 --- /dev/null +++ b/github-action/entrypoint.sh @@ -0,0 +1,177 @@ +#!/usr/bin/env bash + +# Exit immediately if a command exits with a non-zero status. +# Treat unset variables as an error when substituting. +set -eu + +NC='\033[0m' # No Color +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +RED='\033[0;31m' + +if [ -z "$GITHUB_WORKSPACE" ]; then + workdir=$(pwd) +else + workdir="$GITHUB_WORKSPACE" +fi + +CLI_VERSION="$1" +COMMAND="$2" +FILEPATH="$workdir/$3" # Absolute path to the AsyncAPI file +TEMPLATE="$4" +LANGUAGE="$5" +OUTPUT="$workdir/$6" # Absolute path to the output directory +PARAMETERS="$7" +CUSTOM_COMMAND="$8" + +echo "::group::Debug information" +if [ -n "$CLI_VERSION" ] && [ ! "$CLI_VERSION" == "latest" ]; then + echo -e "${BLUE}CLI version:${NC}" "$CLI_VERSION" + # Check if the CLI version is already installed or not + if [ -z $(command -v -- asyncapi) ]; then + output='' + else + output=$(asyncapi --version >/dev/null 2>&1) + fi + # output @asyncapi/cli/1.1.1 linux-x64 node-v20.8.1 + version=$(echo "$output" | cut -d' ' -f1 | cut -d '/' -f3) + if [ "$version" == "$CLI_VERSION" ]; then + echo -e "${BLUE}AsyncAPI CLI already installed:${NC}" "$CLI_VERSION" "...skipping" + else + echo -e "${BLUE}Installing AsyncAPI CLI:${NC}" "$CLI_VERSION" + npm install -g @asyncapi/cli@$CLI_VERSION + fi +else + if [ -z $(command -v -- asyncapi) ]; then + echo -e "${RED}No CLI installation found. Installing the latest one" + npm install -g @asyncapi/cli + fi + echo -e "${BLUE}CLI version:${NC}" "latest" +fi +echo "::endgroup::" + +echo -e "${BLUE}AsyncAPI CLI version:${NC}" "$(asyncapi --version)" + +echo -e "${GREEN}Executing AsyncAPI CLI...${NC}" + +git config --global --add safe.directory "$GITHUB_WORKSPACE" + +if [ -n "$CUSTOM_COMMAND" ]; then + echo "::group::Debug information" + echo -e "${BLUE}Executing custom command:${NC} asyncapi" "$CUSTOM_COMMAND" + eval "asyncapi $CUSTOM_COMMAND" + echo "::endgroup::" + exit 0 +fi + +echo "::group::Debug information" +echo -e "${BLUE}Command:${NC}" "$COMMAND" +echo -e "${BLUE}File:${NC}" "$FILEPATH" +echo -e "${BLUE}Template:${NC}" "$TEMPLATE" +echo -e "${BLUE}Language:${NC}" "$LANGUAGE" +echo -e "${BLUE}Output:${NC}" "$OUTPUT" +echo -e "${BLUE}Parameters:${NC}" "$PARAMETERS" +echo "::endgroup::" + +handle_file_error () { + echo -e "${RED}Validation error: File not found:${NC}" "$1" + echo -e "skipping...\n" +} + +handle_validate () { + echo -e "${BLUE}Validating AsyncAPI file...${NC}" + echo "::group::Debug information" + + if [ ! -f "$FILEPATH" ]; then + handle_file_error "$FILEPATH" + exit 1 + fi + + echo -e "${BLUE}Executing command:${NC}" "asyncapi validate $FILEPATH $PARAMETERS" + eval "asyncapi validate $FILEPATH $PARAMETERS" + echo "::endgroup::" +} + +handle_optimize () { + echo -e "${BLUE}Optimising AsyncAPI file...${NC}" + echo "::group::Debug information" + + if [ ! -f "$FILEPATH" ]; then + handle_file_error "$FILEPATH" + exit 1 + fi + + echo -e "${BLUE}Executing command:${NC}" "asyncapi optimize $FILEPATH $PARAMETERS" + eval "asyncapi optimize $FILEPATH $PARAMETERS" + echo "::endgroup::" +} + +handle_generate () { + echo -e "${BLUE}Generating from AsyncAPI file...${NC}" + + if [ ! -f "$FILEPATH" ]; then + handle_file_error "$FILEPATH" + exit 1 + fi + + # Check if the output directory exists or not and create it if it doesn't + output_dir=$(dirname "$OUTPUT") + + if [ ! -d "$output_dir" ]; then + mkdir -p "$output_dir" + echo -e "${BLUE}Created output directory:${NC}" "$output_dir" + fi + + echo "::group::Debug information" + if [ -n "$LANGUAGE" ]; then + echo -e "${BLUE}Executing command:${NC}" "asyncapi generate models $LANGUAGE $FILEPATH -o $OUTPUT $PARAMETERS" + eval "asyncapi generate models $LANGUAGE $FILEPATH -o $OUTPUT $PARAMETERS" + elif [ -n "$TEMPLATE" ]; then + echo -e "${BLUE}Executing command:${NC}" "asyncapi generate fromTemplate $FILEPATH $TEMPLATE -o $OUTPUT $PARAMETERS" + eval "asyncapi generate fromTemplate $FILEPATH $TEMPLATE -o $OUTPUT $PARAMETERS" + else + echo -e "${RED}Invalid configuration:${NC} Either language or template must be specified." + exit 1 + fi + echo "::endgroup::" +} + +handle_convert () { + echo -e "${BLUE}Converting AsyncAPI file...${NC}" + echo "::group::Debug information" + + if [ ! -f "$FILEPATH" ]; then + handle_file_error "$FILEPATH" + exit 1 + fi + + if [ -z "$OUTPUT" ]; then + echo -e "${BLUE}Executing command:${NC}" "asyncapi convert $FILEPATH $PARAMETERS" + eval "asyncapi convert $FILEPATH $PARAMETERS" + else + # Create the output directory if it doesn't exist + output_dir=$(dirname "$OUTPUT") + + if [ ! -d "$output_dir" ]; then + mkdir -p "$output_dir" + echo -e "${BLUE}Created output directory:${NC}" "$output_dir" + fi + + echo -e "${BLUE}Executing command:${NC}" "asyncapi convert $FILEPATH -o $OUTPUT $PARAMETERS" + eval "asyncapi convert $FILEPATH -o $OUTPUT $PARAMETERS" + fi +} + +if [ $COMMAND == "validate" ]; then + handle_validate +elif [ $COMMAND == "optimize" ]; then + handle_optimize +elif [ $COMMAND == "generate" ]; then + handle_generate +elif [ $COMMAND == "convert" ]; then + handle_convert +else + echo -e "${RED}Invalid command:${NC}" "$COMMAND" + echo -e "${YELLOW}NOTE: Command can be either validate, optimize or generate.${NC}" +fi \ No newline at end of file diff --git a/github-action/test/asyncapi.yml b/github-action/test/asyncapi.yml new file mode 100644 index 00000000000..9ef74d1104b --- /dev/null +++ b/github-action/test/asyncapi.yml @@ -0,0 +1,37 @@ +asyncapi: '2.0.0' +info: + title: Streetlights API + version: '1.0.0' + description: | + The Smartylighting Streetlights API allows you + to remotely manage the city lights. + license: + name: Apache 2.0 + url: 'https://www.apache.org/licenses/LICENSE-2.0' + +servers: + mosquitto: + url: mqtt://test.mosquitto.org + protocol: mqtt + +channels: + light/measured: + publish: + summary: Inform about environmental lighting conditions for a particular streetlight. + operationId: onLightMeasured + message: + payload: + type: object + properties: + id: + type: integer + minimum: 0 + description: Id of the streetlight. + lumens: + type: integer + minimum: 0 + description: Light intensity measured in lumens. + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. diff --git a/github-action/test/bundle/asyncapi.yaml b/github-action/test/bundle/asyncapi.yaml new file mode 100644 index 00000000000..1116cabff5c --- /dev/null +++ b/github-action/test/bundle/asyncapi.yaml @@ -0,0 +1,10 @@ +asyncapi: "2.5.0" +info: + title: Account Service + version: 1.0.0 + description: This service is in charge of processing user signups +channels: + user/signedup: + subscribe: + message: + $ref: "./messages.yaml#/messages/UserSignedUp" \ No newline at end of file diff --git a/github-action/test/bundle/features.yaml b/github-action/test/bundle/features.yaml new file mode 100644 index 00000000000..564ac656d96 --- /dev/null +++ b/github-action/test/bundle/features.yaml @@ -0,0 +1,10 @@ +asyncapi: "2.5.0" +info: + title: Account Service + version: 1.0.0 + description: This service is in charge of processing user logouts +channels: + user/loggedOut: + subscribe: + message: + $ref: "./messages.yaml#/messages/UserLoggedOut" \ No newline at end of file diff --git a/github-action/test/bundle/messages.yaml b/github-action/test/bundle/messages.yaml new file mode 100644 index 00000000000..c6afe2452cf --- /dev/null +++ b/github-action/test/bundle/messages.yaml @@ -0,0 +1,25 @@ +messages: + UserSignedUp: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + email: + type: string + format: email + description: Email of the user + UserLoggedOut: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user + userId: + type: string + description: Id the user + timestamp: + type: number + description: Time stamp when the user logged out diff --git a/github-action/test/dummy.yml b/github-action/test/dummy.yml new file mode 100644 index 00000000000..8bf76f32884 --- /dev/null +++ b/github-action/test/dummy.yml @@ -0,0 +1,390 @@ +asyncapi: '2.3.0' + +externalDocs: + description: Find more info here + url: https://www.asyncapi.com + +info: + title: Dummy example with all spec features included + version: '0.0.1' + description: | + This is an example of AsyncAPI specification file that is suppose to include all possible features of the AsyncAPI specification. Do not use it on production. + + It's goal is to support development of documentation and code generation with the [AsyncAPI Generator](https://github.com/asyncapi/generator/) and [Template projects](https://github.com/search?q=topic%3Aasyncapi+topic%3Agenerator+topic%3Atemplate) + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0 + contact: + name: API Support + url: http://www.asyncapi.com/support + email: info@asyncapi.io + x-twitter: '@AsyncAPISpec' + +tags: + - name: root-tag1 + externalDocs: + description: External docs description 1 + url: https://www.asyncapi.com/ + - name: root-tag2 + description: Description 2 + externalDocs: + url: "https://www.asyncapi.com/" + - name: root-tag3 + - name: root-tag4 + description: Description 4 + - name: root-tag5 + externalDocs: + url: "https://www.asyncapi.com/" + +servers: + dummy-mqtt: + $ref: '#/components/servers/dummyMQTT' + dummy-amqp: + url: amqp://localhost:{port} + protocol: amqp + description: dummy AMQP broker + protocolVersion: "0.9.1" + variables: + port: + enum: + - '15672' + - '5672' + security: + - user-password: [] + dummy-kafka: + url: http://localhost:{port} + protocol: kafka + description: dummy Kafka broker + variables: + port: + default: '9092' + +defaultContentType: application/json + +channels: + dummy/channel/with/{dummy}/parameter/create: + x-dummy-security: + $ref: '#/components/securitySchemes/supportedOauthFlows/flows/clientCredentials' + description: Dummy channel description. + parameters: + dummy: + $ref: '#/components/parameters/dummy' + publish: + summary: Inform whenever something dummy is created. + description: | + Longer description. + + Still dummy though. + operationId: receiveNewDummyInfo + tags: + - name: oparation-tag1 + externalDocs: + description: External docs description 1 + url: https://www.asyncapi.com/ + - name: oparation-tag2 + description: Description 2 + externalDocs: + url: "https://www.asyncapi.com/" + - name: oparation-tag3 + - name: oparation-tag4 + description: Description 4 + - name: oparation-tag5 + externalDocs: + url: "https://www.asyncapi.com/" + traits: + - $ref: '#/components/operationTraits/kafka' + message: + $ref: '#/components/messages/dummyCreated' + + dummy/channel/without/parameter: + $ref: '#/components/channels/dummyChannel' +components: + servers: + dummyMQTT: + url: mqtt://localhost + protocol: mqtt + description: dummy MQTT broker + bindings: + mqtt: + clientId: guest + cleanSession: true + channels: + dummyChannel: + bindings: + amqp: + is: routingKey + subscribe: + operationId: receiveSystemInfo + bindings: + amqp: + expiration: 100000 + userId: guest + cc: [ 'user.logs' ] + priority: 10 + deliveryMode: 2 + mandatory: false + bcc: [ 'external.audit' ] + replyTo: user.signedup + timestamp: true + ack: false + bindingVersion: 0.1.0 + message: + $ref: '#/components/messages/dummyInfo' + messages: + dummyCreated: + name: dummyCreated + title: Dummy created message + summary: This is just a dummy create message + correlationId: + description: This is a dummy correlation ID. + location: $message.header#/correlationId + tags: + - name: message-tag1 + externalDocs: + description: External docs description 1 + url: https://www.asyncapi.com/ + - name: message-tag2 + description: Description 2 + externalDocs: + url: "https://www.asyncapi.com/" + - name: message-tag3 + - name: message-tag4 + description: Description 4 + - name: message-tag5 + externalDocs: + url: "https://www.asyncapi.com/" + headers: + type: object + properties: + my-custom-app-header: + type: string + correlationId: + type: string + payload: + $ref: "#/components/schemas/dummyCreated" + bindings: + kafka: + key: + type: object + properties: + id: + type: string + format: uuid + type: + type: string + enum: [ 'type1', "type2" ] + bindingVersion: '0.1.0' + amqp: + contentEncoding: gzip + messageType: 'user.signup' + bindingVersion: 0.1.0 + x-response: + $ref: "#/components/messages/dummyInfo" + dummyInfo: + name: dummyInfo + title: Dummy system info + summary: This is just a dummy info message + correlationId: + location: $message.header#/correlationId + description: | + More description for a dummy message. + + It is a dummy system info message. + traits: + - $ref: '#/components/messageTraits/commonHeaders' + payload: + $ref: "#/components/schemas/dummyInfo" + examples: + - name: option1example + summary: this is dummy summary for option1example + headers: + my-app-header: 12 + payload: + prop1: option1 + sentAt: 2020-01-31T13:24:53Z + - name: headerExample + headers: + my-app-header: 13 + - payload: + prop1: option2 + sentAt: 2020-01-31T13:24:53Z + + + schemas: + dummyCreated: + type: object + required: + - prop2 + x-schema-extensions-as-object: + type: object + properties: + prop1: + type: string + prop2: + type: integer + minimum: 0 + x-schema-extensions-as-primitive: dummy + x-schema-extensions-as-array: + - "item1" + - "item2" + properties: + prop1: + type: integer + minimum: 0 + description: Dummy prop1 + x-prop1-dummy: dummy extension + prop2: + type: string + description: Dummy prop2 + sentAt: + $ref: "#/components/schemas/sentAt" + dummyArrayWithObject: + $ref: "#/components/schemas/dummyArrayWithObject" + dummyArrayWithArray: + $ref: "#/components/schemas/dummyArrayWithArray" + dummyObject: + $ref: "#/components/schemas/dummyObject" + dummyArrayRank: + $ref: '#/components/schemas/dummyArrayRank' + dummyInfo: + type: object + required: + - prop1 + properties: + prop1: + type: string + enum: + - option1 + - option2 + description: Dummy prop1 + sentAt: + $ref: "#/components/schemas/sentAt" + dummyArrayWithObject: + type: array + items: + $ref: "#/components/schemas/dummyInfo" + dummyArrayWithArray: + type: array + items: + - $ref: "#/components/schemas/dummyInfo" + - type: string + - type: number + dummyObject: + type: object + properties: + dummyObjectProp1: + $ref: "#/components/schemas/sentAt" + dummyObjectProp2: + $ref: "#/components/schemas/dummyRecursiveObject" + dummyObjectProp3: + type: object + additionalProperties: true + dummyObjectProp4: + type: object + additionalProperties: false + dummyRecursiveObject: + type: object + properties: + dummyRecursiveProp1: + $ref: "#/components/schemas/dummyObject" + dummyRecursiveProp2: + type: string + sentAt: + type: string + format: date-time + description: Date and time when the message was sent. + dummyArrayRank: + type: object + properties: + dummyArrayValueRank: + $ref: '#/components/schemas/dummyArrayValueRank' + dummyArrayDimensions: + $ref: '#/components/schemas/dummyArrayArrayDimensions' + dummyArrayValueRank: + description: > + This Attribute indicates whether the val Attribute of the datapoint is an + array and how many dimensions the array has. + type: integer + default: -1 + examples: + - 2 + oneOf: + - const: -1 + description: 'Scalar: The value is not an array.' + - const: 0 + description: 'OneOrMoreDimensions: The value is an array with one or more dimensions.' + - const: 1 + description: 'OneDimension: The value is an array with one dimension.' + - const: 2 + description: 'The value is an array with two dimensions.' + dummyArrayArrayDimensions: + type: array + items: + type: integer + minimum: 0 + examples: + - [3, 5] + + securitySchemes: + user-password: + type: userPassword + apiKey: + type: apiKey + in: user + description: Provide your API key as the user and leave the password empty. + supportedOauthFlows: + type: oauth2 + description: Flows to support OAuth 2.0 + flows: + implicit: + authorizationUrl: 'https://authserver.example/auth' + scopes: + 'dummy:created': Ability to create dummy message + 'dymmy:read': Ability to read dummy info + password: + tokenUrl: 'https://authserver.example/token' + scopes: + 'dummy:created': Ability to create dummy message + 'dymmy:read': Ability to read dummy info + clientCredentials: + tokenUrl: 'https://authserver.example/token' + scopes: + 'dummy:created': Ability to create dummy message + 'dymmy:read': Ability to read dummy info + authorizationCode: + authorizationUrl: 'https://authserver.example/auth' + tokenUrl: 'https://authserver.example/token' + refreshUrl: 'https://authserver.example/refresh' + scopes: + 'dummy:created': Ability to create dummy message + 'dymmy:read': Ability to read dummy info + openIdConnectWellKnown: + type: openIdConnect + openIdConnectUrl: 'https://authserver.example/.well-known' + + parameters: + dummy: + description: The ID of the new dummy message. + schema: + type: string + description: Description that not be rendered, as parameter has explicit description. + + messageTraits: + commonHeaders: + headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + correlationId: + type: string + + operationTraits: + kafka: + bindings: + kafka: + groupId: my-app-group-id + clientId: my-app-client-id + bindingVersion: '0.1.0' \ No newline at end of file diff --git a/github-action/test/specification-invalid.yml b/github-action/test/specification-invalid.yml new file mode 100644 index 00000000000..0cc34cb56f6 --- /dev/null +++ b/github-action/test/specification-invalid.yml @@ -0,0 +1,23 @@ +asyncapi: 2.2.0 +info: + title: Account Service +version: 1.0.0 +description: This service is in charge of processing user signups +channels: + user/signedup: + subscribe: + message: + $ref: '#/components/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 diff --git a/github-action/test/unoptimized.yml b/github-action/test/unoptimized.yml new file mode 100644 index 00000000000..acbed10a65d --- /dev/null +++ b/github-action/test/unoptimized.yml @@ -0,0 +1,78 @@ +asyncapi: 2.0.0 +info: + title: Streetlights API + version: '1.0.0' +channels: + smartylighting/event/{streetlightId}/lighting/measured: + parameters: + #this parameter is duplicated. it can be moved to components and ref-ed from here. + streetlightId: + schema: + type: string + subscribe: + operationId: receiveLightMeasurement + traits: + - bindings: + kafka: + clientId: my-app-id + message: + name: lightMeasured + title: Light measured + contentType: application/json + traits: + - headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + payload: + type: object + properties: + lumens: + type: integer + minimum: 0 + #full form is used, we can ref it to: #/components/schemas/sentAt + sentAt: + type: string + format: date-time + smartylighting/action/{streetlightId}/turn/on: + parameters: + streetlightId: + schema: + type: string + publish: + operationId: turnOn + traits: + - bindings: + kafka: + clientId: my-app-id + message: + name: turnOnOff + title: Turn on/off + traits: + - headers: + type: object + properties: + my-app-header: + type: integer + minimum: 0 + maximum: 100 + payload: + type: object + properties: + sentAt: + $ref: "#/components/schemas/sentAt" +components: + messages: + #libarary should be able to find and delete this message, because it is not used anywhere. + unusedMessage: + name: unusedMessage + title: This message is not used in any channel. + + schemas: + #this schema is ref-ed in one channel and used full form in another. library should be able to identify and ref the second channel as well. + sentAt: + type: string + format: date-time \ No newline at end of file diff --git a/package.json b/package.json index 46a739f2477..15f47abd99b 100644 --- a/package.json +++ b/package.json @@ -169,12 +169,15 @@ "pretest:coverage": "npm run build", "posttest": "rimraf ./test.asyncapi-cli", "release": "semantic-release", - "test": "npm run test:unit", + "test": "npm run test:unit && npm run action:test", "test:unit": "cross-env NODE_ENV=development TEST=1 CUSTOM_CONTEXT_FILENAME=\"test.asyncapi-cli\" CUSTOM_CONTEXT_FILE_LOCATION=\"\" nyc --extension .ts mocha --require ts-node/register --require test/helpers/init.js --reporter spec --timeout 100000 \"test/**/*.test.ts\"", "test:one": "cross-env NODE_ENV=development TEST=1 CUSTOM_CONTEXT_FILENAME=\"test.asyncapi-cli\" CUSTOM_CONTEXT_FILE_LOCATION=\"\" nyc --extension .ts mocha --require ts-node/register --require test/helpers/init.js --reporter spec --timeout 100000", "get-version": "echo $npm_package_version", "createhook": "oclif generate hook myhook --event=command_not_found", - "createhookinit": "oclif generate hook inithook --event=init" + "createhookinit": "oclif generate hook inithook --event=init", + "action:docker:build": "docker build -f github-action/Dockerfile -t asyncapi/github-action-for-cli:latest .", + "action:bump:version": "npm --no-git-tag-version --allow-same-version version $VERSION", + "action:test": "cd github-action && make test" }, "types": "lib/index.d.ts" }