Увидел 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-ов, находятся в переменных групп/проектов.
Все это можно переделать под ваши нужды, я лишь показал способ как это сделать. Надеюсь кому-то будет это полезно :)