Skip to content

feat: split changed-paths composite into core detection + filter stages #151

@gandalf-at-lerian

Description

@gandalf-at-lerian

Request Type

Refactor / simplification

Affected Workflow (if applicable)

Utilities (changed-paths, pr-validation, slack-notify, api-dog-e2e-tests)

Problem / Motivation

The current changed-paths composite handles too many responsibilities in a single ~294-line shell script: git diff detection, path normalization (normalize_to_filter), root consolidation (consolidate_to_root), and directory ignore filtering (ignore_dirs).

This violates single responsibility — callers that only need basic "which paths changed" detection still carry all the consolidation and filtering logic. If a bug is introduced in consolidate_to_root, it breaks every consumer, including those that don't use that feature.

Proposed Solution

Split into two composites:

  1. changed-paths (core) — git diff detection only. Outputs raw list of changed paths. Handles PR, tag push, and first-commit edge cases.

  2. changed-paths-filter — receives a list of paths (from core or any source), applies:

    • normalize_to_filter — strip to filter-path level
    • consolidate_to_root — collapse to root when threshold hit
    • ignore_dirs — exclude directories

Each composite becomes independently testable. Callers compose only what they need.

Alternatives Considered

  • Keep as-is with better test coverage — works but doesn't solve the coupling problem.
  • Split by trigger type (PR vs tag vs first-commit) — too granular, trigger detection is tightly coupled to diff logic.

Example Usage

# Simple case — just need changed paths
- uses: ./src/utils/changed-paths
  id: detect
  with:
    filter-paths: src/security/,src/setup/

# Advanced case — detect + filter
- uses: ./src/utils/changed-paths
  id: detect
  with:
    filter-paths: src/security/,src/setup/

- uses: ./src/utils/changed-paths-filter
  with:
    paths: ${{ steps.detect.outputs.changed_dirs }}
    consolidate-to-root: "true"
    ignore-dirs: "node_modules,.git"

Would This Be a Breaking Change?

No — fully backward compatible

The current changed-paths composite can keep its existing interface as a wrapper that calls both stages internally. New callers get the option to use stages independently.

Checklist

  • I searched existing issues and this is not a duplicate.
  • This feature aligns with the repository's goal of providing reusable, organization-wide workflows.

Additional Context

Discussed during review of PR #144 (pr-security-scan refact). The backward-compatible wrapper approach means zero migration cost for existing callers.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions