Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
128 changes: 2 additions & 126 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,134 +8,13 @@ on:
- devs/**

# Cancel superseded runs on the same ref — a force-push or a new
# commit makes the in-flight matrix obsolete, so don't keep runners
# commit makes the in-flight run obsolete, so don't keep runners
# busy finishing it.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
# Spellcheck source, comments, and docs. Allow-list of project
# nouns lives in _typos.toml; reproduce locally with `typos`.
typos:
name: typos
timeout-minutes: 5
runs-on: ubuntu-26.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: crate-ci/typos@00f422f3b19c57bc6338715ebfe3316d38768461 # v1.50.3

# The agent skills against the binary people actually get: the latest
# release's. The CLI's source isn't in this repository any more, so there is
# no build to check them against. See scripts/check-skills.py.
skills:
name: skills reference real commands
timeout-minutes: 5
runs-on: ubuntu-26.04
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Download the latest release's Linux binary
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh release download --repo "${GITHUB_REPOSITORY}" \
--pattern 'mergify-*-x86_64-unknown-linux-gnu.tar.gz' --dir release
tar -C release -xzf release/mergify-*-x86_64-unknown-linux-gnu.tar.gz
release/mergify --version
- name: Check the skills
run: python3 scripts/check-skills.py release/mergify

# End to end, the one-liner people run: install.sh against the latest
# release's real binaries and SHA256SUMS, served from a local fixture so the
# script's own download, checksum and install paths all run. The release is
# the only place binaries come from now, so this is also what proves the
# current release installs. Plus the two ways a tampered SHA256SUMS must fail
# closed. Windows runs the same POSIX script under git-bash.
install-script-release:
name: install.sh against the latest release (${{ matrix.os }})
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
os: [ubuntu-26.04, macos-15, windows-2025]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- name: Install shellcheck (Linux only)
if: matrix.os == 'ubuntu-26.04'
run: sudo apt-get install -y --no-install-recommends shellcheck
- name: Lint install.sh
if: matrix.os == 'ubuntu-26.04'
run: shellcheck install.sh
# Every binary of the release, so install.sh picks its own target the
# way it does against GitHub; latest-release.json stands in for the
# releases/latest redirect it resolves the version from.
- name: Fetch the latest release as the fixture
id: release
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="$(gh release view --repo "${GITHUB_REPOSITORY}" --json tagName --jq .tagName)"
mkdir -p fixture/release
gh release download "${tag}" --repo "${GITHUB_REPOSITORY}" --dir fixture/release \
--pattern 'mergify-*' --pattern SHA256SUMS
printf '{"tag_name":"%s"}\n' "${tag}" > fixture/release/latest-release.json
ls -la fixture/release
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
- name: Serve the fixture
shell: bash
run: |
cd fixture/release
# `python3` on the Unix runners, `python` on the Windows one.
py=python3; command -v "$py" > /dev/null 2>&1 || py=python
"$py" -m http.server 8765 --bind 127.0.0.1 > /tmp/server.log 2>&1 &
echo $! > /tmp/server.pid
for _ in $(seq 1 50); do
curl -fsS http://127.0.0.1:8765/SHA256SUMS > /dev/null && break
sleep 0.1
done
- name: install.sh installs the latest release
shell: bash
env:
TAG: ${{ steps.release.outputs.tag }}
run: |
set -euo pipefail
MERGIFY_BASE_URL=http://127.0.0.1:8765 MERGIFY_INSTALL_DIR=/tmp/mergify-install ./install.sh
case "$(uname -s)" in MINGW*|MSYS*|CYGWIN*) bin=mergify.exe ;; *) bin=mergify ;; esac
out="$("/tmp/mergify-install/${bin}" --version)"
echo "${out}"
[ "${out}" = "mergify ${TAG}" ] || { echo "expected 'mergify ${TAG}', got '${out}'"; exit 1; }
# sha256sum -c only warns on a malformed line, so install.sh checks the
# line shape itself: both cases must refuse to install.
- name: install.sh rejects a tampered SHA256SUMS
shell: bash
run: |
set -euo pipefail
cd fixture/release
cp SHA256SUMS SHA256SUMS.orig
assets=(mergify-*)
echo "Case 1: wrong but well-formed hashes"
for asset in "${assets[@]}"; do printf '%064d %s\n' 0 "${asset}"; done > SHA256SUMS
if MERGIFY_BASE_URL=http://127.0.0.1:8765 MERGIFY_INSTALL_DIR=/tmp/mergify-bad1 ../../install.sh > /tmp/case1.log 2>&1; then
cat /tmp/case1.log; echo "install.sh accepted wrong checksums"; exit 1
fi
grep -q 'checksum verification failed' /tmp/case1.log
echo "Case 2: malformed lines"
for asset in "${assets[@]}"; do echo "bogus ${asset}"; done > SHA256SUMS
if MERGIFY_BASE_URL=http://127.0.0.1:8765 MERGIFY_INSTALL_DIR=/tmp/mergify-bad2 ../../install.sh > /tmp/case2.log 2>&1; then
cat /tmp/case2.log; echo "install.sh accepted malformed checksums"; exit 1
fi
grep -q 'malformed checksum entry' /tmp/case2.log
mv SHA256SUMS.orig SHA256SUMS
- name: Stop the fixture server
if: always()
shell: bash
run: |
if [ -f /tmp/server.pid ]; then kill "$(cat /tmp/server.pid)" || true; fi

# The published files (see AGENTS.md) come from the CLI's private source,
# copied by ci-bot's public-releases-sync as of each release: an edit made
# here would be silently overwritten by the next sync. Only that sync's own
Expand All @@ -155,7 +34,7 @@ jobs:
run: |
set -euo pipefail
changed="$(git diff --name-only "${BASE_SHA}...HEAD" -- \
README.md install.sh skills .claude-plugin .codex-plugin assets scripts/check-skills.py)"
README.md install.sh skills .claude-plugin .codex-plugin assets)"
if [ -n "${changed}" ]; then
for file in ${changed}; do
echo "::error file=${file}::${file} is published from the CLI's source and synced here at each release; edit it there (see AGENTS.md)"
Expand All @@ -167,9 +46,6 @@ jobs:
ci-gate:
if: ${{ !cancelled() }}
needs:
- typos
- skills
- install-script-release
- synced-files
runs-on: ubuntu-26.04
steps:
Expand Down
16 changes: 4 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ differ:
| `install.sh` | the installer, served from `main` to `curl … \| sh` |
| `skills/` | the agent skills (`npx skills add Mergifyio/mergify-cli`) |
| `.claude-plugin/`, `.codex-plugin/`, `assets/` | the plugin manifests and icon |
| `scripts/check-skills.py` | the skill check CI runs |

A change made to them here is overwritten by the next sync, so CI's
`synced-files` check fails any pull request that edits them, unless it comes
Expand All @@ -27,23 +26,16 @@ that Mergify carries over to the CLI's source.
## Owned here

- `.github/workflows/ci.yaml`, `.mergify.yml`, `renovate.json`,
`_typos.toml`, this `AGENTS.md` and `LICENSE`.
this `AGENTS.md` and `LICENSE`.
- The releases, written by ci-bot's mirror, never by hand. A release carrying
the CLI binaries is Latest, which install.sh, `mergify self-update`, the
Homebrew tap and the docs' CLI reference all follow.
- The issue tracker.

## Checks

CI (`.github/workflows/ci.yaml`, gated by `ci-gate`) runs against the latest
release, since nothing is built here:
The published files are checked in the CLI's source before each release,
against the binary that release ships, so they aren't checked again here. CI
(`.github/workflows/ci.yaml`, gated by `ci-gate`) runs:

- `skills`: `scripts/check-skills.py` checks every skill's front matter and
that every `mergify <group> <subcommand>` it mentions exists in the latest
release's binary.
- `install-script-release`: shellcheck, then install.sh end to end against
the latest release's real files served from a local fixture
(`MERGIFY_BASE_URL`), on Linux, macOS and Windows, including the tampered
`SHA256SUMS` cases.
- `synced-files`: the published files only change through the sync.
- `typos`, with the allow-list in `_typos.toml`.
6 changes: 0 additions & 6 deletions _typos.toml

This file was deleted.

105 changes: 0 additions & 105 deletions scripts/check-skills.py

This file was deleted.