diff --git a/.github/workflows/docs-preview.yml b/.github/workflows/docs-preview.yml new file mode 100644 index 00000000..e8ed7759 --- /dev/null +++ b/.github/workflows/docs-preview.yml @@ -0,0 +1,71 @@ +name: Docs Preview Deploy + +# Runs after the "Docs" workflow completes. Because workflow_run runs in +# the base-repo context, it has a writable GITHUB_TOKEN even when the +# originating run was a fork PR. This lets us deploy a /pr// +# preview for any PR without giving PR-controlled code access to secrets. +on: + workflow_run: + workflows: ["Docs"] + types: [completed] + +permissions: + actions: read # download the artifact from the triggering Docs run + contents: write # push the preview to gh-pages + pull-requests: write # comment the preview URL on the PR + +concurrency: + group: "docs-preview-${{ github.event.workflow_run.head_repository.full_name }}-${{ github.event.workflow_run.head_branch }}" + cancel-in-progress: true + +jobs: + deploy: + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-latest + steps: + - name: Download preview artifact + uses: actions/download-artifact@v4 + with: + name: docs-preview + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + # The artifact comes from a run on PR-controlled code (possibly a fork), + # so pr/NR must be treated as untrusted input. We only accept a plain + # positive integer to prevent script/path injection. + - name: Read PR number + id: pr + run: | + raw=$(tr -d '[:space:]' < pr/NR) + if [[ ! "$raw" =~ ^[1-9][0-9]*$ ]]; then + echo "::error::Invalid PR number in artifact: '$raw'" + exit 1 + fi + echo "number=$raw" >> "$GITHUB_OUTPUT" + + - name: Deploy PR preview to gh-pages + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site + destination_dir: "pr/${{ steps.pr.outputs.number }}" + keep_files: true + + # Pass the PR number through env rather than ${{ }} interpolation so no + # attacker-controlled text can be expanded into the inline script body. + - name: Comment PR with preview URL + uses: actions/github-script@v9 + env: + PR_NUMBER: ${{ steps.pr.outputs.number }} + with: + script: | + const prNumber = Number(process.env.PR_NUMBER); + const url = `https://hiero-ledger.github.io/hiero-enterprise-java/pr/${prNumber}/`; + await github.rest.issues.createComment({ + issue_number: prNumber, + owner: context.repo.owner, + repo: context.repo.repo, + body: `📖 **Docs preview** for this PR: ${url}` + }); diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c37d3683..addaad1a 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,102 +7,79 @@ on: - "docs/**" - "mkdocs.yml" - ".github/workflows/docs.yml" + - ".github/workflows/docs-preview.yml" pull_request: branches: [main] paths: - "docs/**" - "mkdocs.yml" - ".github/workflows/docs.yml" + - ".github/workflows/docs-preview.yml" workflow_dispatch: permissions: - contents: write - pull-requests: write + contents: read concurrency: - group: "pages-${{ github.ref }}" + group: "docs-${{ github.ref }}" cancel-in-progress: true jobs: deploy-production: if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest + permissions: + contents: write steps: - uses: actions/checkout@v6 - - name: Configure Git Credentials - run: | - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - uses: actions/setup-python@v6 with: python-version: "3.x" - - name: Set cache date - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV + - name: Install docs dependencies + run: pip install zensical==0.0.36 - - uses: actions/cache@v5 - with: - key: mkdocs-material-${{ env.cache_id }} - path: ~/.cache - restore-keys: | - mkdocs-material- - - - name: Install MkDocs and Material - run: pip install mkdocs-material "pymdown-extensions" + - name: Build site + run: zensical build --clean - name: Deploy to GitHub Pages - run: mkdocs gh-deploy --force + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./site - # PR preview: build and deploy to .../pr// - deploy-preview: + # PR preview: build only, upload the site as an artifact. + # The deploy to gh-pages/pr// runs in docs-preview.yml via + # workflow_run, so fork PRs can also get a preview without granting + # write access to PR-controlled code. + build-preview: if: github.event_name == 'pull_request' runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - name: Configure Git Credentials - run: | - git config user.name github-actions[bot] - git config user.email 41898282+github-actions[bot]@users.noreply.github.com - - uses: actions/setup-python@v6 with: python-version: "3.x" - - name: Set cache date - run: echo "cache_id=$(date --utc '+%V')" >> $GITHUB_ENV - - - uses: actions/cache@v5 - with: - key: mkdocs-material-${{ env.cache_id }} - path: ~/.cache - restore-keys: | - mkdocs-material- - - - name: Install MkDocs and Material - run: pip install mkdocs-material "pymdown-extensions" + - name: Install docs dependencies + run: pip install zensical==0.0.36 - name: Build site - run: mkdocs build --strict + run: zensical build --clean - - name: Deploy PR preview to gh-pages - uses: peaceiris/actions-gh-pages@v4 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./site - destination_dir: "pr/${{ github.event.pull_request.number }}" - keep_files: true + - name: Save PR metadata + run: | + mkdir -p pr + echo "${{ github.event.pull_request.number }}" > pr/NR - - name: Comment PR with preview URL - uses: actions/github-script@v9 + - name: Upload preview artifact + uses: actions/upload-artifact@v4 with: - script: | - const url = `https://hiero-ledger.github.io/hiero-enterprise-java/pr/${{ github.event.pull_request.number }}/`; - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: `📖 **Docs preview** for this PR: ${url}` - }); + name: docs-preview + path: | + site + pr + if-no-files-found: error + retention-days: 7 diff --git a/docs/assets/favicon.ico b/docs/assets/favicon.ico index 255a5cc3..8428b4a0 100644 Binary files a/docs/assets/favicon.ico and b/docs/assets/favicon.ico differ diff --git a/docs/contributing.md b/docs/contributing.md index ac6688b1..633e9b18 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -11,24 +11,27 @@ This folder contains the source for the [Hiero Enterprise Java technical documen - **`microprofile.md`** — MicroProfile integration. - **`managed-services.md`** — Base module and managed services. -The site is built with [MkDocs](https://www.mkdocs.org/) and the [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) theme. Configuration is in the repository root: `mkdocs.yml`. +The site is built with [Zensical](https://zensical.org/docs/get-started/) using the repository root `mkdocs.yml` for configuration. ## Building locally From the repository root: ```bash -pip install mkdocs-material "pymdown-extensions" -mkdocs serve +pip install zensical==0.0.36 +zensical serve ``` Then open http://127.0.0.1:8000 . ## Publishing -The `.github/workflows/docs.yml` workflow: +Two workflows drive publication: -- **Push to `main`:** Builds and deploys the site to the production URL (root). -- **Pull request:** Builds and deploys a preview to `/pr//` and comments the preview URL on the PR. +- **`.github/workflows/docs.yml`** + - **Push to `main`:** builds the site with `zensical build --clean` and publishes it to the GitHub Pages root. + - **Pull request:** builds the site and uploads it (together with the PR number) as a `docs-preview` artifact. No deploy happens here, so this step is safe for PRs coming from forks. +- **`.github/workflows/docs-preview.yml`** + - Triggered by the `Docs` workflow completing. It downloads the `docs-preview` artifact, deploys it to `gh-pages/pr//`, and comments the preview URL on the PR. Because it runs in the base-repo context, fork PRs also get a preview. Ensure **GitHub Pages** is enabled and set the source to **Deploy from a branch** → branch: `gh-pages`, folder: `/ (root)`. diff --git a/mkdocs.yml b/mkdocs.yml index 783cb8bc..5420600a 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -8,6 +8,7 @@ repo_url: https://github.com/hiero-ledger/hiero-enterprise-java theme: name: material + variant: classic favicon: assets/favicon.ico logo: assets/logo.svg icon: