Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 58 additions & 8 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,84 @@ permissions:
pages: write
id-token: write

concurrency:
group: pages-${{ github.ref }}
cancel-in-progress: false

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Pages
if: github.ref == 'refs/heads/main'
uses: actions/configure-pages@v5
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
cache: pip

- name: Install dependencies
- name: Install WeasyPrint system libraries
run: |
sudo apt-get update
sudo apt-get install -y pandoc weasyprint make
sudo apt-get install -y --no-install-recommends \
libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b \
libcairo2 libgdk-pixbuf-2.0-0

- name: Install Python deps
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt

- name: Build
run: PANDOC=__missing_pandoc__ WEASYPRINT=__missing_weasyprint__ make build
run: python scripts/build.py

- name: Verify committed public artifacts
run: git diff --exit-code public/
- name: Setup Pages
if: github.ref == 'refs/heads/main'
uses: actions/configure-pages@v5

- name: Upload Pages artifact
if: github.ref == 'refs/heads/main'
uses: actions/upload-pages-artifact@v3
with:
path: public/

- name: Upload public/ as workflow artifact (PRs)
if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: public
path: public/
retention-days: 7

lighthouse:
if: github.event_name == 'pull_request'
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Download built site
uses: actions/download-artifact@v4
with:
name: public
path: public

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Run Lighthouse CI
uses: treosh/lighthouse-ci-action@v12
with:
# URLs and staticDistDir live in .lighthouserc.json so the local
# `npx lhci autorun` workflow stays in sync with CI.
uploadArtifacts: true
temporaryPublicStorage: true
configPath: ./.lighthouserc.json

