├── .gitattributes ├── .idea └── .name ├── .gitignore ├── docs └── images │ ├── check-summary.png │ ├── sarif-reporting-pr.png │ ├── checkstyle-xml-reporting.png │ └── sarif-reporting-code-scanning-alerts.png ├── .github ├── dependabot.yml └── workflows │ ├── asciidoctor-ghpages.yml │ ├── move-marketplace-tag.yml │ └── release.yml ├── CODE_OF_CONDUCT.md ├── .editorconfig ├── LICENSE ├── README.adoc └── action.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | *.bat text eol=crlf 2 | *.cmd text eol=crlf 3 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Benedikt, a GitHub Action to check your code with diKTat 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | /#*# 3 | *~ 4 | /README.html 5 | /README.pdf 6 | *.swp 7 | -------------------------------------------------------------------------------- /docs/images/check-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saveourtool/benedikt/HEAD/docs/images/check-summary.png -------------------------------------------------------------------------------- /docs/images/sarif-reporting-pr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saveourtool/benedikt/HEAD/docs/images/sarif-reporting-pr.png -------------------------------------------------------------------------------- /docs/images/checkstyle-xml-reporting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saveourtool/benedikt/HEAD/docs/images/checkstyle-xml-reporting.png -------------------------------------------------------------------------------- /docs/images/sarif-reporting-code-scanning-alerts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/saveourtool/benedikt/HEAD/docs/images/sarif-reporting-code-scanning-alerts.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: "github-actions" 7 | # Workflow files stored in the 8 | # default location of `.github/workflows` 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | This is a small code of conduct to have a good and friendly development in diKTat 4 | 5 | ## Good behavior 6 | 7 | We expect everyone to love each other, be kind and polite. 8 | Do not hate anyone for comments on the review or for bugs that he (or she) made in his code. 9 | 10 | ## Unacceptable behavior 11 | 12 | But if you would like to bully some of our contributors - you are always welcome. 13 | We love critics and do not like to be in comfort zone. 14 | We can even organize some underground boxing match for you somewhere in Russia. -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | indent_size = 4 4 | indent_style = space 5 | insert_final_newline = true 6 | max_line_length = 80 7 | trim_trailing_whitespace = true 8 | 9 | [{*.yaml,*.yml}] 10 | indent_size = 2 11 | ij_visual_guides = none 12 | ij_yaml_align_values_properties = do_not_align 13 | ij_yaml_autoinsert_sequence_marker = true 14 | ij_yaml_block_mapping_on_new_line = false 15 | ij_yaml_indent_sequence_value = true 16 | ij_yaml_keep_indents_on_empty_lines = false 17 | ij_yaml_keep_line_breaks = true 18 | ij_yaml_sequence_on_new_line = false 19 | ij_yaml_space_before_colon = false 20 | ij_yaml_spaces_within_braces = true 21 | ij_yaml_spaces_within_brackets = true 22 | -------------------------------------------------------------------------------- /.github/workflows/asciidoctor-ghpages.yml: -------------------------------------------------------------------------------- 1 | name: GitHub Pages Publish 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | name: Publish GitHub Pages 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v4 16 | 17 | # Includes the AsciiDoctor GitHub Pages Action to convert adoc files to 18 | # html and publish to gh-pages branch. 19 | - name: asciidoctor-ghpages 20 | uses: manoelcampos/asciidoctor-ghpages-action@v2 21 | with: 22 | pdf_build: true 23 | # asciidoctor_params: --attribute=nofooter 24 | asciidoctor_params: --attribute=allow-uri-read 25 | # adoc_file_ext: .ascii # default is .adoc 26 | # source_dir: docs/ # default is . 27 | # slides_build: true 28 | pre_build: | 29 | git rm -rf -- .idea/ .editorconfig .gitignore .gitattributes CODE_OF_CONDUCT.md LICENSE *.yml 30 | # post_build: 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /.github/workflows/move-marketplace-tag.yml: -------------------------------------------------------------------------------- 1 | name: Move the Marketplace tag 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | release-version: 7 | required: true 8 | type: string 9 | 10 | jobs: 11 | dist: 12 | name: Move the Marketplace tag 13 | # See https://docs.github.com/en/actions/learn-github-actions/contexts#github-context 14 | if: github.ref_type == 'tag' 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | 20 | - id: tag 21 | name: Tag name 22 | run: | 23 | VERSION_MAJOR="$(echo '${{ inputs.release-version }}' | sed -nE '/^([0-9]+)\.[^\.]+.*$/s//\1/p')" 24 | echo "name=v${VERSION_MAJOR}" >>"${GITHUB_OUTPUT}" 25 | shell: bash 26 | 27 | # The tag may not exist yet, so continue on error. 28 | - name: Delete local tag 29 | run: | 30 | git tag -d '${{ steps.tag.outputs.name }}' 31 | continue-on-error: true 32 | shell: bash 33 | 34 | # The tag may not exist yet, so continue on error. 35 | - name: Delete remote tag 36 | run: | 37 | git push --delete origin '${{ steps.tag.outputs.name }}' 38 | continue-on-error: true 39 | shell: bash 40 | 41 | - name: Create local tag 42 | run: | 43 | git tag '${{ steps.tag.outputs.name }}' 44 | shell: bash 45 | 46 | - name: Push local tag 47 | run: | 48 | git push origin '${{ steps.tag.outputs.name }}' 49 | shell: bash 50 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Create a new release 2 | 3 | on: 4 | workflow_dispatch: 5 | pull_request: 6 | push: 7 | tags: 8 | - 'v*.*' 9 | # Ignore simple tags which are just "aliases" used by the Marketplace. 10 | - '!v1' 11 | - '!v2' 12 | - '!v3' 13 | - '!v4' 14 | - '!v5' 15 | - '!v6' 16 | - '!v7' 17 | - '!v8' 18 | - '!v9' 19 | 20 | jobs: 21 | version: 22 | name: Calculate the release version 23 | runs-on: ubuntu-latest 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | # Infer the release version. Assumes that tags are named `vX.Y.Z`. 28 | - id: version 29 | run: | 30 | if [[ "${GITHUB_REF_TYPE}" == 'branch' ]] 31 | then 32 | RELEASE_VERSION="${GITHUB_SHA}" 33 | else 34 | RELEASE_VERSION="${GITHUB_REF#'refs/tags/v'}" 35 | RELEASE_VERSION="${RELEASE_VERSION//'/'/_}" 36 | fi 37 | 38 | echo "release-version=${RELEASE_VERSION}" >>"${GITHUB_OUTPUT}" 39 | shell: bash 40 | 41 | - id: release 42 | name: Create the release 43 | if: ${{ github.ref_type == 'tag' }} 44 | uses: actions/create-release@v1 45 | env: 46 | GITHUB_TOKEN: ${{ github.token }} 47 | with: 48 | tag_name: ${{ github.ref }} 49 | release_name: v${{ steps.version.outputs.release-version }} 50 | draft: false 51 | prerelease: false 52 | 53 | outputs: 54 | release-version: ${{ steps.version.outputs.release-version }} 55 | upload-url: ${{ steps.release.outputs.upload_url }} 56 | 57 | move-tag: 58 | name: Move the Marketplace tag 59 | needs: [ version ] 60 | uses: ./.github/workflows/move-marketplace-tag.yml 61 | with: 62 | release-version: ${{ needs.version.outputs.release-version }} 63 | secrets: inherit 64 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = A _GitHub Action_ to check your code with https://github.com/saveourtool/diktat[_diKTat_] 2 | :toc: 3 | :imagesdir: docs/images 4 | :tip-caption: pass:[💡] 5 | 6 | [.float-group] 7 | -- 8 | [.left] 9 | image::https://img.shields.io/badge/License-MIT-yellow.svg[License: MIT,link="https://opensource.org/licenses/MIT"] 10 | 11 | [.left] 12 | image::https://badgen.net/github/release/saveourtool/benedikt/latest?color=green[GitHub release,link=https://github.com/saveourtool/benedikt/releases/latest] 13 | 14 | [.left] 15 | image::https://badgen.net/badge/icon/Ubuntu?icon=terminal&label&color=green[Ubuntu Linux] 16 | 17 | [.left] 18 | image::https://badgen.net/badge/icon/macOS?icon=apple&label&color=green[macOS] 19 | 20 | [.left] 21 | image::https://badgen.net/badge/icon/Windows?icon=windows&label&color=green[Windows] 22 | -- 23 | 24 | [TIP] 25 | ==== 26 | An always updated version of this document is available 27 | link:https://saveourtool.github.io/benedikt/ebook.pdf[here] as a PDF e-book. 28 | ==== 29 | 30 | == Features 31 | 32 | * Customizable `diktat-analysis.yml` xref:#config[location]. You can use the 33 | rule set configuration with an alternate name or at a non-default location. 34 | 35 | * Customizable JVM xref:#java-setup[vendor and version]. You can run _diKTat_ 36 | using a default JVM, or you can set up your own one. 37 | 38 | * Customizable xref:#reporter[reporter] (_SARIF_ or _Checkstyle_ XML). 39 | 40 | * Allows multiple xref:#input-paths[input paths]. If you have a multi-module 41 | project and only wish to check certain directories or modules, you can configure 42 | the action accordingly. 43 | 44 | * The summary page contains statistic about detected errors: 45 | + 46 | image::check-summary.png[diKTat Check summary] 47 | 48 | == Usage 49 | 50 | In the simplest scenario, the action can be used without input parameters; you 51 | just need to check out your code first, using 52 | https://github.com/marketplace/actions/checkout[`actions/checkout`]: 53 | 54 | [source,yaml] 55 | ---- 56 | jobs: 57 | diktat_check: 58 | name: 'diKTat Check' 59 | runs-on: ubuntu-latest 60 | 61 | steps: 62 | - uses: actions/checkout@v4 63 | 64 | - uses: saveourtool/benedikt@v2 65 | ---- 66 | 67 | == Configuration 68 | 69 | [#config] 70 | === `config`: custom configuration file 71 | 72 | * Default: `diktat-analysis.yml` 73 | * Required: **no** 74 | 75 | You can override the name or the path of your YAML configuration file using the 76 | `config` input parameter, e. g.: 77 | 78 | [source,yaml] 79 | ---- 80 | - uses: saveourtool/benedikt@v2 81 | with: 82 | config: path/to/diktat-analysis-custom.yml 83 | ---- 84 | 85 | [#reporter] 86 | === `reporter`: requesting a type of reporter 87 | 88 | If you wish, you can report errors in a different format. 89 | 90 | * Default: `sarif` 91 | * Required: **no** 92 | * Possible values: any of the following. 93 | 94 | ** `sarif`: report errors in the 95 | https://github.com/microsoft/sarif-tutorials/blob/main/docs/1-Introduction.md#what-is-sarif[_SARIF_] 96 | format. The output file will be named `report.sarif` and automatically uploaded 97 | to _GitHub_ using the https://github.com/github/codeql-action/tree/v2/upload-sarif[`upload-sarif`] 98 | action. This will enable the check results to be shown as annotations in the 99 | pull request: 100 | + 101 | image::sarif-reporting-pr.png[diKTat SARIF reporting (Pull Request)] 102 | + 103 | as well as in the _Code scanning alerts_ section of your repository: 104 | + 105 | image::sarif-reporting-code-scanning-alerts.png[diKTat SARIF reporting (Code scanning alerts)] 106 | 107 | ** `checkstyle`: this is the reporter of choice if you ever encounter issues 108 | with the `sarif` reporter. Errors are reported in the 109 | https://github.com/checkstyle/checkstyle[_Checkstyle-XML_] format to the file 110 | named `checkstyle-report.xml`. The report is then consumed by the 111 | https://github.com/reviewdog/reviewdog[`reviewdog`] tool and uploaded to 112 | _GitHub_, resulting in code annotations similar to those produced by the `sarif` 113 | reporter: 114 | + 115 | image::checkstyle-xml-reporting.png[Checkstyle-XML reporting assisted by reviewdog] 116 | 117 | [#input-paths] 118 | === `input-paths`: custom source sets 119 | 120 | * Default: none 121 | * Required: **no** 122 | 123 | One or more patterns which indicate the files or directories to check. Use a 124 | multiline string to specify multiple inputs. 125 | 126 | * If an input is a path to a file, it is passed to _diKTat_ as-is: 127 | + 128 | [source,yaml] 129 | ---- 130 | - uses: saveourtool/benedikt@v2 131 | with: 132 | input-paths: | 133 | path/to/file.kt 134 | ---- 135 | 136 | * If an input is a path to a directory, the directory is recursively traversed, 137 | and all `\*.kt` and `*.kts` files are passed to _diKTat_. 138 | + 139 | [source,yaml] 140 | ---- 141 | - uses: saveourtool/benedikt@v2 142 | with: 143 | input-paths: | 144 | src/main/kotlin 145 | src/test/kotlin 146 | ---- 147 | * If an input is an https://ant.apache.org/manual/dirtasks.html#patterns[_Ant_-style 148 | path pattern] (such as `\\**/*.kt`), _diKTat_ expands it into the list of files 149 | that match the path pattern. Path patterns may be negated, e. g.: 150 | `!src/\**/*Test.kt` or `!src/\**/generated/**`. 151 | + 152 | [source,yaml] 153 | ---- 154 | - uses: saveourtool/benedikt@v2 155 | with: 156 | input-paths: | 157 | **/*.kt 158 | **/*.kts 159 | !**/generated/** 160 | ---- 161 | 162 | If this input parameter is not specified, this is equivalent to setting it to 163 | `.`, meaning _diKTat_ will check all `\*.kt` and `*.kts` files in the project 164 | directory unless configured otherwise. 165 | 166 | [#java-setup] 167 | === `java-distribution` and `java-version`: running _diKTat_ using a custom JVM 168 | 169 | It's possible to run _diKTat_ with a custom JVM using the 170 | https://github.com/actions/setup-java[`actions/setup-java`] action. The 171 | following input parameters may be specified: 172 | 173 | * `java-distribution`: the Java distribution, see the 174 | https://github.com/actions/setup-java/blob/main/README.md#supported-distributions[list 175 | of supported distributions]. 176 | 177 | ** Default: `temurin` 178 | ** Required: **no** 179 | 180 | * `java-version`: the Java version to set up. Takes a whole or semver Java 181 | version. See https://github.com/actions/setup-java/blob/main/README.md#supported-version-syntax[examples 182 | of supported syntax]. 183 | 184 | ** Default: none 185 | ** Required: **no** 186 | 187 | [NOTE] 188 | Setting just the `java-distribution` property in order to use a custom 189 | JDK is not sufficient: you'll need to set **both** `java-distribution` **and** 190 | `java-version`: 191 | 192 | [source,yaml] 193 | ---- 194 | - uses: saveourtool/benedikt@v2 195 | with: 196 | java-distribution: 'temurin' 197 | java-version: 17 198 | ---- 199 | 200 | === `fail-on-error`: suppressing lint errors 201 | 202 | * Default: `true` 203 | * Required: **no** 204 | 205 | If `false`, the errors are still reported, but the step completes successfully. 206 | If `true` (the default), then lint errors reported by _diKTat_ are considered 207 | fatal (i.e. the current step terminates with a failure): 208 | 209 | [source,yaml] 210 | ---- 211 | - uses: saveourtool/benedikt@v2 212 | with: 213 | fail-on-error: true 214 | ---- 215 | 216 | [NOTE] 217 | 218 | This flag only affects the case when _diKTat_ exits with code **1**. Higher 219 | link:https://diktat.saveourtool.com/diktat-cli/#exit-codes[exit 220 | codes] are _always_ fatal. 221 | 222 | === `debug`: enabling debug logging 223 | 224 | * Default: `false` 225 | * Required: **no** 226 | 227 | Debug logging can be enabled by setting the `debug` input parameter to `true`: 228 | 229 | [source,yaml] 230 | ---- 231 | - uses: saveourtool/benedikt@v2 232 | with: 233 | debug: true 234 | ---- 235 | 236 | == Outputs 237 | 238 | The action returns the exit code of the command-line client using the 239 | `exit-code` output parameter, e. g.: 240 | 241 | [source,yaml] 242 | ---- 243 | jobs: 244 | diktat_check: 245 | name: 'diKTat Check' 246 | runs-on: ubuntu-latest 247 | 248 | steps: 249 | - uses: actions/checkout@v4 250 | 251 | - id: diktat 252 | uses: saveourtool/benedikt@v2 253 | 254 | - name: 'Read the exit code of diKTat' 255 | if: ${{ always() }} 256 | run: echo "diKTat exited with code ${{ steps.diktat.outputs.exit-code }}" 257 | shell: bash 258 | ---- 259 | 260 | The exit codes are documented 261 | link:https://diktat.saveourtool.com/diktat-cli/#exit-codes[here]. 262 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://json.schemastore.org/github-action.json 2 | 3 | name: 'Benedi.kt' 4 | author: 'The diKTat Team' 5 | description: 'A GitHub Action to check your code with diKTat' 6 | 7 | # Note: when inverting the default values of boolean flags, be sure to also 8 | # invert the values they're compared to, i.e. if a certain flag is `true` by 9 | # default, then it should be compared with `false`, because `false` is the only 10 | # value which users of our action can explicitly set. Cases when a flag is 11 | # merely inset (i.e. is not equal to either `true` or `false`) are quite common. 12 | inputs: 13 | config: 14 | description: > 15 | The location of the YAML configuration file. By default, 16 | diktat-analysis.yml in the current directory is used. 17 | default: 'diktat-analysis.yml' 18 | required: false 19 | reporter: 20 | description: > 21 | The reporter to use, one of: "sarif" (the default) or "checkstyle". 22 | default: 'sarif' 23 | required: false 24 | input-paths: 25 | description: > 26 | One or more patterns which indicate the files or directories to check. 27 | Use a multiline string to specify multiple inputs. 28 | 29 | If an input is a path to a file, it is passed to diKTat as-is. 30 | 31 | If an input is a path to a directory, the directory is recursively 32 | traversed, and all *.kt and *.kts files are passed to diKTat. 33 | 34 | If an input is an Ant-like path pattern (such as "**/*.kt"), diKTat 35 | expands it into the list of files that match the path pattern. Path 36 | patterns may be negated, e. g.: "!src/**/*Test.kt" or 37 | "!src/**/generated/**". 38 | required: false 39 | java-distribution: 40 | description: > 41 | The Java distribution. See the list of supported distributions at 42 | . 43 | The default is "temurin". 44 | 45 | Note that setting just this property in order to use a custom JDK is not 46 | sufficient: please set "java-version", too. 47 | default: 'temurin' 48 | required: false 49 | java-version: 50 | description: > 51 | The Java version to set up. Takes a whole or semver Java version. See 52 | examples of supported syntax at 53 | . 54 | required: false 55 | debug: 56 | description: > 57 | Whether debug logging should be enabled 58 | default: ${{ false }} 59 | required: false 60 | fail-on-error: 61 | description: > 62 | Whether linter errors are considered fatal (the default is true) 63 | default: ${{ true }} 64 | required: false 65 | 66 | outputs: 67 | exit-code: 68 | description: "The exit code of diKTat" 69 | value: ${{ steps.diktat.outputs.exit-code }} 70 | 71 | runs: 72 | using: "composite" 73 | steps: 74 | - id: setup-java 75 | if: ${{ inputs.java-version != null }} 76 | uses: actions/setup-java@v4 77 | with: 78 | distribution: '${{ inputs.java-distribution }}' 79 | java-version: ${{ inputs.java-version }} 80 | 81 | - id: download-diktat 82 | uses: robinraju/release-downloader@v1.8 83 | with: 84 | repository: "saveourtool/diktat" 85 | tag: "v2.0.0" 86 | fileName: "diktat" 87 | 88 | # GitHub seems to set `-e` internally, so don't fail immediately if diKTat 89 | # returns a non-zero exit code but store the exit code in a variable for 90 | # further processing. 91 | # 92 | # This step is always successful but records the exit code in the 93 | # `steps.diktat.outputs.exit-code` variable. 94 | - id: diktat 95 | run: | 96 | if [[ '${{ inputs.debug }}' == 'true' ]] 97 | then 98 | set -x 99 | fi 100 | DIKTAT_ARGS=('--config' '${{ inputs.config }}' '--reporter' '${{ inputs.reporter }}') 101 | if [[ '${{ inputs.reporter }}' == 'sarif' ]] 102 | then 103 | report_file=${GITHUB_WORKSPACE}/report.sarif 104 | elif [[ '${{ inputs.reporter }}' == 'checkstyle' ]] 105 | then 106 | report_file=${GITHUB_WORKSPACE}/checkstyle-report.xml 107 | else 108 | echo " should be set to or " 109 | exit 1 110 | fi 111 | DIKTAT_ARGS+=('--output' "${report_file}") 112 | 113 | if [[ '${{ inputs.debug }}' == 'true' ]] 114 | then 115 | DIKTAT_ARGS+=('--log-level' 'DEBUG') 116 | fi 117 | 118 | set -o pipefail 119 | IFS=$'\n' 120 | INPUT_PATHS=(${{ inputs.input-paths }}) 121 | DIKTAT_CMD=${GITHUB_WORKSPACE}/diktat 122 | chmod +x ${DIKTAT_CMD} 123 | { ${DIKTAT_CMD} "${DIKTAT_ARGS[@]}" "${INPUT_PATHS[@]}" | tee diktat.log; } && exit_code=$? || exit_code=$? 124 | total_lines=$(wc -l diktat.log | cut -d ' ' -f1) 125 | summary_line_number=$(grep -n 'Summary error count (descending) by rule:' diktat.log | cut -d: -f1) 126 | summary_line=$(tail -n $((total_lines - summary_line_number)) diktat.log | sed -e 's/^ //g' | awk '{ printf("%s,", $0) }' | sed -e 's/,$//g') 127 | echo "summary-line=${summary_line}" >>$GITHUB_OUTPUT 128 | rm -f diktat.log 129 | echo "exit-code=${exit_code}" >>$GITHUB_OUTPUT 130 | env: 131 | GITHUB_TOKEN: ${{ github.token }} 132 | shell: bash 133 | 134 | # Creates a summary report and fails the job if necessary. 135 | # 136 | # If `diktat` exited with code 1 (linter errors), return 0 or 1 depending 137 | # on the value of the `fail-on-error` flag. If the exit code is 2 or 138 | # greater, return it as-is, ignoring the flag. 139 | # 140 | # Note: BSD `awk` apparently doesn't understand `\\s`, that's why we're 141 | # splitting on `: *` (a colon followed by a zero or more space characters). 142 | - id: diktat-summary 143 | if: ${{ always() }} 144 | run: | 145 | if (( ${{ steps.diktat.outputs.exit-code }} == 0 )) 146 | then 147 | status_icon=':heavy_check_mark:' 148 | message='completed successfully' 149 | else 150 | status_icon=':x:' 151 | message='exited with code **${{ steps.diktat.outputs.exit-code }}**' 152 | fi 153 | 154 | diktat='[_diKTat_](https://github.com/saveourtool/diktat)' 155 | 156 | echo "${status_icon} ${diktat} ${message}" >>${GITHUB_STEP_SUMMARY} 157 | 158 | if (( ${{ steps.diktat.outputs.exit-code }} != 0 )) 159 | then 160 | echo '```console' >>${GITHUB_STEP_SUMMARY} 161 | echo "${{ steps.diktat.outputs.summary-line }}" | xargs -d ',' -n1 echo >>${GITHUB_STEP_SUMMARY} 162 | echo '```' >>${GITHUB_STEP_SUMMARY} 163 | fi 164 | 165 | if (( ${{ steps.diktat.outputs.exit-code }} <= 1 )) 166 | then 167 | ${GITHUB_WORKSPACE}/diktat --version | awk '{ split($0, versions, ": *"); print " - _" versions[1] "_: **" versions[2] "**" }' >>${GITHUB_STEP_SUMMARY} 168 | fi 169 | 170 | if (( ${{ steps.diktat.outputs.exit-code }} != 1 )) 171 | then 172 | exit ${{ steps.diktat.outputs.exit-code }} 173 | elif [[ '${{ inputs.fail-on-error }}' != 'false' ]] 174 | then 175 | exit 1 176 | fi 177 | shell: bash 178 | 179 | # When in SARIF reporting mode, upload SARIF reports to GitHub. 180 | - id: upload-sarif 181 | if: ${{ always() && steps.diktat.outputs.exit-code == 1 && inputs.reporter == 'sarif' }} 182 | uses: github/codeql-action/upload-sarif@v3 183 | with: 184 | sarif_file: ${{ github.workspace }}/report.sarif 185 | 186 | # Alternatively, when in Checkstyle reporting mode, upload Checkstyle XML 187 | # using `reviewdog`. 188 | # 189 | # `reviewdog` doesn't play well with manual runs (`workflow_dispatch`): 190 | # it fails with 191 | # 192 | # post failed for %s: failed to create check: POST https://api.github.com/repos/%s/%s/check-runs: 422 No commit found for SHA: [] 193 | - id: reviewdog-install 194 | if: ${{ always() && steps.diktat.outputs.exit-code == 1 && inputs.reporter == 'checkstyle' && github.event_name != 'workflow_dispatch' }} 195 | uses: reviewdog/action-setup@v1 196 | 197 | - id: reviewdog 198 | if: ${{ always() && steps.diktat.outputs.exit-code == 1 && inputs.reporter == 'checkstyle' && github.event_name != 'workflow_dispatch' }} 199 | run: | 200 | if [[ '${{ github.event_name }}' == 'pull_request' ]] 201 | then 202 | reviewdog_reporter='github-pr-check' 203 | else 204 | reviewdog_reporter='github-check' 205 | fi 206 | 207 | reviewdog -f=checkstyle -fail-on-error=false -level=info -name='diKTat errors reported by reviewdog' -reporter="${reviewdog_reporter}" <${GITHUB_WORKSPACE}/checkstyle-report.xml 208 | env: 209 | REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }} 210 | shell: bash 211 | 212 | branding: 213 | icon: 'check-circle' 214 | color: 'purple' 215 | --------------------------------------------------------------------------------