相對現代化的把控前端代碼質量

本站使用「署名 4.0 國際 (CC BY 4.0)」許可協議,歡迎轉載、或從新修改使用,但須要註明來源。 署名 4.0 國際 (CC BY 4.0)javascript

本文做者: 蘇洋html

建立時間: 2018年09月06日 統計字數: 10766字 閱讀時間: 22分鐘閱讀 本文連接: soulteary.com/2018/09/06/…前端


相對現代化的把控前端代碼質量

最近幾天聊天,經常聊到 持續集成 輔助把控 代碼質量 ,之前端團隊爲例,咱們來簡單聊聊。java

本篇極可能是你在網上能找到的使用容器應用最新版本 SonarQube 相對詳細的一篇,或者是惟一一篇,因此若是遇到問題,歡迎和我進行討論溝通。node

如何把控質量

我的認爲把控質量的核心是造成標準避免錯誤引入,從而提升應用的健壯性,下降維護成本和不該存在的複雜度,這裏在不討論 測試 的狀況下,一般的作法無非:linux

  1. 在代碼提交前或後進行 Code Review,按期走讀代碼。
  2. 使用 eslintjshintjslint 等工具在開發環境經過 Git Hook 觸發,進行風格和簡單的質量評估,避免 Bug漏洞壞味道 的代碼提交到平臺。
  3. 配合 pipeline 使用,定義一些過程腳本,在代碼提交後,或者分支合併前去調用以上工具,避免質量不佳的代碼合併到開發主幹,被「傳承」下去。
  4. 使用 istanbul 之類的工具簡單檢查覆蓋率,避免有必定複雜度的業務代碼潛在風險太高。
  5. 人員培訓,技術氛圍建設。

策略的差別

一個良好的開發氛圍,第一條是必不可少的,不管是否使用輔助審查系統,使用審查機制,能夠把不少不合理的設計和明顯使用錯誤的代碼在萌芽期殺死。git

若是輔助手段使用本地運行驗證,在配套前端開發技術設施不完善的狀況下,則可能出現爲了省事卸載 Hook 跳過審查的事件;或者須要額外維護規則更新機制的成本,將團隊代碼規則保存到倉庫或者私有包倉庫的維護成本,甚至是保存倉庫的建設成本。若是雲端執行資源不足的話,本地運行則會是一個很好的補充手段。github

若是使用雲端審查,須要配套設施都相對完善:私有包倉庫、CVS 系統、甚至容器倉庫、CI Runner 執行環境...(後續或許能夠聊聊如何建設這些)web

雲端審查能夠將規則和標準統一,配合 Docker 容器技術能夠輕鬆進行應用資源擴容,遠超本地運行效率,而且能夠進行掃描存檔,客觀的反饋代碼質量和功能加入、人員培訓先後的變化。sql

而技術團隊的氛圍建設、人員的技術培訓是一件長期持久的事情,打造「有人願意教」、「有人願意學」的機會可遇不可求。

相比較之下,若是你的公司已經將 GitLab 升級到了 9.x 以上,而且有資源去作 CI/CD 的事情,那麼直接在 Pipeline 過程當中添加代碼審查是一個相對靠譜的事情。

使用 SonarQube 進行代碼分析

接下來我會演示如何使用 SonarQube 最新版本輔助進行代碼分支把控質量。

我將最新版本的 SonarQubescanner-runner 封裝成了鏡像,避免直接在 GitLab Runner 宿主環境直接執行,污染執行環境。

而後在 CI 階段定義一個新的 Stage,這裏假定叫 sonar 好了。

sonar:
  image: docker.lab.com/sonar-scanner-runner:3.2.0.1227
  script:
    - cd .. && BASE_DIR=$(pwd) && rm -rf /data && ln -s $BASE_DIR/${CI_PROJECT_NAME} /data
    - ls /data
    - echo ${CI_PROJECT_NAME}-${CI_PROJECT_ID}
    - sonar ${CI_PROJECT_NAME}-${CI_PROJECT_ID}
