This is an automated email from the ASF dual-hosted git repository.

meonkeys pushed a commit to branch asf-site
in repository https://gitbox.apache.org/repos/asf/fineract-site.git

commit bb2276d2565e33293b6414d3bc9424c3c151d5d5
Author: Adam Monsen <[email protected]>
AuthorDate: Tue Jul 14 13:04:31 2026 -0700

    automate /docs/VERSION updates
    
    Coded by Claude (model=Sonnet 5, effort=High).
    
    I reviewed and tested this.
---
 README.md                |  33 +++++++++++
 scripts/generate_docs.py | 145 +++++++++++++++++++++++++++++++++++++++++++++++
 scripts/site-tool.sh     |  10 +++-
 3 files changed, 187 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 58b811a..45894e4 100644
--- a/README.md
+++ b/README.md
@@ -54,6 +54,39 @@ docker run --rm -v "${PWD}:/src" -w /src/site-src 
fineract-site build
 docker run --rm -it -p 1313:1313 -v "${PWD}:/src" -w /src/site-src 
fineract-site serve
 ```
 
+## Updating `/docs/VERSION` from a Fineract backend clone
+
+`docs/VERSION` (e.g. `docs/1.16.0-SNAPSHOT`) holds the rendered Fineract API
+documentation built from the 
[apache/fineract](https://github.com/apache/fineract)
+backend. To refresh it:
+
+1. In your clone of `apache/fineract`, generate the docs:
+
+   ```bash
+   ./gradlew asciidoctor
+   ```
+
+   Make sure the clone's working tree is clean (`git status`) — the commit hash
+   is recorded so the copied doc can be traced back to the exact source commit.
+
+2. Run the `docs` command in the site tool image, mounting both repos:
+
+   ```bash
+   docker run --rm -u "$(id -u):$(id -g)" \
+     -v "$PWD:/src" \
+     -v /path/to/fineract:/fineract:ro \
+     -w /src \
+     fineract-site docs --version 1.16.0-SNAPSHOT
+   ```
+
+   The version can also be set via `FINERACT_DOC_VERSION`, and the backend
+   mount path via `FINERACT_REPO_DIR` (default `/fineract`).
+
+This copies `fineract-doc/build/docs/html/en/index.html` from the backend clone
+into `docs/VERSION/index.html`, then rewrites the Google Fonts and Font Awesome
+CDN links to point at the site's local `css/` stylesheets. Versions ending in
+`-SNAPSHOT` are overwritten; released versions are not.
+
 ## Verifying ASF project website compliance
 
 Apache Whimsy periodically checks that the public homepage follows ASF 
conventions.
diff --git a/scripts/generate_docs.py b/scripts/generate_docs.py
new file mode 100644
index 0000000..3ffb3f9
--- /dev/null
+++ b/scripts/generate_docs.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+#   https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+"""Copy generated Fineract API docs from a backend clone into docs/VERSION.
+
+Assumes the backend (apache/fineract) has already been built with
+`./gradlew asciidoctor` and is available at --backend-dir (or
+$FINERACT_REPO_DIR), e.g. mounted as a Docker volume.
+"""
+
+import argparse
+import os
+import shutil
+import subprocess
+import sys
+from pathlib import Path
+
+REPO_ROOT = Path(__file__).resolve().parent.parent
+DEFAULT_BACKEND_DIR = "/fineract"
+DOC_HTML_RELATIVE_PATH = Path("fineract-doc/build/docs/html/en/index.html")
+
+# Same substitution made by hand in commits like 
e70425660b42fc705760006141078e870df0a566.
+GOOGLE_FONTS_LINK = (
+    '<link rel="stylesheet" href="https://fonts.googleapis.com/css?family='
+    "Open+Sans:300,300italic,400,400italic,600,600italic%7CNoto+Serif:400,"
+    '400italic,700,700italic%7CDroid+Sans+Mono:400,700">'
+)
+LOCAL_STYLESHEET_LINK = '<link rel="stylesheet" 
href="../../css/stylesheet.css">'
+FONT_AWESOME_CDN_LINK = (
+    '<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/'
+    'font-awesome/4.7.0/css/font-awesome.min.css">'
+)
+FONT_AWESOME_LOCAL_LINK = '<link rel="stylesheet" 
href="../../css/font-awesome.min.css">'
+
+
+def parse_args():
+    parser = argparse.ArgumentParser(description=__doc__)
+    parser.add_argument(
+        "--version",
+        default=os.environ.get("FINERACT_DOC_VERSION"),
+        help="Doc version folder to write, e.g. 1.16.0-SNAPSHOT "
+        "(default: $FINERACT_DOC_VERSION)",
+    )
+    parser.add_argument(
+        "--backend-dir",
+        default=os.environ.get("FINERACT_REPO_DIR", DEFAULT_BACKEND_DIR),
+        help="Path to the apache/fineract clone "
+        f"(default: $FINERACT_REPO_DIR or {DEFAULT_BACKEND_DIR})",
+    )
+    args = parser.parse_args()
+    if not args.version:
+        parser.error("a version is required: pass --version or set 
FINERACT_DOC_VERSION")
+    return args
+
+
+def run_git(backend_dir, *git_args):
+    return subprocess.run(
+        ["git", "-C", str(backend_dir), *git_args],
+        check=True,
+        capture_output=True,
+        text=True,
+    )
+
+
+def require_clean_git_status(backend_dir):
+    result = run_git(backend_dir, "status", "--porcelain")
+    if result.stdout.strip():
+        sys.exit(
+            f"Backend clone at {backend_dir} is not clean (git status 
--porcelain "
+            "reported changes). Commit or stash them so the copied doc can be "
+            f"traced back to an exact commit:\n{result.stdout}"
+        )
+
+
+def get_commit_hash(backend_dir):
+    return run_git(backend_dir, "rev-parse", "HEAD").stdout.strip()
+
+
+def localize_stylesheets(html_path):
+    text = html_path.read_text(encoding="utf-8")
+    text = text.replace(GOOGLE_FONTS_LINK, LOCAL_STYLESHEET_LINK)
+    text = text.replace(FONT_AWESOME_CDN_LINK, FONT_AWESOME_LOCAL_LINK)
+    if not text.endswith("\n"):
+        text += "\n"
+    html_path.write_text(text, encoding="utf-8")
+
+
+def main():
+    args = parse_args()
+    backend_dir = Path(args.backend_dir)
+
+    if not backend_dir.is_dir():
+        sys.exit(f"Backend directory not found: {backend_dir}")
+
+    source_html = backend_dir / DOC_HTML_RELATIVE_PATH
+    if not source_html.is_file():
+        sys.exit(
+            f"{source_html} not found. Generate it first by running "
+            "'./gradlew asciidoctor' in the backend clone."
+        )
+
+    require_clean_git_status(backend_dir)
+    commit_hash = get_commit_hash(backend_dir)
+    print(f"Backend commit: {commit_hash}")
+
+    github_output = os.environ.get("GITHUB_OUTPUT")
+    if github_output:
+        with open(github_output, "a", encoding="utf-8") as f:
+            f.write(f"fineract_commit={commit_hash}\n")
+
+    dest_dir = REPO_ROOT / "docs" / args.version
+    dest_html = dest_dir / "index.html"
+    is_snapshot = args.version.endswith("-SNAPSHOT")
+
+    if dest_html.exists() and not is_snapshot:
+        sys.exit(
+            f"{dest_html} already exists and {args.version} is not a -SNAPSHOT 
"
+            "version. Refusing to overwrite a released doc."
+        )
+
+    dest_dir.mkdir(parents=True, exist_ok=True)
+    shutil.copy2(source_html, dest_html)
+    localize_stylesheets(dest_html)
+
+    print(f"Wrote {dest_html}")
+
+
+if __name__ == "__main__":
+    main()
diff --git a/scripts/site-tool.sh b/scripts/site-tool.sh
index 139e99d..f821c33 100644
--- a/scripts/site-tool.sh
+++ b/scripts/site-tool.sh
@@ -3,11 +3,12 @@ set -euo pipefail
 
 usage() {
   cat <<'EOF'
-Usage: site-tool <build|check|serve|shell> [args...]
+Usage: site-tool <build|check|docs|serve|shell> [args...]
 
 Commands:
   build  Build site into /src/.build/site and run checks
   check  Run internal link check against /src/.build/site
+  docs   Copy generated Fineract API docs into /src/docs/VERSION
   test   Run unit tests for whimsy checks
   serve  Run hugo server on port 1313
   shell  Open an interactive shell
@@ -52,6 +53,10 @@ run_tests() {
   ruby "${REPO_ROOT}/scripts/test_run_whimsy_checks.rb"
 }
 
+generate_docs() {
+  python3 "${REPO_ROOT}/scripts/generate_docs.py" "$@"
+}
+
 serve_site() {
   cd "${SITE_SRC_DIR}"
   hugo server --bind 0.0.0.0 --baseURL "http://localhost:1313"; --buildDrafts 
--disableFastRender "$@"
@@ -75,6 +80,9 @@ main() {
     check)
       run_checks
       ;;
+    docs)
+      generate_docs "$@"
+      ;;
     test)
       run_tests
       ;;

Reply via email to