]> git.ipfire.org Git - thirdparty/fastapi/sqlmodel.git/commitdiff
🔧 Update docs build setup, add support for sponsors, add sponsor GOVCERT.LU (#720)
authorSebastián Ramírez <tiangolo@gmail.com>
Mon, 4 Dec 2023 12:00:47 +0000 (13:00 +0100)
committerGitHub <noreply@github.com>
Mon, 4 Dec 2023 12:00:47 +0000 (13:00 +0100)
.github/workflows/build-docs.yml
README.md
data/sponsors.yml [new file with mode: 0644]
docs/img/sponsors/govcert.png [new file with mode: 0644]
docs/index.md
mkdocs.insiders.yml
mkdocs.maybe-insiders.yml [new file with mode: 0644]
mkdocs.no-insiders.yml [new file with mode: 0644]
mkdocs.yml
pyproject.toml
scripts/docs.py [new file with mode: 0644]

index 3d29204f7888edc40fd69c4c28550f55a7b4e05f..2e60ed7d395674e1552ba82e3e562506529b6622 100644 (file)
@@ -30,6 +30,8 @@ jobs:
             - pyproject.toml
             - mkdocs.yml
             - mkdocs.insiders.yml
+            - ./github/workflows/build-docs.yml
+            - ./github/workflows/deploy-docs.yml
 
   build-docs:
     needs:
@@ -69,12 +71,10 @@ jobs:
         with:
           key: mkdocs-cards-${{ github.ref }}
           path: .cache
+      - name: Verify README
+        run: python ./scripts/docs.py verify-readme
       - name: Build Docs
-        if: github.event_name == 'pull_request' && github.secret_source != 'Actions'
-        run: python -m poetry run mkdocs build
-      - name: Build Docs with Insiders
-        if: github.event_name != 'pull_request' || github.secret_source == 'Actions'
-        run: python -m poetry run mkdocs build --config-file mkdocs.insiders.yml
+        run: python ./scripts/docs.py build
       - uses: actions/upload-artifact@v3
         with:
           name: docs-site
index a9387c510a8dab77908c8d7de8c292fa8ecbb58d..ba3bb2196e4184ef3e79b73ca6e8ed99ef3cb338 100644 (file)
--- a/README.md
+++ b/README.md
@@ -38,6 +38,14 @@ The key features are:
 * **Extensible**: You have all the power of SQLAlchemy and Pydantic underneath.
 * **Short**: Minimize code duplication. A single type annotation does a lot of work. No need to duplicate models in SQLAlchemy and Pydantic.
 
+## Sponsors
+
+<!-- sponsors -->
+
+<a href="https://www.govcert.lu" target="_blank" title="This project is being supported by GOVCERT.LU"><img src="https://sqlmodel.tiangolo.com/img/sponsors/govcert.png"></a>
+
+<!-- /sponsors -->
+
 ## SQL Databases in FastAPI
 
 <a href="https://fastapi.tiangolo.com" target="_blank"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" style="width: 20%;"></a>
@@ -68,7 +76,7 @@ Successfully installed sqlmodel
 
 ## Example
 
-For an introduction to databases, SQL, and everything else, see the <a href="https://sqlmodel.tiangolo.com" target="_blank">SQLModel documentation</a>.
+For an introduction to databases, SQL, and everything else, see the <a href="https://sqlmodel.tiangolo.com/databases/" target="_blank">SQLModel documentation</a>.
 
 Here's a quick example. âœ¨
 
diff --git a/data/sponsors.yml b/data/sponsors.yml
new file mode 100644 (file)
index 0000000..95cf878
--- /dev/null
@@ -0,0 +1,6 @@
+gold: []
+silver:
+  - url: https://www.govcert.lu
+    title: This project is being supported by GOVCERT.LU
+    img: https://sqlmodel.tiangolo.com/img/sponsors/govcert.png
+bronze: []
diff --git a/docs/img/sponsors/govcert.png b/docs/img/sponsors/govcert.png
new file mode 100644 (file)
index 0000000..0bb4cb9
Binary files /dev/null and b/docs/img/sponsors/govcert.png differ
index 524ef992a37aeea630ae0035c8ab2c0bc7750c0b..f77cc7b8b4ce608a0ce4c60145951cdeb8e3d721 100644 (file)
@@ -1,3 +1,7 @@
+<style>
+.md-content .md-typeset h1 { display: none; }
+</style>
+
 <p align="center">
   <a href="https://sqlmodel.tiangolo.com"><img src="https://sqlmodel.tiangolo.com/img/logo-margin/logo-margin-vector.svg" alt="SQLModel"></a>
 </p>
@@ -38,6 +42,21 @@ The key features are:
 * **Extensible**: You have all the power of SQLAlchemy and Pydantic underneath.
 * **Short**: Minimize code duplication. A single type annotation does a lot of work. No need to duplicate models in SQLAlchemy and Pydantic.
 
+## Sponsors
+
+<!-- sponsors -->
+
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}" style="border-radius:15px"></a>
+{% endfor %}
+{% endif %}
+
+<!-- /sponsors -->
+
 ## SQL Databases in FastAPI
 
 <a href="https://fastapi.tiangolo.com" target="_blank"><img src="https://fastapi.tiangolo.com/img/logo-margin/logo-teal.png" style="width: 20%;"></a>
