Validation during Continuous Integration and Delivery

Use the same validations as in the IDE in your 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 your 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).

qodana concepts.dio
Figure 1. Overview Qodana process

The process is as follows:

  1. Read all or parts of your project sources. This can be source code in any programming language or documentation like AsciiDoc.

  2. Process the files like with all the inspections known from IntelliJ. You can add plugins from the Marketplace like in your IDE to support the languages you need.

  3. 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 your 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.

qodana html report
Figure 2. Qodana report with AsciiDoc inspection warnings

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.

qodana pullrequest status
Figure 3. Status as shown in the pull request

Once the user clicks on the details of the code scanning, they see a list of all new violations.

qodana codescanning results
Figure 4. Details of GitHub Code Scanning

Once the user clicks on one of the annotations, GitHub shows the code.

qodana pullrequest annotation
Figure 5. Annotation in the source 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.

While being production ready, Qodana is still in an early stage. At the moment, some workarounds have been applied to make it work with GitHub Actions and GitHub Code Scanning, future versions of Qodana will provide them out-of-the box.

  1. Setup Qodana configuration file. It is placed in the root folder where it will run.

    doc/qodana.yaml
    version: 1.0
    profile:
      path: asciidoc-inspection.xml
    exclude:
      - name: All
        paths:
          - qodana-baseline.sarif.json
          - .grazie.en.yaml
          - contributors-guide/modules/ROOT/images
          - users-guide/modules/ROOT/images
  2. 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.yaml
    <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="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>
  3. Add a workflow the GitHub repository by adding the following file (see docs.yml in the GitHub repo):

    .github/workflows/docs.yml
    name: 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'
    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
            # Check out current repository
            uses: actions/checkout@v3
    
          - 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.37.18/asciidoctor-intellij-plugin-0.37.18.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=166128'
              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=172750'
              unzip grazie-pro.zip
    
          - name: 'Qodana for Docs'
            uses: JetBrains/qodana-action@v5.1.0
            with:
              # https://hub.docker.com/r/jetbrains/qodana-jvm-community/tags
              args: >
                --linter,jetbrains/qodana-jvm-community:2022.1,
                --project-dir,${{ github.workspace }}/doc,
                -v,${{ github.workspace }}/grazie:/opt/idea/plugins/grazie,
                -v,${{ github.workspace }}/grazie-pro:/opt/idea/plugins/grazie-pro,
                -v,${{ github.workspace }}/asciidoctor-intellij-plugin:/opt/idea/plugins/asciidoctor-intellij-plugin,
                --baseline,qodana-baseline.sarif.json
              use-annotations: false
          - name: Add "doc" to paths as qodana ran from "doc" folder
            # Otherwise, GitHub won't be able to match the reported problems to file in the repository
            run: |
              sed -i 's|"uri": "|"uri": "doc/|g' ${{ runner.temp }}/qodana/results/qodana.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@v2
            with:
              # Path to SARIF file relative to the root of the repository
              sarif_file: ${{ runner.temp }}/qodana/results/qodana.sarif.json
    
      github-pages:
        name: GitHub Pages
        runs-on: ubuntu-latest
        needs:
          - qodana-docs
        if: github.ref_name == 'main'
        permissions:
          # allow publishing of github pages
          contents: write
        steps:
    
          # Download plugin artifact provided by the previous job
          - name: Download Artifact
            uses: actions/download-artifact@v3
            with:
              name: qodana-report
    
          - name: Deploy to GitHub Pages
            uses: peaceiris/actions-gh-pages@v3
            with:
              github_token: ${{ secrets.GITHUB_TOKEN }}
              publish_dir: ./results/report
              destination_dir: ./

Open issues with Qodana

The following issues in the Qodana issue tracker are open. Please consider voting for them to make this integration simpler.

  • QD-1291 Qodana easy plugin installation

  • QD-1291 Add soft wrap to code preview