From 81e711d2cd6e23014c0eaef2ec098fe69b711885 Mon Sep 17 00:00:00 2001
From: Pierre Smeyers <pierre.smeyers@gmail.com>
Date: Sun, 14 Apr 2024 18:02:31 +0200
Subject: [PATCH] feat(ruff): generate JSON report when SonarQube is detected

---
 README.md                      |  9 +++++++++
 templates/gitlab-ci-python.yml | 16 +++++++++++-----
 2 files changed, 20 insertions(+), 5 deletions(-)

diff --git a/README.md b/README.md
index 70999de..d406401 100644
--- a/README.md
+++ b/README.md
@@ -294,6 +294,13 @@ This job **disabled by default** and runs [Ruff](https://docs.astral.sh/ruff/) o
 
 :warning: Ruff can replace isort, Black, Bandit, Pylint and much more. [More info](https://github.com/astral-sh/ruff/blob/main/docs/faq.md#which-tools-does-ruff-replace). 
 
+In addition to logs in the console, this job produces the following reports, kept for one week:
+
+| Report         | Format                                                                       | Usage             |
+| -------------- | ---------------------------------------------------------------------------- | ----------------- |
+| `$PYTHON_PROJECT_DIR/reports/py-ruff.gitlab.json` | [GitLab](https://docs.astral.sh/ruff/settings/#output-format) | [GitLab integration](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscodequality) |
+| `$PYTHON_PROJECT_DIR/reports/py-ruff.native.json` | [JSON](https://docs.astral.sh/ruff/settings/#output-format) | [SonarQube integration](https://docs.sonarqube.org/latest/analysis/external-issues/)<br/>_This report is generated only if SonarQube template is detected_ |
+
 ### SonarQube analysis
 
 If you're using the SonarQube template to analyse your Python code, here is a sample `sonar-project.properties` file:
@@ -317,6 +324,8 @@ sonar.python.coverage.reportPaths=reports/py-coverage.cobertura.xml
 sonar.python.pylint.reportPaths=reports/py-lint.parseable.txt
 # Bandit: CSV format (if enabled)
 sonar.python.bandit.reportPaths=reports/py-bandit.bandit.csv
+# Ruff: JSON format (if enabled)
+sonar.python.ruff.reportPaths=reports/py-ruff.native.json
 ```
 
 More info:
diff --git a/templates/gitlab-ci-python.yml b/templates/gitlab-ci-python.yml
index b7482e7..9db6d40 100644
--- a/templates/gitlab-ci-python.yml
+++ b/templates/gitlab-ci-python.yml
@@ -919,18 +919,24 @@ py-ruff:
       if [[  ${BANDIT_ENABLED} == "true" || ${PYLINT_ENABLED} == "true" || ${PYTHON_ISORT_ENABLED} == "true" || ${PYTHON_BLACK_ENABLED} == "true" ]]; then
         log_warn "Ruff can replace isort, Black, Bandit, Pylint"
       fi
-    # Ruff is self dependent tool (written in Rust), so is can be install alone without project dependency (so not need _pip and _run)
+    # Ruff is self dependent tool (written in Rust), it can be installed without project dependencies (_pip and _run don't look required here)
     - pip install ${PIP_OPTS} ruff
-    - ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --output-format gitlab --output-file reports/ruff.gitlab.json || ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --output-format grouped 
-
+    # JSON output (for SonarQube)
+    - |
+      if [[ "$SONAR_HOST_URL" ]]
+      then
+        ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --exit-zero --output-format json --output-file reports/py-ruff.native.json
+      fi
+    # then GitLab and grouped/console formats
+    - ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --output-format gitlab --output-file reports/py-ruff.gitlab.json || ruff check . ${RUFF_ARGS} ${RUFF_EXCLUDE:---extend-exclude .venv,.cache} --output-format grouped 
   artifacts:
     name: "$CI_JOB_NAME artifacts from $CI_PROJECT_NAME on $CI_COMMIT_REF_SLUG"
     expire_in: 1 day
     when: always
     reports:
-      codequality: $PYTHON_PROJECT_DIR/reports/ruff.gitlab.json
+      codequality: $PYTHON_PROJECT_DIR/reports/py-ruff.gitlab.json
     paths:
-      - "$PYTHON_PROJECT_DIR/reports/ruff.gitlab.json"
+      - "$PYTHON_PROJECT_DIR/reports/py-ruff.*"
   rules:
     # exclude if $RUFF_ENABLED not set
     - if: '$RUFF_ENABLED != "true"'
-- 
GitLab