diary of a lazy developer

Diary of a lazy developer

Tech posts from my projects. Each post lives in its project repo as POST.it.md and POST.en.md, and gets published here automatically by a GitHub Action.

Prerequisites

  • Docker and Docker Compose
  • gh CLI (optional, for manual workflow trigger)

Publishing

Posts are collected from source repos and published to the blog, then cross-posted to social platforms.

Publishing flowchart

EN posts go directly to dev.to (as draft) and Mastodon; Buffer queues them for LinkedIn, Twitter/X and Threads, where you review and approve before publishing.

Publishing sequence diagram

Scheduled publishing (every Saturday at 6:00 UTC) is currently disabled; trigger manually.

To trigger it manually:

  1. Go to Actions > Publish posts
  2. Click “Run workflow” > “Run workflow”

Or from CLI:

gh workflow run publish.yml

To test the whole run without creating any post or draft, use dry-run (the steps still query the APIs and dedup, but log only):

gh workflow run publish.yml -f dry_run=true

The “Run workflow” dialog also exposes a “Dry run” checkbox for the same purpose.

Cross-posting

All secrets go in repo Settings > Secrets and variables > Actions > New repository secret.

dev.to (draft)

  1. On dev.to: Settings > Extensions > DEV Community API Keys > Generate API Key
  2. Secret: DEV_TO_API_KEY

Mastodon (public post with image)

  1. On mastodon.social: Settings > Development > New Application > select read, write and profile
  2. Copy the token: MASTODON_ACCESS_TOKEN

Buffer (LinkedIn, Twitter, Threads queue with review)

  1. Create a free account on buffer.com and connect LinkedIn, Twitter/X and Threads
  2. On buffer.com: My Organization (bottom left) > Apps & Integrations > API (beta) > + New Key
  3. Secret: BUFFER_ACCESS_TOKEN

Post frontmatter

Each post in a source repo has this frontmatter:

---
title: "Docker on EC2 with Terraform"
date: 2026-04-10
categories: [devops]
tags: [terraform, docker, aws, ec2]
repo: bilardi/aws-docker-host
social_summary: "I wrote my first article in the #DiaryOfALazyDeveloper series 🚀\n\n..."
---
Field Required Used by
title yes blog, all social
date yes blog URL
categories yes blog
tags yes blog, social hashtags
repo yes collect-posts.sh
social_summary no EN posts only. Used by Mastodon, Buffer (LinkedIn/Threads). If missing, title is used. Twitter always uses title (280 char limit). Must be under 500 characters including link and hashtags (Mastodon/Threads limit). Buffer counts in UTF-16 code units: emoji above BMP (e.g. 🚀, 🔮, 😄) count as 2 characters each.

#DiaryOfALazyDeveloper is added automatically on all social posts.

Project structure

_layouts/  # leonids theme: page templates
_includes/  # leonids theme: reusable HTML partials
_sass/  # leonids theme: SCSS stylesheets
css/  # leonids theme: compiled CSS
js/  # leonids theme: JavaScript
_posts/  # generated by GitHub Action (gitignored)
img/  # diagrams and favicon
.github/workflows/
    publish.yml  # GitHub Action: collect + commit, then parse and cross-post via github-actions-publish scripts
    collect-posts.sh  # clones source repos, copies POST files
scripts/
    parse-diary.py  # builds posts.json (intermediate format) from _posts/*.en.md
    parse-diary.sh  # wrapper for parse-diary.py
social.yml  # config: hashtag, site_url, channels (parser: diary)
sources.yml  # list of repos to scan for POST.it.md / POST.en.md
docker-compose.yml  # local Jekyll server
_config.yml  # Jekyll configuration

Development

docker compose up

If something is not updated,

rm -rf _site .jekyll-cache .jekyll-metadata
touch .jekyll-metadata; chmod 777 .jekyll-metadata
touch Gemfile.lock; chmod 777 Gemfile.lock
docker compose up

Not commit (there are also in the .gitignore file)

  • _site
  • .jekyll-cache
  • .jekyll-metadata
  • Gemfile.lock
  • posts.json

Linting the parser

scripts/parse-diary.py is a single helper script (no pyproject.toml). Lint and format on demand with ruff:

uvx ruff format scripts/parse-diary.py
uvx ruff check --select E,F,I,B,UP,ANN --ignore E501 scripts/parse-diary.py

Same lightweight setup as github-actions-publish: ANN enforces type annotations (PEP 484), docstrings follow PEP 257 by hand, line length is left to the formatter.

Run the parser tests:

bash tests/test-parse-diary.sh

Blog post

License

This repo is released under the MIT license. See LICENSE for details.