github-webhook-file-filtering
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 createdmodified- Existing files changedremoved- Files deleted
Data Filter Configuration
Basic Syntax
Data filters are defined in the Sensor’s dependencies.filters.data section:
apiVersion: argoproj.io/v1alpha1kind: Sensormetadata: name: github-path-filterspec: 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:
| Syntax | Meaning |
|---|---|
body.field | Access field in webhook body |
# | Iterate over array |
#()# | Flatten nested arrays |
@flatten | Flatten array results |
Important: All paths must start with body. to access the webhook payload.
Working File Path Filter
Recommended Approach: Flattened Multi-Array Path
This is the working solution for filtering on added/modified/removed files:
apiVersion: argoproj.io/v1alpha1kind: Sensormetadata: name: mono-repo-path-filterspec: 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 specHow This Works
-
Path breakdown:
body.commits.#.modified- All modified files across all commits.#()#- Flatten the nested arrays[..., ..., ...]- Combine multiple paths into one result
-
Value matching:
- Values are evaluated as regex patterns
- Multiple values are evaluated with OR logic
.*service/jobs.*matches any path containingservice/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/v1alpha1kind: EventSourcemetadata: name: github-mono-repospec: 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: secretSensor for Service-A
apiVersion: argoproj.io/v1alpha1kind: Sensormetadata: name: service-a-sensorspec: 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.valueFilter 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 matchUsing 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/.*" # MatchesCommon Pitfalls
1. Missing body. Prefix
Wrong:
path: "commits.#.modified" # Missing body prefixCorrect:
path: "body.commits.#.modified"2. Incorrect Array Flattening
Wrong:
path: "body.commits.modified" # Won't iterate commits arrayCorrect:
path: "body.commits.#.modified.#()#" # Iterates and flattens3. Forgetting to Escape Regex
Values are regex patterns. To match literal dots:
value: - ".*\\.config\\.js$" # Matches .config.js files4. 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
- Check webhook delivery in GitHub repo settings → Webhooks
- View EventSource logs:
kubectl logs -l eventsource-name=github-mono-repo - View Sensor logs:
kubectl logs -l sensor-name=service-a-sensor - Test GJSON queries at gjson.dev with your payload