CI/CD 平台迁移实践：从 Travis-CI 转移到 Github Action
自 2019 年 Github 推出了自家的 CI 工具 Github Action 后，我们就在考虑将 CI 从 Travis-CI 迁移到 Github，以降低维护和沟通的成本，并借助于 GitHub Action Marketplace 实现更强的功能。
GitHub CI
自 2019 年 Github 推出了自家的 CI 工具 Github Action 后，我们就在考虑将 CI 从 Travis-CI 迁移到 Github，以降低维护和沟通的成本，并借助于 GitHub Action Marketplace 实现更强的功能。
![](/data/attachment/album/202101/16/182851z3lmlblslo8vw984.jpg)


[LCTT](https://linux.cn/lctt/) 的 CI 已经在 Travis CI 上运转了多年，一致保持着良好的使用体验。自 2019 年 Github 推出了自家的 CI 工具 Github Action 后，我们就在考虑将 CI 从 Travis-CI 迁移到 Github，以降低维护和沟通的成本，并借助于 [GitHub Action Marketplace](https://github.com/marketplace?type=actions) 实现更强的功能。


![项目首页](/data/attachment/album/202101/16/181855t9bbgqoxgtule29z.jpg)


最近，因为 TravisCI 屡屡部署出错，而我们的账户因为使用的较多，已经超出了免费使用的限制，以此为契机，将 CI 从 Travis CI 迁移到 GitHub Action。


![Travis CI 的提醒](/data/attachment/album/202101/16/181856amnmv3df61f1d1ms.png)


### 项目介绍


[Translate Project](https://github.com/LCTT/TranslateProject) 是 [LCTT](https://linux.cn/lctt/) 翻译组的主要协作项目，几百位译者通过 GitHub 进行围绕开源、Linux、软件工程等领域的文章翻译，从 2013 年来，累计了大量的提交，致使项目下有非常多的文件。


[Translate Project](https://github.com/LCTT/TranslateProject) 借助于 CI 帮助译者对基本的文章格式和拉取请求进行检查；并定时执行命令，以进行所有的申请检查，对于超时未完成翻译的工作进行回收；对于文章的状态进行标记，生成相应的徽章。


![生成徽章](/data/attachment/album/202101/16/181856wi9n2nwe1phf22ae.png)


### 迁移思路


Travis CI 和 Github Action 在使用方面，其实总体差异不会太大，都是基于 YAML 文件格式来编写配置文件。不过，和 Travis CI 不同的是，Github Action 支持多个不同的配置文件，因此，你可以根据不同的场景，设定不同的配置文件，降低单个配置的文件的复杂度。


此外，由于我们的脚本中依赖了一些 Travis CI 的环境变量，也需要将其替换为 Github Action 中的相应环境变量，从而确保脚本可以运转。


### 改造实践


#### 1. 分析之前的 CI 流程


我们在 TravisCI 上的 CI 配置文件如图：


![配置文件](/data/attachment/album/202101/16/181856riwfwikwmbcszsfh.png)


总体可以分为三块：


1. 命令区：说明了安装阶段和执行阶段的操作有哪些
2. 条件区：指定了这个配置文件在哪些条件下会生效
3. 部署区：写明了构建产物如何进行部署


在命令区中，有预置的安装过程和后续的执行过程。在安装过程中，安装了一些依赖，并将当前的 pages 资源克隆到本地，以继承上一次构建生成的资料。


在条件区则指明了仅作用于 `master` 分支。


在部署区便是将前面命令区的执行结果进行部署。


![基本流程](/data/attachment/album/202101/16/181859hoijinipsnipilgv.png)


在实际的执行过程中，还会根据环境变量不同，决定是否要执行特定的命令，这部分在后续的改造过程中，就可以调整部署，拆分到不同的文件中。


![构建流程](/data/attachment/album/202101/16/181901kh6vm6mhwnevk6ii.png)


#### 2. 直接套用配置文件


在完成了基本的分析后，就可以建立新的 Action 配置文件了。由于基本的语法很类似，对于其中的不少内容可以进行直接套用。


比如，我们的配置文件在直接套用后，结果如下


![直接套用后的结果](/data/attachment/album/202101/16/181902vcgycyhqpc7fddfz.png)


直接套用的文件已经可以直接运行，不过，这里有很多不满足需要的地方，所以需要做一些修改。


#### 3. 恢复 Travis CI 的环境变量


由于我们使用的 Badge 等生成脚本并非我所编写，所以在这一次的迁移中，并不打算对齐进行调整，以避免出现故障。而脚本中依赖了一些变量，需要将其重新设置出来。


Github Action 提供了一些方法，可以让你手动设置环境变量。你可以在你的构建的步骤中，加入如下代码，从而在构建环境中设定 `TRAVIS_BRANCH` 和 `TRAVIS_EVENT_TYPE` 环境变量，确保你可以使用这个环境变量。



```
 - name: Set ENV variables
        run: |
 echo "::set-env name=TRAVIS\_BRANCH::${TRAVIS\_BRANCH:-$(echo $GITHUB\_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')}" 
 echo "::set-env name=TRAVIS\_EVENT\_TYPE::$(if [ "schedule" == "${{ github.event\_name }}" ]; then echo "cron"; else echo "${{ github.event\_name }}"; fi)"

```

此外，由于 `set-env` 这个方法相对比较危险，你还需要在环境变量中，开启危险函数的执行。



```
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      ACTIONS\_ALLOW\_UNSECURE\_COMMANDS: true

```

#### 4. 拆分配置文件


Github Action 和 TravisCI 不同的一点是你可以将你的 CI 文件拆分成多个文件，从而降低每一个单独的配置文件的复杂度。


根据前面对于流程的分析，可以将我们的 CI 流程拆分成三个部分：


1. 生成 `badge` 文件，应当跟随每一次提交进行
2. 生成 `status` 文件，执行时间较长，可以定期执行
3. 根据拉取请求内容进行整理，做核验


则将我们的配置文件拆分成三个不同的文件：


![](/data/attachment/album/202101/16/181903yayyafv1gyy1v16p.png)


也得益于拆分开，则在 `checker` 中就可以免于安装一些必要的依赖，从而精简 CI 流程，提升 CI 的执行时间。


#### 5. 测试 CI 的运行情况


在完成了配置文件的编写和拆分后，就可以进行本地的执行测试。Github Action 写完了，难免要执行一下，确保整个流程是正常的。


这个时候你可以安装工具（[https://github.com/nektos/act），来在本地执行](https://github.com/nektos/act%EF%BC%89%EF%BC%8C%E6%9D%A5%E5%9C%A8%E6%9C%AC%E5%9C%B0%E6%89%A7%E8%A1%8C) Action ，从而确认你的代码执行是正确的。


![](/data/attachment/album/202101/16/181904kih8dxd9pjqvefhp.jpg)


如果你是 macOS ，只需要执行 `brew install act` 就可以安装 `act` 工具，来完成 `act` 的安装。


安装完成 `act` ，就可以通过执行 `act` 命令来在本地执行 Action ，比如，执行 `act pull_request` 来触发 GitHub 的拉取请求事件


![](/data/attachment/album/202101/16/181904flauoh79vo1v491o.png)


通过本地测试后，再将你的配置文件推送到 GitHub 上，进行生产环境的测试即可。


### 6. 移除 Travis-CI


通过上述的一些步骤，我们完成了从 Travis CI 到 GitHub Action 的迁移，此时，就可以移除项目根目录中的 `.travis.yml` 文件，彻底关闭 Travis CI。


### 7. 替换环境变量


在完成了基本的迁移后，需要对代码中的一些历史问题进行修复。在第三步中，我们对于 Travis-CI 的环境变量进行替换，但长期维护的项目应当尽量将这些未标注上下文的信息替换为有文档标注的，因此，我们需要将其替换。


替换环境变量主要依赖 Github 官方的环境变量说明，你可以参考[官方文档](https://docs.github.com/cn/actions/reference/environment-variables)。


简化后，配置文件从之前的 27 行，减少至 17 行，变得更加的精简、易懂。



```
name: LCTT Article Checker

on:
  pull_request:
    branches: [master]
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      PULL_REQUEST_ID: ${{ github.event.number }}
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0
      - name: "checkout master branch & return to pull request branch"
        run: CURRENT=$(echo ${{github.ref}} |  sed "s|refs/|refs/remotes/|") && git checkout master && git checkout $CURRENT
      - name: run check
        run: sh ./scripts/check.sh;

```

### 8. 修改 GitHub 的分支保护条件


为了确保修改符合标准，我们限制了新的拉取请求必须通过 CI 检查，才能合并进入 `master` 分支，因此，也需要修改相应的分支保护规则，确保设定相应的保护。


![](/data/attachment/album/202101/16/181904ryccly9ro969wr19.png)


### 一些注意事项


#### 1. 环境变量不同


如果你依赖了环境变量，则需要进行相应的修改。或者可以像我一样，先通过 `set-env` 来让本地拥有临时的环境变量，后续再逐步进行迁移。


#### 2. Action 运行依赖要注意安全


Action 执行过程中会有两个部分。Action 本身流程依赖于 `master` 分支，但执行过程中调用的脚本是根据源决定的，因此，从安全角度来看，你应当尽可能将所有的流程放在 Action 中，而不是放在你的源码目录中。


#### 3. 如何触发 CI 的拉取请求检查？


在进行拉取请求测试的时候，需要不断触发不同的提交 ，你可以通过执行 `git commit --allow-empty -m "Trigger notification" && git push` 来触发一个空白的提交， 推送到 Github 后，就可以再次触发拉取请求的构建，提升构建的效率。


### 总结


通过对 TravisCI 的流程整理、代码修改等流程，我们将之前的 Travis-CI 迁移至速度更快、性能更好的 GitHub Action ，一方面可以优化我们的工作流，另一方面，也让我们的代码更加简洁明了。


对于还在使用 Travis CI 的项目来说，也可以考虑迁移到 GitHub Action 中，来优化自己的工作流。


### 参考阅读


* <https://mauricius.dev/run-and-debug-github-actions-locally/>
* <https://jeffrafter.com/working-with-github-actions/>
* <https://developer.okta.com/blog/2020/05/18/travis-ci-to-github-actions>
