Skip to content

Commit 5a1aae2

Browse files
committed
chore: Initial version
Change-Id: I77d06e0194147ae509414c6edb76d36aa42fd635
0 parents  commit 5a1aae2

File tree

6 files changed

+285
-0
lines changed

6 files changed

+285
-0
lines changed

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: github-actions
4+
directory: /
5+
schedule:
6+
interval: daily
7+
# yamllint disable-line rule:quoted-strings
8+
time: "08:00"
9+
timezone: Europe/Paris

.github/workflows/ci.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: Continuous Integration
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
- devs/**
11+
12+
jobs:
13+
linters:
14+
timeout-minutes: 20
15+
runs-on: ubuntu-24.04
16+
steps:
17+
- name: Checkout 🛎️
18+
uses: actions/[email protected]
19+
20+
- name: Actionlint
21+
uses: docker://rhysd/actionlint:latest
22+
with:
23+
args: -color
24+
25+
action:
26+
runs-on: ubuntu-24.04
27+
outputs:
28+
scopes: ${{ steps.action.outputs.scopes }}
29+
everything: ${{ fromJSON(steps.action.outputs.scopes).everything }}
30+
action: ${{ fromJSON(steps.action.outputs.scopes).action }}
31+
steps:
32+
- name: Checkout 🛎️
33+
uses: actions/[email protected]
34+
35+
- name: Trying action
36+
id: action
37+
uses: ./
38+
tests:
39+
if: ${{ !cancelled() }}
40+
runs-on: ubuntu-24.04
41+
needs:
42+
- action
43+
steps:
44+
- name: Check scopes
45+
env:
46+
SCOPES: ${{ needs.action.outputs.scopes }}
47+
EVERYTHING: ${{ needs.action.outputs.everything }}
48+
EVERYTHING_BOOL: ${{ needs.action.outputs.everything == 'true' }}
49+
run: |
50+
echo "SCOPES: $SCOPES"
51+
test "$EVERYTHING" == "true"
52+
test "$EVERYTHING_BOOL" == "true"

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__pycache__
2+
*.pyc
3+
.pytest_cache

.mergify.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
extends: .github
2+
shared:
3+
IsPublicHolidays: &IsPublicHolidays
4+
or:
5+
- current-datetime = XXXX-01-01T00:00/XXXX-01-01T23:59[Europe/Paris]
6+
- current-datetime = XXXX-05-01T00:00/XXXX-05-01T23:59[Europe/Paris]
7+
- current-datetime = XXXX-05-08T00:00/XXXX-05-08T23:59[Europe/Paris]
8+
- current-datetime = XXXX-07-14T00:00/XXXX-07-14T23:59[Europe/Paris]
9+
- current-datetime = XXXX-08-15T00:00/XXXX-08-15T23:59[Europe/Paris]
10+
- current-datetime = XXXX-11-01T00:00/XXXX-11-01T23:59[Europe/Paris]
11+
- current-datetime = XXXX-11-11T00:00/XXXX-11-11T23:59[Europe/Paris]
12+
- current-datetime = XXXX-12-25T00:00/XXXX-12-25T23:59[Europe/Paris]
13+
DefaultQueueOptions: &DefaultQueueOptions
14+
commit_message_template: |
15+
{{ title }} (#{{ number }})
16+
17+
{{ body }}
18+
merge_method: squash
19+
CheckRuns: &CheckRuns
20+
- check-success=linters
21+
- check-success=action
22+
- check-success=tests
23+
24+
scopes:
25+
source:
26+
files:
27+
github:
28+
includes:
29+
- .github/**/*
30+
action:
31+
includes:
32+
- action.yml
33+
everything: {}
34+
35+
queue_rules:
36+
- name: default
37+
<<: *DefaultQueueOptions
38+
autoqueue: true
39+
queue_conditions:
40+
- base=main
41+
- and: *CheckRuns
42+
- or:
43+
- "#approved-reviews-by>=1"
44+
- and:
45+
- author=mergify-ci-bot
46+
- head=trivy/daily-report
47+
- approved-reviews-by=@eng-mgr
48+
- "#changes-requested-reviews-by=0"
49+
- "#review-threads-unresolved=0"
50+
- "#review-requested=0"
51+
merge_conditions:
52+
- and: *CheckRuns
53+
- and:
54+
- not: *IsPublicHolidays
55+
- schedule=Mon-Fri 09:00-17:30[Europe/Paris]

