diff --git a/.github/workflows/sphinxbuild.yml b/.github/workflows/sphinxbuild.yml index 7fab1b919..2b5fc72d4 100644 --- a/.github/workflows/sphinxbuild.yml +++ b/.github/workflows/sphinxbuild.yml @@ -1,4 +1,4 @@ -name: "Pull Request Docs Check" +name: "Build documentation" on: pull_request: @@ -7,78 +7,266 @@ on: - master - stable* +permissions: + contents: read + jobs: - user_manual: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 - - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4 - with: - python-version: '3.12' - cache: 'pip' - - name: Install pip dependencies - run: pip install -r requirements.txt - - name: Build using Makefile - run: cd user_manual && make html - - name: Pack the results in local tar file - shell: bash - run: tar czf /tmp/documentation.tar.gz -C user_manual/_build/html . - - name: Upload static documentation - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: User manual.zip - path: "/tmp/documentation.tar.gz" + build: - user_manual-en: + name: Build ${{ matrix.manual.name }} runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 - - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4 - with: - python-version: '3.12' - - name: Install pip dependencies - run: pip install -r requirements.txt - - name: Build using Makefile - run: cd user_manual && make html-lang-en - developer_manual: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 - - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4 - with: - python-version: '3.12' - cache: 'pip' - - name: Install pip dependencies - run: pip install -r requirements.txt - - name: Build using Makefile - run: cd developer_manual && make html - - name: Pack the results in local tar file - shell: bash - run: tar czf /tmp/documentation.tar.gz -C developer_manual/_build/html/com . - - name: Upload static documentation - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 - with: - name: Developer manual.zip - path: "/tmp/documentation.tar.gz" + strategy: + matrix: + manual: + - name: "user_manual" + directory: "user_manual" + make_target: "html" + build_path: "_build/html" + build_pdf_path: "_build/latex" + publish: true + + - name: "user_manual-en" + directory: "user_manual" + make_target: "html-lang-en" + build_path: "_build/html" + publish: false + + - name: "developer_manual" + directory: "developer_manual" + make_target: "html" + build_path: "_build/html/com" + publish: true + + - name: "admin_manual" + directory: "admin_manual" + make_target: "html" + build_path: "_build/html/com" + build_pdf_path: "_build/latex" + publish: true - admin_manual: - runs-on: ubuntu-latest steps: - - uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 - - uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4 + - name: Cache git metadata + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: - python-version: '3.12' + path: .git + key: git-metadata-${{ github.sha }} + restore-keys: | + git-metadata-${{ github.sha }} + git-metadata + + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Configure apt cache to use /dev/shm + if: ${{ matrix.manual.build_pdf_path }} + run: | + mkdir -p /dev/shm/apt/cache/archives + echo 'Dir::Cache::archives "/dev/shm/apt/cache/archives";' | sudo tee /etc/apt/apt.conf.d/apt-cache-shm + + - name: Cache LaTeX apt packages + if: ${{ matrix.manual.build_pdf_path }} + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: /dev/shm/apt/cache/archives + key: latex-apt-${{ runner.os }}-${{ hashFiles('.github/workflows/sphinxbuild.yml') }} + restore-keys: | + latex-apt-${{ runner.os }}- + + - name: Install LaTeX dependencies + if: ${{ matrix.manual.build_pdf_path }} + run: | + sudo DEBIAN_FRONTEND=noninteractive apt-get update + sudo DEBIAN_FRONTEND=noninteractive apt-get install -y \ + --no-install-recommends \ + python3-pil \ + python3-pip \ + texlive-fonts-recommended \ + latexmk \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-xetex \ + texlive-fonts-extra-links \ + texlive-fonts-extra \ + xindy + + - name: Fix apt cache ownership for caching + if: ${{ matrix.manual.build_pdf_path }} + run: sudo chown -R $(id -u):$(id -g) /dev/shm/apt/cache/archives + + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.10' cache: 'pip' + - name: Install pip dependencies run: pip install -r requirements.txt - - name: Build using Makefile - run: cd admin_manual && make html - - name: Pack the results in local tar file - shell: bash - run: tar czf /tmp/documentation.tar.gz -C admin_manual/_build/html/com . + + - name: Build html documentation + run: cd ${{ matrix.manual.directory }} && make ${{ matrix.manual.make_target }} + + - name: Compute PDF release version + if: ${{ matrix.manual.build_pdf_path }} + id: pdf_version + run: | + branch="${GITHUB_REF#refs/heads/}" + if [[ "$branch" == stable* ]]; then + echo "release=${branch#stable}" >> $GITHUB_OUTPUT + else + echo "release=latest" >> $GITHUB_OUTPUT + fi + + - name: Build pdf documentation + if: ${{ matrix.manual.build_pdf_path }} + env: + DOCS_RELEASE: ${{ steps.pdf_version.outputs.release }} + run: | + set -e + cd ${{ matrix.manual.directory }} + make latexpdf + ls -la ${{ matrix.manual.build_pdf_path }} + cp ${{ matrix.manual.build_pdf_path }}/*.pdf ${{ matrix.manual.build_path }}/ + - name: Upload static documentation - uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 + if: ${{ matrix.manual.publish }} with: - name: Administration manual.zip - path: "/tmp/documentation.tar.gz" + name: ${{ matrix.manual.name }} + path: ${{ matrix.manual.directory }}/${{ matrix.manual.build_path }} + + deploy: + name: Deploy pages + needs: build + runs-on: ubuntu-latest + if: github.event_name == 'push' # Only deploy on push, not PR + + permissions: + contents: write + + steps: + - name: Cache git metadata + uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 + with: + path: .git + key: git-metadata-${{ github.sha }} + restore-keys: | + git-metadata-${{ github.sha }} + git-metadata + + - name: Checkout Github Pages branch + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + ref: gh-pages + fetch-depth: 0 + token: ${{ secrets.COMMAND_BOT_PAT }} + + - name: Download all ${{ needs.build.outputs.branch_name }} artifacts + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + path: artifacts/ + + - name: Get branch name and find latest stable + id: branch + run: | + current_branch="${GITHUB_REF#refs/heads/}" + + # Find the highest numbered stable branch from the remote + highest_stable=$(git ls-remote --heads origin | sed -n 's?.*refs/heads/stable\([0-9]\{2\}\)$?\1?p' | sort -n | tail -1) + highest_stable_branch="stable${highest_stable}" + + echo "Current branch: $current_branch" + echo "Highest stable branch found: $highest_stable_branch" + + # Map actual branch names to deployment folder names + case "$current_branch" in + "master") + echo "branch_name=latest" >> $GITHUB_OUTPUT + ;; + "$highest_stable_branch") + echo "branch_name=stable" >> $GITHUB_OUTPUT + # Also record the numeric version so we can publish to server// too + echo "version_name=${highest_stable}" >> $GITHUB_OUTPUT + ;; + *) + # Remove stable prefix for current branch + current_branch="${current_branch#stable}" + echo "branch_name=$current_branch" >> $GITHUB_OUTPUT + ;; + esac + + echo "Deployment folder name: ${{ steps.branch.outputs.branch_name }}" + echo "Version name for additional deployment (if applicable): ${{ steps.branch.outputs.version_name }}" + + - name: Merge ${{ steps.branch.outputs.branch_name }} documentation artifacts into gh-pages + run: | + # List artifacts + ls -la artifacts/*/ + + # Cleanup old documentation + rm -rf ${{ steps.branch.outputs.branch_name }} + rm -rf server/${{ steps.branch.outputs.branch_name }} + mkdir -p server/${{ steps.branch.outputs.branch_name }} + + # Copy all built documentation into dedicated subdirectories + for artifact in artifacts/*; do + if [ -d "$artifact" ]; then + manual_name="$(basename "$artifact")" + mkdir -p "server/${{ steps.branch.outputs.branch_name }}/$manual_name" + cp -r "$artifact/"* "server/${{ steps.branch.outputs.branch_name }}/$manual_name/" + fi + done + + # Move pdf files to the root of the branch_name + mv server/${{ steps.branch.outputs.branch_name }}/*/*.pdf server/${{ steps.branch.outputs.branch_name }}/ || true + + # If this is the highest stable branch, also deploy to its versioned folder + if [ -n "${{ steps.branch.outputs.version_name }}" ]; then + rm -rf server/${{ steps.branch.outputs.version_name }} + cp -r server/${{ steps.branch.outputs.branch_name }} server/${{ steps.branch.outputs.version_name }} + fi + + # Cleanup + find . -type d -empty -delete + rm -rf artifacts + + - name: Add various redirects for go.php and user_manual english version + run: | + # Fetch source branches so git checkout origin/... works from the gh-pages checkout + git fetch origin ${{ github.event.repository.default_branch }} ${{ github.ref_name }} + + # Generate go.php redirect from main branch + git checkout origin/${{ github.event.repository.default_branch }} -- go.php/index.html + mkdir -p server/${{ steps.branch.outputs.branch_name }}/go.php + mv go.php/index.html server/${{ steps.branch.outputs.branch_name }}/go.php/index.html + + # Generate user_manual english redirect + git checkout origin/${{ github.ref_name }} -- user_manual/index.html + mkdir -p server/${{ steps.branch.outputs.branch_name }}/user_manual + mv user_manual/index.html server/${{ steps.branch.outputs.branch_name }}/user_manual/index.html + + - name: Commit ${{ steps.branch.outputs.branch_name }} documentation and push to gh-pages + run: | + git config --local user.email "nextcloud-command@users.noreply.github.com" + git config --local user.name "nextcloud-command" + git add . + git diff --staged --quiet || git commit -m "chore: deploy documentation for ${{ steps.branch.outputs.branch_name }}" + # Ensure we are up to date with the remote gh-pages branch + git pull --rebase origin gh-pages || true + git push origin gh-pages || echo "Nothing to push (expected if no changes)" + env: + GH_TOKEN: ${{ secrets.COMMAND_BOT_PAT }} + + summary: + needs: build + runs-on: ubuntu-latest + if: always() + + permissions: + contents: read + + name: build-deploy-summary + + steps: + # Only check if the build was successful + - name: Summary status + run: if ${{ needs.build.result != 'success' }}; then exit 1; fi