Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/backfill-episodes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Backfill all episodes
run: pnpm tsx scripts/publish-episodes.ts --backfill
run: pnpm tsx scripts/publish-atproto-episodes.ts --backfill
env:
ATPROTO_HANDLE: ${{ secrets.ATPROTO_HANDLE }}
ATPROTO_APP_PASSWORD: ${{ secrets.ATPROTO_APP_PASSWORD }}
Expand Down
45 changes: 39 additions & 6 deletions .github/workflows/publish-episodes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,53 @@ jobs:
# the site build runs while the publish job is installing dependencies.
# The publish script then waits for the new episode pages to be live
# before publishing documents that link to them.
#
# The rebuild-hash cache tracks which feed content we already rebuilt
# for. The publish-success hash (.feed-hash) is intentionally separate:
# a persistently failing publish must keep retrying, but must not
# trigger a fresh Vercel build on every 30-minute poll.
- name: Restore last rebuild trigger hash
if: steps.config.outputs.configured == 'true'
uses: actions/cache/restore@v4
with:
path: .rebuild-hash
key: rebuild-hash-
restore-keys: |
rebuild-hash-
- name: Trigger site rebuild
if: steps.config.outputs.configured == 'true' && steps.feed.outputs.changed == 'true'
id: rebuild
env:
REBUILD_WEBHOOK: ${{ secrets.REBUILD_WEBHOOK }}
FEED_HASH: ${{ steps.feed.outputs.hash }}
run: |
if [ -n "$REBUILD_WEBHOOK" ]; then
curl -sf -X POST "$REBUILD_WEBHOOK" > /dev/null
echo "triggered=true" >> "$GITHUB_OUTPUT"
echo "Triggered site rebuild."
else
if [ -z "$REBUILD_WEBHOOK" ]; then
echo "triggered=false" >> "$GITHUB_OUTPUT"
echo "fired=false" >> "$GITHUB_OUTPUT"
echo "::notice::REBUILD_WEBHOOK not set — publishing without waiting for a site rebuild."
exit 0
fi
if [ -n "$FEED_HASH" ] && [ "$FEED_HASH" = "$(cat .rebuild-hash 2>/dev/null || true)" ]; then
# triggered=true so the publish script still waits for the pages
# from that earlier build before publishing.
echo "triggered=true" >> "$GITHUB_OUTPUT"
echo "fired=false" >> "$GITHUB_OUTPUT"
echo "Site already rebuilt for this feed content — not triggering again."
exit 0
fi
curl -sf -X POST "$REBUILD_WEBHOOK" > /dev/null
echo "triggered=true" >> "$GITHUB_OUTPUT"
echo "fired=true" >> "$GITHUB_OUTPUT"
echo "Triggered site rebuild."
- name: Record rebuild trigger hash
if: steps.rebuild.outputs.fired == 'true' && steps.feed.outputs.hash != ''
run: printf '%s' "${{ steps.feed.outputs.hash }}" > .rebuild-hash
- name: Save rebuild trigger hash
if: steps.rebuild.outputs.fired == 'true' && steps.feed.outputs.hash != ''
uses: actions/cache/save@v4
with:
path: .rebuild-hash
key: rebuild-hash-${{ steps.feed.outputs.hash }}-${{ github.run_id }}-${{ github.run_attempt }}

publish:
needs: gate
Expand All @@ -119,7 +152,7 @@ jobs:
- name: Install dependencies
run: pnpm install
- name: Publish new episodes
run: pnpm tsx scripts/publish-episodes.ts
run: pnpm tsx scripts/publish-atproto-episodes.ts
env:
ATPROTO_HANDLE: ${{ secrets.ATPROTO_HANDLE }}
ATPROTO_APP_PASSWORD: ${{ secrets.ATPROTO_APP_PASSWORD }}
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,10 +179,10 @@ You can also publish locally:

```bash
# Publish only new episodes
pnpm publish:episodes
pnpm publish:atproto

# Backfill all episodes
pnpm publish:episodes:backfill
pnpm publish:atproto:backfill
```

##### Verification
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
"lint:fix": "eslint . --fix",
"preview": "astro preview",
"start": "astro dev",
"publish:episodes": "tsx scripts/publish-episodes.ts",
"publish:episodes:backfill": "tsx scripts/publish-episodes.ts --backfill",
"publish:atproto": "tsx scripts/publish-atproto-episodes.ts",
"publish:atproto:backfill": "tsx scripts/publish-atproto-episodes.ts --backfill",
"test": "concurrently \"pnpm:test:*(!fix)\" --names \"test:\"",
"test:e2e": "pnpm exec playwright test",
"test:unit": "vitest"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
* STANDARD_SITE_PUBLICATION_RKEY - The publication record key
*
* Usage:
* pnpm publish:episodes # publish new episodes only
* pnpm publish:episodes:backfill # publish all episodes (backfill)
* pnpm publish:atproto # publish new episodes only
* pnpm publish:atproto:backfill # publish all episodes (backfill)
*/

import { htmlToText } from 'html-to-text';
Expand Down Expand Up @@ -62,24 +62,17 @@ async function waitForPage(url: string) {
}
}

// Only validate the fields this script actually uses — requiring unused
// fields makes publishing break whenever the feed host changes something
// irrelevant (e.g. Flightcast's image enclosures have no `type`).
const FeedSchema = object({
items: array(
object({
id: string(),
title: string(),
published: number(),
description: string(),
content_encoded: optional(string()),
itunes_duration: number(),
itunes_episode: optional(number()),
itunes_episodeType: optional(string()),
itunes_image: optional(object({ href: optional(string()) })),
enclosures: array(
object({
url: string(),
type: string()
})
)
itunes_episodeType: optional(string())
})
)
});
Expand Down
Loading