1 背景
目前部門維護自己的元件庫(
miui-desgin
),并釋出到了公司私有的
npm
庫(由
JFrog artifactory
搭建)。元件庫幾乎是照搬了
antd
的檔案組織結構和打包方式,而元件的使用說明文檔也是使用了
dumi
。而元件庫和文檔的釋出仍采取本地執行指令并釋出的方式,雖然前期制定了釋出流程和規範,但從結果上看,依然的存在很多的問題。例如:釋出環境不統一、釋出流程無法保證、釋出流程需要一定的學習成本、每次釋出都需要一定的時間成本等。并且随着項目越來越複雜,參與人數越來越多,以上問題會表現的更加的突出,最終導緻的正式包内容的不可控。
而要解決解決手動釋出元件庫的問題,可以借助
Gitlab CICD
的能力,将元件庫的釋出和文檔的部署過程搬到線上來執行。不過由于大部分的開源項目在
Github
上,且
npm
庫的釋出也并沒有采用自動化,是以可以參考的開源元件自動釋出流程并不多。不過借助網絡上的零散資料和自身部門對元件庫管理的規範,整理出如下的UI庫自動釋出方案。
2 方案
2.1 手動釋出流程
元件庫的釋出包含兩項釋出工作,其一是UI庫的釋出,其二是元件使用文檔的釋出。根據部門制定的元件庫釋出規範,手動發的流程大體如下圖所示:

⚠ 說明:
- 更新version:由釋出者按照語義版本控制規範自行修改
中的
package.json
字段的屬性值。
version
- 添加版本tag:按版本号加v表示tag名稱(例如v1.1.1)。
2.2 釋出流程拆分
根據部門目前
UI
庫的釋出過程,結合
Gitlab
的
CICD
能力,可以将整個釋出流程拆分為三個任務,分别是代碼測試任務、
UI
庫釋出任務和文檔打包部署任務。每個任務具體負責的工作如下圖所示:
相比于手動釋出流程,自動釋出流程添加了
code test
和推送
release
到
Gitlab
兩個子任務,這是為了更規範的釋出
UI
庫和文檔。
2.3 自動釋出流程
借助
Gitlab
的
CICD
能力,當代碼合并到
master
之後,會自動觸發工作流。然後工作流會依次執行代碼測試任務、
UI
庫釋出任務和文檔打包部署任務。同時為了保證
UI
庫和文檔釋出的嚴謹,在
UI
庫釋出任務之前添加了審批環節,需要手動觸發該任務的執行并經過審批後,才會執行
UI
庫的釋出和文檔的部署。
2.4 UI庫版本生成規則
UI
庫的釋出過程借助了semantic-release工具,其完成了
UI
庫釋出任務中除了打包外的所有子任務。UI庫版本的生成嚴格執行語義版本控制規範(
X.Y.Z
),并通過分析上次釋出代碼(目前最新
tag
的代碼)到目前代碼新增的
commit message
來确定待釋出的版本号。
版本生成規則如下:
-
或fix
類型的送出,會将perf
版本号加1PATCH
-
類型的送出,會将feat
版本号加1MINOR
- 包含
字元串的送出,會将breaking change
号加1MAJOR
如果一次釋出過程中包含多個送出,則使用所有送出對應版本号中的最大值作為待釋出的版本号。例如原版本号為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
。
但由于曆史原因,部門成員所在的組整體被賦予了
Maintainers
角色,為了禁止開發者往
master
送出代碼,
roles
需要選擇
No one
,而這又會導緻
release-bot
反向推送到
master
失敗。不過除了設定角色之外,
Gitlab
還支援選擇
deploy key
。
可以按照官方文檔的提示生成并配置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}"
}
]
]
}