如何打造規範的開源項目workflow

前言

通常開源項目正常的開發流程是:javascript

  • 初始階段
    • 建立倉庫
    • git clone repository 到本地
    • 添加修改代碼
    • 提交commit message
    • push到 github 倉庫
  • 迭代階段
    • 切換開發分支
    • 開發新功能
    • 完善測試用例
    • 平常修復bug
    • 文檔的完善
  • 發佈階段
    • 打tag
    • npm publish

表面看起來沒有什麼毛病,可是要作一個規範的多人協做的可維護的開源項目,開發流程上仍是有很多細節的點須要咱們來打磨。html

那在多人協做的開發過程當中到底會碰到哪些沒法統一的行爲?咱們該如何解決這些問題?前端

  • 代碼檢查
  • 提交信息和修改日誌
  • 版本迭代
  • 執行落地

代碼檢查

問題

這是一個老生常談的問題,語句結尾要不要分號?縮進是空格仍是tab?是2個仍是4個?java

解決步驟

目前業界比較統一的作法是使用eslintreact

做爲項目owner,建議全局安裝eslintgit

npm install eslint -g
複製代碼

以後就能夠在本地的項目倉庫中,執行命令:github

eslint --init
複製代碼

能夠有三種選擇:npm

  • 選擇一個流行的樣式規範
  • 自定義的代碼習慣
  • 檢查你項目以前的代碼樣式

常規的前端項目建議選用Standard規範(雖然不是真正的規範,可是屬於業內默認的規範吧),初始化以下:json

{
   "devDependencies": {
        "eslint": "^4.19.1",
        "eslint-plugin-import": "^2.13.0",
        "eslint-config-standard": "^11.0.0",
        "eslint-plugin-standard": "^3.1.0",
        "eslint-plugin-promise": "^3.8.0",
    }
}
複製代碼

React項目建議選用Airbnb規範,初始化後的package.json以下:promise

{
    "devDependencies": {
        "eslint": "^4.19.1",
        "eslint-config-airbnb": "^17.0.0",
        "eslint-plugin-import": "^2.13.0",
        "eslint-plugin-react": "^7.10.0",
        "eslint-plugin-jsx-a11y": "^6.1.1"
    }
}
複製代碼

若是須要單獨定義一些規則,能夠在根目錄下新建一個.eslintrc文件,見具體配置

若是須要忽略一些文件,能夠在根目錄下新建一個.eslintignore文件,見具體配置

最後在package.json中加上命令

{
    "scripts": {
        "lint": "eslint --ext .jsx,.js ."
    }
}
複製代碼

這樣項目成員只須要操做如下步驟

  • vscode中安裝eslint擴展(之後使用vscode打開項目都會檢測項目中的.eslintrc文件進行實時lint提示)
  • cd project && npm install

衍生問題1

若是是以前的老項目接入了eslint,同時加入了git hook來強制執行,會致使以前的錯誤沒修復完沒法提交,那有沒有辦法只檢測當前修改的文件呢?

解決方案

目前社區比較成熟的方案是lint-staged

首先在項目中安裝lint-stagedhusky

husky是用來實現綁定git hooks的一個庫,後面會提到

npm install -D lint-staged husky
複製代碼

而後在項目中的package.json中添加

{
  "scripts": {
    "precommit": "lint-staged"
  },
  "lint-staged": {
    "*.js": ["eslint --fix", "git add"]
  }
}
複製代碼

以上操做在咱們正常的開發流程中作了什麼呢?

git add .以後,git commit以前,會觸發precommit鉤子,執行lint-staged,而後lint-staged會只檢查通過暫存區的文件,根據它的配置項執行命令。

例如上面的配置,就是針對全部修改過的以js爲後綴的文件,依次執行eslint --fix,git add兩個命令,幫你自動修復掉eslint的錯誤,再將修改添加到暫存區,而後一塊兒commit到工做區。

衍生問題2

eslint只是做爲代碼檢測的工具,並無規範開發時的行爲,那可不能夠在編輯器上進行規範呢?

