Files
liqiang b119135836
Build latest book artifacts / build (push) Canceled after 0s
dependency resolution / resolve (3.11) (push) Canceled after 0s
dependency resolution / resolve (3.13) (push) Canceled after 0s
deploy-pages / build (push) Canceled after 0s
deploy-pages / deploy (push) Canceled after 0s
i18n consistency check / check (push) Canceled after 0s
provider adoption tests / test (chapter2/context-compression) (push) Canceled after 0s
provider adoption tests / test (chapter2/prompt-injection) (push) Canceled after 0s
provider adoption tests / test (chapter2/system-hint) (push) Canceled after 0s
provider adoption tests / test (chapter3/log-sanitization) (push) Canceled after 0s
web-search-agent tests / test (push) Canceled after 0s
web-search-agent tests / agentbook (push) Canceled after 0s
ai-agent-book 精选快照(<2MB 代码与文档,来自 github.com/bojieli/ai-agent-book)
2026-08-20 13:12:50 +00:00

289 lines
13 KiB
YAML

name: Build latest book artifacts
# Rebuilds the PDF and EPUB editions whenever the book sources change and
# uploads them to the rolling "latest" pre-release (assets are overwritten in
# place, so the download URLs stay stable). Versioned releases (v1.2, ...) are
# still cut manually at milestones.
on:
push:
branches: [main]
paths:
- 'book/**'
- 'book-zhtw/**'
- 'book-en/**'
- 'book-es/**'
- 'book-id/**'
- 'book-ru/**'
- 'book-ta/**'
- 'book-vi/**'
- 'book-ja/**'
- 'book-ko/**'
- 'book-ar/**'
- 'book-tr/**'
- 'book-hu/**'
- 'book-he/**'
- 'build_epub.sh'
- 'epub.css'
- 'epub_external_links.lua'
- 'flatten_epub_toc.py'
- '.github/workflows/build-latest.yml'
- '.github/scripts/**'
workflow_dispatch:
inputs:
edition:
description: Edition to verify on a non-main ref
required: true
default: all
type: choice
options:
- all
- zh-CN
- zh-TW
- en
- es
- id
- ru
- ta
- vi
- tr
- ko
- hu
- ja
- ar
- he
permissions:
contents: write
concurrency:
# Serialize runs for the same ref without allowing a newer push to cancel
# a long-running build that is already in progress.
group: build-latest-${{ github.ref }}
cancel-in-progress: false
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v5
# ── Build-environment caching ──────────────────────────────────────────
# GitHub-hosted runners are ephemeral, so the ~10 min of tool/font
# installs re-runs on every push. The two heavy pieces — the MacTeX tree
# (~5 min) and the document fonts (~2 min) — are cached across runs and
# only reinstalled on a cache miss.
#
# Bump the trailing "-vN" in a cache key whenever you change what that
# cache holds (the mactex package, or the font cask list / Apple-font
# script) so the next run rebuilds it instead of restoring a stale tree.
# Homebrew cask fonts AND the Apple PingFang download all land in
# ~/Library/Fonts, so one user-writable directory captures every font.
- name: Restore fonts cache
id: fonts-cache
uses: actions/cache@v4
with:
path: ~/Library/Fonts
key: fonts-${{ runner.os }}-${{ runner.arch }}-v4-${{ hashFiles('.github/scripts/install_apple_fonts.sh') }}
# The MacTeX tree is installed by a root pkg into /usr/local/texlive, so it
# can't be extracted straight back as the runner user. Cache a tarball
# instead (a user-owned file actions/cache can read) and restore it with
# sudo. /Library/TeX holds the texbin symlinks and is tarred alongside.
- name: Restore TeX Live cache
id: texlive-cache
uses: actions/cache@v4
with:
path: ~/texlive-cache/texlive.tar
key: texlive-${{ runner.os }}-${{ runner.arch }}-mactex-nogui-v1
- name: Install CLI tools
env:
HOMEBREW_NO_AUTO_UPDATE: '1'
HOMEBREW_NO_INSTALL_CLEANUP: '1'
run: brew install pandoc poppler librsvg epubcheck
- name: Install MacTeX (cache miss)
if: steps.texlive-cache.outputs.cache-hit != 'true'
env:
HOMEBREW_NO_AUTO_UPDATE: '1'
HOMEBREW_NO_INSTALL_CLEANUP: '1'
run: |
brew install --cask mactex-no-gui
mkdir -p ~/texlive-cache
sudo tar -cf ~/texlive-cache/texlive.tar -C / usr/local/texlive Library/TeX
sudo chown "$USER" ~/texlive-cache/texlive.tar
- name: Restore MacTeX from cache (cache hit)
if: steps.texlive-cache.outputs.cache-hit == 'true'
run: sudo tar -xf ~/texlive-cache/texlive.tar -C /
- name: Put TeX on PATH
run: echo "/Library/TeX/texbin" >> "$GITHUB_PATH"
# PingFang is an on-demand font since macOS Sequoia and is absent on fresh
# runners (only an unusable reserved UI copy exists); without it
# rsvg-convert renders Chinese figure text in a fallback font (Japanese
# glyph variants). The Apple-font script fetches the real font from Apple's
# asset CDN. Arabic and Korean fonts are required by release builds; the
# Japanese Noto fonts (WIP ja build) remain non-fatal so a bad cask name
# can never break the release build for the other languages.
- name: Install fonts (cache miss)
if: steps.fonts-cache.outputs.cache-hit != 'true'
env:
HOMEBREW_NO_AUTO_UPDATE: '1'
HOMEBREW_NO_INSTALL_CLEANUP: '1'
run: |
brew install --cask font-dejavu font-noto-sans-cjk-sc font-noto-sans-cjk-tc font-noto-serif-tamil font-amiri font-noto-naskh-arabic font-noto-sans-arabic
brew install --cask font-noto-sans-cjk-jp || true
brew install --cask font-noto-serif-cjk-jp || brew install --cask font-noto-serif-cjk || true
brew install --cask font-noto-sans-cjk-kr
brew install --cask font-noto-serif-cjk-kr || brew install --cask font-noto-serif-cjk
bash .github/scripts/install_apple_fonts.sh
# Refresh fontconfig on every run (the cache restore doesn't touch it).
# PANGOCAIRO_BACKEND=fontconfig at build time: pango's CoreText backend on
# the runners can't use the user-installed fonts and silently substitutes
# another CJK font in SVG figures; the fontconfig backend picks them up.
- name: Refresh font cache
run: fc-cache -f
# Each language is built in its own background job so the XeLaTeX
# passes run concurrently instead of back-to-back. Output is captured per
# language and printed after all jobs finish (interleaved live logs would
# be unreadable). The ja build (WIP) runs in the same batch but is
# non-fatal — only a main-language failure fails the step.
# macOS runners ship bash 3.2, so no associative arrays: pid↔dir pairing
# is carried in a "pid:dir" string list.
- name: Build PDFs
env:
PANGOCAIRO_BACKEND: fontconfig
EDITION: ${{ inputs.edition || 'all' }}
run: |
set -u
if [ "$GITHUB_REF" = "refs/heads/main" ] || [ "$EDITION" = "all" ]; then
main="book book-zhtw book-en book-es book-id book-ru book-vi book-ta book-ar book-tr book-ko book-hu book-he"
optional="book-ja"
else
# workflow_dispatch on a feature branch is a focused edition
# verification run. Release publication remains gated to main.
case "$EDITION" in
zh-CN) main="book" ;;
zh-TW) main="book-zhtw" ;;
en) main="book-en" ;;
es) main="book-es" ;;
id) main="book-id" ;;
ru) main="book-ru" ;;
ta) main="book-ta" ;;
vi) main="book-vi" ;;
tr) main="book-tr" ;;
ko) main="book-ko" ;;
hu) main="book-hu" ;;
ja) main="book-ja" ;;
ar) main="book-ar" ;;
he) main="book-he" ;;
*) echo "::error::Unsupported edition: $EDITION"; exit 2 ;;
esac
optional=""
fi
pids=""
for dir in $main $optional; do
( cd "$dir" && bash build_pdf.sh ) > "build_${dir}.log" 2>&1 &
pids="$pids $!:$dir"
done
fail=0
for pd in $pids; do
pid="${pd%%:*}"; dir="${pd##*:}"
if wait "$pid"; then
echo "OK: $dir"
elif [ "$dir" = "book-ja" ]; then
echo "::warning::$dir PDF build failed (WIP, non-fatal)"
else
echo "::error::PDF build failed for $dir"
fail=1
fi
done
for dir in $main $optional; do
echo "===================== $dir ====================="
cat "build_${dir}.log" 2>/dev/null || true
done
exit $fail
- name: Verify Chinese figure fonts
if: github.ref == 'refs/heads/main'
run: |
python3 .github/scripts/verify_pdf_fonts.py \
"book/深入理解-AI-Agent-李博杰-v2.0.pdf" \
"book-zhtw/深入理解-AI-Agent-李博杰-v2.0-zhtw.pdf"
- name: Build EPUBs
env:
EDITION: ${{ inputs.edition || 'all' }}
run: |
if [ "$GITHUB_REF" = "refs/heads/main" ] || [ "$EDITION" = "all" ]; then
./build_epub.sh all
else
./build_epub.sh "$EDITION"
fi
# WIP: ja EPUB depends on the ja PDF above; non-fatal, not part of `all`.
- name: Build Japanese EPUB (WIP, non-fatal)
if: github.ref == 'refs/heads/main'
continue-on-error: true
run: ./build_epub.sh ja
- name: Build Arabic EPUB (WIP, non-fatal)
if: github.ref == 'refs/heads/main'
continue-on-error: true
run: ./build_epub.sh ar
- name: Upload verification artifacts
if: github.repository != 'bojieli/ai-agent-book' || github.ref != 'refs/heads/main'
uses: actions/upload-artifact@v4
with:
name: book-verification-${{ inputs.edition || 'all' }}
path: |
book*/*.pdf
book*/*.epub
if-no-files-found: error
- name: Upload to the rolling latest release
if: github.repository == 'bojieli/ai-agent-book' && github.ref == 'refs/heads/main'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
out="$(mktemp -d)"
cp "book/深入理解-AI-Agent-李博杰-v2.0.pdf" "$out/AI-Agents-in-Depth-zh-CN.pdf"
cp "book-zhtw/深入理解-AI-Agent-李博杰-v2.0-zhtw.pdf" "$out/AI-Agents-in-Depth-zh-TW.pdf"
cp book-en/AI-Agents-in-Depth-Bojie-Li-v2.0.pdf "$out/AI-Agents-in-Depth-en.pdf"
cp book-es/AI-Agents-en-Profundidad-Bojie-Li-v2.0-es.pdf "$out/AI-Agents-in-Depth-es.pdf"
cp book-id/AI-Agents-in-Depth-Bojie-Li-v2.0-id.pdf "$out/AI-Agents-in-Depth-id.pdf"
cp book-ru/AI-Agents-in-Depth-v2.0-ru.pdf "$out/AI-Agents-in-Depth-ru.pdf"
cp book-ta/AI-Agents-in-Depth-Bojie-Li-v2.0-ta.pdf "$out/AI-Agents-in-Depth-ta.pdf"
cp book-vi/AI-Agents-in-Depth-Bojie-Li-v2.0-vi.pdf "$out/AI-Agents-in-Depth-vi.pdf"
cp book-ar/AI-Agents-in-Depth-v2.0-ar.pdf "$out/AI-Agents-in-Depth-ar.pdf"
cp book-tr/AI-Agents-in-Depth-Bojie-Li-v2.0-tr.pdf "$out/AI-Agents-in-Depth-tr.pdf"
cp book-ko/AI-Agents-in-Depth-v2.0-ko.pdf "$out/AI-Agents-in-Depth-ko.pdf"
cp book-hu/AI-Agents-in-Depth-v2.0-hu.pdf "$out/AI-Agents-in-Depth-hu.pdf"
cp book-he/AI-Agents-in-Depth-v2.0-he.pdf "$out/AI-Agents-in-Depth-he.pdf"
cp "book/深入理解-AI-Agent-李博杰-v2.0.epub" "$out/AI-Agents-in-Depth-zh-CN.epub"
cp "book-zhtw/深入理解-AI-Agent-李博杰-v2.0-zhtw.epub" "$out/AI-Agents-in-Depth-zh-TW.epub"
cp book-en/AI-Agents-in-Depth-Bojie-Li-v2.0.epub "$out/AI-Agents-in-Depth-en.epub"
cp book-es/AI-Agents-en-Profundidad-Bojie-Li-v2.0-es.epub "$out/AI-Agents-in-Depth-es.epub"
cp book-id/AI-Agents-in-Depth-Bojie-Li-v2.0-id.epub "$out/AI-Agents-in-Depth-id.epub"
cp book-ru/AI-Agents-in-Depth-v2.0-ru.epub "$out/AI-Agents-in-Depth-ru.epub"
cp book-ta/AI-Agents-in-Depth-Bojie-Li-v2.0-ta.epub "$out/AI-Agents-in-Depth-ta.epub"
cp book-vi/AI-Agents-in-Depth-Bojie-Li-v2.0-vi.epub "$out/AI-Agents-in-Depth-vi.epub"
cp book-tr/AI-Agents-in-Depth-Bojie-Li-v2.0-tr.epub "$out/AI-Agents-in-Depth-tr.epub"
cp book-ko/AI-Agents-in-Depth-v2.0-ko.epub "$out/AI-Agents-in-Depth-ko.epub"
cp book-hu/AI-Agents-in-Depth-v2.0-hu.epub "$out/AI-Agents-in-Depth-hu.epub"
cp book-he/AI-Agents-in-Depth-v2.0-he.epub "$out/AI-Agents-in-Depth-he.epub"
# WIP: ja artifacts and the Arabic EPUB are copied only if their
# non-fatal builds produced them.
cp book-ja/AI-Agents-in-Depth-Bojie-Li-v2.0-ja.pdf "$out/AI-Agents-in-Depth-ja.pdf" || echo "ja PDF not built yet (WIP) — skipping"
cp book-ja/AI-Agents-in-Depth-Bojie-Li-v2.0-ja.epub "$out/AI-Agents-in-Depth-ja.epub" || echo "ja EPUB not built yet (WIP) — skipping"
cp book-ar/AI-Agents-in-Depth-v2.0-ar.epub "$out/AI-Agents-in-Depth-ar.epub" || echo "ar EPUB not built yet (WIP) — skipping"
gh release upload latest "$out"/* --clobber --repo "${{ github.repository }}"