複製代碼

這裏使用 Publish 模式將掃描結果回傳 SonarQube Web Server,造成持續的報告。

若是你須要將掃描階段定義爲部署前的一個「質量把控關口」,那麼須要再簡單寫一個腳本,在掃描器執行完畢後,抓取當前項目的狀態,是否超過 設定的閾值,從而中斷後續的流程,腳本參考我上一篇 若是不用 Node.js 寫業務 中的使用 Node.js 做爲持續集成的粘合劑,獲取掃描器返回的接口地址中的 status 狀態值便可,比較簡單,就略了。

提交觸發構建

當你提交代碼以後,GitLab Runner 調用鏡像中的掃描器腳本(這裏使用的Runnerdocker 類型的 Runner)進行掃描,若是成功,大概是這個樣子。

CI執行掃描

執行器日誌會返回這個任務的具體執行結果,上文有提到該如何處理。

{
    task: {
        id: "AWWtMWX1Frzdillyw-1a",
        type: "REPORT",
        componentId: "AWWtLY29Frzdillyw-1T",
        componentKey: "leetcode-547",
        componentName: "leetcode-547",
        componentQualifier: "TRK",
        analysisId: "AWWtMWsbbu6HJjdFR-kA",
        status: "SUCCESS",
        submittedAt: "2018-09-06T04:43:40+0000",
        startedAt: "2018-09-06T04:43:41+0000",
        executedAt: "2018-09-06T04:43:42+0000",
        executionTimeMs: 1260,
        logs: false,
        hasScannerContext: true,
        organization: "default-organization"
    }
}
複製代碼

訪問 Web 平臺,能夠看到咱們剛剛提交觸發的測試報告已經生成,若是有缺陷的話,會展現由於什麼,又該如何修正。

掃描結果

相關功能仍是比較多的,參考本文自行搭建後,能夠自行了解。

默認規則列表

若是上面的規則看不太清楚,能夠嘗試瀏覽官方規則列表的在線版本:

固然,若是你願意的話,能夠參考下面的連接進行自定義配置,讓掃描報告中包含覆蓋率,以及使用自定義的 eslint 規則進行補充或者替換默認的規則:

固然,還有一個定製化更強的套路,使用專門的 eslint 插件,目前插件只能跑在老平臺上,感興趣的你若是對 Java 很熟悉,能夠參考官方開源社區的示例和開源的三方 eslint 插件進行升級改造,這裏就不展開了。

官方提供了示例、也有三方插件,你甚至能夠定義若是包含了哪些詞彙、或者文件超出指定大小等就拒絕此次的審查經過,避免代碼合併到主幹分支形成更大的損失。

說了這麼多,那麼如何快速搭建一個相對高可用的 SonarQube 呢。

構建你的平臺鏡像

例子中能夠看到,我我的使用私有域名,並簽署了私有證書,若是你的公司團隊情況相似,能夠直接參考,否則的話,去掉相關代碼便可。(不去掉也無所謂)

下面是個人鏡像,會自動將私有證書進行授信,通常來講將來版本升級,只要修改這個版本號便可使用(7.一、7.二、7.3 驗證經過)。

FROM openjdk:8-alpine

ENV JAVA_CERTS_DIR "$JAVA_HOME/jre/lib/security/"

WORKDIR $JAVA_CERTS_DIR

