From 87bc8afd6fd9c9faa8ff310f9d3f743852787bd3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Mar 2026 12:05:06 +0000 Subject: [PATCH 1/3] Initial plan From df4a88944a2765facec0bef0ef202a3f8b8524fd Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Mar 2026 12:11:15 +0000 Subject: [PATCH 2/3] feat: add publish-versioned-docs workflow and update_docs_index script Co-authored-by: wannaphong <8536487+wannaphong@users.noreply.github.com> --- .github/workflows/publish-versioned-docs.yml | 88 ++++++++ build_tools/github/update_docs_index.py | 221 +++++++++++++++++++ 2 files changed, 309 insertions(+) create mode 100644 .github/workflows/publish-versioned-docs.yml create mode 100644 build_tools/github/update_docs_index.py diff --git a/.github/workflows/publish-versioned-docs.yml b/.github/workflows/publish-versioned-docs.yml new file mode 100644 index 000000000..6b10084b8 --- /dev/null +++ b/.github/workflows/publish-versioned-docs.yml @@ -0,0 +1,88 @@ +# SPDX-FileCopyrightText: 2026 PyThaiNLP Project +# SPDX-FileType: SOURCE +# SPDX-License-Identifier: Apache-2.0 + +# Publish versioned documentation to PyThaiNLP/docs when a release is published. +# +# On each GitHub release: +# 1. Copy PyThaiNLP/dev-docs to PyThaiNLP/docs/{version}/. +# 2. Regenerate PyThaiNLP/docs/index.html to list all released versions. +# 3. Inject the new version entry into PyThaiNLP/dev-docs/index.html. + +name: Publish versioned docs + +on: + release: + types: [published] + +jobs: + publish-versioned-docs: + name: Publish versioned documentation + runs-on: ubuntu-latest + # Only run for the main repository, not forks. + if: github.repository == 'PyThaiNLP/pythainlp' + + steps: + - name: Get version from release tag + id: version + # Strip the leading 'v' from the tag name, e.g. 'v5.3.1' -> '5.3.1'. + run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + + - name: Checkout pythainlp (for scripts) + uses: actions/checkout@v6 + with: + path: pythainlp + + - name: Checkout dev-docs repository + uses: actions/checkout@v6 + with: + repository: PyThaiNLP/dev-docs + token: ${{ secrets.PERSONAL_TOKEN }} + path: dev-docs + + - name: Checkout docs repository + uses: actions/checkout@v6 + with: + repository: PyThaiNLP/docs + token: ${{ secrets.PERSONAL_TOKEN }} + path: docs + + - name: Set up Python + uses: actions/setup-python@v6 + with: + python-version: "3.12" + + - name: Copy dev-docs to versioned directory in docs + run: | + VERSION="${{ steps.version.outputs.version }}" + mkdir -p "docs/${VERSION}" + rsync -a --delete --exclude='.git' dev-docs/ "docs/${VERSION}/" + + - name: Update docs index and dev-docs version list + run: | + python pythainlp/build_tools/github/update_docs_index.py \ + --docs-dir docs \ + --dev-docs-index dev-docs/index.html \ + --version "${{ steps.version.outputs.version }}" + + - name: Commit and push updated docs + run: | + VERSION="${{ steps.version.outputs.version }}" + cd docs + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + git add . + git diff --staged --quiet || \ + git commit -m "Add docs for version ${VERSION}" + git push + + - name: Commit and push updated dev-docs index + run: | + VERSION="${{ steps.version.outputs.version }}" + cd dev-docs + git config user.name 'github-actions[bot]' + git config user.email 'github-actions[bot]@users.noreply.github.com' + git add index.html + git diff --staged --quiet || \ + git commit -m "Update version list for release ${VERSION}" + git push diff --git a/build_tools/github/update_docs_index.py b/build_tools/github/update_docs_index.py new file mode 100644 index 000000000..986291c55 --- /dev/null +++ b/build_tools/github/update_docs_index.py @@ -0,0 +1,221 @@ +# SPDX-FileCopyrightText: 2026 PyThaiNLP Project +# SPDX-FileType: SOURCE +# SPDX-License-Identifier: Apache-2.0 +""" +Update documentation index pages on release. + +This script performs two tasks: + +1. Generates or updates ``index.html`` in the versioned docs repository + (``PyThaiNLP/docs``) to list all released versions as a landing page. +2. Injects or updates a released-versions section in ``index.html`` of the + development docs repository (``PyThaiNLP/dev-docs``). + +Usage:: + + python update_docs_index.py \\ + --docs-dir /path/to/docs \\ + --dev-docs-index /path/to/dev-docs/index.html \\ + --version 5.3.1 +""" + +from __future__ import annotations + +import argparse +import re +import sys +from pathlib import Path + +# Markers used to delimit the injected versions section in dev-docs/index.html. +_VERSIONS_BEGIN: str = "" +_VERSIONS_END: str = "" + +_VERSIONS_SECTION_TMPL: str = """\ + +
+

Released versions

+ +
+""" + +_VERSION_ITEM_TMPL: str = ( + '
  • {v}
  • ' +) + +_DOCS_INDEX_TMPL: str = """\ + + + + + + PyThaiNLP Documentation + + + +

    PyThaiNLP Documentation

    +

    + Latest development docs: + dev-docs +

    +

    Released versions

    + + + +""" + + +def _is_version_dir(name: str) -> bool: + """Return True if *name* looks like a version directory (e.g. ``5.3.1``).""" + return bool(re.match(r"^\d+\.\d+", name)) + + +def _version_key(version: str) -> tuple: + """Return a sort key for a version string.""" + parts = re.split(r"[.\-]", version) + key: list[int] = [] + for part in parts: + try: + key.append(int(part)) + except ValueError: + break + return tuple(key) + + +def _get_version_dirs(docs_dir: Path) -> list[str]: + """Return version directories in *docs_dir*, sorted newest-first.""" + versions = [ + p.name + for p in docs_dir.iterdir() + if p.is_dir() and _is_version_dir(p.name) + ] + versions.sort(key=_version_key, reverse=True) + return versions + + +def update_docs_index(docs_dir: Path) -> None: + """Generate or overwrite ``docs_dir/index.html`` listing all versions. + + :param docs_dir: Path to the versioned documentation repository root. + """ + versions = _get_version_dirs(docs_dir) + items = "\n".join( + f'
  • {v}
  • ' for v in versions + ) + content = _DOCS_INDEX_TMPL.format(items=items) + index_path = docs_dir / "index.html" + index_path.write_text(content, encoding="utf-8") + print(f"Updated {index_path}") + + +def update_dev_docs_index(index_path: Path, version: str) -> None: + """Inject or update a released-versions section in *index_path*. + + Looks for ```` / ```` markers. + If found, prepends *version* to the existing list (skips if already there). + If not found, appends a new section before ```` (or at end of file). + + :param index_path: Path to ``dev-docs/index.html``. + :param version: Version string without leading ``v`` (e.g. ``5.3.1``). + """ + content = index_path.read_text(encoding="utf-8") + new_item = _VERSION_ITEM_TMPL.format(v=version) + + if _VERSIONS_BEGIN in content and _VERSIONS_END in content: + begin = content.index(_VERSIONS_BEGIN) + end = content.index(_VERSIONS_END) + len(_VERSIONS_END) + section = content[begin:end] + + # Skip if this version is already listed. + if f"/{version}/" in section: + print(f"{index_path}: version {version} already present, skipping.") + return + + # Prepend the new item inside the existing