解決方案

主流方案是使用EditorConfig

首先在項目根目錄新建一個.editorconfig文件,根據EditorConfig支持的大部分屬性自行定義

而後再給編輯器安裝EditorConfig的插件,就可使用了,插件安裝可見官方下載

提交信息和修改日誌

問題

  • commit message

    在實際開發的過程當中,其實你們對本身的修改內容並無很好的界定,也沒有統一的格式化,致使了不少時候咱們沒法根據commit message來快速定位修改內容。

  • changelog

    其實一個項目新增功能,修復bug等信息都須要記錄下來,便於區別不一樣版本的新特性,而後手動維護記錄一般容易忘記,致使這一部分常常沒有持續的更新。

解決步驟

目前社區使用最廣的方案是Commitizenconventional-changelog配合使用。

顧名思義

  • commitizen就是用來規範commit message
  • conventional-changelog能夠根據格式化的commit message自動生成CHANGLOG.md

commitizen

有兩種開發方式:

  • 全局安裝(牆裂推薦):

    npm install commitizen -g
    複製代碼

    而後安裝commitizenadpater,好比cz-conventional-changelog(AngularJS的提交慣例)

    npm install -g cz-conventional-changelog
    複製代碼

    而後你就可使用git cz來替換git commit命令來進行代碼提交了。

  • 項目安裝:

    讓你的項目讓別人更友好的接入commit規範,你不可能強制要求別人全局安裝一個工具,就只能在開發依賴裏添加

    做爲項目owner,默認已經全局安裝了commitizen,而後執行:

    commitizen init cz-conventional-changelog --save-dev --save-exact
    複製代碼

    以上命令作了三件事:

    • 在本地安裝cz-conventional-changelog模塊

    • 保存到package.jsondevDependencies

    • package.json的根層級添加了config.commitizen

      "config": {
        "commitizen": {
        	"path": "cz-conventional-changelog"
        }
      }
      複製代碼

    爲了保證其餘貢獻者的倉庫中也能使用同一版本的commitizen,最好在倉庫安裝開發依賴

    npm install -D commitizen
    複製代碼

    而後在項目的package.json中的scripts里加上

    {
      "scripts": {
        "cz": "git-cz"
      }
    }
    複製代碼

    這裏須要注意一點,若是你在scripts腳本中定義了{"commit": "git-cz"}的話,precommit鉤子會在真正commit以前執行兩次,見husky issue,因此自定義另一個名稱就行了。

    而後項目contributors就能夠經過npm run cz來愉快的提交格式化的commit message了。

changelog

仍是國際慣例,全局安裝

npm install -g conventional-changelog-cli
複製代碼

切換到項目目錄後,執行

conventional-changelog -p angular -i CHANGELOG.md -s -r 0
複製代碼

就能夠根據commit message 自動生成一份CHANGELOG.md文件

再配合上package.json裏的scripts

{
    "scripts": {
        "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0"
    }
}
複製代碼

只須要執行npm run changelog就好了,是否是很簡單?

可是該在什麼時機執行上面這條命令呢?

根據文檔推薦的工做流,在修改package.json中的版本以後執行最合適。

不過在下面的版本控制會將工做流改爲用npm version來實現。

{
    "scripts": {
        "version": "npm run changelog && git add CHANGELOG.md"
    }
}
複製代碼

版本迭代

問題

傳統版本迭代步驟

  • package.json中修改遞增version

  • git add -A

  • git commit -m "update version"

  • git push

  • git tag <tag version>

  • git push --tag

  • npm publish

流程過於繁冗,很容易遺漏打tag那一步。

解決步驟

使用npm version命令,從文檔上咱們能夠看到其依據semver支持了大部分alias:

npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git]
複製代碼

例:初始版本爲1.0.0

npm version prepatch //預備補丁版本號 v1.0.1-0

npm version prerelease //預發佈版本號 v1.0.1-1

npm version patch //補丁版本號 v1.0.2

