728x90

 

 

 


 

Jenkins&Springboot CI/CD 정리(4) <Sonar-bot>

 

 

 

3편에 이어 Jenkins CI/CD 정리 시리즈 마지막 4편을 작성해볼까 합니다.

 

마지막 편은 오픈소스인 Sonar-bot 과 Community-branch-plugin 을 이용하여 SonarQube의 분석 결과를 Gitea의

PR Comment로 남겨주는 작업입니다.

 

이번 편은 Sonar-bot이 Gitea를 사용하는 경우에만 해당하며 그 외에 깃헙을 사용하는경우 Community-branch-plugin 설치만 참고를 하시면 좋을 것 같습니다.

 

우선 Sonar-bot 을 Docker Container 로 띄워 사용을 하게 되었는데 그 이유에 대해 말씀을 드리도록 하겠습니다. 

 

SonarQube 에는 Github, Gitlab, Azure, Bitbucket 등 을 지원하여 분석 결과를 PR comment 로 남기게 하는 기능을 지원하고 있습니다. 하지만 현재 필자가 사용하고 있는 Gitea의 경우 SonarQube Community의 공식 답변에도 Gitea는 지원을 하지 않고 있는 것으로 나옵니다. =(

 

그래서 이부분에 대해 연결할 방법을 찾다 한 Gitea의 project를 보았고 Sonar-bot이라는 오픈소스 프로젝트로 Gitea와의 연결을 지원하게 해주는 것을 발견 하였습니다.

 

우선 Sonar-bot을 사용하기 위해선 SonarQube 내의 PR 설정을 해야 하지만 SonarQube는 이 기능을 유료버전인 Developer 또는 Enterprise 버전이 필요합니다. 이 기능을 무료로 사용하기 위한 플러그인이 Community-branch-plugin 이며 이것 또한 오픈소스 프로젝트로 구성되어져 있습니다. =)

 

Gitea가 아니더라도 Github, Gitlab 등 도 SonarQube의 PR Comment 관련 작업을 무료로 사용하기 위해선 Community-branch-plugin이 필요로 합니다.

 

이제 필자가 겪었던 트러블과  트러블 슈팅을 하였던 과정들을 모두 설명을 하며 Sonar-bot 연결을 완성해보도록 하겠습니다. =)

 

 


 

SonarQube 버전과 Community-branch-plugin 버전

필자가 구축을 하며 경험을 한 것을 토대로 작성을 하다보니 SonarQube버전과 Community-branch-plugin의 jar파일의 버전에 혼동이 올 수 있어 미리 필자가 사용한 SonarQube 버전과 Sonarqube Community Branch Plugin 설치시 다운받는 jar파일의 버전을 먼저 말씀드리도록 하겠습니다.

 

필자의 경우 SornarQubeSonarqube Community Branch Plugin 사이 연동에 있어 SonarQube 버전 문제가 발생하여 SonarQube8.4.2버전, Sonarqube Community Branch Plugin 설치시 다운로드 받아야 할 jar파일은 1.5.0 버전을 다운 받았습니다

 

 

(Flow)

1. Gitea feature branch에서 dev branchpr을 날리고 모든 코드리뷰 후 merge

2. Jenkins CI를 통해 sonarqube analysis & sonarqube qualitygate job을 수행

3. Sonarqube의 분석내용을 웹훅을 통해 Sonar-bot으로 전송

4. Sonarbot에서 Gitea로 분석내용을 전송

 

 


 

우선 Sonarqube에서 위의 내용을 적용시키려면 두 가지 방법이 존재합니다. 유료버전인 Developer Edition을 사용하거나 오픈소스 Plugin을 직접 설치 및 설정하여 사용하는 방법이 있습니다. 필자의 경우 무료로 사용을 위해 Sonarqube Community Branch Plugin을 사용하여 진행해보도록 하겠습니다.

 

먼저 Sornaqube 버전에 맞는 Sonarqube Community Branch Plugin을 설치해주도록 합니다.

아래 링크를 통해 plugin jar파일을 다운받도록 하겠습니다.

 

 

