Please enable Javascript to view the contents

GitHub Actions 三步教你打造 ChatOps 系统

 ·  ☕ 4 分钟

在上一篇文档 《使用 ChatOps 改进研发流程》中,通过 ChatOps 给 Pull Requests 提供预览链接提升了敏捷速度。本篇主要描述如何快速实现这个功能。

1. 第一步: 配置一个触发器

1.1 选择一个触发器

在 GitHub 中有三类 Workflows 触发器,定时、人工、自动触发器。我们需要选择一个自动触发器,用于触发执行逻辑。目前 GitHub Actions 支持的自动触发器有 check_run、check_suite、create、delete、deployment、deployment_status、fork、gollum、issue_comment、issues、label、milestone、page_build、project、project_card、project_column、public、pull_request、pull_request_review、pull_request_review_comment、pull_request_target、push、registry_package、release、status、watch、workflow_run。

在 workflows.yaml 文件中,on 关键字下添加触发器:

1
2
3
on:
  issue_comment:
    types: [created]

这里选择的是 issue_comment ,当有 Issues 或者 Pull Requests 被评论时,触发 Actions 的执行。

1.2 定义一个触发关键字

定义关键字是为了关联操作逻辑,主要是匹配过滤,将 /deploydeploy-script 关联起来,将 /clearclear-script 关联起来。

下面是根据指定 trigger 关键字 /deploy 进行触发的 workflows.yaml 片段。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
jobs:
  deploy-check:
    runs-on: ubuntu-latest
    steps:
      - name: acknowledge request to commenter
        id: check
        uses: khan/[email protected]
        with:
          trigger: "/deploy"
          reaction: rocket
        env:
          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
    outputs:
      triggered: ${{ steps.check.outputs.triggered }}
  
  deploy-script:
    if: needs.deploy-check.outputs.triggered == 'true'
    runs-on: ubuntu-latest
    needs: deploy-check
    steps:
    - name: script
      run: |
                echo "start"

2. 第二步: 执行自定义指令

这一步主要是执行一些相应的步骤,用来完成对基础设施的修改。比如,更新服务、部署应用、删除文件等,具有很高的自由度。

这里主要是需要部署新的服务,并提供一个对外可访问的地址。如果是静态项目的预览,直接使用 netlify 提供的预览服务更好。但是,更多的项目,还是需要远程到服务器上进行操作。

下面是一个以 root 用户远程到指定服务器,创建并暴露服务的示例。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
    - name: executing remote ssh commands
    id: deploy_console
    uses: appleboy/[email protected]
    with:
        host: ${{ secrets.IP }}
        username: root
        password: ${{ secrets.PASSWORD }}
        port: 22
        script: |
        kubectl run nginx --image=nginx
        kubectl expose deploy nginx --type=NodePort --port=80 --target-port=80        

可以根据具体需要,在 script 中填充自定义的脚本命令。

3. 第三步: 反馈信息

最后就是需要反馈信息,明确表明任务已经完成,并将完成的结果以某种方式告诉给用户。这里主要提供两种方式:评论回复和 Slack 通知。

3.1 评论回复

添加相关的 Job 可以实现回复指定的 Issues/Pull Requests 的功能。同时,在评论的内容中,我们也可以引用内置的变量,让回复内容更加详细,含义传达更加有效。

1
2
3
4
5
6
7
    - name: Create comment
    uses: peter-evans/[email protected]
    with:
        issue-number: ${{ github.event.issue.number }}
        body: |
        Congratulations! Deployment succeeded.
        reactions: heart, hooray, laugh        

3.2 Slack 通知

在之前的文档中,我已经分享过《如何配置 Slack 通知》 ,这里不再赘述。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
    - uses: 8398a7/[email protected]
    with:
        status: custom
        fields: workflow,job,commit,repo,ref,author,took
        custom_payload: |
        {
            username: 'action-slack',
            icon_emoji: ':octocat:',
            attachments: [{
            color: '${{ job.status }}' === 'success' ? 'good' : '${{ job.status }}' === 'failure' ? 'danger' : 'warning',
            text: `Congratulations! Deployment succeeded.`,
            }]
        }        
    env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}

将上面的片段添加到 workflows 即可。

4. 一些 GitHub Actions 的使用技巧

4.1 切换代码到 Pull Requests 所在分支

在一个 Pull Requests 流程中,通常有两个分支,upstream 和 developer 。而 workflows 的 on 针对当前分支,在 upstream 仓库中,不能直接 Checkout 提交 Pull Requests 的 developer 仓库的分支。

