Skip to content

Commit 249ec55

Browse files
authored
Merge pull request #129 from TUBAF-IfI-LiaScript/copilot/generate-pdfs-for-course-materials
Add PDF generation pipeline with GitHub Releases and docs deployment
2 parents d4f0ab4 + 1b7542c commit 249ec55

1 file changed

Lines changed: 191 additions & 0 deletions

File tree

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
name: Generate PDFs
2+
3+
# Triggered by:
4+
# - push to master that changes lecture markdown files
5+
# - manual dispatch (regenerates PDFs for ALL lecture files)
6+
on:
7+
push:
8+
branches:
9+
- master
10+
paths:
11+
- '[0-9][0-9]_*.md'
12+
workflow_dispatch:
13+
14+
concurrency:
15+
group: pdf-generation
16+
cancel-in-progress: false
17+
18+
permissions:
19+
contents: write
20+
21+
jobs:
22+
# -------------------------------------------------------------------------
23+
# Job 1 – build PDFs and publish GitHub Releases
24+
# -------------------------------------------------------------------------
25+
generate_pdfs:
26+
name: Generate PDFs and create releases
27+
runs-on: ubuntu-latest
28+
steps:
29+
- name: Checkout repository
30+
uses: actions/checkout@v4
31+
with:
32+
fetch-depth: 2
33+
token: ${{ secrets.GITHUB_TOKEN }}
34+
35+
- name: Detect changed lecture files (push) or select all (dispatch)
36+
id: changes
37+
run: |
38+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
39+
# Regenerate PDFs for every numbered lecture file
40+
files=$(ls [0-9][0-9]_*.md 2>/dev/null | tr '\n' ' ')
41+
else
42+
files=$(git diff --name-only HEAD^ HEAD \
43+
| grep -E '^[0-9]{2}_.*\.md$' || true)
44+
files="${files//$'\n'/ }"
45+
fi
46+
echo "changed_files=${files}" >> "$GITHUB_OUTPUT"
47+
echo "Files to process: ${files}"
48+
49+
# -----------------------------------------------------------------------
50+
# Validate that every changed file has a version tag and auto-increment
51+
# the patch component when the corresponding release tag already exists.
52+
#
53+
# Logic:
54+
# 1. Extract version from the <!-- ... --> frontmatter.
55+
# → Fail hard if the tag is absent.
56+
# 2. Compute the release tag (same algorithm as the PDF step below).
57+
# → If the release tag already exists on GitHub, the user forgot to
58+
# bump the version. We increment the patch component in the file.
59+
# 3. Commit & push any modified files with "[skip ci]" so the PDF step
60+
# reads the correct (bumped) version from the working tree.
61+
# -----------------------------------------------------------------------
62+
- name: Check versions and auto-increment patch if tag already exists
63+
if: steps.changes.outputs.changed_files != ''
64+
run: |
65+
set -euo pipefail
66+
67+
git config user.name "github-actions[bot]"
68+
git config user.email "github-actions[bot]@users.noreply.github.com"
69+
70+
bumped_files=""
71+
error_files=""
72+
73+
for file in ${{ steps.changes.outputs.changed_files }}; do
74+
[ -f "$file" ] || continue
75+
76+
filename=$(basename "$file" .md)
77+
78+
# ── 1. Require a version tag ───────────────────────────────────
79+
version=$(grep -oP '(?m)^version:\s*\K[\d.]+' "$file" | head -1 || true)
80+
if [ -z "$version" ]; then
81+
echo "ERROR: $file has no 'version:' tag in its frontmatter." >&2
82+
error_files="$error_files $file"
83+
continue
84+
fi
85+
86+
# ── 2. Compute safe release tag ───────────────────────────────
87+
safe_tag=$(echo "$filename" \
88+
| tr '[:upper:]' '[:lower:]' \
89+
| sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/ß/ss/g' \
90+
-e 's/Ä/ae/g' -e 's/Ö/oe/g' -e 's/Ü/ue/g' \
91+
-e 's/[^a-z0-9_-]//g')
92+
release_tag="${safe_tag}_v${version}"
93+
94+
# ── 3. Auto-increment patch if release tag already exists ─────
95+
if gh release view "$release_tag" > /dev/null 2>&1; then
96+
echo "Tag '$release_tag' already exists for $file – auto-incrementing patch."
97+
98+
# Increment last numeric component: e.g. 1.0.10 → 1.0.11
99+
new_version=$(echo "$version" | awk -F. '{$NF = $NF + 1; print}' OFS='.')
100+
101+
# Replace the version line inside the HTML comment frontmatter.
102+
# The sed pattern handles optional spaces around the colon.
103+
sed -i -E "s/^(version:[[:space:]]*)[0-9]+(\.[0-9]+)*/\1${new_version}/" "$file"
104+
105+
echo " $file: $version → $new_version"
106+
bumped_files="$bumped_files $file"
107+
else
108+
echo "Tag '$release_tag' is new – no version bump needed for $file."
109+
fi
110+
done
111+
112+
# ── Fail if any file was missing a version tag ───────────────────
113+
if [ -n "$error_files" ]; then
114+
echo ""
115+
echo "The following files are missing a 'version:' tag:" >&2
116+
for f in $error_files; do echo " $f" >&2; done
117+
echo "Please add 'version: X.Y.Z' to the HTML comment frontmatter." >&2
118+
exit 1
119+
fi
120+
121+
# ── Commit & push version bumps ───────────────────────────────────
122+
if [ -n "$bumped_files" ]; then
123+
git add $bumped_files
124+
git commit -m "ci: auto-increment patch version for changed courses [skip ci]"
125+
git pull --rebase origin master || true
126+
git push
127+
echo "Version bumps pushed to master."
128+
fi
129+
env:
130+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
131+
132+
- name: Set up Node.js
133+
if: steps.changes.outputs.changed_files != ''
134+
uses: actions/setup-node@v4
135+
with:
136+
node-version: '22'
137+
138+
- name: Install LiaScript exporter
139+
if: steps.changes.outputs.changed_files != ''
140+
run: npm install -g @liascript/exporter
141+
142+
- name: Generate PDFs and publish GitHub Releases
143+
if: steps.changes.outputs.changed_files != ''
144+
run: |
145+
set -euo pipefail
146+
mkdir -p /tmp/pdf_build
147+
148+
for file in ${{ steps.changes.outputs.changed_files }}; do
149+
[ -f "$file" ] || continue
150+
151+
filename=$(basename "$file" .md)
152+
153+
# Safe tag: lowercase, transliterate umlauts, remove non-ASCII
154+
safe_tag=$(echo "$filename" \
155+
| tr '[:upper:]' '[:lower:]' \
156+
| sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/ß/ss/g' \
157+
-e 's/Ä/ae/g' -e 's/Ö/oe/g' -e 's/Ü/ue/g' \
158+
-e 's/[^a-z0-9_-]//g')
159+
160+
# Re-read version from the file (may have been bumped in the
161+
# previous step; the version tag is guaranteed to exist by now).
162+
version=$(grep -oP '(?m)^version:\s*\K[\d.]+' "$file" | head -1)
163+
164+
asset_name="${filename}_v${version}_Documentation"
165+
release_tag="${safe_tag}_v${version}"
166+
167+
echo "==> $file (tag: $release_tag)"
168+
169+
# Generate PDF
170+
liaex \
171+
--input "$file" \
172+
--format pdf \
173+
--output "/tmp/pdf_build/${asset_name}" \
174+
--pdf-timeout 60000
175+
176+
pdf_path="/tmp/pdf_build/${asset_name}.pdf"
177+
178+
if [ ! -f "$pdf_path" ]; then
179+
echo "ERROR: PDF not created for $file" >&2
180+
exit 1
181+
fi
182+
183+
# The version-check step guarantees the tag is new at this point.
184+
gh release create "$release_tag" \
185+
--title "PDF – ${filename} (v${version})" \
186+
--notes "Automated PDF export for \`${file}\` – version ${version}" \
187+
"$pdf_path"
188+
done
189+
env:
190+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
191+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

0 commit comments

Comments
 (0)