From 139c6d18a2a83976e49bd0cbce10f4b40876d6d8 Mon Sep 17 00:00:00 2001 From: Benoit Martin <benoit.martin@orange.com> Date: Mon, 7 Jun 2021 17:40:07 +0200 Subject: [PATCH] feat(sonar): autodetect Merge Request from current branch --- README.md | 23 +++++++++++----------- kicker.json | 9 +++++++-- templates/gitlab-ci-sonar.yml | 37 +++++++++++++++++++++++++++++++++-- 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 28597dd..047b5a4 100644 --- a/README.md +++ b/README.md @@ -29,26 +29,27 @@ It is bound to the `test` stage, and uses the following variables: | :lock: `SONAR_AUTH_TOKEN`| SonarQube authentication [token](https://docs.sonarqube.org/latest/user-guide/user-token/) (depends on your authentication method) | _none_ | | :lock: `SONAR_LOGIN` | SonarQube login (depends on your authentication method) | _none_ | | :lock: `SONAR_PASSWORD` | SonarQube password (depends on your authentication method) | _none_ | -| `SONAR_BASE_ARGS` | SonarQube [analysis arguments](https://docs.sonarqube.org/latest/analysis/analysis-parameters/) | `-Dsonar.host.url=${SONAR_URL} -Dsonar.projectKey=${CI_PROJECT_PATH_SLUG} -Dsonar.projectName=${CI_PROJECT_PATH} -Dsonar.projectBaseDir=. -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.links.ci=${CI_PROJECT_URL}/-/pipelines -Dsonar.links.issue=${CI_PROJECT_URL}/-/issues -Dsonar.branch.name=${CI_COMMIT_REF_NAME}` | +| `SONAR_BASE_ARGS` | SonarQube [analysis arguments](https://docs.sonarqube.org/latest/analysis/analysis-parameters/) | `-Dsonar.host.url=${SONAR_URL} -Dsonar.projectKey=${CI_PROJECT_PATH_SLUG} -Dsonar.projectName=${CI_PROJECT_PATH} -Dsonar.projectBaseDir=. -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.links.ci=${CI_PROJECT_URL}/-/pipelines -Dsonar.links.issue=${CI_PROJECT_URL}/-/issues` | | :lock: `SONAR_GITLAB_TOKEN` | GitLab [access token](https://docs.gitlab.com/ee/user/profile/personal_access_tokens.html) with `api` scope. When set, activates the [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties) integration. | _none_ | +| `SONAR_BRANCH_ANALYSIS_DISABLED` | Set to disable automatic [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/) and [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) | _none_ (enabled) | | `SONAR_GITLAB_ARGS` | Extra arguments to use with [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties) | `-Dsonar.gitlab.url=${CI_SERVER_URL} -Dsonar.gitlab.user_token=${SONAR_GITLAB_TOKEN} -Dsonar.gitlab.project_id=${CI_PROJECT_ID} -Dsonar.gitlab.commit_sha=${CI_COMMIT_SHA} -Dsonar.gitlab.ref_name=${CI_COMMIT_REF_NAME}` | | `SONAR_AUTO_ON_DEV_DISABLED` | When set, SonarQube analysis becomes **manual** on development branches (automatic otherwise) | _none_ | -### About branch analysis +#### Automatic Branch Analysis & Pull Request Analysis -As you can see, default SonarQube analysis arguments uses the [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) -feature (`sonar.branch.name` argument). +By default, this template tries to auto-detect and use [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/) or [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) (depending on the context). -This is a great SonarQube feature but it assumes one of the following conditions: +Those is a great SonarQube features but it assumes one of the following conditions: * you are using a [Developer Edition](https://www.sonarqube.org/developer-edition/) version, -* or you are using Community Edition with an opensource plugin emulating the Branch Analysis feature: - * etiher [sonar-branch-community](https://github.com/msanez/sonar-branch-community), - * or [sonarqube-community-branch-plugin](https://github.com/mc1arke/sonarqube-community-branch-plugin), - * ... +* or you are using Community Edition with an opensource plugin emulating those features, such as [sonarqube-community-branch-plugin](https://github.com/mc1arke/sonarqube-community-branch-plugin). -If you're not in those cases, then the SonarQube analysis will fail with default parameters. You'll have to override the -default `SONAR_BASE_ARGS` and disable it by removing the `sonar.branch.name` argument. +If you're not in one of those cases, then you shall disable this feature by setting `SONAR_BRANCH_ANALYSIS_DISABLED`. + +If you leave the feature enabled, if `SONAR_AUTH_TOKEN` is provided, the template will try to autodetect (using GitLab APIs) an opened merge request matching the current branch: + +* If one is found, a SonarQube [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/) will be made. +* Otherwise, a simple [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/) is performed on the current branch. ### About Sonar GitLab plugin diff --git a/kicker.json b/kicker.json index 54dda86..f84f49d 100644 --- a/kicker.json +++ b/kicker.json @@ -33,14 +33,19 @@ { "name": "SONAR_BASE_ARGS", "description": "SonarQube [analysis arguments](https://docs.sonarqube.org/latest/analysis/analysis-parameters/)", - "default": "-Dsonar.host.url=${SONAR_URL} -Dsonar.projectKey=${CI_PROJECT_PATH_SLUG} -Dsonar.projectName=${CI_PROJECT_PATH} -Dsonar.projectBaseDir=. -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.links.ci=${CI_PROJECT_URL}/-/pipelines -Dsonar.links.issue=${CI_PROJECT_URL}/-/issues -Dsonar.branch.name=${CI_COMMIT_REF_NAME}", + "default": "-Dsonar.host.url=${SONAR_URL} -Dsonar.projectKey=${CI_PROJECT_PATH_SLUG} -Dsonar.projectName=${CI_PROJECT_PATH} -Dsonar.projectBaseDir=. -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.links.ci=${CI_PROJECT_URL}/-/pipelines -Dsonar.links.issue=${CI_PROJECT_URL}/-/issues", "advanced": true }, { "name": "SONAR_GITLAB_TOKEN", - "description": "GitLab API access token. When set, activates the [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties) integration", + "description": "GitLab API access token. When set, activates the [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties) integration, and enables SonarQube [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/)", "secret": true }, + { + "name": "SONAR_BRANCH_ANALYSIS_DISABLED", + "description": "Set to disable automatic [Pull Request Analysis](https://docs.sonarqube.org/latest/analysis/pull-request/) and [Branch Analysis](https://docs.sonarqube.org/latest/branches/overview/)", + "type": "boolean" + }, { "name": "SONAR_GITLAB_ARGS", "description": "Extra arguments to use with [Sonar GitLab plugin](https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties)", diff --git a/templates/gitlab-ci-sonar.yml b/templates/gitlab-ci-sonar.yml index 3c7813c..1b5e2bb 100644 --- a/templates/gitlab-ci-sonar.yml +++ b/templates/gitlab-ci-sonar.yml @@ -28,7 +28,6 @@ variables: -Dsonar.links.homepage=${CI_PROJECT_URL} -Dsonar.links.ci=${CI_PROJECT_URL}/-/pipelines -Dsonar.links.issue=${CI_PROJECT_URL}/-/issues - -Dsonar.branch.name=${CI_COMMIT_REF_NAME} # Sonar GitLab plugin args # see: https://github.com/gabrie-allaigre/sonar-gitlab-plugin/#plugins-properties @@ -118,6 +117,39 @@ stages: fi fi } + + function sonar_autodetect_mr() { + if [[ "$SONAR_BRANCH_ANALYSIS_DISABLED" ]] + then + log_info "Branch Analysis and Merge Request Analysis are disabled" + return + fi + if [[ "$CI_MERGE_REQUEST_ID" ]] + then + # we are in an MR pipeline: no need to pass arguments as the SonarScanner for Maven will + log_info "Merge Request pipeline detected: let Maven plugin handle..." + return + fi + if [[ -n "$SONAR_GITLAB_TOKEN" ]] + then + wget -q "$CI_API_V4_URL/projects/${CI_PROJECT_ID}/merge_requests?state=opened&source_branch=${CI_COMMIT_REF_NAME}&private_token=$SONAR_GITLAB_TOKEN" -O mr.json || log_warn "Failed requesting GitLab API: check \$SONAR_GITLAB_TOKEN" + if [[ -f mr.json ]] && [[ "$(cat mr.json)" != "[]" ]] + then + mr_title=$(sed -E 's/.*"title":"([^"]*)".*/\1/g' < mr.json) + mr_target=$(sed -E 's/.*"target_branch":"([^"]*)".*/\1/g' < mr.json) + mr_id=$(sed -E 's/.*"iid":([0-9]+).*/\1/g' < mr.json) + log_info "Merge Request \\e[33;1m$mr_title\\e[0m detected associated to this branch: trigger MR analysis..." + export sonar_mr_args="-Dsonar.pullrequest.key=$mr_id -Dsonar.pullrequest.branch=${CI_COMMIT_REF_NAME} -Dsonar.pullrequest.base=$mr_target" + else + log_info "No Merge Request associated to this branch: trigger branch analysis..." + export sonar_mr_args="-Dsonar.branch.name=${CI_COMMIT_REF_NAME}" + fi + else + log_info "\$SONAR_GITLAB_TOKEN unset: trigger branch analysis..." + export sonar_mr_args="-Dsonar.branch.name=${CI_COMMIT_REF_NAME}" + fi + } + function unscope_variables() { _scoped_vars=$(env | awk -F '=' "/^scoped__[a-zA-Z0-9_]+=/ {print \$1}" | sort) @@ -265,8 +297,9 @@ sonar: - install_ca_certs "${CUSTOM_CA_CERTS:-$DEFAULT_CA_CERTS}" - eval_java_proxy_args script: + - sonar_autodetect_mr - if [[ "$SONAR_GITLAB_TOKEN" ]]; then sonar_extra_args=$SONAR_GITLAB_ARGS; fi - - sonar-scanner ${TRACE+-Dsonar.verbose=true} $java_proxy_args ${SONAR_AUTH_TOKEN+-Dsonar.login=$SONAR_AUTH_TOKEN} ${SONAR_LOGIN+-Dsonar.login=$SONAR_LOGIN} ${SONAR_PASSWORD+-Dsonar.password=$SONAR_PASSWORD} $SONAR_BASE_ARGS $sonar_extra_args + - sonar-scanner ${TRACE+-Dsonar.verbose=true} $java_proxy_args ${SONAR_AUTH_TOKEN+-Dsonar.login=$SONAR_AUTH_TOKEN} ${SONAR_LOGIN+-Dsonar.login=$SONAR_LOGIN} ${SONAR_PASSWORD+-Dsonar.password=$SONAR_PASSWORD} $SONAR_BASE_ARGS $sonar_extra_args $sonar_mr_args rules: # exclude merge requests - if: $CI_MERGE_REQUEST_ID -- GitLab