This post is about the pipeline that publishes it. It is also the first post sent through the new blog-to-homelab workflow. If you are reading it on the live site, the deployment worked.
Two repos, two pushes
This blog lives in its own repository, and my homelab consumes it as a pinned flake input.
That pin is exact. The homelab deploys the specific commit recorded in its flake.lock,
not whatever happens to be on master.
Which meant publishing a post used to take two trips. Push the post to the blog repo. Then
walk over to the homelab repo, run nix flake update blog,
commit, and push again. Two repos, two pushes, for one blog post.
I got tired of that flow. I also wanted some practice with CI/CD across repositories, because that sort of wiring comes up often in infrastructure work.
Cron or dispatch
I considered a nightly cron job in the homelab repository. At 03:00 KST it would check the blog’s master branch and update the pin if it had moved. The other option was event-driven: the blog repository would tell the homelab whenever master changed.
The trigger
The blog’s side is one small workflow: every push to master sends a repository_dispatch
event to the homelab repo.
name: Trigger homelab deploy
on: push: branches: [master]
jobs: dispatch: runs-on: ubuntu-latest steps: - name: Send repository_dispatch to smg1024/homelab env: GH_TOKEN: ${{ secrets.HOMELAB_PAT }} run: gh api repos/smg1024/homelab/dispatches -f event_type=blog-updatedThe receiving end
When the blog-updated event lands, the homelab’s update-blog workflow takes over. It
runs nix flake update blog and checks the git diff. If nothing changed, the workflow stops.
If flake.lock moved, the workflow commits the change to a separate branch, opens a PR,
and merges it into main after CI passes. The normal homelab deployment then takes over.
flowchart TD
subgraph blog [blog repo]
P[push to master] --> W[trigger workflow]
end
W -->|repository_dispatch| U
subgraph lab [homelab repo]
U[update-blog workflow] --> F[nix flake update blog]
F --> D{lock file changed?}
D -->|no| E[end]
D -->|yes| PR[branch + PR]
PR -->|CI green| M[auto-merge to main]
end
M --> DEP[deploy action] --> N[homelab node]Guardrails for an audience of one
Even the bot’s one-line flake.lock update goes through a branch and PR, with CI running
before it reaches main branch. Branch protection applies to my automation too. A dependency change
in the blog can still break the build, so I want CI to catch it before a homelab node tries to
rebuild.
This is more machinery than a personal blog needs, but the excess is intentional. I wanted to practice the workflow I would use on a team project, and the homelab is where I can do that without making coworkers endure my experiments.
Refresh the site
There are no notifications or deployment dashboards at the end of the chain. I will know it worked the same way a reader will: refresh the site and see the post. If it appears, the single push made it through both repositories.