ADD ssl/*.crt $JAVA_CERTS_DIR
# https://stackoverflow.com/questions/41497871/importing-self-signed-cert-into-dockers-jre-cacert-is-not-recognized-by-the-ser
RUN ls *.crt | xargs -I {} keytool -importcert -storepass changeit -noprompt -trustcacerts -alias {} -file {} -keystore "$JAVA_CERTS_DIR/cacerts"

# https://github.com/SonarSource/docker-sonarqube/blob/4d76dfe9fb4c5d41ba1852cd5072dbff15ca5a20/7.1-alpine/Dockerfile

ENV SONAR_VERSION=7.3 \
    SONARQUBE_HOME=/opt/sonarqube \
    # Database configuration
    # Defaults to using H2
    SONARQUBE_JDBC_USERNAME=sonar \
    SONARQUBE_JDBC_PASSWORD=sonar \
    SONARQUBE_JDBC_URL=

# Http port
EXPOSE 9000

RUN addgroup -S sonarqube && adduser -S -G sonarqube sonarqube

RUN set -x \
    && apk add --no-cache gnupg unzip \
    && apk add --no-cache libressl wget \
    && apk add --no-cache su-exec \
    && apk add --no-cache bash \

    # pub 2048R/D26468DE 2015-05-25
    # Key fingerprint = F118 2E81 C792 9289 21DB CAB4 CFCA 4A29 D264 68DE
    # uid sonarsource_deployer (Sonarsource Deployer) <infra@sonarsource.com>
    # sub 2048R/06855C1D 2015-05-25
    && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys F1182E81C792928921DBCAB4CFCA4A29D26468DE \

    && mkdir /opt \
    && cd /opt \
    && wget -O sonarqube.zip --no-verbose https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-$SONAR_VERSION.zip \
    && wget -O sonarqube.zip.asc --no-verbose https://sonarsource.bintray.com/Distribution/sonarqube/sonarqube-$SONAR_VERSION.zip.asc \
    && gpg --batch --verify sonarqube.zip.asc sonarqube.zip \
    && unzip sonarqube.zip \
    && mv sonarqube-$SONAR_VERSION sonarqube \
    && chown -R sonarqube:sonarqube sonarqube \
    && rm sonarqube.zip* \
    && rm -rf $SONARQUBE_HOME/bin/*

VOLUME "$SONARQUBE_HOME/data"

WORKDIR $SONARQUBE_HOME

COPY run.sh $SONARQUBE_HOME/bin/

ENTRYPOINT ["./bin/run.sh"]
複製代碼

配合的執行腳本:

#!/bin/sh 
# https://raw.githubusercontent.com/SonarSource/docker-sonarqube/4d76dfe9fb4c5d41ba1852cd5072dbff15ca5a20/7.1-alpine/run.sh

set -e

if [ "${1:0:1}" != '-' ]; then
  exec "$@"
fi

chown -R sonarqube:sonarqube $SONARQUBE_HOME
exec su-exec sonarqube \
  java -jar lib/sonar-application-$SONAR_VERSION.jar \
  -Dsonar.log.console=true \
  -Dsonar.jdbc.username="$SONARQUBE_JDBC_USERNAME" \
  -Dsonar.jdbc.password="$SONARQUBE_JDBC_PASSWORD" \
  -Dsonar.jdbc.url="$SONARQUBE_JDBC_URL" \
  -Dsonar.web.javaAdditionalOpts="$SONARQUBE_WEB_JVM_OPTS -Djava.security.egd=file:/dev/./urandom" \
  "$@"
複製代碼

最後是編排工具使用的配置:

# https://github.com/SonarSource/docker-sonarqube/blob/master/recipes.md

version: '3'

services:

  sonarqube:
    image: docker.lab.com/sonar.lab.com:7.3
    expose:
      - 9000
      - 9001
      - 9092
    environment:
      SONARQUBE_JDBC_USERNAME: sonar
      SONARQUBE_JDBC_PASSWORD: sonar
      SONARQUBE_JDBC_URL: 'jdbc:postgresql://db:5432/sonar'
      JAVA_OPTS: '-Duser.timezone=Asia/Shanghai'
    depends_on:
      - db
    volumes:
      - ./data/conf:/opt/sonarqube/conf
      - ./data/data:/opt/sonarqube/data
      - ./data/extensions:/opt/sonarqube/extensions
      - ./data/bundled-plugins:/opt/sonarqube/lib/bundled-plugins
    networks:
      - traefik
    labels:
      - "traefik.enable=true"
      - "traefik.port=9000"
      - "traefik.frontend.rule=Host:sonar.lab.com"
      - "traefik.frontend.entryPoints=http,https"

  db:
    image: postgres:10.4-alpine
    expose:
      - 5432
    environment:
      - POSTGRES_USER=sonar
      - POSTGRES_PASSWORD=sonar
    volumes:
      - ./data/postgresql:/var/lib/postgresql
      # This needs explicit mapping due to https://github.com/docker-library/postgres/blob/4e48e3228a30763913ece952c611e5e9b95c8759/Dockerfile.template#L52
      - ./data/postgresql_data:/var/lib/postgresql/data
    networks:
      - traefik

networks:
  traefik:
    external: true
複製代碼

這裏依舊是使用 Traefik 的服務發現進行自動註冊,擴容我已經講過好屢次了,翻翻前面的文章吧:D。

這裏爲了可以達到用戶和 GitLab 互通等,我還作了一個簡單的默認配置,保存在 data/conf/sonar.properties,並使用編排工具映射到容器內,你也能夠選擇直接把配置打到容器裏,或者走配置中心進行遠程獲取(最佳方案)。

# https://github.com/SonarSource/sonarqube/blob/master/sonar-application/src/main/assembly/conf/sonar.properties

sonar.telemetry.enable=false
sonar.updatecenter.activate=false

sonar.exclusions=bower_components/**/*, node_modules/**/*

