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 ;;
