diff --git a/.github/workflows/pull-request-verification.yml b/.github/workflows/pull-request-verification.yml index 27627a9..b18d7ba 100644 --- a/.github/workflows/pull-request-verification.yml +++ b/.github/workflows/pull-request-verification.yml @@ -29,6 +29,9 @@ jobs: - name: filter-test if: steps.filter.outputs.any != 'true' || steps.filter.outputs.error == 'true' run: exit 1 + - name: changes-test + if: contains(fromJSON(steps.filter.outputs.changes), 'error') || !contains(fromJSON(steps.filter.outputs.changes), 'any') + run: exit 1 test-external: runs-on: ubuntu-latest diff --git a/README.md b/README.md index 145ecc0..448a742 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ For more scenarios see [examples](#examples) section. ## Notes: - Paths expressions are evaluated using [picomatch](https://github.com/micromatch/picomatch) library. Documentation for path expression format can be found on project github page. -- Micromatch [dot](https://github.com/micromatch/picomatch#options) option is set to true. +- Picomatch [dot](https://github.com/micromatch/picomatch#options) option is set to true. Globbing will match also paths where file or folder name starts with a dot. - It's recommended to quote your path expressions with `'` or `"`. Otherwise you will get an error if it starts with `*`. - Local execution with [act](https://github.com/nektos/act) works only with alternative runner image. Default runner doesn't have `git` binary. @@ -66,6 +66,7 @@ For more scenarios see [examples](#examples) section. # What's New +- Configure matrix job to run for each folder with changes using `changes` output - Improved listing of matching files with `list-files: shell` and `list-files: escape` options - Support local changes - Fixed retrieval of all changes via Github API when there are 100+ changes @@ -122,9 +123,9 @@ For more information see [CHANGELOG](https://github.com/actions/checkout/blob/ma # Enables listing of files matching the filter: # 'none' - Disables listing of matching files (default). # 'json' - Matching files paths are formatted as JSON array. - # 'shell' - Space delimited list usable as command line argument list in linux shell. + # 'shell' - Space delimited list usable as command line argument list in Linux shell. # If needed it uses single or double quotes to wrap filename with unsafe characters. - # 'escape'- Space delimited list usable as command line argument list in linux shell. + # 'escape'- Space delimited list usable as command line argument list in Linux shell. # Backslash escapes every potentially unsafe character. # Default: none list-files: '' @@ -147,6 +148,7 @@ For more information see [CHANGELOG](https://github.com/actions/checkout/blob/ma - `'true'` - if **any** of changed files matches any of filter rules - `'false'` - if **none** of changed files matches any of filter rules - If enabled, for each filter it sets output variable with name `${FILTER_NAME}_files`. It will contain list of all files matching the filter. +- `changes` - JSON array with names of all filters matching any of changed files. # Examples @@ -230,6 +232,41 @@ jobs: ``` +
+Use change detection to configure matrix job + +```yaml +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 + steps: + - uses: actions/checkout@v2 + - ... +``` +
+ ## Change detection workflows
@@ -406,7 +443,7 @@ jobs: # Enable listing of files matching each filter. # Paths to files will be available in `${FILTER_NAME}_files` output variable. # Paths will be escaped and space-delimited. - # Output is usable as command line argument list in linux shell + # Output is usable as command line argument list in Linux shell list-files: shell # In this example changed files will be checked by linter. diff --git a/action.yml b/action.yml index d1321d6..41c15ba 100644 --- a/action.yml +++ b/action.yml @@ -37,6 +37,9 @@ inputs: This option takes effect only when changes are detected using git against different base branch. required: false default: '10' +outputs: + changes: + description: JSON array with names of all filters matching any of changed files runs: using: 'node12' main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js index 953026b..3b17e87 100644 --- a/dist/index.js +++ b/dist/index.js @@ -4791,10 +4791,12 @@ async function getChangedFilesFromApi(token, pullRequest) { } function exportResults(results, format) { core.info('Results:'); + const changes = []; for (const [key, files] of Object.entries(results)) { const value = files.length > 0; core.startGroup(`Filter ${key} = ${value}`); if (files.length > 0) { + changes.push(key); core.info('Matching files:'); for (const file of files) { core.info(`${file.filename} [${file.status}]`); @@ -4809,6 +4811,14 @@ function exportResults(results, format) { core.setOutput(`${key}_files`, filesValue); } } + if (results['changes'] === undefined) { + const changesJson = JSON.stringify(changes); + core.info(`Changes output set to ${changesJson}`); + core.setOutput('changes', changesJson); + } + else { + core.info('Cannot set changes output variable - name already used by filter output'); + } core.endGroup(); } function serializeExport(files, format) { diff --git a/src/main.ts b/src/main.ts index 176dafc..e2ccb65 100644 --- a/src/main.ts +++ b/src/main.ts @@ -175,10 +175,12 @@ async function getChangedFilesFromApi( function exportResults(results: FilterResults, format: ExportFormat): void { core.info('Results:') + const changes = [] for (const [key, files] of Object.entries(results)) { const value = files.length > 0 core.startGroup(`Filter ${key} = ${value}`) if (files.length > 0) { + changes.push(key) core.info('Matching files:') for (const file of files) { core.info(`${file.filename} [${file.status}]`) @@ -193,6 +195,14 @@ function exportResults(results: FilterResults, format: ExportFormat): void { core.setOutput(`${key}_files`, filesValue) } } + + if (results['changes'] === undefined) { + const changesJson = JSON.stringify(changes) + core.info(`Changes output set to ${changesJson}`) + core.setOutput('changes', changesJson) + } else { + core.info('Cannot set changes output variable - name already used by filter output') + } core.endGroup() }