SonarQube β ΡΡΠΎ ΠΎΡΠΊΡΡΡΠ°Ρ ΠΏΠ»Π°ΡΡΠΎΡΠΌΠ° Π΄Π»Ρ ΠΎΠ±Π΅ΡΠΏΠ΅ΡΠ΅Π½ΠΈΡ Π½Π΅ΠΏΡΠ΅ΡΡΠ²Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°, ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΈΠ²Π°ΡΡΠ°Ρ Π±ΠΎΠ»ΡΡΠΎΠ΅ ΠΊΠΎΠ»ΠΈΡΠ΅ΡΡΠ²ΠΎ ΡΠ·ΡΠΊΠΎΠ² ΠΏΡΠΎΠ³ΡΠ°ΠΌΠΌΠΈΡΠΎΠ²Π°Π½ΠΈΡ ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡΡΠ°Ρ ΠΏΠΎΠ»ΡΡΠ°ΡΡ ΠΎΡΡΠ΅ΡΡ ΠΏΠΎ ΡΠ°ΠΊΠΈΠΌ ΠΌΠ΅ΡΡΠΈΠΊΠ°ΠΌ, ΠΊΠ°ΠΊ Π΄ΡΠ±Π»ΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅ ΠΊΠΎΠ΄Π°, ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΠΈΠ΅ ΡΡΠ°Π½Π΄Π°ΡΡΠ°ΠΌ ΠΊΠΎΠ΄ΠΈΡΠΎΠ²Π°Π½ΠΈΡ, ΠΏΠΎΠΊΡΡΡΠΈΠ΅ ΡΠ΅ΡΡΠ°ΠΌΠΈ, ΡΠ»ΠΎΠΆΠ½ΠΎΡΡΡ ΠΊΠΎΠ΄Π°, ΠΏΠΎΡΠ΅Π½ΡΠΈΠ°Π»ΡΠ½ΡΠ΅ ΠΎΡΠΈΠ±ΠΊΠΈ ΠΈ Ρ.Π΄. SonarQube ΡΠ΄ΠΎΠ±Π½ΠΎ Π²ΠΈΠ·ΡΠ°Π»ΠΈΠ·ΠΈΡΡΠ΅Ρ ΡΠ΅Π·ΡΠ»ΡΡΠ°ΡΡ Π°Π½Π°Π»ΠΈΠ·Π° ΠΈ ΠΏΠΎΠ·Π²ΠΎΠ»ΡΠ΅Ρ ΠΎΡΡΠ»Π΅ΠΆΠΈΠ²Π°ΡΡ Π΄ΠΈΠ½Π°ΠΌΠΈΠΊΡ ΡΠ°Π·Π²ΠΈΡΠΈΡ ΠΏΡΠΎΠ΅ΠΊΡΠ° Π²ΠΎ Π²ΡΠ΅ΠΌΠ΅Π½ΠΈ.
ΠΠ°Π΄Π°ΡΠ°: ΠΠΎΠΊΠ°Π·ΡΠ²Π°ΡΡ ΡΠ°Π·ΡΠ°Π±ΠΎΡΡΠΈΠΊΠ°ΠΌ ΡΡΠ°ΡΡΡ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° Π² SonarQube.
ΠΡΡΡ Π΄Π²Π° ΡΠΏΠΎΡΠΎΠ±Π° ΡΠ΅ΡΠ΅Π½ΠΈΡ:
- ΠΠ°ΠΏΡΡΠΊΠ°ΡΡ ΡΠΊΡΠΈΠΏΡ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ ΡΡΠ°ΡΡΡΠ° ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° Π² SonarQube. ΠΡΠ»ΠΈ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° Π² SonarQube Π½Π΅ ΠΏΡΠΎΡ ΠΎΠ΄ΠΈΡ, ΡΠΎ ΡΠ΅ΠΉΠ»ΠΈΡΡ ΡΠ±ΠΎΡΠΊΡ.
- ΠΠΎΠΊΠ°Π·ΡΠ²Π°ΡΡ Π½Π° Π³Π»Π°Π²Π½ΠΎΠΉ ΡΡΡΠ°Π½ΠΈΡΠ΅ ΠΏΡΠΎΠ΅ΠΊΡΠ° ΡΡΠ°ΡΡΡ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ
ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°.
Π£ΡΡΠ°Π½ΠΎΠ²ΠΊΠ° SonarQube
ΠΠ»Ρ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠΈ sonarqube ΠΈΠ· rpm ΠΏΠ°ΠΊΠ΅ΡΠΎΠ² Π²ΠΎΡΠΏΠΎΠ»ΡΠ·ΡΠ΅ΠΌΡΡ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠ΅ΠΌ
Π£ΡΡΠ°Π½ΠΎΠ²ΠΈΠΌ ΠΏΠ°ΠΊΠ΅Ρ Ρ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠ΅ΠΌ Π΄Π»Ρ CentOS 7.
yum install -y https://harbottle.gitlab.io/harbottle-main/7/x86_64/harbottle-main-release.rpm
Π£ΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ΡΠ°ΠΌ sonarqube.
yum install -y sonarqube
ΠΡΠΈ ΡΡΡΠ°Π½ΠΎΠ²ΠΊΠ΅ ΡΡΡΠ°Π½ΠΎΠ²ΡΡΡΡ Π±ΠΎΠ»ΡΡΠΈΠ½ΡΡΠ²ΠΎ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ², Π½ΠΎ Π½ΡΠΆΠ½ΠΎ Π΄ΠΎΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ findbugs ΠΈ pmd
yum install -y sonarqube-findbugs sonarqube-pmd
ΠΠ°ΠΏΡΡΠΊΠ°Π΅ΠΌ ΡΠ΅ΡΠ²ΠΈΡ ΠΈ Π΄ΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ Π² Π°Π²ΡΠΎΠ·Π°Π³ΡΡΠ·ΠΊΡ
systemctl start sonarqube
systemctl enable sonarqube
ΠΡΠ»ΠΈ Π΄ΠΎΠ»Π³ΠΎ Π·Π°Π³ΡΡΠΆΠ°Π΅ΡΡΡ, ΡΠΎ Π΄ΠΎΠ±Π°Π²ΡΡΠ΅ Π² ΠΊΠΎΠ½Π΅Ρ ΠΎΠΏΡΠΈΠΉ sonar.web.javaOpts Π³Π΅Π½Π΅ΡΠ°ΡΠΎΡ ΡΠ»ΡΡΠ°ΠΉΠ½ΡΡ ΡΠΈΡΠ΅Π» /dev/./urandom
sonar.web.javaOpts=Π΄ΡΡΠ³ΠΈΠ΅ ΠΏΠ°ΡΠ°ΠΌΠ΅ΡΡΡ -Djava.security.egd=file:/dev/urandom
ΠΠ°ΠΏΡΡΠΊ ΡΠΊΡΠΈΠΏΡΠ° ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ ΡΡΠ°ΡΡΡΠ° ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π° Π² SonarQube.
Π ΡΠΎΠΆΠ°Π»Π΅Π½ΠΈΡ, ΠΏΠ»Π°Π³ΠΈΠ½ sonar-break-maven-plugin Π΄Π°Π²Π½ΠΎ Π½Π΅ ΠΎΠ±Π½ΠΎΠ²Π»ΡΠ»ΡΡ. ΠΠΎΡΡΠΎΠΌΡ Π½Π°ΠΏΠΈΡΠ΅ΠΌ ΡΠ²ΠΎΠΉ ΡΠΊΡΠΈΠΏΡ.
ΠΠ»Ρ ΡΠ΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΡ Π±ΡΠ΄Π΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΡ ΡΠ΅ΠΏΠΎΠ·ΠΈΡΠΎΡΠΈΠΉ
ΠΠΌΠΏΠΎΡΡΠΈΡΡΠ΅ΠΌ Π² Gitlab. ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ ΡΠ°ΠΉΠ» .gitlab-ci.yml:
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=~/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
SONAR_HOST_URL: "http://172.26.9.226:9000"
LOGIN: "admin" # Π»ΠΎΠ³ΠΈΠ½ sonarqube
PASSWORD: "admin" # ΠΏΠ°ΡΠΎΠ»Ρ sonarqube
cache:
paths:
- .m2/repository
build:
image: maven:3.3.9-jdk-8
stage: build
script:
- apt install -y jq || true
- mvn $MAVEN_CLI_OPTS -Dmaven.test.failure.ignore=true org.jacoco:jacoco-maven-plugin:0.8.5:prepare-agent clean verify org.jacoco:jacoco-maven-plugin:0.8.5:report
- mvn $MAVEN_CLI_OPTS -Dmaven.test.skip=true verify sonar:sonar -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$LOGIN -Dsonar.password=$PASSWORD -Dsonar.gitlab.project_id=$CI_PROJECT_PATH -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
- export URL=$(cat target/sonar/report-task.txt | grep ceTaskUrl | cut -c11- ) #URL where report gets stored
- echo $URL
- |
while : ;do
curl -k -u "$LOGIN":"$PASSWORD" "$URL" -o analysis.txt
export status=$(cat analysis.txt | jq -r '.task.status') #Status as SUCCESS, CANCELED, IN_PROGRESS or FAILED
echo $status
if [ ${status} == "SUCCESS" ];then
echo "SONAR ANALYSIS SUCCESS";
break
fi
sleep 5
done
- curl -k -u "$LOGIN":"$PASSWORD" "$URL" -o analysis.txt
- export status=$(cat analysis.txt | jq -r '.task.status') #Status as SUCCESS, CANCELED or FAILED
- export analysisId=$(cat analysis.txt | jq -r '.task.analysisId') #Get the analysis Id
- |
if [ "$status" == "SUCCESS" ]; then
echo -e "SONAR ANALYSIS SUCCESSFUL...ANALYSING RESULTS";
curl -k -u "$LOGIN":"$PASSWORD" "$SONAR_HOST_URL/api/qualitygates/project_status?analysisId=$analysisId" -o result.txt; #Analysis result like critical, major and minor issues
export result=$(cat result.txt | jq -r '.projectStatus.status');
if [ "$result" == "ERROR" ];then
echo -e "91mSONAR RESULTS FAILED";
echo "$(cat result.txt | jq -r '.projectStatus.conditions')"; #prints the critical, major and minor violations
exit 1 #breaks the build for violations
else
echo -e "SONAR RESULTS SUCCESSFUL";
echo "$(cat result.txt | jq -r '.projectStatus.conditions')";
exit 0
fi
else
echo -e "e[91mSONAR ANALYSIS FAILEDe[0m";
exit 1 #breaks the build for failure in Step2
fi
tags:
- docker
Π€Π°ΠΉΠ» .gitlab-ci.yml Π½Π΅ΠΈΠ΄Π΅Π°Π»ΡΠ½ΡΠΉ. Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π»ΡΡ Π΅ΡΠ»ΠΈ Π·Π°Π΄Π°ΡΠΈ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ Π² sonarqube Π·Π°Π²Π΅ΡΡΠ°Π»ΠΈΡΡ ΡΡΠ°ΡΡΡΠΎΠΌ: "SUCCESS". ΠΠΎΠΊΠ° ΡΡΠΎ Π΄ΡΡΠ³ΠΈΠ΅ ΡΡΠ°ΡΡΡΠΎΠ² Π½Π΅ Π±ΡΠ»ΠΎ. ΠΠ°ΠΊ Π±ΡΠ΄ΡΡ Π΄ΡΡΠ³ΠΈΠ΅ ΡΡΠ°ΡΡΡΡ, ΠΏΠΎΠΏΡΠ°Π²Π»Ρ .gitlab-ci.yml Π² ΡΡΠΎΠΌ ΠΏΠΎΡΡΠ΅.
ΠΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΠ΅ Π½Π° Π³Π»Π°Π²Π½ΠΎΠΉ ΡΡΡΠ°Π½ΠΈΡΠ΅ ΠΏΡΠΎΠ΅ΠΊΡΠ° ΡΡΠ°ΡΡΡ ΠΊΠΎΠ½ΡΡΠΎΠ»Ρ ΠΊΠ°ΡΠ΅ΡΡΠ²Π° ΠΈΡΡ ΠΎΠ΄Π½ΠΎΠ³ΠΎ ΠΊΠΎΠ΄Π°
Π£ΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅ΠΌ ΠΏΠ»Π°Π³ΠΈΠ½ Π΄Π»Ρ SonarQube
yum install -y sonarqube-qualinsight-badges
ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ Π² SonarQube ΠΏΠΎ Π°Π΄ΡΠ΅ΡΡ
Π‘ΠΎΠ·Π΄Π°Π΅ΠΌ ΠΎΠ±ΡΡΠ½ΠΎΠ³ΠΎ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ "badges".
ΠΠ°Ρ
ΠΎΠ΄ΠΈΠΌ ΠΏΠΎΠ΄ ΡΡΠΈΠΌ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Π΅ΠΌ Π² SonarQube.
ΠΠ°Ρ ΠΎΠ΄ΠΈΠΌ Π² "My account", ΡΠΎΠ·Π΄Π°Π΅ΠΌ Π½ΠΎΠ²ΡΠΉ ΡΠΎΠΊΠ΅Ρ, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ Ρ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ΠΌ "read_all_repository" ΠΈ Π½Π°ΠΆΠΈΠΌΠ°Π΅ΠΌ "Genereate".
ΠΠΈΠ΄ΠΈΠΌ ΡΡΠΎ ΠΏΠΎΡΠ²ΠΈΠ»ΡΡ ΡΠΎΠΊΠ΅Π½. ΠΠ½ ΠΏΠΎΡΠ²Π»Π΅ΡΡΡ ΡΠΎΠ»ΡΠΊΠΎ 1 ΡΠ°Π·.
ΠΠ°Ρ ΠΎΠ΄ΠΈΠΌ ΠΏΠΎΠ΄ Π°Π΄ΠΌΠΈΠ½ΠΈΡΡΡΠ°ΡΠΎΡΠΎΠΌ.
ΠΠ΄Π΅ΠΌ Π² Configuration -> SVG Badges
ΠΠΎΠΏΠΈΡΡΠ΅ΠΌ ΡΡΠΎΡ ΡΠΎΠΊΠ΅Π½ Π² ΠΏΠΎΠ»Π΅ "Activity badge token" ΠΈ Π½Π°ΠΆΠΈΠΌΠ°Π΅ΠΌ ΠΊΠ½ΠΎΠΏΠΊΡ save.
ΠΠ°Ρ ΠΎΠ΄ΠΈΠΌ Π² Administration -> Security -> Permission Templates -> Default template (ΠΈ Π΄ΡΡΠ³ΠΈΠ΅ ΡΠ°Π±Π»ΠΎΠ½Ρ, ΠΊΠΎΡΠΎΡΡΠ΅ Ρ Π²Π°Ρ Π±ΡΠ΄ΡΡ).
Π£ ΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°ΡΠ΅Π»Ρ badges Π½Π΅ΠΎΠ±Ρ ΠΎΠ΄ΠΈΠΌΠΎ ΡΡΡΠ°Π½ΠΎΠ²ΠΈΡΡ Π³Π°Π»ΠΊΡ "Browse".
Π’Π΅ΡΡΠΈΡΠΎΠ²Π°Π½ΠΈΠ΅.
ΠΠ»Ρ ΠΏΡΠΈΠΌΠ΅ΡΠ° Π²ΠΎΠ·ΡΠΌΠ΅ΠΌ ΠΏΡΠΎΠ΅ΠΊΡ
ΠΠΌΠΏΠΎΡΡΠΈΡΡΠ΅ΠΌ ΡΡΠΎΡ ΠΏΡΠΎΠ΅ΠΊΡ.
ΠΠΎΠ±Π°Π²Π»ΡΡΠ΅ΠΌ ΡΠ°ΠΉΠ» .gitlab-ci.yml Π² ΠΊΠΎΡΠ΅Π½Ρ ΠΏΡΠΎΠ΅ΠΊΡΠ° ΡΠΎ ΡΠ»Π΅Π΄ΡΡΡΠΈΠΌ ΡΠΎΠ΄Π΅ΡΠΆΠΈΠΌΡΠΌ.
variables:
MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=~/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -DinstallAtEnd=true -DdeployAtEnd=true"
SONAR_HOST_URL: "http://172.26.9.115:9000"
LOGIN: "admin" # Π»ΠΎΠ³ΠΈΠ½ sonarqube
PASSWORD: "admin" # ΠΏΠ°ΡΠΎΠ»Ρ sonarqube
cache:
paths:
- .m2/repository
build:
image: maven:3.3.9-jdk-8
stage: build
script:
- mvn $MAVEN_CLI_OPTS -Dmaven.test.failure.ignore=true org.jacoco:jacoco-maven-plugin:0.8.5:prepare-agent clean verify org.jacoco:jacoco-maven-plugin:0.8.5:report
- mvn $MAVEN_CLI_OPTS -Dmaven.test.skip=true verify sonar:sonar -Dsonar.host.url=$SONAR_HOST_URL -Dsonar.login=$LOGIN -Dsonar.password=$PASSWORD -Dsonar.gitlab.project_id=$CI_PROJECT_PATH -Dsonar.gitlab.commit_sha=$CI_COMMIT_SHA -Dsonar.gitlab.ref_name=$CI_COMMIT_REF_NAME
tags:
- docker
Π SonarQube ΠΏΡΠΎΠ΅ΠΊΡ Π±ΡΠ΄Π΅Ρ Π²ΡΠ³Π»ΡΠ΄Π΅ΡΡ ΡΠ°ΠΊ:
ΠΠΎΠ±Π°Π²Π»ΡΠ΅ΠΌ bages Π² README.md ΠΈ ΠΎΠ½ΠΈ Π±ΡΠ΄ΡΡ Π²ΡΠ³Π»ΡΠ΄eΡΡ ΡΠ°ΠΊ:
ΠΠΎΠ΄ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ badges Π²ΡΠ³Π»ΡΠ΄ΠΈΡ ΡΠ°ΠΊ:
Π Π°Π·Π±ΠΎΡ ΡΡΡΠΎΠΊΠΈ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ΅Π½ΠΈΡ badges:
[![Quality Gate](http://172.26.9.115:9000/api/badges/gate?key=com.github.jitpack:maven-simple)](http://172.26.9.115:9000/dashboard?id=com.github.jitpack%3Amaven-simple)
[![ΠΠ°Π·Π²Π°Π½ΠΈΠ΅](http://172.26.9.115:9000/api/badges/gate?key=Project Key)](http://172.26.9.115:9000/dashboard?id=id-ΠΏΡΠΎΠ΅ΠΊΡΠ°)
[![Coverage](http://172.26.9.115:9000/api/badges/measure?key=com.github.jitpack:maven-simple&metric=coverage)](http://172.26.9.115:9000/dashboard?id=com.github.jitpack%3Amaven-simple)
[![ΠΠ°Π·Π²Π°Π½ΠΈΠ΅ ΠΠ΅ΡΡΠΈΠΊΠΈ](http://172.26.9.115:9000/api/badges/measure?key=Project Key&metric=ΠΠΠ’Π ΠΠΠ)](http://172.26.9.115:9000/dashboard?id=id-ΠΏΡΠΎΠ΅ΠΊΡΠ°)
ΠΠ΄Π΅ Π²Π·ΡΡΡ/ΠΏΡΠΎΠ²Π΅ΡΠΈΡΡ Project Key ΠΈ id-ΠΏΡΠΎΠ΅ΠΊΡΠ°.
Project Key Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ ΡΠΏΡΠ°Π²Π° Π²Π½ΠΈΠ·Ρ. Π URL Π½Π°Ρ ΠΎΠ΄ΠΈΡΡΡ id-ΠΏΡΠΎΠ΅ΠΊΡΠ°.
ΠΠΏΡΠΈΠΈ Π΄Π»Ρ ΠΏΠΎΠ»ΡΡΠ΅Π½ΠΈΠ΅ ΠΌΠ΅ΡΡΠΈΠΊ ΠΌΠΎΠΆΠ½ΠΎ
ΠΡΠ΅ pull request Π½Π° ΡΠ»ΡΡΡΠ΅Π½ΠΈΠ΅, ΠΈΡΠΏΡΠ°Π²Π»Π΅Π½ΠΈΡ ΠΎΡΠΈΠ±ΠΎΠΊ
Π’Π΅Π»Π΅Π³ΡΠ°ΠΌ ΡΠ°Ρ ΠΏΡΠΎ SonarQube
Π’Π΅Π»Π΅Π³ΡΠ°ΠΌ ΡΠ°Ρ ΠΏΡΠΎ DevSecOps β Π±Π΅Π·ΠΎΠΏΠ°ΡΠ½ΡΠΉ DevOps
ΠΡΡΠΎΡΠ½ΠΈΠΊ: habr.com