A GitHub Action that scans a directory and generates a matrix of subdirectories for parallelizing downstream jobs.
Perfect for monorepos and projects with multiple components.
---
name: Build All Projects
permissions: { contents: read }
on:
push: {}
jobs:
discover:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.scan.outputs.matrix }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Discover Projects
uses: mirceanton/action-folder-matrix@v1
id: scan
with:
path: './projects'
build:
name: 'Building ${{ matrix.directory }}'
needs: discover
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJson(needs.discover.outputs.matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build
working-directory: ./projects/${{ matrix.directory }}
run: npm ci && npm run build
Input | Description | Required | Default |
---|---|---|---|
path |
Path to the directory to scan for subdirectories | Yes | "." |
include-hidden |
Whether to include hidden directories (starting with .) | No | false |
exclude |
Comma-separated list of directory names to exclude | No | N/A |
filter |
Regular expression pattern to filter directory names (only matching directories will be included) | No | N/A |
metadata-file |
Path to metadata file within each subdirectory (e.g., package.json , Chart.yaml ) |
No | N/A |
changed-only |
Whether to include only directories with changes | No | false |
github-token |
GitHub token used to get changed files (required when changed-only is true) | No | N/A |
The filter
input allows you to include only directories whose names match a regular expression pattern. This is useful
for selecting specific types of directories in complex monorepos.
# Include only directories that start with "service-"
- name: Discover Services
uses: mirceanton/action-folder-matrix@v1
with:
path: './packages'
filter: '^service-.*'
# Include directories that match either "app-" or "lib-" prefix
- name: Discover Apps and Libraries
uses: mirceanton/action-folder-matrix@v1
with:
path: './packages'
filter: '^(app|lib)-.*'
# Include directories ending with "-api" or "-service"
- name: Discover Backend Services
uses: mirceanton/action-folder-matrix@v1
with:
path: './services'
filter: '.*(api|service)$'
You can specify a metadata file to be read from each subdirectory with the metadata-file
input parameter. The contents
of this file will be included in the matrix output, allowing you to use values like version, name, or other parameters
in your downstream jobs.
Supported formats:
- JSON (
.json
) - YAML (
.yaml
or.yml
)
For a monorepo with Node.js packages, you could use:
jobs:
discover:
runs-on: ubuntu-latest
steps:
- name: Discover Projects with Metadata
uses: mirceanton/action-folder-matrix@v1
id: scan
with:
path: './packages'
metadata-file: 'package.json'
filter: '^service-.*' # Only include service packages
build:
name: 'Building ${{ matrix.name }} v${{ matrix.version }}'
needs: discover
runs-on: ubuntu-latest
strategy:
matrix: ${{ fromJson(needs.discover.outputs.matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Build and Publish
working-directory: ./packages/${{ matrix.directory }}
run: |
echo "Building ${{ matrix.name }} version ${{ matrix.version }}"
npm ci && npm run build
npm publish --tag=${{ matrix.version }}
When changed-only
is set to true
, the action will only include directories that contain files modified in the
current push or pull request. This requires a GitHub token with repository access.
- name: Discover Changed Projects
uses: mirceanton/action-folder-matrix@v1
with:
path: './projects'
changed-only: true
github-token: ${{ secrets.GITHUB_TOKEN }}
You can combine multiple filtering options for fine-grained control:
- name: Discover Filtered Projects
uses: mirceanton/action-folder-matrix@v1
with:
path: './packages'
include-hidden: false # Exclude hidden directories
exclude: 'deprecated,old-app' # Exclude specific directories
filter: '^(service|app)-.*' # Only include service-* and app-* directories
changed-only: true # Only include directories with changes
github-token: ${{ secrets.GITHUB_TOKEN }}
The filters are applied in this order:
- Hidden directory check (
include-hidden
) - Exclude list (
exclude
) - Regular expression filter (
filter
) - Changed files check (
changed-only
)
Output | Description |
---|---|
matrix |
JSON array of subdirectory names for use in matrix strategy |
The action always outputs a JSON object that can be directly used with a matrix strategy in downstream jobs:
- When not using metadata files (default behavior):
{
"directory": ["app1", "app2", "lib1", "lib2"]
}
- When using metadata files (with the
metadata-file
input):
{
"include": [
{
"directory": "app1",
"name": "application-one",
"version": "1.0.0"
},
{
"directory": "app2",
"name": "application-two",
"version": "2.3.0"
}
]
}
MIT