index 9f2775ff97af60706f364a3ebc25e178294cf3de..d24d75493070c72e764d0a4593eccb74ef7f62fe 100644 (file)
@@ -1,4 +1,3 @@
-INHERIT: mkdocs.yml
 plugins:
-  - search
-  - social
+  social:
+  typeset:
diff --git a/mkdocs.maybe-insiders.yml b/mkdocs.maybe-insiders.yml
new file mode 100644 (file)
index 0000000..07aefaa
--- /dev/null
@@ -0,0 +1,6 @@
+# Define this here and not in the main mkdocs.yml file because that one could be auto
+# updated and written, and the script would remove the env var
+INHERIT: !ENV [INSIDERS_FILE, './mkdocs.no-insiders.yml']
+markdown_extensions:
+  pymdownx.highlight:
+    linenums: !ENV [LINENUMS, false]
diff --git a/mkdocs.no-insiders.yml b/mkdocs.no-insiders.yml
new file mode 100644 (file)
index 0000000..e69de29
index a41839c12fc78329a907e6d1a375993320ed0f5f..ce98f1524e952430085d06945228149ab1e4deb8 100644 (file)
@@ -1,3 +1,4 @@
+INHERIT: ./mkdocs.maybe-insiders.yml
 site_name: SQLModel
 site_description: SQLModel, SQL databases in Python, designed for simplicity, compatibility, and robustness.
 site_url: https://sqlmodel.tiangolo.com/
@@ -36,6 +37,11 @@ theme:
 repo_name: tiangolo/sqlmodel
 repo_url: https://github.com/tiangolo/sqlmodel
 edit_uri: ''
+plugins:
+  search: null
+  markdownextradata:
+    data: ./data
+
 nav:
   - SQLModel: index.md
   - features.md
@@ -98,30 +104,28 @@ nav:
   - release-notes.md
 
 markdown_extensions:
-- markdown.extensions.attr_list
-- markdown.extensions.tables
-- markdown.extensions.md_in_html
-- toc:
+  markdown.extensions.attr_list:
+  markdown.extensions.tables:
+  markdown.extensions.md_in_html:
+  toc:
     permalink: true
-- pymdownx.superfences:
+  pymdownx.superfences:
     custom_fences:
     - name: mermaid
       class: mermaid
       format: !!python/name:pymdownx.superfences.fence_code_format ''
-- pymdownx.betterem
-- pymdownx.highlight:
-    linenums: !ENV [LINENUMS, false]
-- pymdownx.blocks.details
-- pymdownx.blocks.admonition:
+  pymdownx.betterem:
+  pymdownx.blocks.details:
+  pymdownx.blocks.admonition:
     types:
     - note
     - info
     - tip
     - warning
     - danger
-- pymdownx.blocks.tab:
+  pymdownx.blocks.tab:
     alternate_style: True
-- mdx_include
+  mdx_include:
 
 extra:
   analytics:
index 9bfc434cfb7d9963b508c1c570e46446db576f30..24a6c5c22e2b675c62645dca38e2dd22e0343fd7 100644 (file)
@@ -50,6 +50,8 @@ fastapi = "^0.103.2"
 ruff = "^0.1.2"
 # For FastAPI tests
 httpx = "0.24.1"
+typer-cli = "^0.0.13"
+mkdocs-markdownextradata-plugin = ">=0.1.7,<0.3.0"
 
 [build-system]
 requires = ["poetry-core"]
