Увидел Badges и подчерпнул идею из этого доклада
Привет, коллеги!
Хочу поговорить о такой простой, возможно, бесполезной вещи как баджи(значки).
На самом деле тема уже давно известная всем, но мало у кого доходят руки до того чтобы их сделать , либо просто в них нет необходимости и смысла.
Как это выглядит у меня
Иногда необходимо посмотреть версию сервиса, какая команда закреплена за ним, какая версия jdk/jre используется сейчас для сборки/рантайма и другую необходимую мне информацию о сервисе.
Все, что я перечислил выше и другие полезные мне сведения можно вынести в значки, в шапке репозитория. Сейчас на моих проектах это выглядит вот так:

За обновление всей пачки этих значков отвечает 3 джобы в CI/CD каждого сервиса.
Как сделать такое?
Изначально я решил решил посмотреть на баджи "из коробки" гитлаба.
Такие вещи как, статус пайплайна и покрытие тестами, Gitlab позволяет настроить в пару кликов, по инструкции выше.
Для построения дальнейшей автоматизации - GItlab Project API Badges.
Static Badges
К этому типу значков я отнес те сведения, которые обновляются не регулярно. Например - версия JDK/JRE/MAVEN, закрепленная команда, ссылка на values сервиса:
set-project-java-static-badges: stage: your_stage script: - | base_badges=" TEAM MAVEN JDK JRE CONFIGS" for item in ${base_badges} do id=$(curl --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" | jq '.[] | select(.name == "'${item}'") | .id') curl --request DELETE --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges/"$id"" done - | echo -e "\033[33m Setup TEAM BADGE \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=${TEAM_PINNING_URL}" \ --data "name=TEAM" \ --data-urlencode "image_url=https://img.shields.io/badge/team-2a96e7?style=for-the-badge&logo=jirasoftware&logoColor=white&label=${PRODUCT_TEAM}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup MAVEN BADGE \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=${CI_SERVER_URL}/devops/docker-images/java-images/-/blob/develop/java21/jdk21-maven/Dockerfile" \ --data "name=MAVEN" \ --data-urlencode "image_url=https://img.shields.io/badge/maven-e06666?style=for-the-badge&logo=apachemaven&logoColor=white&label=${MAVEN_VERSION}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup JDK BADGE \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=${CI_SERVER_URL}/backend/microservices/${CI_PROJECT_NAME}/-/blob/develop/.gitlab-ci.yml?ref_type=heads#L19" \ --data "name=JDK" \ --data-urlencode "image_url=https://img.shields.io/badge/JDK-63cde3?style=for-the-badge&logo=openjdk&logoColor=white&label=${JDK_BASE_IMAGE_TAG}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup JRE BADGE \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=${CI_SERVER_URL}/backend/microservices/${CI_PROJECT_NAME}/-/blob/develop/.gitlab-ci.yml?ref_type=heads#L20" \ --data "name=JRE" \ --data-urlencode "image_url=https://img.shields.io/badge/JRE-6a329f?style=for-the-badge&logo=directus&logoColor=white&label=${JRE_BASE_IMAGE_TAG}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup CONFIGS BADGE \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=${CI_SERVER_URL}/backend/microservices-configs/-/tree/dev/${CI_PROJECT_NAME}?ref_type=heads" \ --data "name=CONFIGS" \ --data-urlencode "image_url=https://img.shields.io/badge/configs-0b5394?style=for-the-badge&logo=helm&logoColor=white&label=${CI_PROJECT_NAME}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges"
Sonarqube Badges
Думаю тут все понятно, значки которые берут инфу из SonarQube:
sonarqube-badges ?: stage: test script: - | base_badges=" SONARQUBE_BUGS SONARQUBE_VULNERABILITY SONARQUBE_CODE_SMELL_TOTAL SONARQUBE_CODE_SMELL_CRITICAL SONARQUBE_CODE_COVERAGE" for item in ${base_badges} do id=$(curl --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" | jq '.[] | select(.name == "'${item}'") | .id') curl --request DELETE --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges/"$id"" done - | echo -e "\033[33m Setup SONARQUBE_BUGS BADGE \033[0;m" echo -e "\033[33m Parsing BUGS TOTAL \033[0;m" SONARQUBE_BUGS=$(curl -u "${SONAR_TOKEN}:" "https://cicd.ru/sonarqube/api/issues/search?componentKeys=${SONARQUBE_PROJECT_NAME}&resolved=false&types=BUG&ps=1" | jq .total) echo -e "\033[33m Bugs count:${SONARQUBE_BUGS} \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=https://cicd.ru/sonarqube/project/issues?id=${SONARQUBE_PROJECT_NAME}&resolved=false&types=BUG" \ --data "name=SONARQUBE_BUGS" \ --data-urlencode "image_url=https://img.shields.io/badge/bugs-8fce00?style=flat-square&logo=sonarqube&logoColor=white&label=${SONARQUBE_BUGS}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup SONARQUBE_VULNERABILITY BADGE \033[0;m" echo -e "\033[33m Parsing VULNERABILITY TOTAL \033[0;m" SONARQUBE_VULNERABILITY=$(curl -u "${SONAR_TOKEN}:" "https://cicd.ru/sonarqube/api/issues/search?componentKeys=${SONARQUBE_PROJECT_NAME}&types=VULNERABILITY&ps=1&resolved=false" | jq .total) echo -e "\033[33m Vulnerability count:${SONARQUBE_VULNERABILITY} \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=https://cicd.ru/sonarqube/project/issues?id=${SONARQUBE_PROJECT_NAME}&resolved=false&types=VULNERABILITY" \ --data "name=SONARQUBE_VULNERABILITY" \ --data-urlencode "image_url=https://img.shields.io/badge/vulnerability-8fce00?style=flat-square&logo=sonarqube&logoColor=white&label=${SONARQUBE_VULNERABILITY}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup SONARQUBE_CODE_SMELL_TOTAL BADGE \033[0;m" echo -e "\033[33m Parsing CODE_SMELL_TOTAL TOTAL \033[0;m" SONARQUBE_CODE_SMELL_TOTAL=$(curl -u "${SONAR_TOKEN}:" "https://cicd.ru/sonarqube/api/issues/search?componentKeys=${SONARQUBE_PROJECT_NAME}&types=CODE_SMELL&ps=1&resolved=false" | jq .total) echo -e "\033[33m Code smell total count:${SONARQUBE_CODE_SMELL_TOTAL} \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=https://cicd.ru/sonarqube/project/issues?id=${SONARQUBE_PROJECT_NAME}&resolved=false&types=CODE_SMELL" \ --data "name=SONARQUBE_CODE_SMELL_TOTAL" \ --data-urlencode "image_url=https://img.shields.io/badge/code_smell-8fce00?style=flat-square&logo=sonarqube&logoColor=white&label=${SONARQUBE_CODE_SMELL_TOTAL}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup SONARQUBE_CODE_SMELL_CRITICAL BADGE \033[0;m" echo -e "\033[33m Parsing CODE_SMELL_CRITICAL TOTAL \033[0;m" SONARQUBE_CODE_SMELL_CRITICAL=$(curl -u "${SONAR_TOKEN}:" "https://cicd.ru/sonarqube/api/issues/search?componentKeys=${SONARQUBE_PROJECT_NAME}&types=CODE_SMELL&ps=1&severities=CRITICAL" | jq .total) echo -e "\033[33m Code smell critical count:${SONARQUBE_CODE_SMELL_CRITICAL} \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=https://cicd.ru/sonarqube/project/issues?id=${SONARQUBE_PROJECT_NAME}&resolved=false&severities=CRITICAL&types=CODE_SMELL" \ --data "name=SONARQUBE_CODE_SMELL_CRITICAL" \ --data-urlencode "image_url=https://img.shields.io/badge/critical_code_smell-8fce00?style=flat-square&logo=sonarqube&logoColor=white&label=${SONARQUBE_CODE_SMELL_CRITICAL}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" - | echo -e "\033[33m Setup SONARQUBE_CODE_COVERAGE BADGE \033[0;m" echo -e "\033[33m Parsing CODE_COVERAGE TOTAL \033[0;m" SONARQUBE_CODE_COVERAGE=$(curl -u "${SONAR_TOKEN}:" "https://cicd.ru/sonarqube/api/measures/component?component=${SONARQUBE_PROJECT_NAME}&metricKeys=coverage" | jq -r '.component.measures | .[].value') echo -e "\033[33m Code coverage count:${SONARQUBE_CODE_COVERAGE} \033[0;m" curl --request POST --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=https://cicd.ru/sonarqube/dashboard?id=${SONARQUBE_PROJECT_NAME}" \ --data "name=SONARQUBE_CODE_COVERAGE" \ --data-urlencode "image_url=https://img.shields.io/badge/code_coverage-8fce00?style=flat-square&logo=sonarqube&logoColor=white&label=${SONARQUBE_CODE_COVERAGE}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges"
Deploy Badges
Значек который создается после каждого успешного деплоя:
.after-deploy-env-badge-setup: stage: post-deploy when: on_success script: - | echo -e "\e[35mИдет удаление старого баджа... \e[0m" old_id=$(curl --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" | jq '.[] | select(.name == "'${ENV}'") | .id') curl --request DELETE --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges/"${old_id}"" - | if [[ ${ENV} == *"-"* ]]; then badge_env=$(echo "${ENV//-/--}") else badge_env=${ENV} fi - | echo -e "\033[33m Setup ENV BADGE \033[0;m" curl --request POST --silent --output /dev/null --show-error --fail --header "PRIVATE-TOKEN: ${GITLAB_TOKEN}" \ --data "link_url=${CI_PROJECT_URL}/pipelines/${CI_PIPELINE_ID}" \ --data "name=${ENV}" \ --data-urlencode "image_url=https://img.shields.io/badge/${badge_env}-${COLOR}?style=flat-square&logo=googlechrome&logoColor=white&label=${FINAL_VERSION}" \ "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/badges" dev-badge-setup: variables: ENV: "dev" COLOR: "97d210" needs: - job: deploy-to-dev ? artifacts: true extends: - .after-deploy-env-badge-setup prod-badge-setup: variables: ENV: "prod" COLOR: "cc0000" needs: - job: deploy-to-prod ? artifacts: true extends: - .after-deploy-env-badge-setup
Саммари
Как вы могли заметить, принцип работы этих задачек простой - сначала удаляются старые значки, с помощью for loop, а затем с теми же именами создаются новые значки.
Часть переменных из приведенных выше job-ов, находятся в переменных групп/проектов.
Все это можно переделать под ваши нужды, я лишь показал способ как это сделать. Надеюсь кому-то будет это полезно :)
