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 (
.yamlor.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-fileinput):
{ "include": [ { "directory": "app1", "name": "application-one", "version": "1.0.0" }, { "directory": "app2", "name": "application-two", "version": "2.3.0" } ] }MIT