diff --git a/scripts/docs.py b/scripts/docs.py
new file mode 100644 (file)
index 0000000..cab6c87
--- /dev/null
@@ -0,0 +1,155 @@
+import logging
+import os
+import re
+import subprocess
+from functools import lru_cache
+from http.server import HTTPServer, SimpleHTTPRequestHandler
+from importlib import metadata
+from pathlib import Path
+
+import mkdocs.commands.build
+import mkdocs.commands.serve
+import mkdocs.config
+import mkdocs.utils
+import typer
+from jinja2 import Template
+
+logging.basicConfig(level=logging.INFO)
+
+mkdocs_name = "mkdocs.yml"
+en_docs_path = Path("")
+
+app = typer.Typer()
+
+
+@lru_cache
+def is_mkdocs_insiders() -> bool:
+    version = metadata.version("mkdocs-material")
+    return "insiders" in version
+
+
+@app.callback()
+def callback() -> None:
+    if is_mkdocs_insiders():
+        os.environ["INSIDERS_FILE"] = "./mkdocs.insiders.yml"
+    # For MacOS with insiders and Cairo
+    os.environ["DYLD_FALLBACK_LIBRARY_PATH"] = "/opt/homebrew/lib"
+
+
+index_sponsors_template = """
+{% if sponsors %}
+{% for sponsor in sponsors.gold -%}
+<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
+{% endfor -%}
+{%- for sponsor in sponsors.silver -%}
+<a href="{{ sponsor.url }}" target="_blank" title="{{ sponsor.title }}"><img src="{{ sponsor.img }}"></a>
+{% endfor %}
+{% endif %}
+"""
+
+
+def generate_readme_content() -> str:
+    en_index = en_docs_path / "docs" / "index.md"
+    content = en_index.read_text("utf-8")
+    match_pre = re.search(r"</style>\n\n", content)
+    match_start = re.search(r"<!-- sponsors -->", content)
+    match_end = re.search(r"<!-- /sponsors -->", content)
+    sponsors_data_path = en_docs_path / "data" / "sponsors.yml"
+    sponsors = mkdocs.utils.yaml_load(sponsors_data_path.read_text(encoding="utf-8"))
+    if not (match_start and match_end):
+        raise RuntimeError("Couldn't auto-generate sponsors section")
+    if not match_pre:
+        raise RuntimeError("Couldn't find pre section (<style>) in index.md")
+    frontmatter_end = match_pre.end()
+    pre_end = match_start.end()
+    post_start = match_end.start()
+    template = Template(index_sponsors_template)
+    message = template.render(sponsors=sponsors)
+    pre_content = content[frontmatter_end:pre_end]
+    post_content = content[post_start:]
+    new_content = pre_content + message + post_content
+    return new_content
+
+
+@app.command()
+def generate_readme() -> None:
+    """
+    Generate README.md content from main index.md
+    """
+    typer.echo("Generating README")
+    readme_path = Path("README.md")
+    new_content = generate_readme_content()
+    readme_path.write_text(new_content, encoding="utf-8")
+
+
+@app.command()
+def verify_readme() -> None:
+    """
+    Verify README.md content from main index.md
+    """
+    typer.echo("Verifying README")
+    readme_path = Path("README.md")
+    generated_content = generate_readme_content()
+    readme_content = readme_path.read_text("utf-8")
+    if generated_content != readme_content:
+        typer.secho(
+            "README.md outdated from the latest index.md", color=typer.colors.RED
+        )
+        raise typer.Abort()
+    typer.echo("Valid README âœ…")
+
+
+@app.command()
+def live() -> None:
+    """
+    Serve with livereload a docs site for a specific language.
+
+    This only shows the actual translated files, not the placeholders created with
+    build-all.
+
+    Takes an optional LANG argument with the name of the language to serve, by default
+    en.
+    """
+    # Enable line numbers during local development to make it easier to highlight
+    os.environ["LINENUMS"] = "true"
+    mkdocs.commands.serve.serve(dev_addr="127.0.0.1:8008")
+
+
+@app.command()
+def build() -> None:
+    """
+    Build the docs.
+    """
+    insiders_env_file = os.environ.get("INSIDERS_FILE")
+    print(f"Insiders file {insiders_env_file}")
+    if is_mkdocs_insiders():
+        print("Using insiders")
+    print("Building docs")
+    subprocess.run(["mkdocs", "build"], check=True)
+    typer.secho("Successfully built docs", color=typer.colors.GREEN)
+
+
+@app.command()
+def serve() -> None:
+    """
+    A quick server to preview a built site.
+
+    For development, prefer the command live (or just mkdocs serve).
+
+    This is here only to preview the documentation site.
+
+    Make sure you run the build command first.
+    """
+    typer.echo("Warning: this is a very simple server.")
+    typer.echo("For development, use the command live instead.")
+    typer.echo("This is here only to preview the documentation site.")
+    typer.echo("Make sure you run the build command first.")
+    os.chdir("site")
+    server_address = ("", 8008)
+    server = HTTPServer(server_address, SimpleHTTPRequestHandler)
+    typer.echo("Serving at: http://127.0.0.1:8008")
+    server.serve_forever()
+
+
+if __name__ == "__main__":
+    app()