docs: drop the as-of date stamps from prose #165
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update Preview PDF | |
| on: | |
| push: | |
| branches: | |
| - master | |
| workflow_dispatch: | |
| permissions: {} | |
| concurrency: | |
| group: preview-pdf | |
| cancel-in-progress: true | |
| jobs: | |
| build: | |
| permissions: | |
| contents: read | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | |
| with: | |
| persist-credentials: false | |
| - name: Install locked Node dependencies | |
| env: | |
| PUPPETEER_SKIP_DOWNLOAD: "true" | |
| run: npm ci | |
| - name: Check project rules and metadata | |
| run: | | |
| python3 check_project_rules.py | |
| npm test | |
| - name: Install Chromium | |
| uses: browser-actions/setup-chrome@2e1d749697dd1612b833dba4a722266286fbefcd # v2.1.2 | |
| with: | |
| chrome-version: stable | |
| - name: Install CJK fonts and PDF inspection tools | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y fonts-noto-cjk fonts-noto-cjk-extra poppler-utils | |
| - name: Resolve latest mdPress release | |
| run: | | |
| url="$(curl -fsSL --retry 3 -o /dev/null -w '%{url_effective}' https://github.com/yeasy/mdPress/releases/latest)" | |
| version="${url##*/v}" | |
| test -n "$version" || { echo "could not resolve latest mdPress release"; exit 1; } | |
| echo "MDPRESS_VERSION=$version" >> "$GITHUB_ENV" | |
| echo "resolved mdPress $version" | |
| - name: Install mdPress (checksum-verified) | |
| run: | | |
| archive="$RUNNER_TEMP/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz" | |
| curl -fsSL --retry 3 \ | |
| "https://github.com/yeasy/mdPress/releases/download/v${MDPRESS_VERSION}/mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz" \ | |
| -o "$archive" | |
| expected="$(curl -fsSL --retry 3 "https://github.com/yeasy/mdPress/releases/download/v${MDPRESS_VERSION}/checksums.txt" \ | |
| | awk -v f="mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz" '$2==f {print $1}')" | |
| test -n "$expected" || { echo "no published checksum for mdpress_${MDPRESS_VERSION}_linux_amd64.tar.gz"; exit 1; } | |
| echo "${expected} $archive" | sha256sum -c - | |
| tar xzf "$archive" -C "$RUNNER_TEMP" mdpress | |
| mkdir -p "$RUNNER_TEMP/bin" | |
| install -m 0755 "$RUNNER_TEMP/mdpress" "$RUNNER_TEMP/bin/mdpress" | |
| echo "$RUNNER_TEMP/bin" >> "$GITHUB_PATH" | |
| - name: Prepare PDF sources | |
| run: python3 tools/prepare_pdf_sources.py --book-dir . --out "$RUNNER_TEMP/docker_practice-pdf-src" | |
| - name: Build latest preview PDF | |
| working-directory: ${{ runner.temp }}/docker_practice-pdf-src | |
| run: | | |
| # mdPress PDF generation drives headless Chrome, which intermittently dies with | |
| # "websocket url timeout reached" + dbus errors. Retry the build, not the whole job. | |
| mdpress() { local a; for a in 1 2 3; do command mdpress "$@" && return 0; | |
| echo "::warning::mdpress attempt $a failed; retrying in 10s"; sleep 10; done; return 1; } | |
| mkdir -p "$GITHUB_WORKSPACE/dist" | |
| mdpress build --format pdf --output "$GITHUB_WORKSPACE/dist/docker_practice.pdf" | |
| - name: Verify preview PDF | |
| run: | | |
| title=$(python3 -c 'import json; print(json.load(open("book.json", encoding="utf-8"))["title"])') | |
| python3 tools/verify_artifacts.py \ | |
| --title "$title" \ | |
| --pdf dist/docker_practice.pdf \ | |
| --checksums dist/SHA256SUMS | |
| (cd dist && sha256sum -c SHA256SUMS) | |
| - name: Upload verified preview bundle | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: docker-practice-preview | |
| path: dist/ | |
| if-no-files-found: error | |
| publish: | |
| permissions: | |
| contents: write | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| steps: | |
| - name: Download verified preview bundle | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| name: docker-practice-preview | |
| path: dist | |
| - name: Recheck preview checksum | |
| run: (cd dist && sha256sum -c SHA256SUMS) | |
| - name: Write release notes | |
| run: | | |
| cat > dist/release-notes.md <<EOF | |
| Auto-updated preview PDF from \`${GITHUB_SHA::7}\`. | |
| - Branch: \`${GITHUB_REF_NAME}\` | |
| - Commit: https://github.com/${GITHUB_REPOSITORY}/commit/${GITHUB_SHA} | |
| - Run: https://github.com/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID} | |
| This is a mutable preview without formal provenance. Use a tagged release for attested artifacts. | |
| EOF | |
| - name: Synchronize mutable preview tag | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| if [[ ! "$GITHUB_REPOSITORY" =~ ^[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+$ ]]; then | |
| echo "Invalid GITHUB_REPOSITORY: $GITHUB_REPOSITORY" >&2 | |
| exit 1 | |
| fi | |
| if [[ ! "$GITHUB_SHA" =~ ^[0-9a-f]{40}$ ]]; then | |
| echo "Invalid GITHUB_SHA" >&2 | |
| exit 1 | |
| fi | |
| probe_dir=$(mktemp -d) | |
| trap 'rm -rf "$probe_dir"' EXIT | |
| set +e | |
| gh api --include --method GET \ | |
| "repos/${GITHUB_REPOSITORY}/git/ref/tags/preview-pdf" \ | |
| >"$probe_dir/response" 2>"$probe_dir/error" | |
| probe_rc=$? | |
| set -e | |
| http_status=$(awk '$1 ~ /^HTTP\// && $2 ~ /^[0-9][0-9][0-9]$/ { status=$2 } END { print status }' "$probe_dir/response") | |
| if [[ $probe_rc -eq 0 && "$http_status" == "200" ]]; then | |
| gh api --silent --method PATCH \ | |
| "repos/${GITHUB_REPOSITORY}/git/refs/tags/preview-pdf" \ | |
| --raw-field sha="$GITHUB_SHA" \ | |
| --field force=true | |
| elif [[ $probe_rc -ne 0 && "$http_status" == "404" ]]; then | |
| gh api --silent --method POST \ | |
| "repos/${GITHUB_REPOSITORY}/git/refs" \ | |
| --raw-field ref="refs/tags/preview-pdf" \ | |
| --raw-field sha="$GITHUB_SHA" | |
| else | |
| cat "$probe_dir/response" >&2 | |
| cat "$probe_dir/error" >&2 | |
| echo "Preview tag lookup failed (exit=$probe_rc, HTTP=${http_status:-unavailable}); refusing to mutate refs or releases." >&2 | |
| exit 1 | |
| fi | |
| - name: Create or update preview release | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| error_file=$(mktemp) | |
| trap 'rm -f "$error_file"' EXIT | |
| set +e | |
| gh release view preview-pdf >/dev/null 2>"$error_file" | |
| release_rc=$? | |
| set -e | |
| if [[ $release_rc -eq 0 ]]; then | |
| gh release edit preview-pdf \ | |
| --title "Latest Preview PDF" \ | |
| --notes-file dist/release-notes.md \ | |
| --prerelease | |
| elif [[ "$(tr -d '\r' < "$error_file")" == "release not found" ]]; then | |
| gh release create preview-pdf \ | |
| --title "Latest Preview PDF" \ | |
| --notes-file dist/release-notes.md \ | |
| --prerelease \ | |
| --latest=false \ | |
| --verify-tag | |
| else | |
| cat "$error_file" >&2 | |
| echo "Preview release lookup failed (exit=$release_rc); refusing to create or edit the release." >&2 | |
| exit 1 | |
| fi | |
| - name: Replace preview assets | |
| run: | | |
| gh release delete-asset preview-pdf latest.pdf -y || true | |
| gh release upload preview-pdf \ | |
| dist/docker_practice.pdf \ | |
| dist/SHA256SUMS \ | |
| --clobber |