From 71d5dad817de4718b7dcceaedefef084c36e2182 Mon Sep 17 00:00:00 2001 From: Sam Chau Date: Thu, 29 Jan 2026 11:23:52 +1030 Subject: [PATCH] feat: add workflow to generate schema diagram and update README --- .github/workflows/generate-schema-diagram.yml | 39 ++++++++++++ README.md | 3 + scripts/generate-schema-diagram.sh | 61 +++++++++++++++++++ 3 files changed, 103 insertions(+) create mode 100644 .github/workflows/generate-schema-diagram.yml create mode 100755 scripts/generate-schema-diagram.sh diff --git a/.github/workflows/generate-schema-diagram.yml b/.github/workflows/generate-schema-diagram.yml new file mode 100644 index 0000000..f896bed --- /dev/null +++ b/.github/workflows/generate-schema-diagram.yml @@ -0,0 +1,39 @@ +name: Generate Schema Diagram + +on: + workflow_dispatch: + push: + paths: + - ops/0.schema.sql + - scripts/generate-schema-diagram.sh + - .github/workflows/generate-schema-diagram.yml + +permissions: + contents: write + +jobs: + generate: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install Graphviz + run: sudo apt-get update && sudo apt-get install -y graphviz + + - name: Generate diagram + run: ./scripts/generate-schema-diagram.sh + + - name: Commit updates + run: | + if git diff --quiet; then + echo "No changes to commit." + exit 0 + fi + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add .github/image/schema.svg .github/image/schema-dark.svg README.md + git commit -m "chore: update schema diagram" + git push diff --git a/README.md b/README.md index 3c3ff25..c3e0f59 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,9 @@ This repository hosts the base schema applied to all

+Diagram is auto-generated from `ops/0.schema.sql` by the +`generate-schema-diagram` workflow. Do not edit the SVGs by hand. + ## Documentation - [Manifest Specification](docs/manifest.md) - Required manifest file format for diff --git a/scripts/generate-schema-diagram.sh b/scripts/generate-schema-diagram.sh new file mode 100755 index 0000000..2162fc2 --- /dev/null +++ b/scripts/generate-schema-diagram.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +schema_sql="$repo_root/ops/0.schema.sql" +out_dir="$repo_root/.github/image" + +tmp_dir="$(mktemp -d)" +dot_file="$tmp_dir/schema.dot" + +SCHEMA_SQL="$schema_sql" DOT_FILE="$dot_file" python3 - <<'PY' +import os +import re +from pathlib import Path + +schema_sql = Path(os.environ["SCHEMA_SQL"]).read_text(encoding="utf-8") + +create_table_re = re.compile(r"CREATE\s+TABLE\s+([A-Za-z0-9_]+)\s*\(", re.IGNORECASE) +references_re = re.compile(r"REFERENCES\s+([A-Za-z0-9_]+)", re.IGNORECASE) + +tables = set(create_table_re.findall(schema_sql)) +blocks = re.split(r"CREATE\s+TABLE\s+", schema_sql, flags=re.IGNORECASE)[1:] + +edges = set() +for block in blocks: + name_match = re.match(r"([A-Za-z0-9_]+)", block) + if not name_match: + continue + table_name = name_match.group(1) + for ref in references_re.findall(block): + edges.add((table_name, ref)) + +lines = [] +lines.append("digraph schema {") +lines.append(" rankdir=LR;") +lines.append(" splines=true;") +lines.append(" overlap=false;") +lines.append("") +for table in sorted(tables): + lines.append(f' "{table}";') +lines.append("") +for src, dst in sorted(edges): + lines.append(f' "{src}" -> "{dst}";') +lines.append("}") + +Path(os.environ["DOT_FILE"]).write_text("\n".join(lines) + "\n", encoding="utf-8") +PY + +mkdir -p "$out_dir" + +dot -Tsvg -o "$out_dir/schema.svg" \ + -Gbgcolor="#ffffff" \ + -Nshape="box" -Nstyle="filled" -Nfillcolor="#f8f8f8" -Ncolor="#444444" -Nfontcolor="#111111" -Nfontname="Helvetica" -Nfontsize="12" \ + -Ecolor="#666666" \ + "$dot_file" + +dot -Tsvg -o "$out_dir/schema-dark.svg" \ + -Gbgcolor="#0b0b0b" \ + -Nshape="box" -Nstyle="filled" -Nfillcolor="#1f1f1f" -Ncolor="#777777" -Nfontcolor="#f5f5f5" -Nfontname="Helvetica" -Nfontsize="12" \ + -Ecolor="#aaaaaa" \ + "$dot_file"