13. Sonarqube實現(xiàn)代碼掃描

1 代碼質(zhì)量測試

官方網(wǎng)站:http://www.sonarqube.org/

SonarQube 是一個用于代碼質(zhì)量管理的開放平臺,通過插件機制,SonarQube可以
集成不同的測試工具,代碼分析工具,以及持續(xù)集成工具,例如 Hudson/Jenkins 等

下載地址:https://www.sonarqube.org/downloads/

七個維度檢測代碼質(zhì)量:

復(fù)雜度分布:代碼復(fù)雜度過高將難以理解
重復(fù)代碼:程序中包含大量復(fù)制、粘貼的代碼而導(dǎo)致代碼臃腫,sonar 可以展示源碼中重復(fù)嚴重的地方
單元測試統(tǒng)計:統(tǒng)計并展示單元測試覆蓋率,開發(fā)或測試可以清楚測試代碼的覆蓋情況
代碼規(guī)則檢查:檢查代碼是否符合規(guī)范
注釋率:若代碼注釋過少,特別是人員變動后,其他人接手比較難接手;若過多,又不利于閱讀
潛在的 Bug:檢測潛在的 bug
結(jié)構(gòu)與設(shè)計:找出循環(huán),展示包與包、類與類之間的依賴、檢查程序之間耦合度

2 Sonarqube

2.1 Sonarqube架構(gòu)

圖片.png
Sonarqube代碼檢測功能由Sonarqube服務(wù)器端提供
SonarScanner需要在執(zhí)行代碼掃描的服務(wù)器安裝, 用于掃描代碼, 并且上傳到Sonarqube Server端

2.2 Sonarqube部署環(huán)境

10.0.0.139  Sonarqube Server 4G 2c  v7.9.6
10.0.0.149 PGSQL 4G 2c
Jenkins master服務(wù)器負責(zé)代碼掃描, 需要安裝Sonar Scanner

2.3 Sonarqube Server安裝

2.3.1 包下載

https://www.sonarqube.org/downloads/

root@sonarserver:~# ls
sonarqube-7.9.6.zip

2.3.2 配置環(huán)境依賴

  • 內(nèi)核參數(shù)要求
root@sonarserver:~# vim /etc/sysctl.conf

vm.max_map_count=262144
fs.file-max=65536 
root@sonarserver:~# sysctl -p
vm.max_map_count = 262144
fs.file-max = 65536
  • 文件描述符限制
root@sonarserver:~# vim /etc/security/limits.conf
sonarqube - nofile 65536
sonarqube - nproc 65536  

2.3.3 創(chuàng)建sonarqube用戶

Sonarqube Server不能用root賬戶啟動

root@sonarserver:~# useradd -m -r -s /bin/bash sonarqube

2.3.4 安裝jdk-11

Sonarqube Server只支持jdk-11, 而SonarScanner支持jdk8和jdk11

root@sonarserver:~# apt -y install openjdk-11-jdk
root@sonarserver:~# reboot 

2.3.5 安裝PGSQL

Sonarqube7.x開始支持PGSQL, 支持v10和v9.3-v9.6, 字符集必須是UTF-8

root@pgsql:~# apt-cache madison postgresql
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-security/main amd64 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-security/main i386 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-updates/main amd64 Packages
postgresql | 10+190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-updates/main i386 Packages
postgresql |     10+190 | http://mirrors.aliyun.com/ubuntu bionic/main amd64 Packages
postgresql |     10+190 | http://mirrors.aliyun.com/ubuntu bionic/main i386 Packages
postgresql-common |        190 | http://mirrors.aliyun.com/ubuntu bionic/main Sources
postgresql-common | 190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-security/main Sources
postgresql-common | 190ubuntu0.1 | http://mirrors.aliyun.com/ubuntu bionic-updates/main Sources
root@pgsql:~# apt install postgresql -y

切換到 postgres 操作,PostgresSQL 安裝后會自動創(chuàng)建 postgres 用戶且沒有密碼. 數(shù)據(jù)庫的創(chuàng)建必須使用postgres賬戶操作

root@pgsql:~# su -  postgres
postgres@pgsql:~$ psql -U postgres
psql (10.17 (Ubuntu 10.17-0ubuntu0.18.04.1))
Type "help" for help.

postgres=#  CREATE DATABASE sonar;
CREATE DATABASE
postgres=# CREATE USER sonar WITH ENCRYPTED PASSWORD '123456';
CREATE ROLE
postgres=# GRANT ALL PRIVILEGES ON DATABASE sonar TO sonar;
GRANT
postgres=#  ALTER DATABASE sonar OWNER TO sonar;
ALTER DATABASE

