argoproj / argo-workflows

Workflow Engine for Kubernetes
https://argo-workflows.readthedocs.io/
Apache License 2.0
14.83k stars 3.17k forks source link

Conditionally Run Workflows Based on Git Artifact Files Changed #8415

Open tony-mw opened 2 years ago

tony-mw commented 2 years ago

Summary

It would be useful to add a key:list(values) option to the git artifact stanza of the Workflow/Workflow-Template CRD where an operator can specify the paths of files that, when modified, will trigger the workflow.

Use Cases

I ran into a scenario where I needed this functionality to set a working directory for a later stage in my workflow, based on the files changed in the repo. That was specifically for a Terraform workflow, but I could see this also being useful in monorepos containing multiple microservices where builds should only happen when code specific directories has changed.

I was able to achieve this by developing a custom go program that leverages the go-git package to derive file changes that occur when an Event triggers a Workflow. This runs as a pre-build stage in the workflow currently, and passes the working directories from one stage to the next.

Here is a snippet of my code which is triggered if the event is a pull request that I think could likely be a good starting point to add this feature. (If the event is just a commit to main or any branch that builds, there is less logic because you only have to compare the 2 latest commits instead of every ancestor of main)

    ref, _ := repo.Log(&git.LogOptions{
        From:  myBranchRef,
    })

    ref.ForEach(func(c *object.Commit) error {
        ancestor, _ := c.IsAncestor(currentCommit)
        if logger.Check() {
            log.Printf("Is ancestor: %t", ancestor)
        }
        if ancestor {
            appendOn = false
            return nil
        }
        if appendOn {
            commits = append(commits, c)
        }
        return nil
    })

    for _, v := range commits {
        diff, err := v.Patch(currentCommit)
        if err != nil {
            log.Fatal(err)
        }
        filesPatched := diff.FilePatches()
        for _, fileList := range filesPatched {
            if fileList.IsBinary() {
                log.Println("Ignoring binary files")
                continue
            }
            from, to := fileList.Files()
            if from.Path() == to.Path() {
                filesChanged = append(filesChanged, from.Path())
            } 
        }
    }

Message from the maintainers:

Love this enhancement proposal? Give it a 👍. We prioritise the proposals with the most 👍.

terrytangyuan commented 2 years ago

Use Argo Events to setup a GitHub event source: https://github.com/argoproj/argo-events/blob/master/docs/eventsources/setup/github.md

And then trigger a Argo workflow: https://github.com/argoproj/argo-events/blob/master/docs/sensors/triggers/argo-workflow.md

tony-mw commented 2 years ago

Right, that works in GitHub... but the problem is that some source control tools don't send you which files change in their event

terrytangyuan commented 2 years ago

File event source might be what you want: https://github.com/argoproj/argo-events/blob/master/docs/eventsources/setup/file.md

OneCricketeer commented 1 year ago

File event source might be what you want

Am I missing some context? How would this help with Git event trigger?