Skip to content

CI Optimization: Skip Linting for README Changes in GitHub Actions

In a high-scale microservices monorepo, triggering expensive linting or testing jobs for documentation-only changes (like README.md updates) results in wasted compute minutes and developer friction. As a Senior Cloud Architect, optimizing the CI/CD feedback loop is critical for maintaining developer velocity and reducing cloud costs.

This guide addresses how to implement path-based filtering to intelligently skip jobs based on the specific files modified within a pull request or push event.

The goal is to prevent the linting job from executing if the diff contains only README.md files within the services/ directory, but to ensure it runs if any .py, .js, .go, or configuration files are touched within those same directories.

When the filter is not configured, you see unnecessary resource consumption in the GitHub Actions runner:

Terminal window
# GitHub Actions Runner Log
2023-10-27T10:15:22.441Z [INFO] - Starting Job: Linter
2023-10-27T10:15:24.120Z [DEBUG] - Checking changed files...
2023-10-27T10:15:25.500Z [DEBUG] - Files detected: services/auth-api/README.md
2023-10-27T10:15:26.800Z [INFO] - Running 'npm run lint'...
2023-10-27T10:16:45.120Z [INFO] - Job completed. Duration: 1m 22s.
# Result: Successfully linted, but 82 seconds of runner time wasted on MD files.

Before applying the fix, verify your environment and repository structure:

  1. Directory Structure: Confirm if services are nested (e.g., services/api-gateway/, services/user-service/).
  2. Trigger Type: Identify if you are triggering on push, pull_request, or both.
  3. Glob Pattern Accuracy: Ensure your glob patterns correctly distinguish between root-level documentation and service-level documentation.
  4. Workflow Granularity: Decide if you want to skip the entire workflow or just a specific job within the workflow.

Method 1: Workflow-Level Filtering (Simplest)

Section titled “Method 1: Workflow-Level Filtering (Simplest)”

If your entire workflow consists only of linting, use the native on.<event>.paths-ignore configuration. This prevents the workflow from even being queued.

name: Microservice-Linter
on:
push:
branches:
- main
paths:
- 'services/**' # Trigger if anything in services changes
paths-ignore:
- 'services/**/README.md' # EXCEPT if it is only a README
- 'docs/**' # Ignore root docs
pull_request:
paths:
- 'services/**'
paths-ignore:
- 'services/**/README.md'
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Linter
run: |
echo "Executing code quality checks..."
# Your lint command here

Method 2: Job-Level Filtering (For Complex Monorepos)

Section titled “Method 2: Job-Level Filtering (For Complex Monorepos)”

In many cloud environments, you might have one workflow that builds an image and lints code. You want the lint job to skip on README.md changes, but perhaps you still want a documentation-sync job to run. For this, use the dorny/paths-filter action.

name: CI-Pipeline
on:
pull_request:
branches: [main]
jobs:
changes:
runs-on: ubuntu-latest
outputs:
code: ${{ steps.filter.outputs.code }}
steps:
- uses: actions/checkout@v4
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
code:
- 'services/**'
- '!services/**/README.md'
lint-service:
needs: changes
if: ${{ needs.changes.outputs.code == 'true' }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Environment
uses: actions/setup-node@v3
with:
node-version: '18'
- name: Install Dependencies
run: npm ci
- name: Lint
run: npm run lint
  1. Glob Negation: In Method 2, the ! symbol explicitly negates the pattern. This tells the runner: “Check all files in services, but subtract any README.md from that list.”
  2. Short-Circuiting: By using the if conditional in Method 2, the lint-service job will show as “Skipped” in the GitHub UI, providing a clear visual cue to developers that the CI behaved as expected.
  3. Environment Efficiency: This logic reduces the load on your GitHub-hosted or self-hosted runners, preventing queue backups during high-volume documentation updates.