Changelog Publication on Autopilot: GitHub Commits → Telegram + WordPress

When you frequently roll out new features, you need to notify your team, users, and search engines. The latter is important for SEO — Google takes into account whether the product is evolving or abandoned.

Doing this manually after each push becomes a routine that you quickly forget. I set up automation: when deploying, GitHub Actions sends a notification to Telegram and creates a changelog post on the site.

What You’ll Get

  • When pushing to production, a message is automatically sent to the Telegram channel
  • A post is created in WordPress with the “changelog” category in the desired language
  • You can skip notifications by adding [skip-public] in the commit

Message format:

🏴 Update v1.30

— Added OAuth authentication
— Fixed bug with menu display
— Updated dependencies

How the Git Repository is Structured

The main branch contains the production version of the site. There are other branches where I and other developers work. Auto-deploy is set up: when pushing to main, the project is automatically deployed to production via GitHub Actions.

This is where we’ll integrate automation. In the same workflow, we’ll add steps to gather all commits from the last deploy and send them to the Telegram channel and the site as a post.

Step 1: Create a Telegram Bot

Open @BotFather in Telegram and create a bot with the /newbot command. You’ll get a token like this:

1234567890:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw

Create a channel and add the bot as an administrator. To get the channel’s Chat ID:

  1. Send any message to the channel
  2. Open this in the browser: https://api.telegram.org/bot{TOKEN}/getUpdates
  3. In the JSON response, find chat.id — this is the Chat ID of the channel (starts with a minus)

Example response:

{
  "message": {
    "chat": {
      "id": -1001234567890,
      "title": "My Channel"
    }
  }
}

Chat ID of the channel: -1001234567890

Step 2: Configure the WordPress REST API

To create posts through the API, you need an Application Password:

  1. WordPress Admin → Users → your profile
  2. Scroll down to “Application Passwords”
  3. Enter a name (e.g., “GitHub Actions”) and click “Add New”
  4. Copy the generated password — it is shown only once.

Step 3: Add Secrets to GitHub

In the repository: Settings → Secrets and variables → Actions → New repository secret. Add the following:

TELEGRAM_BOT_TOKEN    — bot token
TELEGRAM_CHAT_ID      — channel ID (with minus, e.g., -1001234567890)
WP_USER               — WordPress admin login
WP_APP_PASSWORD       — Application Password
WP_SITE_URL           — site address (https://example.com)

Step 4: Create a Version File

In the root of the repository, create a VERSION file with the base version:

1.0

GitHub Actions will automatically add the build number: 1.42, 1.43, etc.

Step 5: GitHub Actions Workflow

Create a file .github/workflows/deploy.yml:

name: Deploy

on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Needed for git log

      - name: Generate version
        id: version
        run: |
          BASE_VERSION=$(cat VERSION)
          FULL_VERSION="${BASE_VERSION}.${{ github.run_number }}"
          echo "version=$FULL_VERSION" >> $GITHUB_OUTPUT

      - name: Send to Telegram
        if: ${{ !contains(github.event.head_commit.message, '[skip-public]') }}
        env:
          TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
          TELEGRAM_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
        run: |
          COMMITS=$(git log --pretty=format:"— %s" ${{ github.event.before }}..${{ github.sha }} --no-merges)
          
          if [ -z "$COMMITS" ]; then
            echo "No commits to report"
            exit 0
          fi
          
          VERSION="${{ steps.version.outputs.version }}"
          MESSAGE=$(printf "🏴 Update v%s\n\n%s" "$VERSION" "$COMMITS")
          
          curl -s -X POST "https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage" \
            -d chat_id="${TELEGRAM_CHAT_ID}" \
            -d text="$MESSAGE"

      - name: Create changelog post
        if: ${{ !contains(github.event.head_commit.message, '[skip-public]') }}
        env:
          WP_USER: ${{ secrets.WP_USER }}
          WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
          WP_SITE_URL: ${{ secrets.WP_SITE_URL }}
        run: |
          COMMITS=$(git log --pretty=format:"— %s" ${{ github.event.before }}..${{ github.sha }} --no-merges)
          
          if [ -z "$COMMITS" ]; then
            exit 0
          fi
          
          VERSION="${{ steps.version.outputs.version }}"
          TITLE="Update v${VERSION}"
          
          # Get or create the changelog category
          CAT_ID=$(curl -s -u "${WP_USER}:${WP_APP_PASSWORD}" \
            "${WP_SITE_URL}/wp-json/wp/v2/categories?slug=changelog" | jq -r '.[0].id // empty')
          
          if [ -z "$CAT_ID" ]; then
            CAT_ID=$(curl -s -u "${WP_USER}:${WP_APP_PASSWORD}" \
              -X POST "${WP_SITE_URL}/wp-json/wp/v2/categories" \
              -H "Content-Type: application/json" \
              -d '{"name":"Changelog","slug":"changelog"}' | jq -r '.id')
          fi
          
          # Create the post
          curl -s -u "${WP_USER}:${WP_APP_PASSWORD}" \
            -X POST "${WP_SITE_URL}/wp-json/wp/v2/posts" \
            -H "Content-Type: application/json" \
            -d "$(jq -n \
              --arg title "$TITLE" \
              --arg content "$COMMITS" \
              --argjson categories "[$CAT_ID]" \
              '{title: $title, content: $content, status: "publish", categories: $categories}')"

Polylang: Multilingual Support

The site of my product is built on WordPress and it is multilingual — I use the Polylang Pro plugin for this. Therefore, when creating a post, it is necessary to specify the language of the commits.

Polylang adds a lang field to the REST API. We pass it in the JSON request:

curl -X POST ".../wp-json/wp/v2/posts" \
  -d '{
    "title": "Update v1.30",
    "content": "— commit 1",
    "lang": "ru"
  }'

The language slug (ru, en) can be found in the admin: Languages → Languages → Code column.

In the future, changelog can be automatically translated into all site languages using neural networks — but that’s a topic for a separate article.

Skipping Notifications

Sometimes you need to push technical changes without public notification. Add [skip-public] in the commit message:

git commit -m "Refactor config [skip-public]"
git push origin main

GitHub Actions checks the condition !contains(github.event.head_commit.message, '[skip-public]') and skips the notification steps.

Summary

Now every push to main automatically:

  1. Generates a version from the VERSION file + build number
  2. Gathers the list of commits using git log
  3. Sends a beautiful message to Telegram
  4. Creates a post on the site in the changelog category

Setting up takes 15-20 minutes and saves time on every release.

keyboard_arrow_up