Deploy Jekyll site to Pages with node.js #203
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
| # This workflow uses actions that are not certified by GitHub. | |
| # They are provided by a third-party and are governed by | |
| # separate terms of service, privacy policy, and support | |
| # documentation. | |
| name: Deploy Jekyll site to Pages with node.js | |
| on: | |
| # Runs on pushes targeting the default branch | |
| push: | |
| branches: ["master"] | |
| # Daily rebuild at 14:00 Asia/Tbilisi (UTC+4) | |
| schedule: | |
| - cron: '0 10 * * *' | |
| # Manual rebuild from Actions UI | |
| workflow_dispatch: | |
| inputs: | |
| submit_all_posts: | |
| description: Submit all post URLs to IndexNow | |
| type: boolean | |
| default: false | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | |
| INDEXNOW_KEY: 981d750614024cc991d7768d5e500d5c | |
| INDEXNOW_HOST: eugenetheengineer.com | |
| SITE_URL: https://eugenetheengineer.com | |
| # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages | |
| permissions: | |
| contents: read | |
| pages: write | |
| id-token: write | |
| # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. | |
| # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. | |
| concurrency: | |
| group: "pages" | |
| cancel-in-progress: false | |
| jobs: | |
| # Build job | |
| build: | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| - name: Setup Ruby | |
| uses: ruby/setup-ruby@v1 | |
| with: | |
| ruby-version: '3.3.8' # Not needed with a .ruby-version file | |
| bundler-cache: true # runs 'bundle install' and caches installed gems automatically | |
| cache-version: 0 # Increment this number if you need to re-download cached gems | |
| - name: Setup Pages | |
| id: pages | |
| uses: actions/configure-pages@v6 | |
| - name: install node.js | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24.14.1 | |
| - name: Install JS dependencies | |
| run: npm ci | |
| - name: Build JS assets | |
| run: npm run build | |
| - name: Build with Jekyll | |
| # Outputs to the './_site' directory by default | |
| run: bundle exec jekyll build --baseurl "${{ steps.pages.outputs.base_path }}" | |
| env: | |
| JEKYLL_ENV: production | |
| - name: Upload artifact | |
| # Automatically uploads an artifact from the './_site' directory by default | |
| uses: actions/upload-pages-artifact@v4 | |
| # Deployment job | |
| deploy: | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| runs-on: ubuntu-24.04 | |
| needs: build | |
| steps: | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v5 | |
| indexnow: | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| runs-on: ubuntu-24.04 | |
| needs: deploy | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 2 | |
| - name: Submit URLs to IndexNow | |
| env: | |
| SUBMIT_ALL: ${{ github.event_name == 'workflow_dispatch' && inputs.submit_all_posts || 'false' }} | |
| run: | | |
| set -euo pipefail | |
| post_to_url() { | |
| local file="$1" | |
| local slug | |
| slug=$(basename "$file" .md | sed -E 's/^[0-9]{4}-[0-9]{2}-[0-9]{2}-//') | |
| echo "${SITE_URL}/posts/${slug}/" | |
| } | |
| post_is_published() { | |
| local file="$1" | |
| local post_date_line post_epoch now_epoch file_date | |
| post_date_line=$(grep -m1 '^date:' "$file" 2>/dev/null | sed -E 's/^date:[[:space:]]*//' || true) | |
| if [ -n "$post_date_line" ]; then | |
| post_epoch=$(date -u -d "$post_date_line" +%s 2>/dev/null || echo "") | |
| fi | |
| if [ -z "${post_epoch:-}" ]; then | |
| file_date=$(basename "$file" .md | grep -oE '^[0-9]{4}-[0-9]{2}-[0-9]{2}' || true) | |
| [ -n "$file_date" ] || return 1 | |
| post_epoch=$(date -u -d "${file_date} 00:00:00" +%s) | |
| fi | |
| now_epoch=$(date -u +%s) | |
| [ "$post_epoch" -le "$now_epoch" ] | |
| } | |
| mapfile -t POST_FILES < <( | |
| if [ "$SUBMIT_ALL" = "true" ]; then | |
| find _posts -maxdepth 1 -name '*.md' -type f | sort | |
| else | |
| git diff --name-only --diff-filter=AM HEAD~1 HEAD -- '_posts/*.md' || true | |
| fi | |
| ) | |
| if [ "${#POST_FILES[@]}" -eq 0 ] || [ -z "${POST_FILES[0]:-}" ]; then | |
| echo "No post URLs to submit to IndexNow." | |
| exit 0 | |
| fi | |
| URLS=() | |
| for file in "${POST_FILES[@]}"; do | |
| [ -f "$file" ] || continue | |
| if ! post_is_published "$file"; then | |
| echo "Skipping unpublished (future-dated) post: $file" | |
| continue | |
| fi | |
| URLS+=("$(post_to_url "$file")") | |
| done | |
| if [ "${#URLS[@]}" -eq 0 ]; then | |
| echo "No valid post URLs to submit to IndexNow." | |
| exit 0 | |
| fi | |
| echo "Submitting ${#URLS[@]} URL(s) to IndexNow:" | |
| printf ' %s\n' "${URLS[@]}" | |
| URLS_JSON=$(printf '%s\n' "${URLS[@]}" | jq -R . | jq -s .) | |
| KEY_LOCATION="${SITE_URL}/${INDEXNOW_KEY}.txt" | |
| PAYLOAD=$(jq -n \ | |
| --arg host "$INDEXNOW_HOST" \ | |
| --arg key "$INDEXNOW_KEY" \ | |
| --arg keyLocation "$KEY_LOCATION" \ | |
| --argjson urlList "$URLS_JSON" \ | |
| '{host: $host, key: $key, keyLocation: $keyLocation, urlList: $urlList}') | |
| HTTP_CODE=$(curl -sS -o /tmp/indexnow-response.txt -w "%{http_code}" \ | |
| -X POST "https://api.indexnow.org/indexnow" \ | |
| -H "Content-Type: application/json; charset=utf-8" \ | |
| -d "$PAYLOAD") | |
| echo "IndexNow response (${HTTP_CODE}):" | |
| cat /tmp/indexnow-response.txt | |
| echo | |
| case "$HTTP_CODE" in | |
| 200|202) | |
| echo "IndexNow submission accepted." | |
| ;; | |
| *) | |
| echo "IndexNow submission failed with HTTP ${HTTP_CODE}." | |
| exit 1 | |
| ;; | |
| esac |