Skip to content

Commit e50ab19

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

File tree

6 files changed

+327
-0
lines changed

6 files changed

+327
-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: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
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: &DefaultReviewCond
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]
56+
57+
- name: lowprio
58+
<<: *DefaultQueueOptions
59+
autoqueue: true
60+
queue_conditions:
61+
- base=main
62+
- and: *CheckRuns
63+
- "#commits=1"
64+
- or:
65+
- and:
66+
- author=mergify-ci-bot
67+
- head~=^clifus/
68+
- "title~=^chore: bump"
69+
- and:
70+
- author=mergify-ci-bot
71+
- head=trivy/daily-report
72+
- label!=new CVE
73+
- and:
74+
- author=mergify-ci-bot
75+
- head=openapi-spec-sync
76+
- author=dependabot[bot]
77+
merge_method: merge
78+
merge_conditions:
79+
- and: *CheckRuns
80+
- and:
81+
- not: *IsPublicHolidays
82+
- schedule=Mon-Fri 09:00-17:00[Europe/Paris]
83+
batch_size: 7
84+
batch_max_wait_time: 5min
85+
commit_message_template:
86+
queue_branch_merge_method: fast-forward
87+
88+
pull_request_rules:
89+
- name: request review
90+
conditions:
91+
- -author=dependabot[bot]
92+
- -author=mergify-ci-bot
93+
- -merged
94+
- -closed
95+
- and: *CheckRuns
96+
- "#changes-requested-reviews-by=0"
97+
- review-requested!=@devs
98+
- not:
99+
or: *DefaultReviewCond
100+
actions:
101+
request_reviews:
102+
teams:
103+
- devs

README.md

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
# gha-mergify-ci-scopes
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+
```
54+
55+
### 2. Set Up Your Workflow
56+
57+
```yaml
58+
name: Continuous Integration
59+
on:
60+
pull_request_target:
61+
types:
62+
- opened
63+
64+
jobs:
65+
scopes:
66+
runs-on: ubuntu-22.04
67+
outputs:
68+
js: ${{ fromJSON(steps.scopes.outputs.scopes).js }}
69+
python: ${{ fromJSON(steps.scopes.outputs.scopes).python }}
70+
merge-queue: ${{ fromJSON(steps.scopes.outputs.scopes).merge-queue }}
71+
steps:
72+
- uses: actions/checkout@v5
73+
- name: Get PR scopes
74+
id: scopes
75+
uses: Mergifyio/gha-mergify-ci-scopes
76+
77+
python:
78+
if: ${{ needs.scopes.outputs.python == 'true' }}
79+
needs: scopes
80+
uses: ./.github/workflows/python.yaml
81+
secrets: inherit
82+
83+
js:
84+
if: ${{ needs.scopes.outputs.js == 'true' }}
85+
needs: scopes
86+
uses: ./.github/workflows/js.yaml
87+
secrets: inherit
88+
89+
integration:
90+
if: ${{ needs.scopes.outputs.merge-queue == 'true' }}
91+
needs: scopes
92+
uses: ./.github/workflows/integration.yaml
93+
secrets: inherit
94+
95+
alls-green:
96+
if: ${{ !cancelled() }}
97+
needs:
98+
- python
99+
- js
100+
- integration
101+
runs-on: ubuntu-latest
102+
steps:
103+
- name: Verify all jobs succeeded
104+
uses: re-actors/alls-green@release/v1
105+
with:
106+
allowed-skips: ${{ toJSON(needs) }}
107+
jobs: ${{ toJSON(needs) }}
108+
```
109+
110+
## Outputs
111+
112+
Each scope defined in `.mergify.yml` becomes an output:
113+
- `scopes.<scope-name>`: Returns `true` if the scope is affected, `false` otherwise
114+
- `scopes.merge-queue`: Automatically set to `true` when running in a merge queue
115+
116+
## Requirements
117+
118+
- 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)