本文翻譯自: https://www.infoq.com/article...
原文做者: Victor Grazi , Bryan Gardner
譯文原地址: https://weyunx.com/2019/02/28...
過去開發者花上幾周或幾個月開發完一個應用功能以後,他們須要進行合併代碼的工做。這時候須要有專人,也許是版本管理員,把全部的新功能集成起來,解決代碼衝突、而後準備發佈新的版本。代碼的合併老是讓人擔驚受怕,畢竟會伴隨着不可預見的錯誤,這可能讓咱們一個挺好的應用變成了「集成地獄」。在 2000 年的時候,Kent Beck 發佈了具備開創性的著做《Extreme Programming Explained》,其中提出了「持續集成」的概念,即開發人員須要每幾個小時或最多一天內進行編譯而後合併代碼到主分支最後再運行自動化測試。html
說明:本文的項目是使用 Java 和 Maven,使用 GitLab CI 來執行腳本(Jenkins 和 GitHub CI plugin 也一樣支持)。使用 Jira 來跟蹤問題單,IntelliJ IDEA 做爲 IDE,Nexus 做爲倉庫管理,Ansible 做爲自動化部署工具。java
Gitflow 提倡使用 feature branches 模式來開發各個相互獨立的功能,同時分紅不一樣的分支以便進行集成和發佈,以下圖:git
做爲 Git 使用者,咱們應該對 master 分支已經不陌生了,它是 Git 初始化項目的時候默認建立的分支,是項目的主幹。在使用 Gitflow 模式以前,你極可能會直接提交代碼到 master 分支上。正則表達式
開始使用 Gitflow 以前,須要作一步一次性的初始化動做,就是從 master 分支上建立一個 develop 分支。自此,develop 分支將變成一個相似全能的分支,用來存放、測試全部的代碼,同時也是主要是用來合併代碼、集成功能的分支。express
做爲一個開發人員,在這是不容許直接提交代碼到 develop 分支上的,更更更不容許直接提交到 master 分支。master 分支表明的是一個「stable」的分支,包含的是已投產或即將投產的代碼。若是一段代碼在 master 分支上,即表明它已經投產或即將投產發佈。服務器
develop 分支表明着「unstable」,它包含了須要編譯而且須要測試經過的代碼,甚至是沒有完成的代碼,因此稱之爲「unstable」。併發
接下來將介紹咱們是如何開展工做的:ide
好比,當你被派到了一個 Jira 問題單,你須要當即從 delevop 分支上建立一個 feature 分支。工具
在 feature 分支的命名規則上,咱們約定以 「feat-」開頭,後面跟上問題單編號。如「feat-SDLC-123-add-name-field」。以「feat-」開頭,可讓 CI 服務器識別出這是一個 feature 分支,「SDLC-123」是咱們 Jira 問題單的編號,能夠連接到問題單,剩下的部分則是對該功能的簡短的說明。gitlab
這樣,咱們的開發工做就能夠並行地開展,每一個人均可以同時在各自的 feature 分支上開發,當咱們持續的將功能 merge 到 develop 分支上後,咱們能夠大大減小變成「集成地獄」的可能。
如今咱們讓團隊更頻繁的提交代碼,那麼,咱們是怎麼避免衝突呢?答案是使用 GitLab CI 來進行 build,咱們將 GitLab CI 綁定到以「feat-」開頭命名的分支即 feature 分支,在 feature 分支上執行 Maven verify (本地編譯以及運行 tests),但不發佈到 Nexus 倉庫。
GitLab CI 是經過項目根目錄裏的 .gitlab-ci.yml
文件進行配置,包含了 CI/CD 的各個步驟。這個功能的絕妙之處是它能夠將運行腳本和代碼提交進行綁定。
以下是 GitLab CI 的配置例子,其中咱們經過正則表達式來綁定了 feature 分支:
feature-build: stage: build script: - mvn clean verify sonar:sonar only: - /^feat-\w+$/
團隊提倡頻繁地提交代碼,每次提交代碼都會獨立的運行 tests,以保證當前提交的代碼不會影響到項目原有的任何其它功能。
接下來咱們該討論測試覆蓋率,IntelliJ idea 自帶 coverage 運行模式,容許運行測試代碼檢查測試覆蓋率,會經過側邊欄粉色或綠色來標記是否被測試代碼覆蓋到。同時建議在 Maven 裏添加測試覆蓋率插件,如 jacoco,它能夠在 GitLab CI 運行集成編譯的時候生成報告。
Maven 的 test 階段執行單元測試,verify 階段執行集成測試。建議安裝 SonarQube 和 Maven SonarQube 插件來進行靜態代碼的分析和測試。這樣,每個 feature 分支的每一次提交都會執行上述全部的 test。
回到 Gitflow,如今咱們已經開發完了新功能,同時將代碼提交到了 feature 分支,根據「持續集成」到思想,咱們要求開發團隊須要頻繁地把代碼從 feature 分支 merge 到 develop 分支上,要求頻率最晚不超過一天。
同時 GitLab 裏內置了一個代碼複查的機制,即發起一個 merge 請求後,咱們必須複查完代碼才能夠將代碼 merge 到 develop 分支上。
根據不一樣的 SDLC(軟件開發生命週期)要求,好比咱們強制不一樣的且具備相關職責的開發人員進行代碼複查,或者能夠更簡單點,開發人員本身複查本身的代碼,這樣起碼鼓勵了開發人員能夠至少複查一下本身的代碼,固然也很明顯的增長了不少不靠譜的風險。
最終,通過幾天的努力,項目功能已經開發完畢,並且已經所有 merge 到 develop 分支上,並驗證完畢,同時,其它幾個功能也開發完畢也準備發佈。記住此時咱們只是在每一次的提交時進行了驗證,並無進行部署,如發佈 SNAPSHOT 版本到 Nexus 倉庫上,這是咱們下一步將要作的。
此時,咱們在 develop 分支上新建一個 release 分支,然而與傳統的 Gitflow 不一樣,新建的 release 分支是以版本號來命名,版本號命名規則可參考這裏。若是 SNAPSHOT 版本的版本號是 1.2.1-SNAPSHOT,那麼這次的 release 分支應該命名爲 1.2.1。
配置 GitLab CI 使用正則表達式來識別一個 release 分支,同時執行相關的腳本。
release-build: stage: build script: - mvn versions:set -DnewVersion=${CI_COMMIT_REF_NAME}-SNAPSHOT # now commit the version to the release branch - git add . - git commit -m "create snapshot [ci skip]" - git push # Deploy the binary to Nexus: - mvn deploy only: - /^\d+\.\d+\.\d+$/ except: - tags
主要特別注意的是提交的時候須要加上 [ciskip]
防止新的提交再次觸發 GitLab CI,從而進入死循環。
在測試中,不免發現 bug,咱們能夠直接在 release 分支上修改,修改完後再 merge 到 develop 分支上(develop 分支包含的是已發佈或者即將發佈的代碼)。
最後, release 分支被驗證經過,咱們將會把它 merge 到 master 分支中。合併時,release 分支中的版本號仍是 SNAPSHOT 版本,GitLab runner 會經過 Maven 版本插件將版本號後綴 SNAPSHOT 去掉,同時生成下一個 SNAPSHOT 版本號併發布到 Nexus。此時還會將其部署到 UAT 環境中進行測試,測試無問題後再部署到生產環境。
相關的 CI 配置以下:
master-branch-build: stage: build script: # Remove the -SNAPSHOT from the POM version - mvn versions:set -DremoveSnapshot # use the Maven help plugin to determine the version. Note the grep -v at the end, to prune out unwanted log lines. - export FINAL_VERSION=$(mvn --non-recursive help:evaluate -Dexpression=project.version | grep -v '\[.*') # Stage and commit the binaries (again using [ci skip] in the comment to avoid cycles) - git add . - git commit -m "Create release version [ci skip]" # Tag the release - git tag -a ${FINAL_VERSION} -m "Create release version" - git push - mvn sonar:sonar deploy artifacts: paths: # list our binaries here for Ansible deployment in the master-branch-deploy stage - target/my-binaries-*.jar only: - master master-branch-deploy: stage: deploy dependencies: - master-branch-build script: # "We would deploy artifacts (target/my-binaries-*.jar) here, using ansible only: - master
還有一個必須說明的分支是 hotfixes 分支。這個分支是負責在生產環境上發現的問題,如 bug 或者性能問題等。 hotfixes 分支和 release 分支相似,都以 release 版本號命名,惟一的區別就是 hotfixes 是新建於 master 分支,release 分支則是從 develop 分支而來。
hotfix 就是這樣,和 release 同樣,都會觸發 Nexus SNAPSHOT 發佈,而後部署到 UAT 環境。當一切都沒問題驗證經過後,須要再將它 merge 回 develop 分支,而後再 merge 到 master 以進行投產發佈。
總結圖表以下:
以上就是 Gitflow 的特色,咱們建議你們積極嘗試文中所說的各類方法,能夠帶來以下一些優點:
如今互聯網公司都在討論「持續交付」,若是你的團隊天天都會發布不少版本,本文的方法估計不太適合你,若是你所在的是一個傳統企業,如一些金融機構,在版本發佈方面更加謹慎,那本文所介紹的分支管理、持續集成、自動化測試以及自動化部署等方面內容也許對你有所幫助。原文篇幅較長,只把主要部分翻譯了過來,就看成拋磚引玉,要是感興趣能夠深刻研究,若是發現譯文存在錯誤或其餘須要改進的地方,歡迎斧正。