GitHub - mc1arke/sonarqube-community-branch-plugin: A plugin that allows branch analysis and pull request decoration in the Comm

A plugin that allows branch analysis and pull request decoration in the Community version of Sonarqube - GitHub - mc1arke/sonarqube-community-branch-plugin: A plugin that allows branch analysis and...

github.com

 

 

여기부터는 필자가 겪은 트러블에 대한 내용입니다 설치방법만 참고만 해주세요 !

Sonar-bot 설치방법과 셋팅 방법은 동일하니 이부분만 동일하게 수행해주시길 바랍니다. =)

 

필자의 경우 처음 시도를 하였을 때 SonarQube9.7버전으로 사용하고 있었기 때문에 1.12.0버전의 최신버전 jar파일을 다운받아주었습니다. ()

 

 

이제 이 jar 파일을 SonarQubeextensions/plugin 디렉토리 안에 넣어주어야 합니다. 필자의 경우 도커 컨테이너로 SonarQube를 띄우고 있기 때문에 다음과 같이 컨테이너 내부에 접속하여 위치를 확인해보았습니다.

 

docker cp C:\Users\Bryant\Desktop\sonar-plugin\sonarqube-community-branch-plugin-1.12.0.jar 8d08b007a19b:opt/sonarqube/extensions/plugins

로컬환경의 파일을 위와 같은 명령어로 SonarQube의 컨테이너 디렉토리 경로 안으로 붙여넣기를 진행해주었습니다. 도커에서는 파일을 전송하려할 때 cp 명령어를 사용합니다. =)

(필자의 경우 SonarQube를 로컬환경인 윈도우 운영체제에서 컨테이너를 띄운 상태입니다.)

 

필자는 위의 명령어를 입력하였을 때 copying between containers is not supported 라는 에러가 나왔는데요. 이부분은 Stackoverflow의 글을 참고해보니 필자의 경우 윈도우 환경에서 도커 컨테이너를 띄우고 있는데 경로표시에 있어 C:/ 에서 C: 를 컨테이너 이름으로 인식할 수도 있다고 하네요. =)

 

docker cp "C:\Users\Bryant\Desktop\sonar-plugin\sonarqube-community-branch-plugin-1.12.0.jar" 8d08b007a19b:opt/sonarqube/extensions/plugins

그래서 다음과 같이 C: 로 시작하는 경로 부분을 “ “ 로 묶어주어 해결하였습니다. =)

 

 

Sonarqube 컨테이너 내부에 들어와 확인을 하였을 때 정상적으로 jar 파일이 들어온 것을 확인하였습니다. =)

 

다음으로 해주어야 할 일은 sonar.properties를 통해 SonarQube의 설정을 변경해주어야 합니다.

 

sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.12.0.jar=web
sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.12.0.jar=ce

다음과 같이 맨 뒤에 jar파일의 버전을 자신이 SonarQube버전에 맞추어 다운 받은 jar파일의 버전과 동일하게 입력하여 주시면 됩니다.

 

 

이 경우 위 설정을 컨테이너 내에 접속하여 직접 입력하는 방법도 있겠지만 필자의 경우 Sonar.propertiesJenkins에서 관리하고 있기 때문에 위 설정 내용을 다음과 같이 jenkins에 추가해주었습니다. 다른 방식으로는 프로젝트 내에 sonar.properties 를 만들어 관리하거나 Jenkinsfile에 Sonar-Scanner Stage부분에서 직접 명시를 할 수 도 있습니다.

 

 

업데이트를 위해 SonarQube 컨테이너를 재시작 해주었습니다.

 

재시작을 해주었고 위와 같이 MarketplaceCommunity Branch Plugin이 잘 설치된 것을 확인할 수 있습니다.

 

 

 

Sonar-bot 설치 및 셋팅

 

먼저 아래 링크를 통해 프로젝트 파일을 다운받아줍니다.

 

 

gitea-sonarqube-bot

Decorate Gitea Pull Requests with SonarQube analysis results

codeberg.org

 

바탕화면이나 사용하고자 하는 경로에 디렉토리를 하나 만들어줍니다.

 