deploy:
if: github.ref == 'refs/heads/main'
needs: build
Expand Down
13 changes: 13 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,16 @@
*.bak
dist/
src/*private*

# Build artifacts (regenerated in CI)
public/

# Local Python build env
.venv/
.venv-build/
__pycache__/
*.pyc

# Lighthouse local reports
lighthouse-*.html
.lighthouseci/
24 changes: 24 additions & 0 deletions .lighthouserc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"ci": {
"collect": {
"staticDistDir": "./public",
"url": [
"http://localhost/index.html",
"http://localhost/cv-executive.de.html",
"http://localhost/cv-technical.de.html"
Comment on lines +6 to +8
],
"settings": {
"preset": "desktop",
"onlyCategories": ["performance", "accessibility", "best-practices", "seo"]
}
},
"assert": {
"assertions": {
"categories:performance": ["error", { "minScore": 0.95 }],
"categories:accessibility": ["error", { "minScore": 1 }],
"categories:best-practices": ["error", { "minScore": 1 }],
"categories:seo": ["error", { "minScore": 1 }]
Comment thread
CybotTM marked this conversation as resolved.
}
}
}
}
97 changes: 38 additions & 59 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,61 +1,40 @@
PANDOC ?= pandoc
WEASYPRINT ?= weasyprint
CSS := assets/style.css
PUBLIC := public
SRC := src

EXEC_MD := $(SRC)/cv-executive.de.md
TECH_MD := $(SRC)/cv-technical.de.md

EXEC_HTML := $(PUBLIC)/cv-executive.de.html
TECH_HTML := $(PUBLIC)/cv-technical.de.html
EXEC_PDF := $(PUBLIC)/cv-executive.de.pdf
TECH_PDF := $(PUBLIC)/cv-technical.de.pdf
INDEX_HTML := $(PUBLIC)/index.html

.PHONY: build html pdf index check clean

build: html pdf index
html: $(EXEC_HTML) $(TECH_HTML)
pdf: $(EXEC_PDF) $(TECH_PDF)
index: $(INDEX_HTML)

$(PUBLIC):
mkdir -p $(PUBLIC)

$(EXEC_HTML): $(EXEC_MD) $(CSS) | $(PUBLIC)
@if command -v $(PANDOC) >/dev/null 2>&1; then \
$(PANDOC) $< -f markdown -t html5 --standalone --metadata title="Executive CV" --metadata lang="de" --css=../$(CSS) -o $@; \
else \
python3 scripts/render_html.py $< $@ ../$(CSS); \
fi

$(TECH_HTML): $(TECH_MD) $(CSS) | $(PUBLIC)
@if command -v $(PANDOC) >/dev/null 2>&1; then \
$(PANDOC) $< -f markdown -t html5 --standalone --metadata title="Technical CV" --metadata lang="de" --css=../$(CSS) -o $@; \
else \
python3 scripts/render_html.py $< $@ ../$(CSS); \
fi

$(EXEC_PDF): $(EXEC_HTML) $(CSS)
@if command -v $(WEASYPRINT) >/dev/null 2>&1; then \
$(WEASYPRINT) $< $@; \
else \
python3 scripts/render_pdf.py $< $@; \
fi

$(TECH_PDF): $(TECH_HTML) $(CSS)
@if command -v $(WEASYPRINT) >/dev/null 2>&1; then \
$(WEASYPRINT) $< $@; \
else \
python3 scripts/render_pdf.py $< $@; \
fi

$(INDEX_HTML): $(EXEC_HTML)
cp $(EXEC_HTML) $(INDEX_HTML)

check: build
git diff --exit-code public/
PYTHON ?= python3
VENV ?= .venv

.PHONY: help build serve clean install lighthouse

help:
@echo "make install - create venv and install dependencies"
@echo "make build - build public/ from src/ (HTML + PDF)"
@echo "make serve - build and serve public/ on http://localhost:8000"
@echo "make lighthouse - run a local Lighthouse audit (needs npx)"
@echo "make clean - remove public/ and venv"

$(VENV)/bin/python:
$(PYTHON) -m venv $(VENV) || (which uv && uv venv $(VENV))
$(VENV)/bin/python -m pip install -U pip || $(VENV)/bin/python -m ensurepip --upgrade
$(VENV)/bin/python -m pip install -r requirements.txt

install: $(VENV)/bin/python

build: install
$(VENV)/bin/python scripts/build.py

serve: build
@echo "Serving public/ on http://localhost:8000"
$(PYTHON) -m http.server 8000 -d public

lighthouse: build
@echo "Running Lighthouse on built public/"
npx --yes lighthouse "file://$(CURDIR)/public/index.html" \
--quiet --chrome-flags="--headless" \
--output html --output-path ./lighthouse-index.html
npx --yes lighthouse "file://$(CURDIR)/public/cv-executive.de.html" \
--quiet --chrome-flags="--headless" \
--output html --output-path ./lighthouse-executive.html
npx --yes lighthouse "file://$(CURDIR)/public/cv-technical.de.html" \
--quiet --chrome-flags="--headless" \
--output html --output-path ./lighthouse-technical.html

clean:
rm -f $(EXEC_HTML) $(TECH_HTML) $(EXEC_PDF) $(TECH_PDF) $(INDEX_HTML)
rm -rf public $(VENV) lighthouse-*.html
73 changes: 42 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,54 +2,65 @@

Source-controlled CV workflow for Sebastian Mendel.

Published version:
Published version: <https://cybottm.github.io/cv/>

<https://cybottm.github.io/cv/>

## Files
## Layout

| Path | Purpose |
|---|---|
| `src/cv-executive.de.md` | Short public executive CV |
| `src/cv-technical.de.md` | More detailed public technical CV |
| `public/index.html` | GitHub Pages entry point |
| `public/cv-executive.de.html` | Generated executive HTML CV |
| `public/cv-executive.de.pdf` | Generated executive PDF CV |
| `public/cv-technical.de.html` | Generated technical HTML CV |
| `public/cv-technical.de.pdf` | Generated technical PDF CV |
| `assets/style.css` | Shared print-friendly stylesheet |
| `Makefile` | Local build commands |

## Build
| `src/cv-executive.de.md` | Source: short executive CV (Markdown + YAML front-matter) |
| `src/cv-technical.de.md` | Source: longer technical CV |
| `templates/base.html.j2` | Jinja2 base template (`<head>`, OG, JSON-LD, etc.) |
| `templates/cv.html.j2` | CV page template |
| `templates/index.html.j2` | Landing page template |
| `assets/style.css` | Editorial CSS (screen + print) |
| `assets/fonts/*.woff2` | Self-hosted Source Serif 4 + Inter (variable, OFL) |
| `assets/favicon.svg` | Monogram favicon |
| `scripts/build.py` | The whole build: MD → HTML → PDF + index |
| `requirements.txt` | Python deps (pinned) |
| `Makefile` | Convenience targets (`build`, `serve`, `lighthouse`, `clean`) |
| `.github/workflows/build.yml` | GitHub Actions: build, Lighthouse-CI on PRs, Pages deploy |
| `public/` | **Build artifact** — generated, not committed |

## Build locally

You need Python 3.13 and the WeasyPrint runtime libs (Pango, Cairo, HarfBuzz, gdk-pixbuf).

Requirements:
```bash
# Debian/Ubuntu
sudo apt-get install -y libpango-1.0-0 libpangoft2-1.0-0 libharfbuzz0b libcairo2 libgdk-pixbuf-2.0-0

- `make`
- `pandoc`
- `weasyprint`
make install # creates .venv/ and installs requirements.txt
make build # writes public/cv-*.de.html + .pdf and public/index.html
make serve # builds, then serves public/ on http://localhost:8000
```

Build all generated files:
Skip PDF rendering during a fast iteration:

```bash
make build
.venv/bin/python scripts/build.py --no-pdf
```

Check that generated files are up to date:
## Local Lighthouse audit

```bash
make check
make lighthouse # writes lighthouse-*.html for each page
```

Remove generated HTML/PDF files:
## Editing content

```bash
make clean
```
Each `src/cv-*.de.md` has a YAML front-matter block: `variant`, `short_label`,
`lang`, `title`, `description`, `updated`, `og_locale`. The body is plain Markdown.
The `<h1>` and tagline are rendered from `templates/cv.html.j2`, not from the MD,
so the MD body should start at `## Profil`.

## Source of truth
## CI / publishing

The Markdown files in `src/` are the source of truth. Files in `public/` are generated artifacts for GitHub Pages and downloadable HTML/PDF versions.
- Every push and PR builds the site.
- PRs additionally run [`treosh/lighthouse-ci-action`](https://github.com/treosh/lighthouse-ci-action) and post results.
- Pushes to `main` deploy to GitHub Pages.

## Publishing
## License

GitHub Pages serves the generated files from `public/`. The default published CV is `public/index.html`.
CV content © Sebastian Mendel. Source code (templates, scripts, CSS) under the
repository's license; bundled fonts (Source Serif 4, Inter) under SIL OFL.
7 changes: 7 additions & 0 deletions assets/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/fonts/Inter-Variable-Italic.woff2
Binary file not shown.
Binary file added assets/fonts/Inter-Variable.woff2
Binary file not shown.
Binary file added assets/fonts/SourceSerif4-Variable-Italic.woff2
Binary file not shown.
Binary file added assets/fonts/SourceSerif4-Variable.woff2
Binary file not shown.
Loading
Loading