LaTeX 文書のコンパイルを GitHub Actions で自動化する
はじめに
latexmk で組版の繰り返しを自動化し、TeX Live 入りコンテナと Makefile で環境を固定して手元でコンパイルできるようにすると、あと一歩で「push したら勝手にビルドされ、PDF が落ちてくる」状態にできます。
この記事では、その組版を GitHub Actions に載せます。ローカルで使っているのと同じ TeX Live イメージを CI 上でも使うので、「手元で通れば CI でも通る」が保てます。
最小のワークフロー
.github/workflows/latex.yml を置きます。container: にローカルと同じイメージを指定すると、ジョブの各ステップがそのコンテナの中で実行されます。TeX Live と latexmk はイメージに入っているので、追加インストールは要りません。
name: build-pdf
on:
push:
paths: ['**.tex', '**.bib', '.latexmkrc', '.github/workflows/latex.yml']
pull_request:
paths: ['**.tex', '**.bib', '.latexmkrc']
# 同じ ref で新しい push があったら古い実行は打ち切る
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
container: texlive/texlive:TL2024 # ローカルと同じタグに揃える
steps:
- uses: actions/checkout@v4
- name: Compile
run: latexmk main.tex
- name: Upload PDF
uses: actions/upload-artifact@v4
with:
name: main-pdf
path: main.pdf
# 失敗時はログも持ち帰れるようにしておく
- name: Upload log on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: latex-log
path: '*.log'
texlive/texlive イメージは git を含むため、actions/checkout はコンテナ内でもそのまま動きます。paths: フィルタで、原稿に関係ないコミットではワークフローを起こさないようにしています。
Makefile を再利用する
TeX Live 入りコンテナの Makefile は「docker run でコンテナを起動し、その中で latexmk を呼ぶ」構造でした。GitHub Actions ではジョブ自体がすでにコンテナ内なので、docker run の層は不要です。build ターゲットの中身が latexmk $(DOC).tex だけなら、CI からは次のように直接呼べます。
- name: Compile
run: make build # 中身は latexmk main.tex
コンテナ起動の有無だけが違い、組版コマンドとその設定(.latexmkrc)はローカルと CI で完全に同一になります。「ローカルは make、CI はイメージ直実行、コマンドは共通」という形が、そのまま GitHub Actions にも当てはまります。
生成物の受け取り方
用途に応じて 3 通りあります。
1. Artifact として毎回受け取る
上の例のとおり actions/upload-artifact を使います。実行結果ページからダウンロードできます。保持期間は既定 90 日で、retention-days: で短くできます。レビュー用の一時的な PDF はこれで十分です。
2. Pull Request にコメントで知らせる
PR のたびにビルドが通ったこと(と Artifact へのリンク)をコメントしておくと、レビュアーが迷いません。
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body: `PDF をビルドしました → 実行ページの Artifacts からダウンロードできます。`
})
3. タグを打ったら Release に添付する
版として確定した PDF を配布したいときは、タグ push をトリガーに Release へ添付します。
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
container: texlive/texlive:TL2024
permissions:
contents: write # Release 作成に必要
steps:
- uses: actions/checkout@v4
- run: latexmk main.tex
- uses: softprops/action-gh-release@v2
with:
files: main.pdf
Pull Request で差分を見る
原稿レビューでは「どこが変わったか」が PDF 上で見えると効率的です。latexdiff で旧版との差分文書を作り、その PDF も一緒に上げておきます。
- name: Build diff against base branch
if: github.event_name == 'pull_request'
run: |
git config --global --add safe.directory "$GITHUB_WORKSPACE"
git fetch origin "${{ github.base_ref }}" --depth=1
git show "origin/${{ github.base_ref }}:main.tex" > base.tex
latexdiff base.tex main.tex > diff.tex
latexmk diff.tex
- name: Upload diff PDF
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: diff-pdf
path: diff.pdf
safe.directory の指定は、コンテナ内の利用者とチェックアウト先の所有者がずれて git がリポジトリを拒否するのを避けるためです。
ビルドを速く・安定させる
- イメージのタグを固定する:
latestではなくTL2024のように年号で固定すると、TeX Live の更新でビルドが急に変わることがなくなります。ローカルの Dockerfile と同じタグに揃えるのが要点です。 tlmgr installを CI でやらない:必要なパッケージは Dockerfile の段階でイメージ側に入れておき、CI では入れない。実行ごとのネットワーク待ちが消えます。latexmkに任せる:組版回数の判断は latexmk がやるので、ワークフロー側でlatexを複数回呼ぶような記述は不要です。-interaction=nonstopmodeを.latexmkrcに入れておく:エラーで対話待ちになり CI がハングするのを防ぎます(latexmk の記事の設定例に含めてあります)。
なお、イメージを用意せず手軽に済ませたい場合は xu-cheng/latex-action のような専用アクションもありますが、やっていることは「TeX Live 環境で latexmk を回す」で同じです。ローカルとイメージを共有したいなら container: 方式が素直です。
関連記事
- latexmk — CI で 1 コマンドに任せる組版の反復
- TeX Live 入りコンテナと Makefile — CI と共有するイメージと
.latexmkrc - Docker の基本 —
container:に指定するイメージのしくみ - Git と GitHub の基本 — push・PR という契機のもとになる考え方
まとめ
- ローカルで使っている TeX Live イメージを
container:に指定すれば、GitHub Actions でも同じ環境で組版できる。 - CI ではコンテナ起動が不要なので、
latexmk(またはmake build)を直接呼ぶだけ。設定は.latexmkrcに集約してローカルと共有する。 - 成果物は Artifact/PR コメント/Release 添付から用途に合わせて選ぶ。
latexdiffを挟めば PR で変更箇所を PDF で確認できる。
「latexmk で繰り返しを自動化 → コンテナで環境を固定 → GitHub Actions で契機を自動化」と重ねると、原稿を push するだけで最新の PDF が手に入る状態になります。