-
-
Notifications
You must be signed in to change notification settings - Fork 5
Post: blog has moved #27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "name": "Jacob Coffee", | ||
| "bio": "Python Software Foundation Staff. Litestar Maintainer.", | ||
| "github": "JacobCoffee", | ||
| "avatar": "https://avatars.githubusercontent.com/u/45884264", | ||
| "twitter": "_scriptr", | ||
| "bluesky": "scriptr.dev", | ||
| "mastodon": "https://fosstodon.org/@Monorepo", | ||
| "website": "https://scriptr.dev", | ||
| "featured": false | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| --- | ||
| title: The Python Insider Blog Has Moved! | ||
| publishDate: '2026-03-03' | ||
| updatedDate: '2026-03-03' | ||
| author: Jacob Coffee | ||
| description: 'Python Insider now lives at blog.python.org, backed by a Git repository. All 307 posts from the Blogger era have been migrated, and old URLs redirect automatically.' | ||
| tags: | ||
| - python | ||
| - community | ||
| published: true | ||
| legacyUrl: /2026/03/the-python-insider-blog-has-moved.html | ||
| --- | ||
|
|
||
| import ShowcasePostCards from '../../../src/components/showcase/ShowcasePostCards.astro'; | ||
| import ShowcaseTagCloud from '../../../src/components/showcase/ShowcaseTagCloud.astro'; | ||
| import ShowcaseAuthors from '../../../src/components/showcase/ShowcaseAuthors.astro'; | ||
| import ShowcaseSearch from '../../../src/components/showcase/ShowcaseSearch.astro'; | ||
|
|
||
| Python Insider now lives at [blog.python.org](https://blog.python.org), backed by a Git repository. All 307 posts from the Blogger era have been migrated over, and old URLs redirect to the new ones automatically. Your RSS readers should pick up the new feed without any action on your part, but if something looks off, the new feed URL is [blog.python.org/rss.xml](https://blog.python.org/rss.xml). | ||
|
|
||
| ## Why we moved | ||
|
|
||
| Blogger worked fine for a long time, but contributing to the blog meant having a Google account and using Blogger's editor. That's a higher bar than it needs to be. The new setup is just Markdown files in a Git repo. If you can open a pull request, you can write a post. | ||
|
|
||
| Posts live in `content/posts/{slug}/index.md` with YAML frontmatter for the title, date, authors, and tags. Images go right next to the post in the same directory. No special tooling required beyond a text editor. | ||
|
|
||
| ## Contributing | ||
|
|
||
| Want to write about a Python release, core sprint, governance update, or anything else that belongs on the official Python blog? Here's the short version: | ||
|
|
||
| 1. Fork [python/python-insider-blog](https://github.com/python/python-insider-blog) | ||
| 2. Create a new directory under `content/posts/` with your post slug | ||
| 3. Add an `index.md` with your content (and optionally upload your images) | ||
| 4. Open a PR | ||
|
|
||
| The repo README has more detail on frontmatter fields and local development if you want to preview your post before submitting. | ||
|
|
||
| ## What's new on the site | ||
|
|
||
| Beyond the content itself, the new site has a few features the old Blogger setup never had. Here's a live look: | ||
|
|
||
| ### Browse & filter posts | ||
|
|
||
| All posts are browsable with pagination, a year filter, and a tag sidebar. Click any tag or year to narrow things down. | ||
|
|
||
| <ShowcasePostCards /> | ||
|
|
||
| ### Every author has a page | ||
|
|
||
| See who's been writing, how much they've contributed, and browse their posts individually. | ||
|
|
||
| <ShowcaseAuthors /> | ||
|
|
||
| ### Tags at a glance | ||
|
|
||
| Every tag across the archive, ranked by how often it appears. Great for finding all the release announcements or security updates in one place. | ||
|
|
||
| <ShowcaseTagCloud /> | ||
|
|
||
| ### Search everything | ||
|
|
||
| Hit <kbd>Ctrl+K</kbd> (or <kbd>Cmd+K</kbd> on Mac) from any page to open the command palette. It searches across all 307+ posts by title, author, tags, and description. There are also keyboard chord shortcuts for quick navigation. | ||
|
|
||
| <ShowcaseSearch /> | ||
|
|
||
| ### And more | ||
|
|
||
| - **RSS feed** at [blog.python.org/rss.xml](https://blog.python.org/rss.xml), compatible with the old Blogger feed URL so existing subscribers don't need to change anything. | ||
| - **Dark mode** that follows your system preference (try the toggle in the header). | ||
| - **Open Graph images** generated automatically for every post, so links shared on social media get proper preview cards. | ||
|
|
||
| ## What's under the hood | ||
|
|
||
| The site is built with [Astro](https://astro.build) and deployed as fully static HTML. There's a [Keystatic](https://keystatic.com) CMS available in dev mode if you prefer a visual editor over raw Markdown, but it's entirely optional. Tailwind handles the styling. The whole thing builds and deploys through GitHub Actions. | ||
|
|
||
| ## Links | ||
|
|
||
| - New site: [blog.python.org](https://blog.python.org) | ||
| - Repository: [github.com/python/python-insider-blog](https://github.com/python/python-insider-blog) | ||
| - RSS feed: [blog.python.org/rss.xml](https://blog.python.org/rss.xml) | ||
|
|
||
| If you spot broken links, missing images, or formatting issues from the migration, [file an issue](https://github.com/python/python-insider-blog/issues) on the repo. PRs are welcome too. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| --- | ||
| import { getCollection } from "astro:content"; | ||
| import { slugify, withBase } from "../../lib/utils"; | ||
|
|
||
| const allPosts = await getCollection("posts"); | ||
| const publishedPosts = allPosts.filter((p) => p.data.published); | ||
| const allAuthors = await getCollection("authors"); | ||
|
|
||
| const authorCounts = new Map<string, number>(); | ||
| for (const post of publishedPosts) { | ||
| const slug = slugify(post.data.author); | ||
| authorCounts.set(slug, (authorCounts.get(slug) || 0) + 1); | ||
| } | ||
|
|
||
| const authorsWithCounts = allAuthors | ||
| .map((a) => ({ | ||
| slug: a.id, | ||
| name: a.data.name, | ||
| github: a.data.github, | ||
| count: authorCounts.get(a.id) || 0, | ||
| })) | ||
| .filter((a) => a.count > 0) | ||
| .sort((a, b) => b.count - a.count); | ||
|
|
||
| const topAuthors = authorsWithCounts.slice(0, 6); | ||
| const maxCount = topAuthors[0]?.count ?? 1; | ||
| --- | ||
|
|
||
| <div class="not-prose my-8 overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800"> | ||
| <div class="flex items-center justify-between border-b border-zinc-200 bg-zinc-50 px-5 py-3 dark:border-zinc-800 dark:bg-zinc-900/50"> | ||
| <div class="flex items-center gap-2"> | ||
| <svg class="h-4 w-4 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"> | ||
| <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" stroke-linecap="round" stroke-linejoin="round" /> | ||
| <circle cx="9" cy="7" r="4" stroke-linecap="round" stroke-linejoin="round" /> | ||
| <path d="M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75" stroke-linecap="round" stroke-linejoin="round" /> | ||
| </svg> | ||
| <span class="text-sm font-semibold text-zinc-700 dark:text-zinc-300" style="font-family: var(--font-display);">Authors</span> | ||
| <span class="text-xs text-zinc-400 dark:text-zinc-500">{authorsWithCounts.length} contributors</span> | ||
| </div> | ||
| <a href={withBase("/authors")} class="text-xs font-medium text-[#306998] hover:underline dark:text-[#ffd43b]"> | ||
| View all → | ||
| </a> | ||
| </div> | ||
| <div class="space-y-0.5 p-3"> | ||
| {topAuthors.map((author) => { | ||
| const pct = Math.round((author.count / maxCount) * 100); | ||
| return ( | ||
| <a | ||
| href={withBase(`/authors/${author.slug}`)} | ||
| class="group flex items-center gap-3 rounded-lg px-3 py-2 transition-colors hover:bg-zinc-100 dark:hover:bg-zinc-800/60" | ||
| > | ||
| {author.github ? ( | ||
| <img | ||
| src={`https://github.com/${author.github}.png`} | ||
| alt="" | ||
| class="h-6 w-6 flex-shrink-0 rounded-full" | ||
| loading="lazy" | ||
| /> | ||
| ) : ( | ||
| <div class="flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full bg-zinc-200 text-xs font-bold text-zinc-500 dark:bg-zinc-700 dark:text-zinc-400"> | ||
| {author.name.charAt(0)} | ||
| </div> | ||
| )} | ||
| <span class="w-36 flex-shrink-0 truncate text-sm font-semibold text-zinc-700 dark:text-zinc-300" style="font-family: var(--font-display);"> | ||
| {author.name} | ||
| </span> | ||
| <div class="h-1.5 flex-1 overflow-hidden rounded-full bg-zinc-100 dark:bg-zinc-800"> | ||
| <div | ||
| class="h-full rounded-full bg-[#306998] transition-all duration-500 group-hover:opacity-80 dark:bg-[#ffd43b]" | ||
| style={`width: ${Math.max(pct, 4)}%;`} | ||
| /> | ||
| </div> | ||
| <span class="w-8 flex-shrink-0 text-right text-xs tabular-nums font-medium text-zinc-400 dark:text-zinc-500"> | ||
| {author.count} | ||
| </span> | ||
| </a> | ||
| ); | ||
| })} | ||
| </div> | ||
| </div> |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,100 @@ | ||||||
| --- | ||||||
| import { getCollection } from "astro:content"; | ||||||
| import { formatDate, postUrl, slugify, withBase } from "../../lib/utils"; | ||||||
|
||||||
| import { formatDate, postUrl, slugify, withBase } from "../../lib/utils"; | |
| import { formatDate, postUrl, withBase } from "../../lib/utils"; |
Copilot
AI
Mar 3, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The filter allPosts.filter((p) => p.data.published) is applied four times — on lines 7, 13, 20, and 36. With 300+ posts in the collection, this means iterating the full array four times unnecessarily. Consider extracting this into a publishedPosts variable (as is done in the sibling components ShowcaseTagCloud.astro and ShowcaseAuthors.astro) and reusing it throughout.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The bio field contains a typo: "Infradwre" should be "Infrastructure".