Deploy NoteNextra to GitHub Pages #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy NoteNextra to GitHub Pages | |
| on: | |
| push: | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| full_rebuild: | |
| description: Rebuild all microsites with distribute | |
| required: false | |
| default: false | |
| type: boolean | |
| permissions: | |
| contents: write | |
| env: | |
| SITE_URL: 'https://notenetra.trance-0.com' | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: 'true' | |
| jobs: | |
| detect: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| matrix: ${{ steps.collect.outputs.matrix }} | |
| any_changed: ${{ steps.collect.outputs.any_changed }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - id: collect | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| mapfile -t modules < <(find content -mindepth 1 -maxdepth 1 -type d | sed 's#^content/##' | sort) | |
| if [[ ${#modules[@]} -eq 0 ]]; then | |
| echo 'matrix={"include":[]}' >> "$GITHUB_OUTPUT" | |
| echo 'any_changed=false' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.full_rebuild }}" == "true" ]]; then | |
| selected=("${modules[@]}") | |
| else | |
| before='${{ github.event.before }}' | |
| head='${{ github.sha }}' | |
| if [[ -z "$before" || "$before" == "0000000000000000000000000000000000000000" ]]; then | |
| before=$(git rev-list --max-count=1 HEAD^ 2>/dev/null || true) | |
| fi | |
| if [[ -z "$before" ]]; then | |
| changed_files=$(git ls-files) | |
| else | |
| changed_files=$(git diff --name-only "$before" "$head") | |
| fi | |
| shared_changed=false | |
| selected=() | |
| while IFS= read -r file; do | |
| [[ -z "$file" ]] && continue | |
| case "$file" in | |
| content/index*|content/about*|content/contact*|content/_meta.js|app/*|app/**|components/*|components/**|scripts/*|scripts/**|distribute/*|distribute/**|public/*|public/**|package.json|package-lock.json|next.config.mjs|mdx-components.js) | |
| shared_changed=true | |
| ;; | |
| esac | |
| if [[ "$file" == content/*/* || "$file" == public/*/* ]]; then | |
| module=$(printf '%s' "$file" | cut -d/ -f2) | |
| if [[ -n "$module" && -d "content/$module" ]]; then | |
| selected+=("$module") | |
| fi | |
| fi | |
| done <<< "$changed_files" | |
| if [[ "$shared_changed" == true ]]; then | |
| selected=("${modules[@]}") | |
| fi | |
| fi | |
| if [[ ${#selected[@]} -eq 0 ]]; then | |
| echo 'matrix={"include":[]}' >> "$GITHUB_OUTPUT" | |
| echo 'any_changed=false' >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| mapfile -t unique_selected < <(printf '%s\n' "${selected[@]}" | awk 'NF && !seen[$0]++') | |
| json='{"include":[' | |
| first=true | |
| for module in "${unique_selected[@]}"; do | |
| if [[ "$first" == true ]]; then | |
| first=false | |
| else | |
| json+=',' | |
| fi | |
| json+="{\"module\":\"$module\"}" | |
| done | |
| json+=']}' | |
| echo 'any_changed=true' >> "$GITHUB_OUTPUT" | |
| echo "matrix=$json" >> "$GITHUB_OUTPUT" | |
| build_modules: | |
| needs: detect | |
| if: needs.detect.outputs.any_changed == 'true' | |
| runs-on: ubuntu-latest | |
| strategy: | |
| fail-fast: false | |
| max-parallel: 1 | |
| matrix: ${{ fromJson(needs.detect.outputs.matrix) }} | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Check runner node | |
| run: | | |
| node --version | |
| npm --version | |
| - run: npm install --no-audit --no-fund | |
| - name: Build module export with distribute | |
| env: | |
| KEEP_PAGES: ${{ matrix.module }} | |
| BASE_PATH: | |
| run: | | |
| npm run build:distribute | |
| mkdir -p module-dist/${{ matrix.module }}/site | |
| cp -a out/. module-dist/${{ matrix.module }}/site/ | |
| - uses: actions/upload-artifact@v5 | |
| with: | |
| name: pages-${{ matrix.module }} | |
| path: module-dist/${{ matrix.module }} | |
| if-no-files-found: error | |
| deploy: | |
| needs: [detect, build_modules] | |
| if: always() && needs.detect.result == 'success' && (needs.build_modules.result == 'success' || needs.build_modules.result == 'skipped') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Check runner node | |
| run: | | |
| node --version | |
| npm --version | |
| - name: Prepare gh-pages working tree | |
| shell: bash | |
| run: | | |
| mkdir -p deploy | |
| if git ls-remote --exit-code --heads origin gh-pages >/dev/null 2>&1; then | |
| git fetch origin gh-pages:gh-pages | |
| git worktree add deploy gh-pages | |
| else | |
| git worktree add --orphan deploy | |
| cd deploy | |
| git rm -rf . >/dev/null 2>&1 || true | |
| touch .nojekyll | |
| fi | |
| - uses: actions/download-artifact@v5 | |
| if: needs.detect.outputs.any_changed == 'true' | |
| with: | |
| pattern: pages-* | |
| path: artifacts | |
| merge-multiple: false | |
| - name: Overlay rebuilt module directories and shared shell | |
| if: needs.detect.outputs.any_changed == 'true' | |
| shell: bash | |
| run: | | |
| shopt -s nullglob | |
| mapfile -t modules < <(find content -mindepth 1 -maxdepth 1 -type d | sed 's#^content/##' | sort) | |
| shared_synced=false | |
| for artifact in artifacts/pages-*; do | |
| module=$(basename "$artifact" | sed 's/^pages-//') | |
| mkdir -p "deploy/$module" | |
| find "deploy/$module" -mindepth 1 -maxdepth 1 -exec rm -rf {} + || true | |
| cp -a "$artifact/site/$module/." "deploy/$module/" | |
| if [[ "$shared_synced" == false ]]; then | |
| for item in deploy/*; do | |
| name=$(basename "$item") | |
| if [[ "$name" == ".git" ]]; then | |
| continue | |
| fi | |
| keep=false | |
| for module_name in "${modules[@]}"; do | |
| if [[ "$name" == "$module_name" ]]; then | |
| keep=true | |
| break | |
| fi | |
| done | |
| if [[ "$keep" == false ]]; then | |
| rm -rf "$item" | |
| fi | |
| done | |
| for item in "$artifact"/site/*; do | |
| name=$(basename "$item") | |
| skip=false | |
| for module_name in "${modules[@]}"; do | |
| if [[ "$name" == "$module_name" ]]; then | |
| skip=true | |
| break | |
| fi | |
| done | |
| if [[ "$skip" == false ]]; then | |
| cp -a "$item" deploy/ | |
| fi | |
| done | |
| shared_synced=true | |
| fi | |
| done | |
| touch deploy/.nojekyll | |
| - name: Refresh Pagefind across deployed tree | |
| if: needs.detect.outputs.any_changed == 'true' | |
| run: npx --yes pagefind --site deploy --output-path deploy/_pagefind | |
| - name: Commit and push gh-pages | |
| shell: bash | |
| run: | | |
| cd deploy | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add -A | |
| if git diff --cached --quiet; then | |
| echo "No deploy changes to commit" | |
| exit 0 | |
| fi | |
| git commit -m "Deploy GitHub Pages for ${GITHUB_SHA::7}" | |
| git push origin HEAD:gh-pages |