修改監(jiān)聽地址, 使用root賬號配置

root@pgsql:~# vim /etc/postgresql/10/main/postgresql.conf
listen_addresses = '*'  # 修改第59行

開啟遠程訪問

root@pgsql:~# vim /etc/postgresql/10/main/pg_hba.conf
host    all             all             10.0.0.0/24            md5 # 修改第92行, 允許某個網(wǎng)段或者某臺主機訪問

重啟服務(wù)

root@pgsql:~# systemctl restart postgresql
root@pgsql:~# ss -ntl
State                 Recv-Q                 Send-Q                                  Local Address:Port                                   Peer Address:Port                 
LISTEN                0                      128                                           0.0.0.0:5432          # 監(jiān)聽在0.0.0.0                              0.0.0.0:*                    
LISTEN                0                      128                                     127.0.0.53%lo:53                                          0.0.0.0:*                    
LISTEN                0                      128                                           0.0.0.0:22                                          0.0.0.0:*                    
LISTEN                0                      128                                              [::]:5432                                           [::]:*                    
LISTEN                0                      128                                              [::]:22                                             [::]:* 

2.3.6 安裝Sonarqube Server

root@sonarserver:~# mkdir /apps
root@sonarserver:~# ls
sonarqube-7.9.6.zip
root@sonarserver:~# unzip sonarqube-7.9.6.zip  -d /apps
root@sonarserver:~# cd /apps
root@sonarserver:/apps# ll
total 12
drwxr-xr-x  3 root root 4096 Jul  6 22:33 ./
drwxr-xr-x 25 root root 4096 Jul  6 22:32 ../
drwxr-xr-x 11 root root 4096 Mar  1 09:21 sonarqube-7.9.6/
root@sonarserver:/apps# ln -sv sonarqube-7.9.6/ sonarqube
'sonarqube' -> 'sonarqube-7.9.6/'
root@sonarserver:/apps# chown -R sonarqube.sonarqube /apps/sonarqube
root@sonarserver:/apps# chown -R sonarqube.sonarqube /apps/sonarqube/
root@sonarserver:/apps# ll /apps
total 12
drwxr-xr-x  3 root      root      4096 Jul  6 22:34 ./
drwxr-xr-x 25 root      root      4096 Jul  6 22:32 ../
lrwxrwxrwx  1 sonarqube sonarqube   16 Jul  6 22:34 sonarqube -> sonarqube-7.9.6//
drwxr-xr-x 11 sonarqube sonarqube 4096 Mar  1 09:21 sonarqube-7.9.6/
sonarqube@sonarserver:/apps/sonarqube$ vim conf/sonar.properties 
sonarqube@sonarserver:/apps/sonarqube$ grep -E '^[a-zA-Z]' conf/sonar.properties 
sonar.jdbc.username=sonar  # 數(shù)據(jù)庫賬號
sonar.jdbc.password=123456 # 密碼
sonar.jdbc.url=jdbc:postgresql://10.0.0.149/sonar # 數(shù)據(jù)庫地址

2.3.7 啟動服務(wù)

使用sonarqube普通賬戶啟動, 如果用root賬戶啟動, 那么ES服務(wù)無法啟動, 間接造成Sonarqube無法啟動

