天天看點

UI元件庫接入Gitlab CICD實踐

1 背景

目前部門維護自己的元件庫(​

​miui-desgin​

​​),并釋出到了公司私有的​

​npm​

​​庫(由​

​JFrog artifactory​

​​搭建)。元件庫幾乎是照搬了​

​antd​

​​的檔案組織結構和打包方式,而元件的使用說明文檔也是使用了​

​dumi​

​。而元件庫和文檔的釋出仍采取本地執行指令并釋出的方式,雖然前期制定了釋出流程和規範,但從結果上看,依然的存在很多的問題。例如:釋出環境不統一、釋出流程無法保證、釋出流程需要一定的學習成本、每次釋出都需要一定的時間成本等。并且随着項目越來越複雜,參與人數越來越多,以上問題會表現的更加的突出,最終導緻的正式包内容的不可控。

而要解決解決手動釋出元件庫的問題,可以借助​

​Gitlab CICD​

​​的能力,将元件庫的釋出和文檔的部署過程搬到線上來執行。不過由于大部分的開源項目在​

​Github​

​​上,且​

​npm​

​庫的釋出也并沒有采用自動化,是以可以參考的開源元件自動釋出流程并不多。不過借助網絡上的零散資料和自身部門對元件庫管理的規範,整理出如下的UI庫自動釋出方案。

2 方案

2.1 手動釋出流程

元件庫的釋出包含兩項釋出工作,其一是UI庫的釋出,其二是元件使用文檔的釋出。根據部門制定的元件庫釋出規範,手動發的流程大體如下圖所示:

UI元件庫接入Gitlab CICD實踐
 ⚠ 說明:
  • 更新version:由釋出者按照​​語義版本控制​​​規範自行修改​

    ​package.json​

    ​​中的​

    ​version​

    ​字段的屬性值。
  • 添加版本tag:按版本号加v表示tag名稱(例如v1.1.1)。

2.2 釋出流程拆分

根據部門目前​

​UI​

​​庫的釋出過程,結合​

​Gitlab​

​​的​

​CICD​

​​能力,可以将整個釋出流程拆分為三個任務,分别是代碼測試任務、​

​UI​

​庫釋出任務和文檔打包部署任務。每個任務具體負責的工作如下圖所示:

UI元件庫接入Gitlab CICD實踐

相比于手動釋出流程,自動釋出流程添加了​

​code test​

​​和推送​

​release​

​​到​

​Gitlab​

​​兩個子任務,這是為了更規範的釋出​

​UI​

​庫和文檔。

2.3 自動釋出流程

借助​

​Gitlab​

​​的​

​CICD​

​​能力,當代碼合并到​

​master​

​​之後,會自動觸發工作流。然後工作流會依次執行代碼測試任務、​

​UI​

​​庫釋出任務和文檔打包部署任務。同時為了保證​

​UI​

​​庫和文檔釋出的嚴謹,在​

​UI​

​​庫釋出任務之前添加了審批環節,需要手動觸發該任務的執行并經過審批後,才會執行​

​UI​

​庫的釋出和文檔的部署。

UI元件庫接入Gitlab CICD實踐
UI元件庫接入Gitlab CICD實踐

2.4 UI庫版本生成規則

​UI​

​​庫的釋出過程借助了​​semantic-release​​​工具,其完成了​

​UI​

​​庫釋出任務中除了打包外的所有子任務。UI庫版本的生成嚴格執行​​語義版本控制​​​規範(​

​X.Y.Z​

​​),并通過分析上次釋出代碼(目前最新​

​tag​

​​的代碼)到目前代碼新增的​

​commit message​

​來确定待釋出的版本号。

版本生成規則如下:

  • ​fix​

    ​​或​

    ​perf​

    ​​類型的送出,會将​

    ​PATCH​

    ​版本号加1
  • ​feat​

    ​​類型的送出,會将​

    ​MINOR​

    ​版本号加1
  • 包含​

    ​breaking change​

    ​​字元串的送出,會将​

    ​MAJOR​

    ​号加1

如果一次釋出過程中包含多個送出,則使用所有送出對應版本号中的最大值作為待釋出的版本号。例如原版本号為1.2.3,目前代碼相比于1.2.3的代碼新增了1個​

​fix​

​​和1個​

​feat​

​送出,目前代碼的版本号為1.3.0(即1.2.4和1.3.0中取較大的值)。

如果一次釋出過程中的送出都沒有命中版本生成規則,UI庫釋出的任務依然會執行,但由于沒有UI庫要釋出的内容,會跳過本次的釋出(不執行​

​push​

​​、​

​release​

​​、​

​publish​

​等操作)。從實際效果上看,這種情況下隻會執行代碼測試和文檔的打包部署。這種場景對于隻修改和釋出說明文檔很有意義,可以避免無意義的UI庫版本的更新。

2.5 代碼推送權限控制

為了更好的規範代碼送出和釋出流程,應該禁止普通開發者直接往​

​master​

​​送出代碼,而是通過建立分支進行開發,之後再發送​

​merge​

​​請求合并到​

​master​

​​,經過代碼​

​review​

​​和代碼測試之後,最終合并進入​

​master​