그리고 다운받은 프로젝트의 config 디렉토리 안에 있는 config.yaml파일을 복사하여 바탕화면에 생성한 디렉토리에 붙여넣어주겠습니다.

 

이제 아래와 같이 config.yml을 수정하여자신의 gitea에 대한 정보와 sonarqube에 대한 정보를 기입해줍니다.

 

 

 

모든 정보를 입력하였다면 이제 Sonar-bot Container 를 띄우도록 합니다.

 

(출처: https://codeberg.org/justusbunsi/gitea-sonarqube-bot)

 

도커 컨테이너 띄우기 전 tag 확인

 

가장 최신 버전인 v0.2.2 버전의 태그를 이용하여 컨테이너를 실행시켜주었습니다.

 

docker run -d -it -p 9001:9001 -e "GITEA_SQ_BOT_PORT=9001" -v "C:\Users\Bryant\Desktop\testSonarBot\config.example.yaml:/home/bot/config/config.yaml" justusbunsi/gitea-sonarqube-bot:v0.2.2

필자는 테스트를 위해 Desktop 경로에 testSonarBot 이라는 디렉토리를 만들어준 후 그 안에 설정이 수정된 yml 파일을 위치시켜주었습니다. -v 옵션인 볼륨설정을 통해 로컬환경에 위치시킨 수정된 .yml 파일을 Sonar-bot 컨테이너 내부의 /home/bot/config/config.yaml 과 싱크를 시켜줍니다.

 

우선 컨테이너는 잘 띄워졌고 Config의 설정변경 사항이 잘 적용 되어 졌는지 보겠습니다.

 

Exec -it (컨테이너ID[두글자정도만 입력해줘도 무방합니다]) /bin/bash

 

Sonar-bot 컨테이너 내부 접속 후

cd config
cat config.yaml

cat 명령어를 이용해 컨테이너 내부의 .yml 파일이 수정된 파일로 잘 변경되어 있는지 확인해줍니다.

Docker 볼륨 옵션이 정상적으로 작동하여 설정변경이 잘 이루어진걸 확인할 수 있습니다.

 

localhost:9001로 접속을 해보면 404 page not found 가 뜰텐데 정상입니다.

 

다음은 Sonar-Qube 서버에 접속 후 사용하고 있는 프로젝트 내의 Project Setting - webhook 에 들어가 webhook을 설정해주었습니다.

 

https://<bot IP:9001>/hooks/sonarqube

bot IP는 sonarbot 컨테이너가 띄워져 있는 서버의 IP를 입력해주세요.

 

필자의 경우 Jenkins CI/CD 시리즈의 3편에서 말했듯 SonarQube와 Sonar-bot을 로컬환경에 컨테이너로 띄워 사용하기 위해 공유기 포트포워딩을 해주었고 bot IP에는 필자의 공유기 Ip 주소를 입력하였습니다.

 

 

 

다음은 Security에 들어가 Browse를 허용해줍니다.

 

http://{bot IP:9001}/hooks/gitea

Gitea도 다음과 같이 Sonar-bot에 대한 webhook 설정을 해줍니다.

 

이제 모든 셋팅이 끝났고 테스트를 진행해보아야 하는데 필자의 경우 Jenkins 빌드시 다음과 같은 에러가 나왔습니다.

 

문제의 원인을 파악해보려 하던 중 필자의 SonarQube의 버전은 9.7 버전 이였지만 Community-branch-plugin 은 아직 SonarQube9.6버전까지 지원을 안 한다는 것을 확인하여 버전을 낮추기로 결정하였습니다. =(

 

 

(해당 문제에 대한 issue 링크입니다)

 

Plugin v1.12.0 incompatible with SonarQube v9.7.0 · Issue #674 · mc1arke/sonarqube-community-branch-plugin

Describe the bug The v1.12.0 version of this plugin doesn't seem to be compatible with SonarQube v9.7.0. To Reproduce Install v1.12.0 to SonarQube v9.7.0. Expected behavior I'd expect the p...

github.com

 

SonarQube버전을 downgrade 하려 했으나 레퍼런스도 많지 않아 보이고 과정이 쉽지 않을 것 같다는 판단과 현재는 구축해보는 것에 초점을  SonarQube 8.4버전의 이미지를 다시 받아 구축을 해보기로 하였습니다.

 

8.4 버전을 선택한 이유는 위의 에러에 대한 원인을 찾던 중 Sonarqube Community Branch Plugin을 설치 할 때 컨테이너에 넣어준 jar파일을 /opt/sonarqube/lib/common에도 넣어주어야 하는데 필자가 사용했던 9.7번전에서는 이경로가 존재하지 않았고 이게 특정 버전부터 /lib/common 경로가 사라진것으로 확인되었습니다.

 

 

(해당 이슈에 대한 링크)

 

Plugin doesn't work with sonarqube 8.9 - No more lib/common folder · Issue #350 · mc1arke/sonarqube-community-branch-plugin

Describe the bug I've upgraded my sonarqube server to version 8.9 released yesterday and the plugin does not work anymore. There are no more lib/common folder in this latest version of sonarqub...

github.com

 


 

 

 

(이 부분 부터는 정상작동 가능한 설정을 담은 설명입니다 !)

 

 

우선 SonarQube를 8.4 버전으로 설치해주었습니다. 만약 이번 시리즈를 잘 따라오셨다면 이미 SonarQube 는 8.4.2 버전으로 잘 설치되어 있을 겁니다. =)

 

 

이후 SonarQube 8.4.2 버전에 맞는 sonarqube-community-branch-plugin-1.5.0.jar 파일을 다시 다운받아 주었습니다.

 

GitHub - mc1arke/sonarqube-community-branch-plugin: A plugin that allows branch analysis and pull request decoration in the Comm

A plugin that allows branch analysis and pull request decoration in the Community version of Sonarqube - GitHub - mc1arke/sonarqube-community-branch-plugin: A plugin that allows branch analysis and...

github.com

 

docker cp "C:\Users\Bryant\Desktop\sonar-plugin\sonarqube-community-branch-plugin-1.5.0.jar" 7faa39a9853e:opt/sonarqube/extensions/plugins

docker cp "C:\Users\Bryant\Desktop\sonar-plugin\sonarqube-community-branch-plugin-1.5.0.jar" 7faa39a9853e:opt/sonarqube/lib/common

그리고 해당 jar 파일을 SonarQube 컨테이너 내부의 opt/sonarqube/extensions/plugins 와 sonarqube/lib/common 경로에 cp 명령어로 넣어주었습니다.

 

 

위와 같이 파일이 정상적으로 컨테이너 내부에 들어갔는지 확인도 꼭 해주세요! =)

 

sonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=web
sonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=ce

필자의 경우 Jenkins에서 관리하고 있는 SonarQubeproperties 설정에서 jar파일의 버전이 바뀌었으니

해당 버전에 맞게 1.5.0으로 바꾸어 주었습니다.

 

docker restart sonarqube

이제 SonarQube container를 다시 시작한 후 플러그인이 잘 설치되었는지 확인해주겠습니다.

 

 

정상적으로 1.5.0 버전의 Community branch plugin이 설치가 되었습니다. =)

 

필자가 겪은 트러블 내용에서 Sonar-bot 설치와 yml 파일 수정 및 sonar-bot에 대한 SonarQube & Gitea 의  Webhook 설정을 모두 하셨다면 대략적인 준비는 끝이 났습니다.

 

 

이제 추가적인 셋팅을 진행하도록 하겠습니다.

 

먼저 필자와 같이 로컬환경에 SonarQube를 구축하였다면 SonarQube 설정에 들어가 base url 을 포트포워딩한 공유기 공인 IP주소:9000 으로 명시를 해주어야 합니다.

 

 

위와 같이 설정을 진행해 주세요.

 

 

그 다음 PR comment를 위한 프로젝트를 하나 더 생성해주도록 합니다. 이때 프로젝트 생성시 token 생성은 따로 하지 않고 아래와 같이 기존에 사용하던 token 사용을 해줍니다. 

 