sonar.core.serverBaseURL=https://sonar.lab.com

# GitLab Authentication
sonar.auth.gitlab.enabled=true
sonar.auth.gitlab.url=https://gitlab.lab.com
sonar.auth.gitlab.applicationId=YOUR
sonar.auth.gitlab.secret=YOUR
sonar.auth.gitlab.allowUsersToSignUp=true
sonar.auth.gitlab.ignore_certificate=true

# GitLab Reporting
sonar.gitlab.url=https://gitlab.lab.com
sonar.gitlab.ignore_certificate=true
sonar.gitlab.user_token=YOUR
複製代碼

若是你有想定製修改的地方,能夠參考官方文檔,限於篇幅和時間,這裏也先略過,後面還有好多內容。

構建你的掃描器鏡像

掃描器我這裏分爲了兩部分,一個鏡像是給用戶使用的,也就是跨平臺的 掃描工具,另一個是專屬於 GitLab Runner的掃描器。

二者差別主要是是否要進行文件掛載、以及是否包含默認執行入口,爲了方便維護,我將跨平臺的鏡像設計爲基礎鏡像,使用腳本基於基礎鏡像進行修改。

下面是基礎鏡像:

FROM java:openjdk-8u45-jre

MAINTAINER soulteary <soulteary@gmail.com>

ENV NODE_VERSION 10.8.0
ENV SONAR_RUNNER_VERSION 3.2.0.1227
ENV SONAR_RUNNER_DIR sonar-scanner
ENV SONAR_RUNNER_HOME /opt/${SONAR_RUNNER_DIR}
ENV SONAR_RUNNER_PACKAGE sonar-scanner-cli-${SONAR_RUNNER_VERSION}-linux.zip
ENV HOME ${SONAR_RUNNER_HOME}

WORKDIR /opt

RUN wget https://sonarsource.bintray.com/Distribution/sonar-scanner-cli/${SONAR_RUNNER_PACKAGE} && \
    unzip ${SONAR_RUNNER_PACKAGE} && \
    mv ${SONAR_RUNNER_DIR}-${SONAR_RUNNER_VERSION}-linux ${SONAR_RUNNER_DIR} && \
    rm ${SONAR_RUNNER_PACKAGE}

RUN groupadd -r sonar && \
    useradd -r -s /usr/sbin/nologin -d ${SONAR_RUNNER_HOME} -c "Sonar service user" -g sonar sonar && \
    chown -R sonar:sonar ${SONAR_RUNNER_HOME} && \
    mkdir -p /data && \
    chown -R sonar:sonar /data

RUN curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh | bash && \
    export NVM_DIR="$HOME/.nvm" && \. "$NVM_DIR/nvm.sh" && \
    nvm install ${NODE_VERSION} && nvm alias default ${NODE_VERSION}

