0%

# gogs使用webhook部署react单页应用

Posted on 2020-02-22 Edited on 2020-02-23 In 持续集成 Views: Disqus:

众所周知，我是个前端彩笔，但是也想做点自己可以用的工具页面，所以就让朋友推荐了蚂蚁出品的 ant design，说基本可以直接 ctrl-c ctrl-v，实测对我这种来说还是有点难的，不过也能写点，但是现在碰到的问题是怎么部署到自己的服务器上去
用 ant design 写的是个单页应用，实际来说就是一个 html 加 css 跟 js，最初的时候是直接 build 完就 scp 上去，也考虑过 rsync 之类的，但是都感觉不够自动化，正好自己还没这方面的经验就想折腾下，因为我自己搭的仓库应用是 gogs，搜了一下主要是跟 drones 配合做 ci/cd，研究了一下发现其实这个事情没必要这么搞(PS：drone 也不好用)，整个 hook 就可以了, 但是实际上呢，这东西也不是那么简单
首先是需要在服务器上装 webhook，这个我一开始用 snap 安装，但是出现问题，run 的时候会出现后面参数带的 hooks.json 文件找不到，然后索性就直接 github 上下最新版，放 /usr/local/bin 了，webhook 的原理呢其实也比较简单，就是起一个 http 服务，通过 post 请求调用，解析下参数，如果跟配置的参数一致，就调用对应的命令或者脚本。

## 配置 hooks.json

webhook 的配置，需要的两个文件，一个是 hooks.json，这个是 webhook 服务的配置文件，像这样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    [
      {
        "id": "redeploy-app",
        "execute-command": "/opt/scripts/redeploy.sh",
        "command-working-directory": "/opt/scripts",
        "pass-arguments-to-command":
        [
          {
            "source": "payload",
            "name": "head_commit.message"
          },
          {
            "source": "payload",
            "name": "pusher.name"
          },
          {
            "source": "payload",
            "name": "head_commit.id"
          }
        ],
        "trigger-rule":
        {
          "and":
          [
            {
              "match":
              {
                "type": "payload-hash-sha1",
                "secret": "your-github-secret",
                "parameter":
                {
                  "source": "header",
                  "name": "X-Hub-Signature"
                }
              }
            },
            {
              "match":
              {
                "type": "value",
                "value": "refs/heads/master",
                "parameter":
                {
                  "source": "payload",
                  "name": "ref"
                }
              }
            }
          ]
        }
      }
    ]

这是个跟 github搭配的示例，首先 id 表示的是这个对应 hook 的识别 id，也可以看到这个 hooks.json 的结构是这样的一个数组，然后就是要执行的命令和命令执行的参数，值得注意的是这个`trigger-rule`,就是请求进来了回去匹配里面的，比如前一个是一个加密的，放在请求头里，第二个 match 表示请求里的 ref 是个 master 分支，就可以区分分支进行不同操作，但是前面的加密配合 gogs 使用的时候有个问题(PS: webhook 的文档是真的烂)，gogs 设置 webhook 的加密是用的

> 密钥文本将被用于计算推送内容的 SHA256 HMAC 哈希值，并设置为 `X-Gogs-Signature` 请求头的值。

这种加密方式，所以 webhook 的这个示例的加密方式不行，但这货的文档里居然没有说明支持哪些加密，神TM，后来还是翻 issue 翻到了, 需要使用这个`payload-hash-sha256`

## 执行脚本 redeploy.sh

脚本类似于这样

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    #!/bin/bash -e

    function cleanup {
          echo "Error occoured"
    }
    trap cleanup ERR

    commit_message=$1 # head_commit.message
    pusher_name=$2 # pusher.name
    commit_id=$3 # head_commit.id

    cd ~/do-react-example-app/
    git pull origin master
    yarn && yarn build

就是简单的拉代码，然后构建下，真实使用时可能不是这样，因为页面会部署在 nginx 的作用目录，还需要 rsync 过去，这部分可能还涉及到两个问题第一个是使用 rsync 还是其他的 cp，不过这个无所谓；第二个是目录权限的问题，以我的系统ubuntu 为例，默认用户是 ubuntu，nginx 部署的目录是 www，所以需要切换用户等操作，一开始是想用在shell 文件中直接写了密码，但是不知道咋传，查了下是类似于这样 `echo "passwd" | sudo -S cmd`，通过管道命令往后传，然后就是这个`-S`, 参数的解释是`-S, --stdin read password from standard input`,但是这样么也不是太安全的赶脚，又看了下还有两种方法，

- 就是给root 设置一个不需要密码的命令类似于这样，

      1
      2
      myusername ALL = (ALL) ALL
      myusername ALL = (root) NOPASSWD: /path/to/my/program

- 另一种就是把默认用户跟 root 设置成同一个 group 的

## 使用

真正实操的时候其实还有不少问题，首先运行 webhook 就碰到了我前面说的，使用 snap 运行的时候会找不到前面的 hooks.json配置文件，执行`snap run webhook -hooks /opt/hooks/hooks.json -verbose`就碰到下面的`couldn't load hooks from file! open /opt/hooks/hooks.json: no such file or directory`，后来直接下了个官方最新的 release，就直接执行 `webhook -hooks /opt/hooks/hooks.json -verbose` 就可以了，然后是前面的示例配置文件里的几个参数，比如`head_commit.message` 其实 gogs 推过来的根本没这玩意，而且都是数组，不知道咋取，烂文档，不过总比搭个 drone 好一点就忍了。补充一点就是在 debug 的时候需要看下问题出在哪，看看脚本有没有执行，所以需要在前面的 json 里加这个参数`"include-command-output-in-response": true`, 就能输出来脚本执行结果

请我喝杯咖啡

WeChat Pay

Alipay

- Post author: Nicksxs
- Post link: https://nicksxs.me/2020/02/22/gogs使用webhook部署react单页应用/
- Copyright Notice: All articles in this blog are licensed under BY-NC-SA unless stating additionally.