Using existing token을 선택하고 해당 토큰의 이름을 입력해줍니다. 기존에 사용하던 토큰의 이름은 My Account - Security 에서 확인이 가능합니다.

 

이렇게 프로젝트를 하나 더 생성한 이유는 sonar-bot 을 사용하여 SonarQube pull request 분석을 진행할 때 Jenkinsfile 내에서  SonarQube-Scanner 를 두 번 진행하여야 합니다. 하지만 하나의 프로젝트 내에서 해당 분석을 진행하면 pr-branch에 대한 분석이 정상적으로 이루어 지지 않고 다음과 같이 모두 0으로 표시 됩니다.

 

 

프로젝트 생성을 완료 하였다면 이제 Jenkins 서버로 가서 새로운 SonarQube 프로젝트에 접근할 수 있도록 설정을 진행해주도록 하겠습니다. =)

 

필자의 경우 SonarQube properties 설정인 sonar.projectKey= 와 sonar.projectName= 만 Jenkins 서버에서 관리를 하고 있기 때문에 SonarQube Server 설정을 하나 더 만들어 주었습니다. 

 

 

 

Name은 Jenkinsfile의 Sonar-Scanner Stage에서

withSonarQubeEnv(credentialsId:"sonarqube-token",installationName:'SonarQube-DEV')

다음과  같이 installtionName으로 사용할 ID 값 입니다.

 

 

이제 Jenkinsfile에서 추가 구성을 해보도록 하겠습니다.

 

-Dsonar.pullrequest.key='${PR_ID}'
-Dsonar.pullrequest.branch='${PR_BRANCH}'

 

Pull request 프로젝트의 분석을 위해선 위의 sonar properties 설정이 필요한데 PR_number 는 지속적으로 값이 변경되는 부분이고 PR_branch 또한 어떤 feature branch에서 dev branch 로 merge 를 하는지 지속해서 변경되는 값이기에 해당 PR number 와 branch 값을 얻기 위해 필자는 Jenkinsfile의 첫 번째 Stage인 Set Variable 이라는 변수에 값을 할당하여 다른 Stage에서도 사용이 가능하도록 하는 곳에서 설정을 해주었습니다. 

 

 

 필자의 경우 해당 값을 얻기 위해 git에서 제공하는 환경 변수 값인 ${env.CHANGE_ID}${env.CHANGE_BRANCH} 를 사용해보았지만 모두 null 값이 찍혔고 위의 환경변수는 Github를 사용시에 사용할 수 있는 환경 변수라는 것 같다는 생각이 들었습니다.

 

여러 방식을 시도해보았지만 기본적으로 제공되는 환경변수값을 통해서는 해당 PR_ID 와 PR_Branch 를 얻을 수 없다는 생각에 Stack Over Flow에 질문을 하였고 해답을 찾게 되었습니다. =)

 

 

How to get pr number of gitea at jenkins pipeline?

I'm using gitea & jenkins & sonarqube combination now. I need pr number of gitea for sonarqube pr comment but i don't know how to get pr number at jenkins pipeline. I tried env variables like

stackoverflow.com

 

필자가 받은 답변의 내용으로 곰곰히 생각을 아이디어가 떠올랐고 해당 값이 포함되어 나오는 환경변수에서 subString과 split을 이용하여 해당 값만 추출하는 방식을 선택하였습니다.

 

필자의 경우 Slack 을 통해 Stage 별 알림을 받고 있는 상태였습니다.

알림 내용중 PR merge로 인해 발생된 Jenkins build의 경우 필자가 Set Variable Stage 에서 설정한 아래 환경변수에서

다음과 같은 #109 라는 PR number 와 localtest 라는 feature branch의 값을 확인 할 수 있었습니다.

// Git Commit 메시지
GIT_COMMIT_MESSAGE = sh(script: "git --no-pager show -s --format=%B ${env.GIT_COMMIT}", returnStdout: true).trim();

 

 

GIT_COMMIT_MESSAGE 라는 변수에 담기는 값을 이용하여 substing 과 split을 이용해 PR_number와 PR-branch를 얻을 수 있었습니다.

 

