DEV Community

Cover image for Nobody reads commit history, so I built a Slack bot that tells your team what to test
Stephan Fühner
Stephan Fühner

Posted on

Nobody reads commit history, so I built a Slack bot that tells your team what to test

"Hey, has staging been updated? What's new, what can I test?"

Ever heard that question from your team? I did, several times. I'm a software engineer and product manager in a small startup team. As an engineer, I can look into our GitLab and check the history, but other members of the team like designers, PMs, or even the CEO with no engineering background don't have access and wouldn't understand a commit history even if they did.

There are already tools for posting commit history on pushes: changelog tools for external users, DORA metrics for engineers. But those are either customer-facing changelog tools or raw deploy-status pings. Nothing that gives internal, non-technical teammates an automatic, plain-language summary of what just landed on staging.

So I decided to build a quick solution in my free time: StagingBrief.

Whenever a pipeline successfully runs and deploys to the infrastructure, the notify step checks the diff between the current commit and the last successful pipeline's commit. Commit messages and file changes are then sent to an LLM to summarise, and the result is posted as a Slack notification.

Just a simple GitLab CI step and a Docker image that handles everything. No separate backend, no database, no service to maintain. And no code is currently sent to the LLM, just commit messages and which files have changed.

Example output, not a real deployment.


The scratch vs. alpine issue

My goal was a single small Docker image: the Go binary plus TLS certificates for the HTTPS API calls. I used a scratch image and everything worked great on my machine and in a plain Docker container.

Then I set up the notify step in our GitLab pipeline. It failed on the first run with a vague "container unready" message. Great.

Our GitLab runners are Kubernetes-based. Turns out GitLab's Kubernetes executor does more than just run the container. Before the entrypoint executes, the runner tries to inject a small helper process into the job's container to manage the workspace. That helper needs something to work with: a shell, basic filesystem tools. The scratch image has none of that. The injection fails silently, and the pod never becomes ready.

The frustrating part was that everything worked flawlessly in every environment I tested locally. Docker Desktop runs the entrypoint directly. Even a self-hosted runner without Kubernetes should have worked fine.

The fix was switching from scratch to alpine. Image size went from ~8MB to ~18MB. Still tiny, but now compatible with GitLab's Kubernetes runner.


How it was built

Built with Go. I wrote the first pass myself, then used Claude Code for optimizations, error handling, and tests along the way.


Two things I'm still thinking about

Notification frequency. On a branch with high commit frequency, this could produce spam, countering the exact reason I built it in the first place. Too many messages lead to people ignoring some of them, muting the channel, or just losing track of what actually changed. Throttling and compacting would help, but I also want to keep the tool stateless, so this needs some thought.

Sending code instead of just metadata. Maybe sending actual code diffs to the LLM would lead to better summaries and better testing outcomes. The downside: token cost could add up quickly if not controlled, and a solid file-exclude list, things like package.json which add no value to the summary, would need to be built first.


If this sounds like your team, give it a shot. It's a five-minute setup.

notify-staging:
  stage: notify
  image: bytesfue/stagingbrief:latest # or pin to a specific version for reproducibility
  script:
    - /notify
  rules:
    - if: '$CI_COMMIT_BRANCH == "develop" && $CI_PIPELINE_SOURCE == "push"'
  variables:
    GITLAB_PROJECT_ID: $CI_PROJECT_ID
    GITLAB_TOKEN: $STAGINGBRIEF_GITLAB_TOKEN
    LLM_PROVIDER: openai  # optional - default if unset; use "claude" to switch providers
    OPENAI_API_KEY: $STAGINGBRIEF_OPENAI_KEY
    SLACK_BOT_TOKEN: $STAGINGBRIEF_SLACK_BOT_TOKEN
    SLACK_CHANNEL_ID: $STAGINGBRIEF_SLACK_CHANNEL_ID
    GITLAB_PROJECT_NAME: "Your Project Name"
Enter fullscreen mode Exit fullscreen mode

GitHub: https://github.com/bytesfue/stagingbrief
Docker Hub: https://hub.docker.com/r/bytesfue/stagingbrief

Top comments (0)