# CI/CD for a print artifact: one principle, two projects

Why run GitHub Actions CI/CD pipelines for PDF print artifacts? Building press-ready PDFs locally relies on developer workstation state: different TeX Live releases alter line hyphenation, paragraph breaking, and page counts.

Enters continuous integration for print. Running pinned TeX Live containers inside GitHub Actions runners produces deterministic press-ready PDFs on every commit.

<figure>
  ![An exhausted typesetter sits at a workbench surrounded by thousands of identical printed copies, with a tiny typo circled in an open book. The vast stacks of copies emphasize the cost of discovering an error after printing.](https://redaction-technique.org/images/blog/cicd-for-print-artifacts-manual-correction.webp)
  <figcaption>Without CI/CD, a tiny typo can mean an expensive reprint of thousands of copies.</figcaption>
</figure>

## Environment variability hazards

Local build environments introduce silent compilation drift:

- **TeX Live version discrepancies:** Differing package versions shift hyphenation matrices across machines.
- **Font metric shifts:** Local font updates alter character widths and paragraph pagination.
- **Unverified local builds:** Relying on contributor workstation builds risks sending unverified binaries to print shops.

Continuous integration solves environment drift by compiling source files inside isolated, pinned Linux containers.

## Multi-author book builds

A three-volume book project compiles PDF output on every commit to `main`:

```mermaid
flowchart TB
    ed1["Editor 1"]
    ed2["Editor 2"]
    ed3["Contributor"]
    git["Git<br/>commit · push"]
    github["GitHub<br/>branch: main"]
    ci["GitHub Actions<br/>Ubuntu AMD64 · TeX Live 2023"]
    tools["LuaLaTeX ×3<br/>makeglossaries · pdfjam"]
    pdf(["PDF files<br/>Volume I · printer's copy · flatplan"])

    ed1 --> git
    ed2 --> git
    ed3 --> git
    git --> github
    github --> ci
    ci --> pdf
    ci -.-> tools
    tools -.-> pdf
  classDef source fill:#f8fafc,stroke:#94a3b8,stroke-width:1.5px,color:#334155,rx:6,ry:6;
  classDef step fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e40af,font-weight:bold,rx:6,ry:6;
  classDef accent fill:#eef2ff,stroke:#6366f1,stroke-width:2px,color:#3730a3,font-weight:bold,rx:6,ry:6;
  classDef warn fill:#fffbeb,stroke:#f59e0b,stroke-width:1.5px,color:#92400e,rx:6,ry:6;
  classDef good fill:#f0fdf4,stroke:#22c55e,stroke-width:1.75px,color:#166534,font-weight:bold,rx:6,ry:6;
  class ed1,ed2,ed3 source;
  class git,github,ci step;
  class tools accent;
  class pdf good;
  linkStyle default stroke:#64748b,stroke-width:1.75px;
```

Pinning the pipeline to TeX Live 2023 locks layout rendering rules across years of maintenance edits.

## Automated poster publication

An annual planning poster pipeline builds six distinct PDF/X-4 variants from a single YAML data edit:

1. **YAML pull request:** Non-technical contributors edit `planning/events-*.yaml` via GitHub web interfaces.
2. **Automated semantic diff comments:** On every pull request affecting `planning/`, the CI workflow executes `diff_saison.py` and posts a sticky comment comparing dates, prices, and events between seasons so reviewers inspect business changes rather than raw syntax diffs.
3. **Automated CMYK conversion:** `prepare_images.py` converts embedded sRGB images to FOGRA39 CMYK.
4. **Preflight verification:** `preflight.py` verifies resolution, font embedding, and PDF/X-4 conformance.

```mermaid
flowchart TB
    yaml["events.yaml edit<br/>on GitHub.com"]
    pr["Pull Request"]
    diff["CI diff job<br/>comment: changed dates · prices · events"]
    merge["Merge"]
    build["GitHub Actions<br/>Ubuntu AMD64 · TeX Live 2023<br/>Python 3.x · FOGRA39 ICC"]
    artifacts(["6 × PDF/X-4<br/>FR · EN · ES<br/>current + upcoming season"])

    yaml --> pr
    pr --> diff
    diff --> merge
    merge --> build
    build --> artifacts
  classDef source fill:#f8fafc,stroke:#94a3b8,stroke-width:1.5px,color:#334155,rx:6,ry:6;
  classDef step fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e40af,font-weight:bold,rx:6,ry:6;
  classDef accent fill:#eef2ff,stroke:#6366f1,stroke-width:2px,color:#3730a3,font-weight:bold,rx:6,ry:6;
  classDef warn fill:#fffbeb,stroke:#f59e0b,stroke-width:1.5px,color:#92400e,rx:6,ry:6;
  classDef good fill:#f0fdf4,stroke:#22c55e,stroke-width:1.75px,color:#166534,font-weight:bold,rx:6,ry:6;
  class yaml source;
  class pr,merge step;
  class diff,build accent;
  class artifacts good;
  linkStyle default stroke:#64748b,stroke-width:1.75px;
```

## Provenance and traceability

Both build architectures embed compilation metadata directly inside generated deliverables. Book colophons record Git commit hashes, hostnames, and LuaTeX engine versions. PDF/X-4 files embed XMP build metadata for press auditing.

Running build environments in CI replaces workstation guesswork with deterministic compilation guarantees. The next step is publishing containerized Docker build images to Docker Hub for identical offline local reproduction.

## External sources

- [GitHub Actions: the CI used](https://docs.github.com/en/actions)
- [Continuous integration / delivery concepts](https://en.wikipedia.org/wiki/CI/CD)
- [Pinned TeX Live as the canonical environment](https://tug.org/texlive/)

<small>*Hero image: ["The Binding Machine"](https://www.flickr.com/photos/mstharpe/4079657793) by [Ms. Tharpe](https://www.flickr.com/photos/mstharpe/), licensed under [CC BY 2.0](https://creativecommons.org/licenses/by/2.0/).*</small>

---

Source: https://redaction-technique.org/blog/cicd-for-print-artifacts