먼저 위 출력 내용을 보면 PR_number는 고정적으로 (# ) 으로 감싸져 나오는 값이였고 feature branch 또한 from 과 into 라는 고정 출력 값에 감싸져 나오는 것을 확인하였습니다.

 

// Git Commit 메시지
GIT_COMMIT_MESSAGE = sh(script: "git --no-pager show -s --format=%B ${env.GIT_COMMIT}", returnStdout: true).trim();
//PR_ID
PR_ID = "${GIT_COMMIT_MESSAGE}".substring("${GIT_COMMIT_MESSAGE}".indexOf('#')+1,"${GIT_COMMIT_MESSAGE}".indexOf(')')).trim();
//PR_BRANCH
PR_BRANCH = "${GIT_COMMIT_MESSAGE}".split("from")[1].split("into")[0].trim();

위 코드와 같이 PR_ID 와 PR_BRANCH 라는 변수에 해당 값만 추출이 되도록 해주었고 아래와 같이 기대하던 결과 값을 얻을 수 있었습니다.

 

 

 

아래는 필자가 설정한 Jenkinsfile 설정 값입니다.

stage("Set Variable") {
            steps {
                script {
                    DOCKER_IMAGE = ''
                    //생성할 Docker Image 이름 지정
                    DOCKER_IMAGE_NAME = "gunyoung/dev"
                    //Container Registry 경로
                    IMAGE_STORAGE = "https://registry.hub.docker.com/"
                    //Container Registry 접근 Credential id
                    IMAGE_STORAGE_CREDENTIAL = "Docker-id"
                    //알림받을 채널
                    SLACK_CHANNEL = "jenkins"
                    SLACK_START_AND_FINISH_COLOR = "#778899";
                    SLACK_SUCCESS_COLOR = "#2C953C";
                    SLACK_FAIL_COLOR = "#FF3232";
                    // Git Commit 계정
                    GIT_COMMIT_AUTHOR = sh(script: "git --no-pager show -s --format=%an ${env.GIT_COMMIT}", returnStdout: true).trim();
                    // Git Commit 메시지
                    GIT_COMMIT_MESSAGE = sh(script: "git --no-pager show -s --format=%B ${env.GIT_COMMIT}", returnStdout: true).trim();
                    //PR_ID
                    PR_ID = "${GIT_COMMIT_MESSAGE}".substring("${GIT_COMMIT_MESSAGE}".indexOf('#')+1,"${GIT_COMMIT_MESSAGE}".indexOf(')')).trim();
                    //PR_BRANCH
                    PR_BRANCH = "${GIT_COMMIT_MESSAGE}".split("from")[1].split("into")[0].trim();
                }
            }
            post {
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_START_AND_FINISH_COLOR,
                        message:
                        "==================================================================\n" +
                        "\n" +
                        "배포 파이프라인이 시작되었습니다.\n" +
                        "${env.JOB_NAME}(${env.BUILD_NUMBER})\n" +
                        "\n" +
                        "-GIT_PR_ID-\n" +
                        ":  ${PR_ID}\n" +
                        "\n" +
                        "-GIT_PR_BRANCH-\n" +
                        ":  ${PR_BRANCH}\n" +
                        "\n" +
                        "-GIT_COMMIT_AUTHOR-\n" +
                        ":  ${GIT_COMMIT_AUTHOR}\n" +
                        "\n" +
                        "-GIT_COMMIT_MESSAGE-\n" +
                        ":  ${GIT_COMMIT_MESSAGE}\n" +
                        "\n" +
                        "<-More info->\n" +
                        "${env.BUILD_URL}"
                    )
                }
            }
        }

먼저 Set Variable Stage에서 두 값을 추출하기 위한 설정과 해당 값을 변수에 담아주도록 하겠습니다.

 