README.md

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# gha-mergify-ci
2+
3+
A GitHub Action that detects which parts of your monorepo are affected by a pull request, so you can run only the relevant tests.
4+
5+
## The Problem
6+
7+
In monorepos, running all tests for every pull request wastes time and resources. While GitHub Actions offers path filtering:
8+
9+
```yaml
10+
on:
11+
pull_request:
12+
paths:
13+
- 'js/**'
14+
```
15+
16+
This approach has a critical flaw: when a job doesn't run, you can't tell if it was skipped due to the filter or if CI failed to start.
17+
This becomes especially problematic with merge queues, where you don't want to skip tests on the second PR just because the first PR in the queue modified different files.
18+
19+
## The Solution
20+
21+
This action analyzes changed files and returns "scopes" indicating which parts of your codebase are affected. It's merge queue-aware, ignoring changes from PRs ahead in the queue to ensure accurate test selection.
22+
23+
When running in a merge queue context, the action automatically adds a `merge-queue` scope for integration tests.
24+
25+
## Usage
26+
27+
The example bellow demonstrate how to setup a monorepo containing a Python and a Javascript project.
28+
29+
The Python jobs will ran only if `*.py` are modified, same the Javascript jobs and `*.js` files.
30+
31+
An additional job called `integration` will run only when on Mergify merge-queue branches.
32+
33+
### 1. Configure Scopes
34+
35+
Create a `.mergify.yml` file in your repository root:
36+
37+
```yaml
38+
scopes:
39+
source:
40+
files:
41+
python:
42+
includes:
43+
- **/*.py
44+
js:
45+
includes:
46+
- **/*.js
47+
48+
queue_rules:
49+
- name: default
50+
autoqueue: true
51+
queue_conditions:
52+
- check-success: alls-green
53+
merge_conditions:
54+
- check-success: alls-green
55+
```
56+
57+
### 2. Set Up Your Workflow
58+
59+
```yaml
60+
name: Continuous Integration
61+
on:
62+
pull_request_target:
63+
types:
64+
- opened
65+
66+
jobs:
67+
scopes:
68+
runs-on: ubuntu-22.04
69+
outputs:
70+
js: ${{ fromJSON(steps.scopes.outputs.scopes).js }}
71+
python: ${{ fromJSON(steps.scopes.outputs.scopes).python }}
72+
merge-queue: ${{ fromJSON(steps.scopes.outputs.scopes).merge-queue }}
73+
steps:
74+
- uses: actions/checkout@v5
75+
- name: Get PR scopes
76+
id: scopes
77+
uses: Mergifyio/gha-mergify-ci
78+
with:
79+
action: scopes
80+
token: ${{ secrets.MERGIFY_TOKEN }}
81+
82+
83+
python:
84+
if: ${{ needs.scopes.outputs.python == 'true' }}
85+
needs: scopes
86+
uses: ./.github/workflows/python.yaml
87+
secrets: inherit
88+
89+
js:
90+
if: ${{ needs.scopes.outputs.js == 'true' }}
91+
needs: scopes
92+
uses: ./.github/workflows/js.yaml
93+
secrets: inherit
94+
95+
integration:
96+
if: ${{ needs.scopes.outputs.merge-queue == 'true' }}
97+
needs: scopes
98+
uses: ./.github/workflows/integration.yaml
99+
secrets: inherit
100+
101+
alls-green:
102+
if: ${{ !cancelled() }}
103+
needs:
104+
- python
105+
- js
106+
- integration
107+
runs-on: ubuntu-latest
108+
steps:
109+
- name: Verify all jobs succeeded
110+
uses: re-actors/alls-green@release/v1
111+
with:
112+
allowed-skips: ${{ toJSON(needs) }}
113+
jobs: ${{ toJSON(needs) }}
114+
```
115+
116+
## Outputs
117+
118+
Each scope defined in `.mergify.yml` becomes an output:
119+
- `scopes.<scope-name>`: Returns `true` if the scope is affected, `false` otherwise
120+
- `scopes.merge-queue`: Automatically set to `true` when running in a merge queue
121+
122+
## Requirements
123+
124+
- Python >= 3.10 (available in the runner environment)

action.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: 'mergify-ci-scopes'
2+
description: 'Mergify: return the scopes of a pull request depending on the changed files'
3+
branding:
4+
icon: arrow-up
5+
color: 'blue'
6+
inputs:
7+
token:
8+
required: false
9+
description: Mergify CI token
10+
mergify_api_url:
11+
required: false
12+
description: URL of the Mergify API
13+
outputs:
14+
scopes:
15+
description: stringified JSON mapping with names of all scopes matching any of changed files
16+
value: ${{ steps.scopes-detection.outputs.scopes }}
17+
runs:
18+
using: "composite"
19+
steps:
20+
- name: Setup Python 🔧
21+
uses: actions/[email protected]
22+
with:
23+
python-version: "3.13"
24+
25+
- name: Install dependencies
26+
shell: bash
27+
run: |
28+
# pip install mergify-cli
29+
pip install -e git+https://github.com/Mergifyio/mergify-cli@devs/sileht/test-bin#egg=mergify-cli
30+
31+
- name: Detect scopes
32+
id: scopes-detection
33+
shell: bash
34+
run: mergify ci scopes --write $RUNNER_TEMP/mergify-scopes.json
35+
36+
- name: Upload scopes to Mergify API
37+
shell: bash
38+
if: ${{ inputs.token }}
39+
env:
40+
MERGIFY_TOKEN: ${{ inputs.token }}
41+
MERGIFY_API_URL: ${{ inputs.mergify_api_url }}
42+
run: mergify ci scopes-send --file $RUNNER_TEMP/mergify-scopes.json

0 commit comments

Comments
 (0)