如何使用 Github Action 管理 Issue
前言
Code
查看代碼,或者只是把 github 當成一個代碼倉庫,但是 github 還提供了很多好用的功能。
其中,GitHub Action 就是一個很好用的功能,本文將通過幾個管理Issue
的示例帶大家瞭解 GitHub Action:
什麼是 Github Action
github 給所有用戶都提供了臨時可用的虛擬機, 我們通過創建 github action 工作流來使用這個虛擬機. 我們可以使用它來實現自動化部署、自動化測試、代碼檢查、管理 Issues...
使用步驟
在學習之前還需要準備一些資料:
-
Github Action 文檔
-
官方倉庫中有很多可以複用的 Action, 通過
uses
字段引用就可以直接使用了。 -
阮一峯的 YAML 教程;
也推薦大家使用 Vscode GitHub Action 插件,這個插件在登錄後可以用來做語法校驗,還能查看運行過的記錄。
除了這些資料之外還有些基礎概念需要了解:
-
事件: 在工作流中可以監聽 github 的一些事件, 在事件觸發後執行我們定義的工作流;
-
上下文: github 上下文包含有關工作流運行和觸發運行的事件的信息,可以讀取環境變量中的大多數 github 上下文數據,並允許我們通過變量訪問這些數據。
-
變量: 變量提供了一種存儲和重用非敏感配置信息的方法。 可以將任何配置數據(如編譯器標誌、用戶名或服務器名稱)存儲爲變量。 變量在運行工作流的運行器計算機上插值。 在操作或工作流步驟中運行的命令可以創建、讀取和修改變量。
-
表達式: 可以使用表達式來運算工作流程文件中的變量。
-
祕鑰: 普通變量中存儲的信息並不安全,很容易泄露,一些需要保密的信息就可以存儲到祕鑰中。
如果不想去從頭學習yml
語法, 可以先了解一些yml
的基礎用法:
-
大小寫敏感
-
使用縮進表示層級關係
-
縮進時不允許使用 Tab 鍵,只允許使用空格。
-
縮進的空格數目不重要,只要相同層級的元素左側對齊即可
下面開始介紹 GitHub Action 的用法
使用 github Action ,第一步需要在項目根目錄下創建.github/workflows
文件夾, 所有的工作流文件都要放到這個文件夾,當事件觸發時會自動執行;
大家可以通過這個 workflow 文件示例來簡單瞭解下各個字段的用處:
name: build # workflow的名稱,缺省時會使用文件名
on: # workflow監聽事件
push # 具體的事件
branches: # 在這些分支上纔會觸發
- main
- 'mona/octocat'
- 'releases/**'
jobs: # 執行的工作的集合
build: # ‘build’是一個自定義的工作的id<job_id>
name: rele # 當前工作的名稱
runs-on: ubuntu-latest # 因爲工作實際是運行在虛擬機上的,runs-on就是指定虛擬機的版本
steps: # steps是步驟的集合
- name: checkout # name是指定當前工作的名稱 在workflow(工作流)文件的steps中,每個用‘-’代替縮進視爲一個步驟的開始
uses: actions/checkout@v2 # uses字段是選擇一個可以直接複用的action,並且在github action store中的action可以直接使用,不需要下載
- name: setting env
id: setting # id 是步驟的唯一標識符,可以使用 id 在上下文中引用該步驟
env: # 設置環境變量
NODEV: 18
run: echo "nodev=$NODEV" >> $GITHUB_OUTPUT # run字段會在命令行執行一條命令,這個命令是將"nodev=18"寫入到$GITHUB_OUTPUT,這樣可以爲'output'添加test屬性值爲test1,詳情參考
- name: addnode
uses: actions/setup-node@v3 # 使用node環境
with: # 爲‘uses’使用的action傳遞參數
node-version: ${{steps.setting.output.nodev}} # 使用上面設置的變量
在編寫工作流文件之前有兩件事要做:
一. 可以在 github 或者 github action 的倉庫裏查找公用 action. 這樣可以減少很多工作量:
常用的 action 有:
-
checkout: 幫我們自動把項目克隆到虛擬機上
-
Setup Node: 自動安裝 node
-
issues-helper: 輔助處理 issues
二. 如果沒有設置 action 的讀寫權限,第一次運行會報錯:
再次運行:
下面通過一些具體示例給大家介紹一些Github Action
的用法:
-
檢查 issues 格式是否規範, 並關閉不規範 issue
在開源項目中,很多人都會提一些 issue。爲了方便開發者查看,可以上傳 issue 模版,並且根據模版校驗 issue 格式,然後關閉不符合模板格式的 issue。
在這個示例主要介紹腳本執行怎麼向
github上下文
注入變量,我們可以參考 github 設置環境變量的教程.這個腳本可以配合
.github/ISSUE_TEMPLATE
文件夾中的 issue 模板使用的,將.md
文件放入這個文件夾中就可以作爲 Issue 的默認模板;Alt text 選擇 Bug 提交將使用這個模板:
--- name: Bug 提交 about: 使用此模板來提交一個 bug。 --- # BUG 提交 ## 描述該錯誤 簡明扼要地描述一下這個錯誤是什麼。 可以添加屏幕截圖以幫助解釋你的問題。 ## 復現 這個 BUG 的復現步驟: 1. ... 2. ... 3. ... ... 或者添加錄屏鏈接 ## 運行結果 預期的結果: ... ... 實際的結果: ... ... ## 運行環境信息 - Device: [e.g. 設備名稱] - OS: [e.g. 操作系統] - Browser [e.g. 瀏覽器] - Version [e.g. 瀏覽器版本] ## 其它 在此添加關於問題的任何其它信息。
選擇功能請求將使用這個模板:
--- name: 功能請求 about: 使用此模板來提交一個功能請求。 --- # 功能請求 ## 你期望添加什麼樣的功能? 你期望新增功能的描述,或者示例鏈接。
檢查 issue 格式的腳本:
// action_script/lintIssue.js const issueText = process.env.ISSUE const textSplit = issueText .split( ` ` ) .map((str) => str.replace('\r', '')) const bugHandle = () => { // 缺少錯誤描述 const desIndex = textSplit.indexOf('## 描述該錯誤') if (desIndex === -1) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少錯誤描述') return } const repeatIndex = textSplit.indexOf('## 復現') if (repeatIndex === -1) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少復現步驟') return } const desContent = textSplit .slice(desIndex + 1, repeatIndex) .join('') .replaceAll(' ', '') if (!desContent) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少錯誤描述') return } // 缺少復現步驟 const runResultIndex = textSplit.indexOf('## 運行結果') if (runResultIndex === -1) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少運行結果') return } const repeatContent = textSplit .slice(repeatIndex + 1, runResultIndex) .join('') .replaceAll(' ', '') if (!repeatContent) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少復現步驟') return } // 運行結果 const envIndex = textSplit.indexOf('## 運行環境信息') if (envIndex === -1) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少運行環境信息') return } const resContent = textSplit .slice(runResultIndex + 1, envIndex) .join('') .replaceAll(' ', '') if (!resContent) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少運行結果') return } // 運行環境信息 const otherIndex = textSplit.indexOf('## 其他') || textSplit.length + 1 const envContent = textSplit.slice(envIndex + 1, otherIndex) const envReg = /\[e\.g\..{5,}\]/ let hasDevice = false let hasOS = false let hasBrowser = false let hasVersion = false let errMsg = '' envContent.forEach((str) => { if (str.match(envReg)) { if (str.includes('Device')) { hasDevice = true } else if (str.includes('OS')) { hasOS = true } else if (str.includes('Browser')) { hasBrowser = true } else if (str.includes('Version')) { hasVersion = true } } }) if (!hasDevice) { errMsg += '缺少設備名稱;' } else if (!hasOS) { errMsg += '缺少操作系統名稱;' } else if (!hasBrowser) { errMsg += '缺少瀏覽器名稱;' } else if (!hasVersion) { errMsg += '缺少瀏覽器版本;' } if (errMsg) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=' + errMsg) } else { console.log('ISSUE_CHECK_RESULT=pass') } } const featureHandle = () => { // 缺少錯誤描述 const desIndex = textSplit.indexOf('## 你期望添加什麼樣的功能?') const desContent = textSplit .slice(desIndex + 1, textSplit.length) .join('') .replaceAll(' ', '') .replaceAll('\n', '') if (desIndex === -1 || desIndex === textSplit.length - 1 || !desContent) { console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=缺少功能描述') return } else { console.log('ISSUE_CHECK_RESULT=pass') } } if (textSplit[0] === '# BUG 提交') { console.log('ISSUE_CHECK_TYPE=bug') bugHandle() } else if (textSplit[0] === '# 功能請求') { console.log('ISSUE_CHECK_TYPE=feature') featureHandle() } else { console.log('ISSUE_CHECK_TYPE=invalid') console.log('ISSUE_CHECK_RESULT=unqualified') console.log('ISSUE_CHECK_REPLY=這不是一個BUG或者功能請求') }
工作流示例文件:
# .github/workflows/close-non_standard-issue.yml name: close non-standard issues on: issues: types: [opened, edited] # issue 打開或者編輯後 jobs: close-issue: runs-on: ubuntu-latest env: ISSUE: ${{ github.event.issue.body }} steps: - name: 'checkout' uses: actions/checkout@v3 - name: Setup node uses: actions/setup-node@v3 with: node-version: 18 registry-url: https://registry.npmjs.com/ - name: lint sh run: node ./action_script/lintIssue.js >> "$GITHUB_ENV" # 設置自定義github變量 - name: add-label uses: actions-cool/issues-helper@v3 with: actions: 'add-labels' token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} labels: ${{env.ISSUE_CHECK_TYPE}} - name: 'close-issue' if: ${{env.ISSUE_CHECK_RESULT == 'unqualified'}} uses: actions-cool/issues-helper@v3 with: actions: 'close-issue' token: ${{ secrets.GITHUB_TOKEN }} body: | Hello @${{ github.event.issue.user.login }}.你的Issue因爲下面的原因被關閉了: ${{env.ISSUE_CHECK_REPLY}}
-
如果是做一些簡單的校驗可以使用 actions-cool/issues-helper@v3 中的 check-issue:
這個示例主要是演示運算符的使用:
name: add label of non_standard Issue on: issues: types: [opened, edited] jobs: check-issue: runs-on: ubuntu-latest steps: - id: check-issue # 必須使用id,不然不能訪問到運行結果 uses: actions-cool/issues-helper@v3 with: actions: "check-issue" token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} title-includes: "【,BUG,】" # 標題包含['【','BUG','】'] body-includes: "問題描述,問題復現步驟" # 內容包含 ['問題描述','問題復現步驟'] - name: add-label uses: actions-cool/issues-helper@v3 if: ${{steps.check-issue.outputs.check-result == 'true'}} # 如果判斷條件是 'true', 繼續運行 with: actions: "add-labels" token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} # 當前Issue的編號 labels: "bug" # 添加標籤: 'bug'
-
關閉缺少復現步驟的 Issue
有些 Issue 雖然通過了格式檢查,但是還會缺少一些步驟,或者不能復現。我們可以手動添加 label,並且在三天不活躍的情況下自動關閉。
這個示例主要是介紹怎麼執行定時任務:
# .github/workflows/close-inactive-issue.yml name: close inactive issue on: schedule: - cron: "00 12,00,18 * * *" # 在每天標準時間的12:00/00:00/18:00 執行 jobs: check-inactive-info: runs-on: ubuntu-latest steps: - name: need reproduction uses: actions-cool/issues-helper@v3 with: # 關閉有label是'need reproduction',並且三天不活躍的Issue actions: "close-issues" token: ${{ secrets.GITHUB_TOKEN }} labels: "need reproduction" inactive-day: 3
-
添加標籤時自動評論、關閉 BUG
有些常用的評論內容,或者用的比較多的操作,每次使用都比較繁瑣。我們可以在添加標籤的時候自動評論,或者執行對應的操作。比如:自動評論歡迎詞,關閉手動篩選出來不符合 issue 模版的 issue 並告訴用戶原因。
這個示例是介紹在
.yml
文件中長文本的寫法name: Issue Labeled # .github/workflows/issue-labeled.yml # 在issue添加標籤後回覆對應的評論 on: issues: types: [labeled] jobs: reply-labeled: runs-on: ubuntu-latest steps: # 需要幫助 - name: contribution welcome if: github.event.label.name == 'help wanted' uses: actions-cool/issues-helper@v3 with: actions: "create-comment" issue-number: ${{ github.event.issue.number }} body: | 你好 @${{ github.event.issue.user.login }},我們完全同意你的提議/反饋,歡迎直接在此倉庫 [創建一個 Pull Request](https://github.com/NI-Web-Infra-Team/vue3-template/pulls) 來解決這個問題。請將 Pull Request 發到 `dev` 分支,提供改動所需相應的 changelog、TypeScript 定義、測試用例、文檔等,並確保 CI 通過,我們會盡快進行 Review,提前感謝和期待您的貢獻。 # 補充復現流程 - name: need reproduction if: github.event.label.name == 'need reproduction' uses: actions-cool/issues-helper@v3 with: actions: "create-comment" issue-number: ${{ github.event.issue.number }} body: | 你好 @${{ github.event.issue.user.login }}, 我們需要你提供一個在線的重現實例以便於我們幫你排查問題。可以通過點擊 [此處](https://codepen.io/pen/) 創建或者提供一個最小化的 GitHub 倉庫。3 天內未跟進此 issue 將會被自動關閉。 - name: invalid if: github.event.label.name == 'invalid' uses: actions-cool/issues-helper@v3 with: actions: "create-comment, close-issue" issue-number: ${{ github.event.issue.number }} body: | 你好 @${{ github.event.issue.user.login }},爲了能夠進行高效溝通,我們對 issue 有一定的格式要求,你的 issue 因爲不符合要求而被自動關閉。你可以通過模板來創建 issue 以方便我們定位錯誤。謝謝配合!
-
使用 ftp 自動部署
如果有在公網的服務器,可以在編譯完成後打包發送到自己的服務器實現自動部署。 在 github 中搜索 ftp action, 第一個 SamKirkland/FTP-Deploy-Action 就是將 github 項目部署到 ftp 服務器的:
最後這個示例介紹的是怎麼設置祕鑰:
name: ftp send file on: workflow_dispatch # 手動部署 jobs: web-deploy: name: Deploy runs-on: ubuntu-latest steps: - name: Get latest code uses: actions/checkout@v3 # 拉取項目代碼 - name: Setup node uses: actions/setup-node@v3 # 安裝node with: node-version: 18 registry-url: https://registry.npmjs.com/ - name: install package run: npm i # 安裝項目依賴 - name: build run: npm run build # 編譯 - name: pack run: zip -q -r dist.zip ./dist # 打包成zip - name: Sync files uses: SamKirkland/FTP-Deploy-Action@v4.3.4 # 上傳到ftp服務器 with: server: 10.52.0.x # 服務器地址 username: testusername # 服務器用戶名 password: ${{ secrets.ftp_password }} # 服務器密碼
-
設置在 action 中可以訪問的祕鑰
服務器密碼
secrets.ftp_password
,就是在 github 中設置的祕鑰:
結語
通過使用 Github Action 來管理 Issue,可以有效的提高生產力和效率,在自動化、協作、代碼質量管理等方面都有提升,並幫助我們更好地組織和管理問題。文章篇幅有限,我們暫且介紹到這裏,感興趣的小夥伴們可以再自行探索。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/OSFYVnhtCsvfvRCP3VPJww