//Sonarqube Scanner - dev
        stage("sonarqube analysis-dev") {
            when {
                branch "develop"
            }
            steps{
                script{
                    def scannerHome = tool 'jenkins Global Tool Configuration에서 등록한 SonarQube Scanner 이름';
                    withSonarQubeEnv(credentialsId:"jenkins에서 등록한 sonarqube credential",installationName:'jenkins 설정에서 등록한 sonarqube 이름') {
                    sh "${scannerHome}/bin/sonar-scanner \
                        -Dsonar.branch.name=master \    <---- 이부분이 추가 되었는데 master는 SonarQube 프로젝트의 default branch 이름입니다.
                        -Dsonar.language=java \
                        -Dsonar.java.source=1.8 \
                        -Dsonar.sources=src/main/java \
                        -Dsonar.test=src/test/java \
                        -Dsonar.test.inclusion=**/*Test.java \
                        -Dsonar.issuesReport.console.enable=true \
                        -Dsonar.junit.reportPaths=build/test-results/test \
                        -Dsonar.java.binaries=build/classes \
                        -Dsonar.java.coveragePlugin=jacoco \
                        -Dsonar.coverage.jacoco.xmlReportPaths=build/jacoco/jacoco.xml \
                        -Dsonar.java.libraries.empty=true \
                        -Dsonar.sourceEncoding=UTF-8 \
                        -Dsonar.exclusions=**/dto/**,**/exception/**,**/constant/**,**/SpringInitProjectApplication.java,**/WebRestController.java,**/FileUploadYaml.java \
                        -Dsonar.java.checkstyle.reportPaths=build/reports/checkstyle-output/checkstyle-report.xml \
                        -Dsonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=web \
                        -Dsonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=ce \
                        "
                    }
                }
            }
            post{
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "Dev branch SonarQube Scanning 을 성공하였습니다."
                    )
                    echo "Success sonarqube analysis"
                }
                failure {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_FAIL_COLOR,
                        message: "Dev branch SonarQube Scanning 을 실패하였습니다.\n" +
                        "\n" +
                        "<-More info->\n" +
                        "${env.BUILD_URL}console\n" +
                        "=================================================================="
                    )
                    echo "Fail sonarqube analysis"
                }
            }
        }

SonarQube Scanner 를 이용한 분석을 두번 진행해주어야 하는데 먼저 기존에 생성했던 SonarQube 프로젝트로 진행을 해줍니다.

 

//Sonarqube Scanner - feature(dev로 merge될 branch)
        stage("sonarqube analysis-feature") {
            when {
                branch "develop"
            }
            steps{
                script{
                    def scannerHome = tool 'SonarQube-Scanner-Feature';
                    withSonarQubeEnv(credentialsId:"sonarqube-token",installationName:'SonarQube-PR') {
                    sh "${scannerHome}/bin/sonar-scanner \
                        -Dsonar.pullrequest.key='${PR_ID}' \
                        -Dsonar.pullrequest.base=master \
                        -Dsonar.pullrequest.branch='${PR_BRANCH}' \
                        -Dsonar.language=java \
                        -Dsonar.java.source=1.8 \
                        -Dsonar.sources=src/main/java \
                        -Dsonar.test=src/test/java \
                        -Dsonar.test.inclusion=**/*Test.java \
                        -Dsonar.issuesReport.console.enable=true \
                        -Dsonar.junit.reportPaths=build/test-results/test \
                        -Dsonar.java.binaries=build/classes \
                        -Dsonar.java.coveragePlugin=jacoco \
                        -Dsonar.coverage.jacoco.xmlReportPaths=build/jacoco/jacoco.xml \
                        -Dsonar.java.libraries.empty=true \
                        -Dsonar.sourceEncoding=UTF-8 \
                        -Dsonar.exclusions=**/dto/**,**/exception/**,**/constant/**,**/SpringInitProjectApplication.java,**/WebRestController.java,**/FileUploadYaml.java \
                        -Dsonar.java.checkstyle.reportPaths=build/reports/checkstyle-output/checkstyle-report.xml \
                        -Dsonar.web.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=web \
                        -Dsonar.ce.javaAdditionalOpts=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-1.5.0.jar=ce \
                        "
                    }
                }
            }
            post{
                success {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_SUCCESS_COLOR,
                        message: "Feature branch SonarQube Scanning 을 성공하였습니다."
                    )
                    echo "Success sonarqube analysis"
                }
                failure {
                    slackSend (
                        channel: SLACK_CHANNEL,
                        color: SLACK_FAIL_COLOR,
                        message: "Feature branch SonarQube Scanning 을 실패하였습니다.\n" +
                        "\n" +
                        "<-More info->\n" +
                        "${env.BUILD_URL}console\n" +
                        "=================================================================="
                    )
                    echo "Fail sonarqube analysis"
                }
            }
        }
