arturz

Back

Introduction#

Imagine the following scenario: you merge the latest changes to the main branch, and CI passes ✅. Everything’s looking good!

You have a standard GitHub Actions workflow that runs CI on every push and pull request on both main and staging branches:

on:
  pull_request:
    branches: [ main, staging ]
  push:
    branches: [ main, staging ]
yaml

You also have a CD configured that automatically deploys the latest changes from staging branch, so you create a PR to merge changes from main to staging to live test new features in the staging environment.

Suddenly, CI status on the main branch changes from ✅ to ❌️.

What happened?

You see that the PR failed. GitHub Actions attaches check results to commit hashes, not branches. The status you see on a branch is the status of its latest commit, and since your main branch and new PR both point to the same commit, the PR’s check failure shows up on main too.

If you go into failure details on your main branch, you’ll see both checks:

  1. ❌️ CI / build (pull_request)
  2. ✅ CI / build (push)

And because at least one of them is failing, the whole check is red.

What can be done about it#

A modern DevOps industry standard is to use the Build Once, Deploy Anywhere pattern instead of environment branching to deploy to different environments.

But there are a lot of legacy codebases and simpler setups out there, and there’s no simple solution that does not have its trade-off.

You can create a GitHub branch protection rule to only require a push check on main for passing ✅. But by the time someone creates a new check, let’s say for E2E tests, you will likely have forgotten about this rule, and it won’t show on main as a failure ❌️ until someone notices. Right now, it’s not possible to create a rule that requires all checks except pull_request.

You can also configure your GitHub Actions workflow not to run checks on PRs to staging, but then you’ll find out about errors only after they are merged into staging.

Resolution#

After fixing failing CI on new PR and rerunning checks (or after merging it and pushing new commits to main branch), the old pull_request check is overwritten and main turns green again ✅.