ENV JAVA_CERTS_DIR "$JAVA_HOME/jre/lib/security"

ADD /ssl/*.crt /tmp/

ADD run.sh ${SONAR_RUNNER_HOME}/bin/

# https://stackoverflow.com/questions/41497871/importing-self-signed-cert-into-dockers-jre-cacert-is-not-recognized-by-the-ser
RUN ls /tmp/*.crt | xargs -I {} keytool -importcert -storepass changeit -noprompt -trustcacerts -alias {} -file {} -keystore "$SONAR_RUNNER_HOME$JAVA_CERTS_DIR/cacerts" && \
    cp /tmp/*.crt /usr/share/ca-certificates && update-ca-certificates && \
    rm -rf /tmp/*.crt && \
    ln ${SONAR_RUNNER_HOME}/bin/run.sh /bin/sonar

# https://stackoverflow.com/questions/28740785/error-in-sonarqube-when-launching-svn-blame
RUN echo "sonar.host.url=https://sonar.lab.com" >> ${SONAR_RUNNER_HOME}/conf/sonar-scanner.properties && \
    echo "sonar.projectBaseDir=/data"           >> ${SONAR_RUNNER_HOME}/conf/sonar-scanner.properties && \
    echo "sonar.sources=/data"                  >> ${SONAR_RUNNER_HOME}/conf/sonar-scanner.properties && \
    echo "sonar.scm.disabled=true"              >> ${SONAR_RUNNER_HOME}/conf/sonar-scanner.properties

USER sonar

VOLUME /data

ENTRYPOINT ["/bin/sonar"]
複製代碼

能夠看到,基礎鏡像包含可配置化的 Node 版本,以及可配置的掃描器,固然,也支持私有證書的授信。

在本地執行的話,到項目代碼根目錄,須要輸入下面的命令運行便可,結果等同使用 CI Runner 執行。

docker run --rm -it -v `pwd`:/data docker.lab.com/sonar-scanner:3.2.0.1227 YOUR_PROJECT_ID
複製代碼

交付給 CI 使用的鏡像大體相同,前文提到的腳本內容以下:

#!/usr/bin/env bash 
cat ../normal/Dockerfile | \
sed 's/"\/bin\/sonar"/"\/bin\/bash"/g' | \
sed 's/ENTRYPOINT/CMD/g' | \
sed 's/VOLUME \/data//g' | \
sed 's/USER sonar//g' | tee Dockerfile
複製代碼

在執行完畢你會得到另一個去除了部份內容的 Dockerfile

如何使用,在上一小節定義 GitLab Runner 有提過,定義 image 字段後,添加一行執行腳本 sonar YOUR_PROJECT_ID 便可。

關於 CI Runner

至於文章中一直提到的 CI Runner,若是公司爲你準備好了,直接使用就是了。

若是尚未,參考下面命令,根據本身需求進行調整,註冊一個 docker 類型的執行器便可。

gitlab-runner register -n \
    --url https://gitlab.lab.com/ \
    --registration-token $YOUR_TOKEN \
    --executor docker \
    --description "docker runner" \
    --docker-image "docker.lab.com/docker-with-certs:stable" \
    --docker-privileged --tls-ca-file=/lab.com.crt
複製代碼

其餘

最後,我特別喜歡來自 sonarlint 的一句話,也送給你:

Fix issues before they exist

今天下午還有事情,行文倉促,不免有誤,若是你發現問題,歡迎向我反饋。

--EOF


我如今有一個小小的折騰羣,裏面彙集了一些喜歡折騰的小夥伴。

在不發廣告的狀況下,咱們在裏面會一塊兒聊聊軟件、HomeLab、編程上的一些問題,也會在羣裏不按期的分享一些技術沙龍的資料。

喜歡折騰的小夥伴歡迎掃碼添加好友。(請註明來源和目的,不然不會經過審覈) 關於折騰羣入羣的那些事

關於折騰羣入羣的那些事

相關文章
相關標籤/搜索