-Dsonar.pullrequest.key='${PR_ID}' \
-Dsonar.pullrequest.base=master \
-Dsonar.pullrequest.branch='${PR_BRANCH}' \

다음은 PR branch에 대한 분석인데 위 3가지 설정값이 다르게 설정된다는 것을 확인해주세요.

 

 

 

이제 Sonar-bot 컨테이너 내부의 설정파일과 -v 옵션으로 볼륨설정을 해둔 로컬환경의 yml 파일을 조금 수정해주도록 하겠습니다.

 

먼저 Gitea의 PR comment 에 담길 분석 결과 값 중 new_security_hotspots 값을 추가하여 받도록 설정해줍니다. =)

 

그 다음 namingPattern 의 기존에 켜져있던 정규표현식 부분을 주석처리 해주시고 맨 아래의 정규표현식 주석을 해제해주세요.

 

 

수정된 설정파일이 반영되도록 sonar-bot 컨테이너를 재시작해줍니다. =)

 

 

 

이제 정말 끝이 난 것 같지만 아직 한가지 작업을 더 진행해주어야 합니다....! =(

 

 

SonarQube에서 PR branch 분석은 Main branch인 Master 에서 이루어지지 않고 계속해서 branch 가 생성되며 분석결과가 담깁니다.

 

그렇기 때문에 새로 생성한  FeatuePR 이라는 프로젝트에는 Master branch에 아무런 결과 값이 없어 sonar-bot이 정상적으로 작동하지 않습니다. =(

 

 

조금 번거롭지만 Jenkinsfile 내에서 위 3개 설정을 잠시 지우고 

-Dsonar.branch.name=master \

를 추가하여 Jenkins build를 한 번 진행해주도록 합니다.

 

그럼 다음과 같이 새로 생성한 프로젝트의  master branch에도 결과 값이 담기게 됩니다 !

 

 

이제 다시 Jenkinsfile의 featurePR 의 Sonnar-Scanner 설정에서

-Dsonar.branch.name=master \

위 값을 지워주고 

-Dsonar.pullrequest.key='${PR_ID}' \
-Dsonar.pullrequest.base=master \
-Dsonar.pullrequest.branch='${PR_BRANCH}' \

pullrequest 설정값 3가지를 다시 넣어줍니다.

 

 

 

이제 모든 작업이 끝났습니다.

 

 

Gitea에서 dev branch로 PR을 날린 후 merge 를 하게 되면 아래와 같이 Jenkins build의 SonarQube Quality Gate가 끝난 후 PR comment 가 달리는 것을 확인 할 수 있습니다. =)

 

 

 

sonar-bot 컨테이너 log를 확인하여 web-hook 이 정상적으로 작동하는지 확인 할 수 있습니다. =)

 

 

 

Jenkinsfile 전체 소스코드는 필자의 깃헙을 확인해주시기 바랍니다. =)

 

GitHub - 0AndWild/Jenkins-CICD: Jenkins Ci tool을 활용한 CI/CD 구축

Jenkins Ci tool을 활용한 CI/CD 구축. Contribute to 0AndWild/Jenkins-CICD development by creating an account on GitHub.

github.com

 

 


 

 

 

이상으로 Sonar-bot을 이용한 SonarQube PR comment 까지 마무리하며

Jenkins&Springboot CI/CD 정리 시리즈를 마치도록 하겠습니다. =)

 

 

혹여나 Sonar-bot을 이용하여 SonarQube & Gitea PR comment 작업을 하시는데 있어

어려운 부분이 있으시면 댓글을 남겨주시기 바랍니다 !

 

 

 

긴 글 읽어주셔서 감사합니다 !

 

 

 

 

 

 

 

 

 

 

728x90
반응형
복사했습니다!