下面这段片段,可以将代码切换到待合并的开发者分支上。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
    - name: get pull request ref
      id: get_pull_request_ref
      uses: octokit/[email protected]
      with:
        route: GET /repos/:repository/pulls/:issue_id
        repository: ${{ github.repository }}
        issue_id: ${{ github.event.issue.number }}
      env:
        GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
    - uses: actions/[email protected]
      with:
        repository: ${{ fromJson(steps.get_pull_request_ref.outputs.data).head.repo.full_name }}
        ref: ${{ fromJson(steps.get_pull_request_ref.outputs.data).head.ref }}

4.2 使用 Deployment 维护部署的状态

GitHub 提供了一个名为 Deployment 的对象,用来管理部署的事件和状态。下面是一个时序图:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
+---------+             +--------+            +-----------+        +-------------+
| Tooling |             | GitHub |            | 3rd Party |        | Your Server |
+---------+             +--------+            +-----------+        +-------------+
     |                      |                       |                     |
     |  Create Deployment   |                       |                     |
     |--------------------->|                       |                     |
     |                      |                       |                     |
     |  Deployment Created  |                       |                     |
     |<---------------------|                       |                     |
     |                      |                       |                     |
     |                      |   Deployment Event    |                     |
     |                      |---------------------->|                     |
     |                      |                       |     SSH+Deploys     |
     |                      |                       |-------------------->|
     |                      |                       |                     |
     |                      |   Deployment Status   |                     |
     |                      |<----------------------|                     |
     |                      |                       |                     |
     |                      |                       |   Deploy Completed  |
     |                      |                       |<--------------------|
     |                      |                       |                     |
     |                      |   Deployment Status   |                     |
     |                      |<----------------------|                     |
     |                      |                       |                     |

在页面上的效果如下图:

使用的方法,可以参考文末提供的链接。

我最终没有采用这种方式的原因是,在 Pull Requests 下,upstream 不存在 developer 的 PR 分支时,页面找不到 Deployment。好吧,我知道你没明白,不过没关系,推荐用这种方式管理 Deployment,可以先试试。

4.3 变量的调试方法

在 GitHub Actions 中内置了很多变量,使用第三方 Actions 也会得到很多变量。在调试过程中,如果对变量存在性或值内容存在疑惑,可以直接打印查看。

下面就是一个示例:

1
2
3
    - name: echo
      run: |
                echo ${{ steps.get_pull_request_ref.outputs.data }}

最终打印的部分结果如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "url": "https://api.github.com/repos/***/console/pulls/7",
    "id": 548619025,
    "node_id": "MDExOlB1bGxSZXF1ZXN0NTQ4NjE5MDI1",
    "html_url": "https://github.com/***/console/pull/7",
    "diff_url": "https://github.com/***/console/pull/7.diff",
    "patch_url": "https://github.com/***/console/pull/7.patch",
    "issue_url": "https://api.github.com/repos/***/console/issues/7",
    "number": 7,
    "state": "open",
    "locked": false,
    "title": "Feat/workspace group",
    ...
}

在整个过程中,调试是非常耗时的,我们要掌握一定的方法,才能事半功倍。

4.4 Output 传递 Step 之间的变量

使用 Output 和 Env 都可以实现 Step 之间的变量传递,这里以 Output 为例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
      - name: set SERVICE_PORT
        id: set_port
        run: |
                    echo "::set-output name=SERVICE_PORT::$(sshpass  -p "${{ secrets.QING_PASSWORD }}" ssh -o StrictHostKeyChecking=no [email protected]${{ secrets.EIP }} "kubectl get svc ${{ env.SERVICE_NAME }} -o json | jq .spec.ports[].nodePort")"
      - name: Create comment
        uses: peter-evans/[email protected]
        with:
          issue-number: ${{ github.event.issue.number }}
          body: |
                        Congratulations! Deployment succeeded. This is the [preview link](http://${{ secrets.EIP }}:${{ steps.set_port.outputs.SERVICE_PORT }}/) .
          reactions: heart, hooray, laugh

首先通过执行 sshpass 命令拿到服务的端口,设置为 output 变量。然后,在其他的 Step 中,通过 ${{ steps.set_port.outputs.SERVICE_PORT }} 的方式,引用跨 Step 的变量值。

5. 参考


微信公众号
作者
微信公众号