paths-filter
paths-filter copied to clipboard
Is there a way to list only folders with changes
I'm working on a repo where this GitHub Action would be very useful. The folder structure is:
.
└── .github
└── workflows
└── deploy.yml
├── README.md
└── Services
├── serviceone
│ └── bunch_of_files
├── servicetwo
│ └── bunch_of_files
└── servicethree
└── bunch_of_files
The deploy.yml
file currently looks like
name: 'Deploy'
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Check which services were modified
uses: dorny/paths-filter@v2
id: filter
with:
list-files: shell
filters: |
services:
- 'Services/**'
- name: Deploy changed services
if: ${{ steps.filter.outputs.services == 'true' }}
run: |
echo "All changes:"
for i in ${{ steps.filter.outputs.services_files }}; do echo $i | awk ; done
Instead of outputting the individual files changes in Services/**
is there a way to just output the folders containing changes such as
Services/serviceone
Services/servicethree
Thanks!
I have exactly the same requirement! I want to trigger a Terraform plan, based on changed files in a certain directory, so if this is possible it would be really nice!
For what its worth I was able to accomplish this for my use case by following the example: Use change detection to configure matrix job
From the Readme https://github.com/dorny/paths-filter#conditional-execution
@ndpete what did you do to go from changed files to the directories? Did you add an extra step with some shell scripts?
So my filters are just slightly different than the example. The key on the filter is a directory name and the value is the directory. After the matrix is setup I just set a default working-directory to the output from the matrix which is the key and therefore the directory I need to run from. Below is the example modified similiar to what I have.
jobs:
# JOB to run change detection
changes:
runs-on: ubuntu-latest
outputs:
# Expose matched filters as job 'packages' output variable
packages: ${{ steps.filter.outputs.changes }}
steps:
# For pull requests it's not necessary to checkout the code
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
package1: src/package1
package2: src/package2
# JOB to build and test each of modified packages
build:
needs: changes
strategy:
matrix:
# Parse JSON array containing names of all filters matching any of changed files
# e.g. ['package1', 'package2'] if both package folders contains changes
package: ${{ fromJSON(needs.changes.outputs.packages) }}
runs-on: ubuntu-latest
defaults:
run:
working-directory: src/${{ matrix.package }}
steps:
- uses: actions/checkout@v2
- ...
So the two key points are key in the filter is the directory name and then the part:
defaults:
run:
working-directory: src/${{ matrix.package }}
This sets the working directory for the matrix jobs to src/{whatever the current matrix job is}
Does that make any sense? I could mock up a repo that shows the process if needed.
@ndpete - does this mean you have to update the workflow file each time you add another "package" in the src directory?
in past I used shell script similar to this:
for f in {{ steps.filter.outputs.packages }}; do echo $(dirname $f);done | sort | cut ... | uniq
I put all of the above in a composite action so I have simple workflow, but it would be a lot nicer if it was part of the paths-filter action itself :(
also, it's best to include an aggregate check which can be used in branch protection rules as the actual checks vary due to the matrix set up
@ahrenstein @vincentgna
I ended up with this hacky solution:
jobs:
changes:
runs-on: ubuntu-latest
# Required permissions
# permissions:
# pull-requests: read
outputs:
# Expose matched filters as job 'packages' output variable
packages: ${{ steps.filter.outputs.changes }}
directories: ${{ steps.transform.outputs.directories }}
steps:
# For pull requests it's not necessary to checkout the code
- name: Checkout
uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
base: ${{ github.ref }}
list-files: shell
filters: |
azure:
- azure/**
- name: transform to directories
id: transform
continue-on-error: false
run: |
folders=()
for f in ${{ steps.filter.outputs.azure_files }}; \
do \
echo "Adding $(dirname $f) to folders"; \
folders+=($(dirname $f)); \
done
unique_folders=($(printf "%s\n" "${folders[@]}" | sort -u | tr '\n' ' '))
echo "directories=$(jq --compact-output --null-input '$ARGS.positional' --args -- ${unique_folders[@]})" >> $GITHUB_OUTPUT
terraform:
needs: changes
name: "Terraform"
runs-on: ubuntu-latest
strategy:
matrix:
directory: ${{ fromJSON(needs.changes.outputs.directories) }}
steps:
- name: test
run: echo ${{ matrix.directory }}
It would be great to add an option that simulates it, something like list-directories: shell
. I don't mind adding a PR if it's accepted by the owners.