​​,并觸發元件庫釋出流程。​

​Gitlab​

​​本身支援設定保護分支和允許推送到​

​master​

​​的角色,一般情況下,可以設定隻允許​

​Maintainers​

​​送出代碼到​

​master​

​​,這樣普通開發者便無法直接送出到​

​master​

​。

UI元件庫接入Gitlab CICD實踐

但由于曆史原因,部門成員所在的組整體被賦予了​

​Maintainers​

​​角色,為了禁止開發者往​

​master​

​​送出代碼,​

​roles​

​​需要選擇​

​No one​

​​,而這又會導緻​

​release-bot​

​​反向推送到​

​master​

​​失敗。不過除了設定角色之外,​

​Gitlab​

​​還支援選擇​

​deploy key​

​。

UI元件庫接入Gitlab CICD實踐

可以按照官方文檔的提示生成并配置​​deploy key​​​,同時将私鑰配置到項目​

​CICD​

​​配置的環境變量中.。通過​

​yml​

​​檔案的如下配置,可以在​

​UI​

​​庫釋出階段,使用​

​deploy key​

​來反推代碼到master。

before_script:
    - mkdir -p <sub>/.ssh
    # 将生成私鑰寫入.ssh中
    - echo "$RELEASE_PRIVATE_KEY" > </sub>/.ssh/id_ed25519; chmod 0600 ~/.ssh/id_ed25519
    - echo "StrictHostKeyChecking no " > /root/.ssh/config
    # 重置origin
    - git remote rm origin
    - git remote add origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
    - npm config set registry https://xxxx.xiaomi.net/xxxx/npm/mi-npm      

3 流程源碼

3.1 依賴

項目使用​​semantic-release​​工具來釋出UI庫,需要提前安裝以下的依賴。

  • ​@semantic-release​

  • ​@semantic-release/commit-analyzer​

  • ​@semantic-release/release-notes-generator​

  • ​@semantic-release/changelog​

  • ​@semantic-release/gitlab​

  • ​@semantic-release/npm​

  • ​@semantic-release/git​

3.2 CICD環境變量

  • ​NPM_TOKEN​

    ​​:​

    ​@semantic-release/npm​

    ​釋出包到私有源會預設讀取該參數。
  • ​GITLAB_TOKEN​

    ​​:​

    ​@semantic-release/gitlab​

    ​​釋出​

    ​release​

    ​​到​

    ​Gitlab​

    ​會讀取該參數。
  • ​RELEASE_PRIVATE_KEY​

    ​​:​

    ​deploy key​

    ​​對應的私鑰,用于反向推送版本修改資訊和​

    ​changelog​

    ​​到​

    ​master​

    ​。

3.3 YML配置

# 規則
.rules:
  - &is-merge-request-to-production
    if: $CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $PRODUCTION_BRANCH
  # 生産分支 + 不是由釋出機器人反推的commit
  - &is-release
    if: $CI_COMMIT_REF_NAME != $PRODUCTION_BRANCH || $CI_COMMIT_TITLE =<sub> /^chore:\srelease\s/
    when: never

# 設定環境變量預設值
variables:
  # 打包反向推送tag、changelog的git使用者名
  GIT_AUTHOR_NAME: 'release-bot'
  PRODUCTION_BRANCH: 'master'
  # 審批人
  CI_APPROVER: [email protected]

default:
  image: node:14-alpine
  before_script:
    # 設定為小米私有源
    - npm config set registry https://xxxx.xiaomi.net/xxxx/npm/mi-npm
   
cache:
  key: $CI_PROJECT_ID
  paths:
    - node_modules

stages:
- test
- publish_npm
- deploy_docs

test:
  stage: test
  script:
    - yarn
    - yarn test
  rules:
    - *is-merge-request-to-production
    - *is-release
    - when: on_success

build_and_publish_npm:
  stage: publish_npm
  # node14 + git 環境
  image: timbru31/node-alpine-git:14
  approval: true
  before_script:
    - mkdir -p </sub>/.ssh
    - echo "$RELEASE_PRIVATE_KEY" > <sub>/.ssh/id_ed25519; chmod 0600 </sub>/.ssh/id_ed25519
    - echo "StrictHostKeyChecking no " > /root/.ssh/config
    - git remote rm origin
    - git remote add origin git@$CI_SERVER_HOST:$CI_PROJECT_PATH.git
    - npm config set registry https://xxxx.xiaomi.net/xxxx/npm/mi-npm
  script:
    - yarn
    - yarn build
    - yarn semantic-release
  rules:
    - *is-release
    - when: manual


build_and_deploy_docs:
  stage: deploy_docs
  script:
    - yarn
    - yarn deploy:site
  rules:
    - *is-release
    - when: on_success      

3.4 releaserc配置

{
    "branches": ["master"],
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      [
        "@semantic-release/changelog",
        {
          "changelogFile": "CHANGELOG.md"
        }
      ],
      "@semantic-release/gitlab",
      "@semantic-release/npm",
      [
        "@semantic-release/git",
        {
          "assets": ["package.json", "CHANGELOG.md"],
          "message": "chore: release ${nextRelease.version}"
        }
      ]
    ]
  }      

4 結語

繼續閱讀