From c6b3007995162b81bae3d83668ad2d8e9a8199df Mon Sep 17 00:00:00 2001 From: Lorenzo Iovino Date: Tue, 29 Sep 2026 00:17:42 +0200 Subject: [PATCH] feat: publish scheduled posts on their pubDate with a daily build --- .github/workflows/main.yml | 4 ++++ src/pages/blog.astro | 3 ++- src/pages/blog/[slug].astro | 3 ++- src/pages/blog/tag/[tag].astro | 3 ++- src/pages/rss.xml.ts | 3 ++- src/utils/posts.ts | 13 +++++++++++++ 6 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 src/utils/posts.ts diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ecb5f61..e94eb6e 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -3,6 +3,10 @@ name: Deploy to OVH VPS on: push: branches: [main] + # Daily rebuild at 07:00 Rome (summer time) publishes posts whose pubDate is today + schedule: + - cron: "0 5 * * *" + workflow_dispatch: jobs: deploy: diff --git a/src/pages/blog.astro b/src/pages/blog.astro index 49c0ba7..83ed80b 100644 --- a/src/pages/blog.astro +++ b/src/pages/blog.astro @@ -1,6 +1,7 @@ --- import type { CollectionEntry } from "astro:content"; import { getCollection } from "astro:content"; +import { isPublished } from "../utils/posts"; import { Image } from "astro:assets"; import Footer from "../components/Footer.astro"; import Navbar from "../components/Navbar.astro"; @@ -11,7 +12,7 @@ type BlogPost = CollectionEntry<"blog">; const allPosts: BlogPost[] = await getCollection("blog"); const sortedPosts: BlogPost[] = allPosts - .filter((post: BlogPost) => !post.data.draft) + .filter((post: BlogPost) => isPublished(post)) .sort((a: BlogPost, b: BlogPost) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()); const allTags: Record = sortedPosts.reduce( diff --git a/src/pages/blog/[slug].astro b/src/pages/blog/[slug].astro index 0efc822..bd1a09e 100644 --- a/src/pages/blog/[slug].astro +++ b/src/pages/blog/[slug].astro @@ -1,6 +1,7 @@ --- import type { CollectionEntry } from "astro:content"; import { getCollection } from "astro:content"; +import { isPublished } from "../../utils/posts"; import { Image } from "astro:assets"; import BaseLayout from "../../layouts/BaseLayout.astro"; import Navbar from "../../components/Navbar.astro"; @@ -15,7 +16,7 @@ type BlogPost = CollectionEntry<"blog">; export async function getStaticPaths() { const blogEntries: BlogPost[] = await getCollection("blog"); - return blogEntries.map((entry: BlogPost) => ({ + return blogEntries.filter((entry: BlogPost) => isPublished(entry)).map((entry: BlogPost) => ({ params: { slug: entry.slug }, props: { entry }, })); diff --git a/src/pages/blog/tag/[tag].astro b/src/pages/blog/tag/[tag].astro index 9c44873..6e45b62 100644 --- a/src/pages/blog/tag/[tag].astro +++ b/src/pages/blog/tag/[tag].astro @@ -1,6 +1,7 @@ --- import type { CollectionEntry } from "astro:content"; import { getCollection } from "astro:content"; +import { isPublished } from "../../../utils/posts"; import { Image } from "astro:assets"; import Footer from "../../../components/Footer.astro"; import Navbar from "../../../components/Navbar.astro"; @@ -10,7 +11,7 @@ type BlogPost = CollectionEntry<"blog">; export async function getStaticPaths() { const allPosts: BlogPost[] = await getCollection("blog"); - const publishedPosts: BlogPost[] = allPosts.filter((post: BlogPost) => !post.data.draft); + const publishedPosts: BlogPost[] = allPosts.filter((post: BlogPost) => isPublished(post)); const allTags = new Set(); publishedPosts.forEach((post: BlogPost) => { diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts index aadd7cd..4de78bf 100644 --- a/src/pages/rss.xml.ts +++ b/src/pages/rss.xml.ts @@ -1,11 +1,12 @@ import rss from "@astrojs/rss"; import { getCollection } from "astro:content"; +import { isPublished } from "../utils/posts"; import type { APIContext } from "astro"; export async function GET(context: APIContext) { const blog = await getCollection("blog"); const publishedPosts = blog - .filter((post) => !post.data.draft) + .filter((post) => isPublished(post)) .sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf()); return rss({ diff --git a/src/utils/posts.ts b/src/utils/posts.ts new file mode 100644 index 0000000..bf0623d --- /dev/null +++ b/src/utils/posts.ts @@ -0,0 +1,13 @@ +import type { CollectionEntry } from "astro:content"; + +type BlogPost = CollectionEntry<"blog">; + +// A post with a future pubDate stays in the repo but is left out of the build +// until that day (Rome calendar day, not UTC): the scheduled CI build publishes +// it. `astro dev` shows everything so scheduled posts can be previewed. +export function isPublished(post: BlogPost, now: Date = new Date()): boolean { + if (post.data.draft) return false; + if (import.meta.env.DEV) return true; + const today = new Intl.DateTimeFormat("en-CA", { timeZone: "Europe/Rome" }).format(now); + return post.data.pubDate.toISOString().slice(0, 10) <= today; +}