Purpose

Configure Argo Events to trigger workflows only when specific file paths are modified in GitHub push events. This is essential for mono-repo setups where you want different workflows for different directories.

Architecture Overview

GitHub Push Event
┌─────────────────┐
│ EventSource │ (Receives webhook)
│ (github type) │
└────────┬────────┘
┌─────────────────┐
│ Sensor │ (Applies data filters)
│ │ ← FILE PATH FILTERING HERE
└────────┬────────┘
┌─────────────────┐
│ Argo Workflow │ (Triggered if filter passes)
└─────────────────┘

GitHub Push Event Payload Structure

Understanding the webhook payload is critical. A GitHub push event contains:

{
"ref": "refs/heads/main",
"commits": [
{
"id": "abc123",
"message": "Update service",
"added": ["service/jobs/new-file.ts"],
"removed": ["old/deprecated.ts"],
"modified": ["service/common/utils.ts", "README.md"]
},
{
"id": "def456",
"message": "Another commit",
"added": [],
"removed": [],
"modified": ["service/jobs/handler.ts"]
}
]
}

Key arrays per commit:

  • added - New files created
  • modified - Existing files changed
  • removed - Files deleted

Data Filter Configuration

Basic Syntax

Data filters are defined in the Sensor’s dependencies.filters.data section:

apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: github-path-filter
spec:
dependencies:
- name: github-dep
eventSourceName: github
eventName: example
filters:
data:
- path: <GJSON_PATH>
type: string
value:
- "<REGEX_PATTERN>"

GJSON Path Syntax

Argo Events uses GJSON for path queries. Key syntax:

SyntaxMeaning
body.fieldAccess field in webhook body
#Iterate over array
#()#Flatten nested arrays
@flattenFlatten array results

Important: All paths must start with body. to access the webhook payload.

Working File Path Filter

This is the working solution for filtering on added/modified/removed files:

apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: mono-repo-path-filter
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: github-dep
eventSourceName: github
eventName: push
filters:
data:
- path: "[body.commits.#.modified.#()#,body.commits.#.added.#()#,body.commits.#.removed.#()#]"
type: string
value:
- ".*service/jobs.*"
- ".*service/common.*"
triggers:
- template:
name: trigger-workflow
k8s:
operation: create
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
# ... workflow spec

How This Works

  1. Path breakdown:

    • body.commits.#.modified - All modified files across all commits
    • .#()# - Flatten the nested arrays
    • [..., ..., ...] - Combine multiple paths into one result
  2. Value matching:

    • Values are evaluated as regex patterns
    • Multiple values are evaluated with OR logic
    • .*service/jobs.* matches any path containing service/jobs

Alternative Flatten Syntax

Another working syntax using @flatten:

filters:
data:
- path: "[body.commits.#.modified.@flatten,body.commits.#.added.@flatten,body.commits.#.removed.@flatten].@flatten.@flatten"
type: string
value:
- "example/.*"

Complete Example: Mono-Repo with Multiple Services

Scenario

mono-repo/
├── service-a/
├── service-b/
├── shared/
└── docs/

Goal: Trigger service-a workflow only when service-a/ or shared/ changes.

EventSource

apiVersion: argoproj.io/v1alpha1
kind: EventSource
metadata:
name: github-mono-repo
spec:
service:
ports:
- port: 12000
targetPort: 12000
github:
mono-repo:
repositories:
- owner: your-org
names:
- mono-repo
webhook:
endpoint: /push
port: "12000"
method: POST
url: https://your-ingress.example.com
events:
- push
apiToken:
name: github-access
key: token
webhookSecret:
name: github-access
key: secret

Sensor for Service-A

apiVersion: argoproj.io/v1alpha1
kind: Sensor
metadata:
name: service-a-sensor
spec:
template:
serviceAccountName: operate-workflow-sa
dependencies:
- name: service-a-changes
eventSourceName: github-mono-repo
eventName: mono-repo
filters:
data:
# Filter for branch
- path: body.ref
type: string
value:
- "refs/heads/main"
- "refs/heads/develop"
# Filter for file paths
- path: "[body.commits.#.modified.#()#,body.commits.#.added.#()#,body.commits.#.removed.#()#]"
type: string
value:
- ".*service-a/.*"
- ".*shared/.*"
triggers:
- template:
name: build-service-a
k8s:
operation: create
source:
resource:
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: build-service-a-
spec:
entrypoint: build
arguments:
parameters:
- name: commit-sha
templates:
- name: build
inputs:
parameters:
- name: commit-sha
container:
image: your-build-image:latest
command: ["/bin/sh", "-c"]
args:
- |
echo "Building service-a at commit {{inputs.parameters.commit-sha}}"
# Your build commands here
parameters:
- src:
dependencyName: service-a-changes
dataKey: body.after
dest: spec.arguments.parameters.0.value

Filter Logic and Operators

Default Behavior: AND

Multiple data filters are combined with AND logic by default:

filters:
data:
- path: body.ref
type: string
value: ["refs/heads/main"] # Must match
- path: "[body.commits.#.modified.#()#]"
type: string
value: [".*service/.*"] # AND must match

Using OR Logic

Set dataLogicalOperator to change behavior:

filters:
dataLogicalOperator: "or" # Any filter passing triggers
data:
- path: body.field1
type: string
value: ["pattern1"]
- path: body.field2
type: string
value: ["pattern2"]

Multiple Values = OR

Within a single filter, multiple values are evaluated as OR:

- path: "[body.commits.#.modified.#()#]"
type: string
value:
- ".*service-a/.*" # Matches OR
- ".*service-b/.*" # Matches OR
- ".*shared/.*" # Matches

Common Pitfalls

1. Missing body. Prefix

Wrong:

path: "commits.#.modified" # Missing body prefix

Correct:

path: "body.commits.#.modified"

2. Incorrect Array Flattening

Wrong:

path: "body.commits.modified" # Won't iterate commits array

Correct:

path: "body.commits.#.modified.#()#" # Iterates and flattens

3. Forgetting to Escape Regex

Values are regex patterns. To match literal dots:

value:
- ".*\\.config\\.js$" # Matches .config.js files

4. Not Handling Empty Arrays

If no files were modified/added/removed, the path may return empty. Consider:

  • Using dataLogicalOperator: "or" if you have multiple path conditions
  • Testing with commits that actually change files

Debugging Tips

  1. Check webhook delivery in GitHub repo settings → Webhooks
  2. View EventSource logs: kubectl logs -l eventsource-name=github-mono-repo
  3. View Sensor logs: kubectl logs -l sensor-name=service-a-sensor
  4. Test GJSON queries at gjson.dev with your payload

Sources

  1. Argo Events Data Filter Documentation
  2. Stack Overflow: Argo Events mono-repo path filtering
  3. GitHub Issue : Multiple path filter best practices
  4. Argo Events GitHub EventSource Setup
  5. Example GitHub Sensor YAML
  6. GJSON Path Syntax