众所周知,Git在多人协作方面是一个非常便捷的选择(其他同类工具也有Google Doc,腾讯文档等,以上工具的优势在于Word形式的所见即所得编辑,但是对于版本管理,以及其他文件格式的支持则没有那么好了)。因此,聚聚@taroxd在自己负责的一个小说翻译中,使用了Git来与其他翻译人员进行协作(项目地址)。大概是出于排版方便的目的,他使用tex进行文档的编写,也因此带来了生成pdf的需求。他目前的解决方案是,在自己部署好的本地环境下,使用cmd脚本进行生成与push操作。不过,手动进行生成的时效性相对没有那么高,也并不是所有参与者都有tex相关的一整套环境,能够发现其中的一些语法错误。本文尝试通过Appveyor 的 CI 功能,对生成tex的流程进行自动化处理,解决以上问题,提高在发布方面的便捷性。

Gitlab CI 相关

之前工作上主要使用的是私有服务器上搭建的 Gitlab CI 来进行相关的自动化流程,于是也简单介绍一下。以我的理解,Gitlab CI 框架的主要特点是流水线,以及可以通过映像来对运行环境进行预先配置。以下是一个 .gitlab-ci.yml 文件的例子: 上面的文件中,通过 image 指定了下面所有的过程都会基于 maven:latest 镜像的环境下运行,也就不需要额外的配置操作了。其余的代码则定义了三个任务,这三个任务分别属于 build,test,和 deploy 环节,以上面 stages 中定义的顺序进行运行。每一个任务可以拥有其自己特殊的配置,如 deploy 任务中定义的 only ,意味着仅在 master 分支上进行这个任务。利用不同的任务,可以清晰地将不同流程区分开来,在 CI 界面上,也能更好地区分是哪一部分出现了问题。 如果使用 GitLab CI 进行自动部署,我们可以预先将所有环境在 Dockerfile 中配置妥当,仅在 CI 脚本中进行编译操作,使编译/部署操作得以快速完成。然而,对应于 Github 的 GitLab CI 服务仅在2019年9月之前免费,于是只能另寻其他的 CI 服务。

在Appveyor上配置CI

之前与@Genteure的讨论中了解到了这个平台。其优势主要在于可以选择Windows作为运行/测试的环境,对于.Net相关流程的支持也相对更好。出于熟悉的目的,选择了这个平台进行部署。最终的代码如下
appveyor.yml
build_pdf.sh
Appveyor并不允许用户将一个 docker image 设置为基础镜像,但是它提供的运行时环境中,已经预装了许多常用的开发运行时,可以按照具体的需求切换到相应的版本。自动生成 epub 的脚本有 Ruby 2.3.0+ 的需求,于是上面通过 rvm 进行相关的版本切换。 与GitLab不同,Appveyor固定使用 build_script, deploy_script 来描述不同阶段的行为,但是可以使用 for 语句内带条件的配置信息对默认的设置进行补充/覆盖。上面的配置中即是在当前分支为 master 时额外执行 deploy 脚本。 为了生成pdf文件,我们需要预先安装好一整套的 tex 环境。从 luatexja 的文档中了解到,它可以在 Tex Live 2018 以上版本中,使用 tlmgr 可以直接安装。也就是说,只要配置好了 Tex Live 2018,其实就可以生成这个文档了。说到环境,自然又想到了 Docker。虽然不能设置 Docker Image 为测试环境,但是Appveyor的系统内是提供的 Docker 的,于是可以借助现成的 Tex Live 2018 环境镜像了。上面的脚本将工作目录映射到容器中,然后在容器里调用 build_pdf.sh 进行剩余的操作。 在生成完相关的文件后,需要把那些文件上传到原repo的gh-pages分支上。Github 提供了 Personal Access Token (后称PAT)的机制用于这些自动化脚本的操作,利用 PAT 可以方便的控制每个 Token 的权限范围,并可以随时吊销,保证账户的安全。不过因为appveyor.yml文件是公开的,这是不是意味着 PAT 会不可避免的公开呢?答案是否定的。在Appveyor中,可以对一些环境变量进行加密。yml 文件中实际存放着的是加密后的 Token,密钥由平台进行保管。当进入 CI 流程时,再由平台对这个密钥进行解密,内部得以访问到正确的 Token。
通过以上的配置,当自己向 master 分支提交新的变更时,这些变更就会实时通过 CI 反映到pdf上了。不过因为使用的 Tex Live 2018 镜像大小有3.7G,而每次 CI 都要重新进行下载,实测一次 pdf 生成过程需要耗费7分钟左右的时间,可能需要通过 Git Hook 连接到自有的服务器进行生成,才能获得更好的效果了。希望Appveyor之后能提供一些编译环境的缓存机制,避免一下这方面的消耗吧。 注1:taroxd最后拒绝了这次Pull Request 注2:我的脑子已经变成Gitlab的形状啦….