/til/

2025 0509 Argo Workflows path trigger

In Argo Workflows, you can have a Sensor trigger only when specific paths in a repo have changed, but it isn’t well documented. Here’s how it works.

Trigger on any change

You’ll want to make sure this is working first.

  1. Deploy a WorkflowTemplate; here we’ll assume called build-example is already created.

  2. A webhook EventSource

    apiVersion: argoproj.io/v1alpha1
    kind: EventSource
    metadata:
    name: example-webhook
    namespace: argowf
    spec:
    replicas: 2
    service:
        ports:
        - name: http
            port: 12000
            targetPort: 12000
    webhook:
        gitea-webhook:
        endpoint: /gitea
        method: POST
        port: "12000" # Has to be a string because lol
    
  3. Configure a repository in Gitea to call that webhook on every push

  4. Configure a Sensor. Replace REPO_OWNER/REPO_NAME with the owner and name of the repo in Gitea. Note: you’ll also need to define a trigger,

    apiVersion: argoproj.io/v1alpha1
    kind: Sensor
    metadata:
    name: workflow-build-example-project
    namespace: argowf
    spec:
    template:
        serviceAccountName: argowf-sensor
        container:
        env:
            - name: LOG_LEVEL
            value: "debug"
    
    dependencies:
        - name: gitea-webhook-dep
          eventSourceName: example-webhook
          eventName: gitea-webhook
          filters:
            data:
            - path: body.repository.full_name
                type: string
                value:
                - "REPO_OWNER/REPO_NAME"
    
    triggers:
    - template:
        name: argo-workflow-trigger
        argoWorkflow:
          operation: submit
          source:
            resource:
              apiVersion: argoproj.io/v1alpha1
              kind: Workflow
              metadata:
                generateName: wf-build-example-
                namespace: argowf
              spec:
                workflowTemplateRef:
                  name: build-example
    
  5. This will trigger your build-example WorkflowTemplate any time you push to the REPO_OWNER/REPO_NAME git repository in your Gitea server.

Trigger for specific path

It’s possible to trigger only on specific paths, but it isn’t well documented and the syntax is really confusing.

To make this work, you need to add another data filter. For instance, this will match on any file starting with some/path/.* (including subfolders):

      filters:
        # Require that all of the data filters match; boolean AND
        dataLogicalOperator: "and"
        data:
          # The same filter we had above, matching on the specific repo
          - path: body.repository.full_name
            type: string
            value:
              - "REPO_OWNER/REPO_NAME"
          # A new filter, requiring that at least one of the files added/changed/removed in the commit is under some/path/ in the repo
          - path: "[body.commits.#.modified.@flatten,body.commits.#.added.@flatten,body.commits.#.removed.@flatten].@flatten.@flatten"
            type: string
            value:
              - '"some/path/.*'

How does this work?

First, note that how this works depends entirely on the webhook payload from your Git server. I’m using Gitea, which is supposedly compatible with Github, but this isn’t a standard. If you’re using some other Git server, you’ll need to figure out what its webhook payload body looks like. (One way to do this is by creating a Sensor and reading the logs of the Sensor container while pushing a commit.)

Gitea (and GitHub) send(s) a rather large JSON payload, including a list of commits and a list of files modified/added/removed in each. For instance, a commit that changes some/path/README.md and adds some/path/main.c will include this (heavily truncated):

{
  "body": {
    "commits": [
      {
        "added": [
          "some/path/main.c"
        ],
        "modified": [
          "some/path/README.md"
        ]
      }
    ]
  }
}

In the path field of a data filter, Argo Workflows supports something called GJSON Path syntax, which we use to collapse all modified, added, and removed lists into a SINGLE list containing all the files that were added, modified, or removed, like this:

["some/path/main.c", "some/path/README.md"]

The value field of the data filter is a regexp that operates on that JSON string, as a string. To be clear, it doesn’t understand JSON at all, and does not operate on individual list items. For non-pathological repositories you can just match on double quotes " as the beginning/end of file names; in theory you could have a repo with files that contain quotes, but my advice is: do not do that.

Here’s a simple case matching a single sub-path:

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

Note that the whole thing is wrapped in single quotes '; this is so the double quote " character is parsed as part of the string.

Trigger for a list of paths

Here’s a more complicated case, matching any of several sub-paths, separated by pipes. Note the double quote " as the first character, indicating that all of these path fragments must be at the beginning.

- path: "[body.commits.#.modified.@flatten,body.commits.#.added.@flatten,body.commits.#.removed.@flatten].@flatten.@flatten"
  type: string
  value:
  - '"(path/one|path/two/that/is/deeper|path3|etc)'

See also

I’ve adapted this from my labnotes, which I used for general documentation of my kubernasty homelab cluster.

References

Responses

Webmentions

Hosted on remote sites, and collected here via Webmention.io (thanks!).

Comments

Comments are hosted on this site and powered by Remark42 (thanks!).