npm version preminor //預備次版本號 v1.1.0-0

npm version minor //次版本號 v1.1.0

npm version premajor //預備主版本號 v2.0.0-0

npm version major //主版本號 v2.0.0

當在倉庫中執行npm version時,會自動提交git commit並打上git tag

當使用-m參數時,就能夠自定義發佈版本的信息,其中%s能夠用來代替當前版本號

npm version patch -m "upgrade to %s for reasons"
複製代碼

這樣之後版本迭代只須要如下步驟

  • npm version patch | minor | major | ...etc
  • git push
  • git push --tag
  • npm publish

衍生問題

如何發佈beta,rc,alpha版本呢?若是發佈了,應該如何安裝?

解決方案

首先咱們要理解這些版本的含義

  • alpha:內部測試版本
  • beta: 公開測試版本
  • rc: 候選版本(Release Candidate)

而後將package.jsonversion改爲x.x.x-beta

配合npm publish --tag <tag>,咱們能夠發佈對應的dist-tag

舉個例子:

使用npm publish --tag beta發佈後,而後就可使用npm install <pkg>@beta安裝對應版本的包。

咱們能夠經過npm dist-tag ls <pkg>來查看包的dist-tag

{
    latest: 1.0.1, // 這就是npm publish默認發佈的tag
    beta: 1.0.1-beta
}
複製代碼

當咱們的beta版本穩定後,可使用npm dist-tag add x.x.x-beta latest設置爲穩定版本。

執行落地

問題

正常工做流咱們分爲兩塊:

  • 開發流程

    在開發流程中,咱們須要保障

    • 代碼lint經過
    • 單元測試經過
    • 規範的提交信息(optional)
  • 發佈流程

    在發佈流程中,咱們須要保障

    • 打包經過
    • 生成CHANGELOG
    • 規範的版本號迭代

解決方案

根據上述兩種流程,咱們可使用git hooknpm hook

開發流程

在上面已經介紹過,咱們選用husky做爲git hook的實現工具

npm install -D husky
複製代碼

代碼lint和單元測試,咱們能夠放到precommit中執行,修改鉤子執行的命令

{
    "scripts": {
    	"test": "jest",
        "precommit": "lint-staged && npm run test"
    }
}
複製代碼

commit message lint的解決方案:commitlint

npm install -D @commitlint/config-conventional @commitlint/cli
複製代碼

而後在package.json中配置鉤子

{
    "scripts": {
        "commitmsg": "commitlint -E GIT_PARAMS"
    },
    "commitlint": {
        "extends": ["@commitlint/config-conventional"],
        "rules": {
            "subject-case": [0]
        }
    }
}
複製代碼

這樣咱們在git commit執行以前驗證了eslint是否經過,測試用例是否經過,commit message是否符合規範。

固然也能夠在commit後面添加參數--no-verify來跳過commit message lint

發佈流程

  • bump version

    修改package.json

    {
        "scripts": {
            "version": "npm run changelog && git add CHANGELOG.md",
            "postversion": "git push && git push --tags"
        }
    }
    複製代碼

    而後執行npm version patch | minor | major

  • npm publish

    添加prepublishOnly hook

    {
        "scripts": {
            "prepublishOnly ": "npm run build"
        }
    }
    複製代碼

    而後執行npm publish

執行npm version命令時會依次執行npm script中的preversionversionpostversion三個鉤子,具體詳情見文檔

prepublishOnly只會在npm publish以前執行,prepareprepublish都會在npm publish和不帶參數的npm install時執行,見npm script文檔

結尾

至此,咱們已經基本打造了一個比較完善的開源項目workflow。

對於項目開發者來講,只須要作如下幾點改變:

  • 編輯器安裝eslinteditorconifg插件
  • 使用git cz提交信息
  • 使用npm version patch | minor | patch來進行版本迭代

是否是更簡單方便了呢?

歡迎你們拍磚,廣納良言!

參考文獻

相關文章
相關標籤/搜索