Build and Deploy Blog #354
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: Build and Deploy Blog | |
| on: | |
| push: | |
| branches: [main] # rebuild whenever a PR merges (or any push to main) | |
| issues: | |
| types: [opened, edited, deleted, labeled, unlabeled, reopened, closed] | |
| issue_comment: | |
| types: [created, edited, deleted] | |
| schedule: | |
| - cron: '0 5,17 * * *' # twice daily | |
| workflow_dispatch: # manual trigger | |
| permissions: | |
| contents: read | |
| issues: read | |
| pages: write | |
| id-token: write | |
| jobs: | |
| build-and-deploy: | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: github-pages | |
| url: ${{ steps.deployment.outputs.page_url }} | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/setup-python@v6 | |
| with: | |
| python-version: '3.11' | |
| - run: pip install -r requirements.txt | |
| - name: Restore YouTube cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: _cache/youtube.json | |
| key: youtube-cache-${{ github.run_id }} | |
| restore-keys: | | |
| youtube-cache- | |
| - name: Detect GitHub Pages domain | |
| id: pages-domain | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| REPO: ${{ github.repository }} | |
| run: | | |
| repo_name="${REPO##*/}" | |
| cname="$(gh api "repos/${REPO}/pages" --jq '.cname // ""' 2>/dev/null || true)" | |
| if [ -n "$cname" ]; then | |
| echo "base_path=/" >> "$GITHUB_OUTPUT" | |
| echo "custom_domain=$cname" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "base_path=/${repo_name}/" >> "$GITHUB_OUTPUT" | |
| echo "custom_domain=" >> "$GITHUB_OUTPUT" | |
| fi | |
| # ------------------------------------------------------------------ | |
| # Fetch stages — each runs independently. | |
| # continue-on-error: true means a transient API failure (e.g. YouTube | |
| # RSS 404) turns the step yellow but does NOT stop the workflow. | |
| # Any ::warning:: annotations emitted here appear in the Actions UI. | |
| # ------------------------------------------------------------------ | |
| - name: "Stage 01 — Fetch GitHub profile" | |
| continue-on-error: true | |
| run: python blog/01_fetch_profile.py | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| YOUTUBE_CHANNEL_IDS: ${{ vars.YOUTUBE_CHANNEL_IDS }} | |
| HN_USERNAME: ${{ vars.HN_USERNAME }} | |
| - name: "Stage 02 — Fetch GitHub Issues (My Writing)" | |
| continue-on-error: true | |
| run: python blog/02_fetch_issues.py | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| - name: "Stage 03 — Fetch YouTube (My Watching)" | |
| continue-on-error: true | |
| run: python blog/03_fetch_youtube.py | |
| env: | |
| YOUTUBE_PLAYLIST_IDS: ${{ vars.YOUTUBE_PLAYLIST_IDS }} | |
| YOUTUBE_CHANNEL_IDS: ${{ vars.YOUTUBE_CHANNEL_IDS }} | |
| - name: "Stage 04 — Fetch Hacker News (My Reading)" | |
| continue-on-error: true | |
| run: python blog/04_fetch_hn.py | |
| env: | |
| HN_USERNAME: ${{ vars.HN_USERNAME }} | |
| - name: "Stage 06 — Fetch GitHub Contributions" | |
| continue-on-error: true | |
| run: python blog/06_fetch_contributions.py | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_CONTRIBUTIONS_USER: ${{ vars.GITHUB_CONTRIBUTIONS_USER }} | |
| GITHUB_CONTRIBUTIONS_LIMIT: ${{ vars.GITHUB_CONTRIBUTIONS_LIMIT }} | |
| # ------------------------------------------------------------------ | |
| # Render — reads all four cache files and writes _site/. | |
| # Warnings from every fetch stage appear in the generated HTML footer. | |
| # ------------------------------------------------------------------ | |
| - name: "Stage 05 — Render HTML" | |
| run: python blog/05_render.py | |
| env: | |
| GITHUB_REPOSITORY: ${{ github.repository }} | |
| GITHUB_RUN_ID: ${{ github.run_id }} | |
| BASE_PATH: ${{ steps.pages-domain.outputs.base_path }} | |
| YOUTUBE_PLAYLIST_IDS: ${{ vars.YOUTUBE_PLAYLIST_IDS }} | |
| FEED_SOURCES: ${{ vars.FEED_SOURCES }} | |
| BLOG_CONFIGURED: ${{ vars.BLOG_CONFIGURED }} | |
| - name: Add custom domain | |
| if: ${{ steps.pages-domain.outputs.custom_domain != '' }} | |
| run: printf '%s\n' '${{ steps.pages-domain.outputs.custom_domain }}' > _site/CNAME | |
| - name: Upload Pages artifact | |
| uses: actions/upload-pages-artifact@v5 | |
| with: | |
| path: ./_site | |
| - name: Deploy to GitHub Pages | |
| id: deployment | |
| uses: actions/deploy-pages@v5 | |