Using Gitlab Variables in Gitlab README.md for SonarQube Badges

IMPORTANT!

You should implement a branch/logic to avoid triggering the .gitlab-ci.yml in an infinite loop because you are asking to update a repository file from the CI itself

The approach is:

  1. Prepare README.md with special delimiters around the badge
  2. Substitute old/initial badge by payload (you should build it, not shown here) in the repository loaded README.md
  3. urlencode the substituted content
  4. Update the repository with the Gitlab API

README.md

Hello
[//]: # (-- start --)
Initial non working badge
[//]: # (-- end --)
World

.gitlab-ci.yml

update_readme:
  script:
  - curl --request PUT --header 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v4/projects/13083/repository/README%2Emd?branch=master&content=$(urlencode "$(sed 's_\[//\]: # (-- end --)_\n&_g;s_\(\[//\]: # (-- start --)\)[^\n]*\n_\1\npayload\n_g' README.md)")&commit_message=update%20file'

In sed command, substitute payload with your actual badge (you should build it, not shown here)

  • The solution is to write the README.md using the Update existing file in repository API
  • The README.md should use the special string delimiters that do not appear rendered (they are like hidden comments). These delimiters are always in the file, they do not get substituted. Only what it is in between them get subtituted. This way you can automatically update the badge each time you run the .gitlab-ci.yml (only the badge get updated)
  • The substitution is done by the sed command so you need to add the path to the README.md
  • The update API needs the content to be urlencoded (so the sed command is wrapped by a bash urlencode() function that should be loaded first (loading not shown):

urlencode()

urlencode() {
    # urlencode <string>
    old_lc_collate=$LC_COLLATE
    LC_COLLATE=C

    local length="${#1}"
    for (( i = 0; i < length; i++ )); do
        local c="${1:i:1}"
        case $c in
            [a-zA-Z0-9.~_-]) printf "$c" ;;
            *) printf '%%%02X' "'$c" ;;
        esac
    done

    LC_COLLATE=$old_lc_collate
}

Notes: The [//]: # (-- start --) does not affect the render of your README.md so you can use it like hidden comments

Replace your private token with a Gitlab CI Secret variable


The variables in https://gitlab.com/help/ci/variables/README.md are present only in a CI environment (i.e. a job), so you can't use them in the Markdown viewer when displaying the file. - That's a great idea for a feature proposal, though. I opened one - https://gitlab.com/gitlab-org/gitlab-ce/issues/32255. Feel free to chime in.

What you could do is add a placeholder where you want those variables to go and then create a job which sed's them.

update_readme:
  script:
    - echo $CI_PROJECT_NAME # Sanity check
    - sed -ie "s/{THIS}/$CI_PROJECT_NAME/g" README.md

Note the use of double-quotes (") and not single quotes ('). Using double-quotes will interpolate $CI_PROJECT_NAME while single-quotes would just retain it's literal value.