Validation during Continuous Integration and Delivery
Use the same validations as in the IDE in the CI/CD setup.
Qodana to run the IntelliJ AsciiDoc plugin in CD/CD
JetBrains published Qodana that wraps the smart features of IntelliJ into a container, so it can be used on the command line as a Docker container. To make this simpler to use, it has been wrapped as a GitHub action.
For AsciiDoc files, it will highlight all the problems that are highlighted in the IDE as well, including broken links (with the help of the AsciiDoc plugin) as well as grammar errors (with the help of the Grazie and Grazie Professional plugins).
The process is as follows:
-
Read all or parts of the project’s sources. This can be source code in any programming language or documentation like AsciiDoc.
-
Process the files like with all the inspections known from IntelliJ. Users can add plugins from the Marketplace like in their IDE to support the languages they need.
-
Generate a report as HTML to be used in a browser, as well as a SARIF report that can be processed by GitHub Code Scanning or other subsequent steps in the CI/CD pipeline.
Example output
HTML report
See below for an HTML report that Qodana generates. With the GitHub Action setup below, it will be attached as a ZIP file to workflow run instance.
The CI/CD process can publish the HTML report to a webserver so users can access it. In the example below, the GitHub action pushes the latest report to the GitHub pages of the AsciiDoc plugin project.
Pull request annotation
See below for a screenshot of an annotated GitHub pull request. Using the SARIF integration, GitHub can compare the pull request with the base branch and will show only new problems introduced by the pull request.
These examples show AsciiDoc syntax errors as examples. This setup shows Grammar in the same way.
Once the user clicks on the details of the code scanning, they see a list of all new violations.
Once the user clicks on one of the annotations, GitHub shows the code.
Example setup for GitHub Actions
This describes the setup used for this plugin. With the benefit of being a real-world scenario, some steps might be more complicated than a simple setup.
-
Setup Qodana configuration file. It is placed in the root folder where it will run.
doc/qodana.yamlversion: 1.0 profile: path: doc/asciidoc-inspection.xml exclude: - name: All paths: - doc/qodana-baseline.sarif.json - doc/.grazie.en.yaml - doc/asciidoc-inspection.xml - doc/contributors-guide/modules/ROOT/images - doc/users-guide/modules/ROOT/images - doc/users-guide/modules/ROOT/examples - CHANGELOG.adoc - README.adoc - build.gradle - buildLexer.xml - settings.gradle - .github - config - gradle - gradlew - gradlew.bat - src - testData
-
Setup file with all inspections to run. It is placed in the root folder where it will run. For this setup, all inspections are specified one-by-one. Alternative setups could configure only deviations from a standard configuration.
doc/asciidoc-inspection.xml<component name="InspectionProjectProfileManager"> <profile version="1.0" is_locked="true"> <!-- GrazieInspection normally has a TYPO preference --> <inspection_tool class="GrazieInspection" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocAnchorWithoutId" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocAttributeContinuation" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocBlockMacroShouldBeInlineMacro" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocDescriptionExists" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocDescriptionLength" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocHeadingStyle" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocHorizontalRule" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocInlineMacroShouldBeBlockOrPreprocessorMacro" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocLinkResolve" enabled="true" level="ERROR" enabled_by_default="true" /> <inspection_tool class="AsciiDocListingStyle" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocPageBreak" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocReferencePattern" enabled="true" level="ERROR" enabled_by_default="true" /> <inspection_tool class="AsciiDocXrefWithFileExtension" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocXrefWithNaturalCrossReference" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocAttributeShouldBeDefined" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocObsoletePassthrough" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="AsciiDocUnresolvedAntoraModule" enabled="true" level="ERROR" enabled_by_default="true" /> <inspection_tool class="SpellCheckingInspection" enabled="true" level="WARNING" enabled_by_default="true"> <option name="processCode" value="true" /> <option name="processLiterals" value="true" /> <option name="processComments" value="true" /> </inspection_tool> <inspection_tool class="Style" enabled="true" level="WARNING" enabled_by_default="true" /> </profile> </component>
-
Add a workflow the GitHub repository by adding the following file (see docs.yml in the GitHub repo):
.github/workflows/docs.ymlname: Qodana Documentation validation on: push: branches-ignore: - 'dependabot/**' paths: - 'doc/**' - '.github/workflows/docs.yml' - 'qodana.yaml' pull_request: paths: - 'doc/**' - '.github/workflows/docs.yml' - 'qodana.yaml' concurrency: # Only run once for latest commit per ref and cancel other (previous) runs. group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: qodana-docs: name: Qodana Docs runs-on: ubuntu-latest permissions: # necessary for the runs of push to store security events in the repo # GitHub code scanning will treat any grammar error like any security event. security-events: write steps: - name: Fetch Sources if: github.event_name != 'pull_request' uses: actions/checkout@v4 - name: Fetch Sources if: github.event_name == 'pull_request' uses: actions/checkout@v4 with: fetch-depth: ${{ github.event.pull_request.commits }} - name: Download AsciiDoc plugin for AsciiDoc checks run: | curl -L -o asciidoctor-intellij-plugin.zip https://github.com/asciidoctor/asciidoctor-intellij-plugin/releases/download/0.41.14/asciidoctor-intellij-plugin-0.41.14.zip unzip asciidoctor-intellij-plugin.zip - name: Download Grazie plugin for grammar checks # https://plugins.jetbrains.com/plugin/12175-grazie/versions run: | curl -L -o grazie.zip 'https://plugins.jetbrains.com/plugin/download?rel=true&updateId=508282' unzip grazie.zip - name: Download Grazie Professional plugin for grammar checks # https://plugins.jetbrains.com/plugin/16136-grazie-professional/versions run: | curl -L -o grazie-pro.zip 'https://plugins.jetbrains.com/plugin/download?rel=true&updateId=529722' unzip grazie-pro.zip - name: Create empty folder to overwrite disabled plugin run: | mkdir empty - name: Get two more commits so Qodana we can identify the changes if: github.event_name == 'pull_request' run: git fetch --deepen=2 - name: 'Qodana for Docs' uses: JetBrains/qodana-action@v2024.2.6 with: upload-result: true # https://hub.docker.com/r/jetbrains/qodana-jvm-community/tags # this disables the Gradle plugin to avoid the Gradle initialization and the dependency download # as that is not necessary for the Grazie and AsciiDoc plugins to check spelling and links. # TODO: the plugin `org.jetbrains.plugins.gradle` should also be suppressed, but the parameter doesn't allow # a comma when called from the Qodana action. Therefore overwrite it with an empty folder. args: > --linter,jetbrains/qodana-jvm-community:2024.2, --property=idea.suppressed.plugins.id=com.intellij.gradle, -v,${{ github.workspace }}/grazie:/opt/idea/plugins/grazie, -v,${{ github.workspace }}/empty:/opt/idea/plugins/gradle-java, -v,${{ github.workspace }}/grazie-pro:/opt/idea/plugins/grazie-pro, -v,${{ github.workspace }}/asciidoctor-intellij-plugin:/opt/idea/plugins/asciidoctor-intellij-plugin, --baseline,doc/qodana-baseline.sarif.json # https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github#example-workflow-that-runs-the-eslint-analysis-tool - name: Upload SARIF report to GitHub # so that it is present on all pull requests and GitHub shows the comparison results uses: github/codeql-action/upload-sarif@v3 with: # Path to SARIF file relative to the root of the repository sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json - name: Upload artifact uses: actions/upload-pages-artifact@v3 with: path: ${{ runner.temp }}/qodana/results/report github-pages: environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} name: GitHub Pages runs-on: ubuntu-latest needs: - qodana-docs if: github.ref_name == 'main' permissions: pages: write id-token: write steps: - name: Setup Pages uses: actions/configure-pages@v5 - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v4