sonarqube@sonarserver:/apps/sonarqube$ ./bin/linux-x86-64/sonar.sh start
Starting SonarQube...
Started SonarQube.
sonarqube@sonarserver:/apps/sonarqube$ tail logs/*.log

2021.07.06 22:41:32 INFO  app[][o.s.a.SchedulerImpl] Process[ce] is up
2021.07.06 22:41:32 INFO  app[][o.s.a.SchedulerImpl] SonarQube is up

2.3.8 訪問sonarqube

賬號:admin
密碼:admin

圖片.png

2.3.9 使用官方提供的Service文件啟動sonarqube

  • 先停止服務(wù)
sonarqube@sonarserver:~$ /apps/sonarqube/bin/linux-x86-64/sonar.sh stop
Gracefully stopping SonarQube...
Stopped SonarQube.
  • 使用root賬號, 創(chuàng)建Service文件
root@sonarserver:~# vim /etc/systemd/system/sonarqube.service 

[Unit]                                                                                                                                                                      
Description=SonarQube service
After=syslog.target network.target

[Service]
Type=simple
User=sonarqube
Group=sonarqube
PermissionsStartOnly=true
ExecStart=/usr/bin/nohup /usr/bin/java -Xms1024m -Xmx1024m -Djava.net.preferIPv4Stack=true -jar /apps/sonarqube/lib/sonar-application-7.9.6.jar
StandardOutput=syslog
LimitNOFILE=131072
LimitNPROC=8192
TimeoutStartSec=5
Restart=always
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

root@sonarserver:~# systemctl daemon-reload
root@sonarserver:~# systemctl restart sonarqube
root@sonarserver:~# systemctl enable --now sonarqube
Created symlink /etc/systemd/system/multi-user.target.wants/sonarqube.service → /etc/systemd/system/sonarqube.service.
root@sonarserver:/apps/sonarqube# ss -ntl
State                Recv-Q                Send-Q                                     Local Address:Port                               Peer Address:Port                
LISTEN               0                     128                                        127.0.0.53%lo:53                                      0.0.0.0:*                   
LISTEN               0                     128                                              0.0.0.0:22                                      0.0.0.0:*                   
LISTEN               0                     128                                                 [::]:22                                         [::]:*                   
LISTEN               0                     25                                                     *:9000                                          *:*                   
LISTEN               0                     128                                   [::ffff:127.0.0.1]:9001                                          *:*   

2.3.10 安裝中文插件

圖片.png

插件保存目錄

root@sonarserver:~# ll /apps/sonarqube/extensions/plugins/
total 87836
drwxr-xr-x 2 sonarqube sonarqube     4096 Mar  1 09:10 ./
drwxr-xr-x 5 sonarqube sonarqube     4096 Jul  6 22:41 ../
-rw-r--r-- 1 sonarqube sonarqube      224 Mar  1 09:10 README.txt
-rw-r--r-- 1 sonarqube sonarqube   287504 Mar  1 09:10 sonar-auth-github-plugin-1.5.0.870.jar
-rw-r--r-- 1 sonarqube sonarqube  3312399 Mar  1 09:10 sonar-auth-saml-plugin-1.2.0.682.jar
-rw-r--r-- 1 sonarqube sonarqube  4094975 Mar  1 09:10 sonar-csharp-plugin-7.15.0.8572.jar
-rw-r--r-- 1 sonarqube sonarqube  7015434 Mar  1 09:10 sonar-css-plugin-1.1.1.1010.jar
-rw-r--r-- 1 sonarqube sonarqube  1544789 Mar  1 09:10 sonar-flex-plugin-2.5.1.1831.jar
-rw-r--r-- 1 sonarqube sonarqube  3903342 Mar  1 09:10 sonar-go-plugin-1.1.1.2000.jar
-rw-r--r-- 1 sonarqube sonarqube  1727846 Mar  1 09:10 sonar-html-plugin-3.1.0.1615.jar
-rw-r--r-- 1 sonarqube sonarqube    15098 Mar  1 09:10 sonar-jacoco-plugin-1.0.2.475.jar
-rw-r--r-- 1 sonarqube sonarqube  8302745 Mar  1 09:10 sonar-java-plugin-5.13.1.18282.jar
-rw-r--r-- 1 sonarqube sonarqube  6866969 Mar  1 09:10 sonar-javascript-plugin-5.2.1.7778.jar
-rw-r--r-- 1 sonarqube sonarqube  7595999 Mar  1 09:10 sonar-kotlin-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonarqube sonarqube   300503 Mar  1 09:10 sonar-ldap-plugin-2.2.0.608.jar
-rw-r--r-- 1 sonarqube sonarqube  5105268 Mar  1 09:10 sonar-php-plugin-3.2.0.4868.jar
-rw-r--r-- 1 sonarqube sonarqube  2752167 Mar  1 09:10 sonar-python-plugin-1.14.1.3143.jar
-rw-r--r-- 1 sonarqube sonarqube 10036210 Mar  1 09:10 sonar-ruby-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonarqube sonarqube  9202024 Mar  1 09:10 sonar-scala-plugin-1.5.0.315.jar
-rw-r--r-- 1 sonarqube sonarqube  2538373 Mar  1 09:10 sonar-scm-git-plugin-1.12.1.2064.jar
-rw-r--r-- 1 sonarqube sonarqube  7229293 Mar  1 09:10 sonar-scm-svn-plugin-1.9.0.1295.jar
-rw-r--r-- 1 sonarqube sonarqube  2239156 Mar  1 09:10 sonar-typescript-plugin-1.9.0.3766.jar
-rw-r--r-- 1 sonarqube sonarqube  3580236 Mar  1 09:10 sonar-vbnet-plugin-7.15.0.8572.jar
-rw-r--r-- 1 sonarqube sonarqube  2242738 Mar  1 09:10 sonar-xml-plugin-2.0.1.2020.jar

看到install pending后, 要點擊重啟服務(wù)器, 以便開始安裝

圖片.png
圖片.png
圖片.png

2.4 Sonar-Scanner安裝

Sonar-Scanner可以部署在單獨的服務(wù)器, 也可以部署在Jenkins服務(wù)器, Jenkins把代碼拉取到本地后, 直接通過Sonar-Scanner掃描

下載地址:https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/
官方文檔:https://docs.sonarqube.org/latest/analysis/scan/sonarscanner/

root@jenkins:/opt# ls
sonar-scanner-cli-4.5.0.2216-linux.zip
root@jenkins:~# unzip sonar-scanner-cli-4.5.0.2216-linux.zip -d /apps/
root@jenkins:/apps# ln -sv sonar-scanner-4.5.0.2216-linux/ sonar-scanner
root@jenkins:/apps# cd sonar-scanner
root@jenkins:/apps/sonar-scanner# vim conf/sonar-scanner.properties
#----- Default SonarQube server
sonar.host.url=http://10.0.0.139:9000

#----- Default source code encoding
sonar.sourceEncoding=UTF-8  

2.5 利用官方提供的bug代碼進行掃描測試

https://github.com/SonarSource/sonar-scanning-examples

將示例代碼傳到Jenkins服務(wù)器

root@jenkins:~# cd /opt
root@jenkins:/opt# ls
sonar-scanning-examples-master.zip
root@jenkins:/opt# unzip sonar-scanning-examples-master.zip
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner# cd src/ # 代碼示例存放位置
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src# ll
total 80
drwxr-xr-x 20 root root 4096 Jun 24 16:41 ./
drwxr-xr-x  5 root root 4096 Jun 24 16:41 ../
drwxr-xr-x  2 root root 4096 Jun 24 16:41 abap/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 cobol/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 directory/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 erlang/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 flex/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 html/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 javascript/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 kotlin/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 package/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 php/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 pli/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 python/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 rpg/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 samples/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 sql/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 swift/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 vb6/
drwxr-xr-x  2 root root 4096 Jun 24 16:41 xml/

掃描php代碼, 每個代碼目錄都要有一個sonar-project.properties文件, 來指定項目名稱, 掃描代碼后會在sonarqube顯示

root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# vim ../../sonar-project.properties 

sonar.projectKey=org.sonarqube:sonarqube-scanner                                                                                                                            
sonar.projectName=Example of SonarQube Scanner Usage
sonar.projectVersion=1.0

sonar.sources=src,copybooks

sonar.sourceEncoding=UTF-8

## Cobol Specific Properties

# comma-separated paths to directories with copybooks
sonar.cobol.copy.directories=copybooks
# comma-separated list of suffixes
sonar.cobol.file.suffixes=cbl,cpy
sonar.cobol.copy.suffixes=cpy



## Flex Specific Properties

# retrieve code coverage data from the Cobertura report
sonar.flex.cobertura.reportPath=coverage-report/coverage-cobertua-flex.xml



# PL/I Specific Properties
sonar.pli.marginLeft=2
sonar.pli.marginRight=0

root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# ll
total 16
drwxr-xr-x  2 root root 4096 Jun 24 16:41 ./
drwxr-xr-x 20 root root 4096 Jun 24 16:41 ../
-rw-r--r--  1 root root 5559 Jun 24 16:41 Math.php

sonar-project.properties文件拷貝到php目錄下, 做修改

root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner# cp sonar-project.properties src/php/
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner# cd src/php
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# vim sonar-project.properties

sonar.projectKey=sonarqube-sample-php-projectKey                                                                                                                            
sonar.projectName=sonarqube-sample-php-projectName
sonar.projectVersion=1.0

sonar.sources=src # src目錄相對于php目錄, 因此, 在php目錄下還要創(chuàng)建src目錄, 存放php代碼
sonar.language=php
sonar.sourceEncoding=UTF-8

root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# mkdir src
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# mv Math.php src/
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# ll
total 16
drwxr-xr-x  3 root root 4096 Jul  6 23:47 ./
drwxr-xr-x 20 root root 4096 Jun 24 16:41 ../
-rw-r--r--  1 root root  172 Jul  6 23:47 sonar-project.properties
drwxr-xr-x  2 root root 4096 Jul  6 23:47 src/
root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# ll src/
total 16
drwxr-xr-x 2 root root 4096 Jul  6 23:47 ./
drwxr-xr-x 3 root root 4096 Jul  6 23:47 ../
-rw-r--r-- 1 root root 5559 Jun 24 16:41 Math.php

php目錄下執(zhí)行掃描命令

root@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php# /apps/sonar-scanner/bin/sonar-scanner
...
INFO: ANALYSIS SUCCESSFUL, you can browse http://10.0.0.139:9000/dashboard?id=sonarqube-sample-php-projectKey
...
NFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 8.974s
INFO: Final Memory: 6M/24M
INFO: 
  • 查看結(jié)果
圖片.png
圖片.png

3 Gitlab+Jenkins+Sonarqube結(jié)合使用

讓Jenkins到Gitlab拉取代碼到本地, 之后使用SonarScanner進行代碼掃描, 然后傳到Sonarqube

3.1 通過Jenkins插件執(zhí)行代碼掃描

3.1.1 創(chuàng)建一個測試項目, 測試web-02項目克隆

圖片.png
圖片.png
圖片.png
圖片.png

3.1.2 Jenkins安裝插件

圖片.png
root@jenkins:/tmp# systemctl restart jenkins

3.1.3 在Jenkins上, 配置Sonarqube Server地址

圖片.png
圖片.png

3.1.4 在Jenkins上, 配置Sonarscanner的路徑

圖片.png
圖片.png
  • 如果Jenkins服務(wù)器可以聯(lián)網(wǎng), 也可使用自動安裝, 這樣Jenkins會自動下載Scanner到本地, 如果不能上網(wǎng), 就要通過離線安裝包的方式

3.1.5 在Jenkins上, 配置項目構(gòu)建

選擇項目 --> 配置 --> 構(gòu)建 --> Execute SonarQube Scanner --> 將Analysis properties里的內(nèi)容填寫為代碼掃描的properties文件里的內(nèi)容

圖片.png
jenkins@jenkins:/opt/sonar-scanning-examples-master/sonarqube-scanner/src/php$ vim sonar-project.properties 

sonar.projectKey=sonarqube-sample-php-projectKey
sonar.projectName=sonarqube-sample-php-projectName
sonar.projectVersion=1.0

sonar.sources=src
sonar.language=php
sonar.sourceEncoding=UTF-8

本案例內(nèi)容

sonar.projectKey=project-web-02
sonar.projectName=project-web-02
sonar.projectVersion=1.0

sonar.sources=./ # 這里寫./表示當前目錄, 也就是相對于/var/lib/jenkins/workspace/test-scanner目錄, Scanner會掃描該目錄下的所有文件. 如果代碼放到了$WORKSPACE/src目錄, 那么這里就寫src
sonar.languagehtml # web-02里只有一個html文件
sonar.sourceEncoding=UTF-8
  • 執(zhí)行構(gòu)建
圖片.png
  • Sonarqube Server查看結(jié)果
圖片.png

3.2 通過腳本自定義代碼掃描

配置項目構(gòu)建時, 無需指定git倉庫, 也無需使用Scanner插件, 而是統(tǒng)一把流程定義在構(gòu)建的Shell腳本中.

先在Jenkins服務(wù)器上, 用Jenkins用戶運行腳本測試, 如果沒問題, 再把腳本保存的構(gòu)建的Shell腳本中

先用root用戶創(chuàng)建/data/jenkins/qq目錄, 然后授權(quán)給jenkins用戶
root@jenkins:~# mkdir -pv /data/jenkins/qq
root@jenkins:~# chown -R jenkins.jenkins /data/jenkins/
切換到j(luò)enkins用戶下, 創(chuàng)建腳本

jenkins@jenkins:/opt$ vim sonar.sh

#!/bin/bash
  
cd /data/jenkins/qq # 進到項目目錄

rm -rf * && git clone git@10.0.0.239:qq/web-02.git # 刪除舊的項目內(nèi)容, clone新的內(nèi)容
 
cd web-02 # 進到項目里面

cat >> sonar-project.properties <<EOF # 創(chuàng)建properties文件
sonar.projectKey=project-web-02-script
sonar.projectName=project-web-02-script
sonar.projectVersion=1.0
sonar.sources=./
sonar.languagehtml
sonar.sourceEncoding=UTF-8
EOF

 
/apps/sonar-scanner/bin/sonar-scanner # 開啟scanner, 會掃描當前目錄下所有的文件
INFO: Analysis total time: 3.226 s
INFO: ------------------------------------------------------------------------
INFO: EXECUTION SUCCESS
INFO: ------------------------------------------------------------------------
INFO: Total time: 3.916s
INFO: Final Memory: 12M/44M
INFO: ------------------------------------------------------------------------

測試沒問題, 保存到Jenkins配置

圖片.png

圖片.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容