77 branches : [main]
88
99jobs :
10- # Discover all projects in the repository
10+ # Discover all projects in the repository and filter by changed files
1111 discover :
1212 runs-on : ubuntu-latest
1313 outputs :
14- node-projects : ${{ steps.find -projects.outputs.node-projects }}
15- poetry-projects : ${{ steps.find -projects.outputs.poetry-projects }}
16- uv-projects : ${{ steps.find -projects.outputs.uv-projects }}
17- pip-projects : ${{ steps.find -projects.outputs.pip-projects }}
14+ node-projects : ${{ steps.filter -projects.outputs.node-projects }}
15+ poetry-projects : ${{ steps.filter -projects.outputs.poetry-projects }}
16+ uv-projects : ${{ steps.filter -projects.outputs.uv-projects }}
17+ pip-projects : ${{ steps.filter -projects.outputs.pip-projects }}
1818 steps :
1919 - uses : actions/checkout@v4
20+ with :
21+ fetch-depth : 0
22+
23+ - name : Get changed files
24+ id : changed-files
25+ run : |
26+ if [ "${{ github.event_name }}" == "pull_request" ]; then
27+ # For PRs, compare against the base branch
28+ CHANGED_FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | tr '\n' ' ')
29+ else
30+ # For pushes, compare against the previous commit
31+ CHANGED_FILES=$(git diff --name-only HEAD~1...HEAD 2>/dev/null | tr '\n' ' ' || echo "")
32+ fi
33+ echo "Changed files: $CHANGED_FILES"
34+ echo "files=$CHANGED_FILES" >> $GITHUB_OUTPUT
2035
2136 - name : Find all projects
2237 id : find-projects
@@ -41,11 +56,79 @@ jobs:
4156 done | sort -u | jq -R -s -c 'split("\n") | map(select(length > 0))')
4257 echo "pip-projects=$PIP_PROJECTS" >> $GITHUB_OUTPUT
4358
59+ - name : Filter projects by changed files
60+ id : filter-projects
61+ run : |
62+ CHANGED_FILES="${{ steps.changed-files.outputs.files }}"
63+
64+ echo "DEBUG: Changed files = '$CHANGED_FILES'"
65+
66+ # If no changed files detected (e.g., first commit), run all projects
67+ if [ -z "$CHANGED_FILES" ]; then
68+ echo "No changed files detected, running all projects"
69+ echo "node-projects=${{ steps.find-projects.outputs.node-projects }}" >> $GITHUB_OUTPUT
70+ echo "poetry-projects=${{ steps.find-projects.outputs.poetry-projects }}" >> $GITHUB_OUTPUT
71+ echo "uv-projects=${{ steps.find-projects.outputs.uv-projects }}" >> $GITHUB_OUTPUT
72+ echo "pip-projects=${{ steps.find-projects.outputs.pip-projects }}" >> $GITHUB_OUTPUT
73+ exit 0
74+ fi
75+
76+ # Check if CI workflow itself changed - if so, run all projects
77+ if echo "$CHANGED_FILES" | grep -qE "(^|[[:space:]])\.github/workflows/ci\.yml([[:space:]]|$)"; then
78+ echo "CI workflow changed, running all projects"
79+ echo "node-projects=${{ steps.find-projects.outputs.node-projects }}" >> $GITHUB_OUTPUT
80+ echo "poetry-projects=${{ steps.find-projects.outputs.poetry-projects }}" >> $GITHUB_OUTPUT
81+ echo "uv-projects=${{ steps.find-projects.outputs.uv-projects }}" >> $GITHUB_OUTPUT
82+ echo "pip-projects=${{ steps.find-projects.outputs.pip-projects }}" >> $GITHUB_OUTPUT
83+ exit 0
84+ fi
85+
86+ # Filter projects based on changed files
87+ filter_projects() {
88+ local projects_json="$1"
89+ local matched_projects=""
90+
91+ # Parse JSON array and check each project
92+ while IFS= read -r project; do
93+ [ -z "$project" ] && continue
94+
95+ # Remove leading ./ for comparison
96+ project_path="${project#./}"
97+
98+ # Check if any changed file starts with this project path
99+ for changed_file in $CHANGED_FILES; do
100+ changed_file_clean="${changed_file#./}"
101+ if [[ "$changed_file_clean" == "$project_path"* ]]; then
102+ if [ -z "$matched_projects" ]; then
103+ matched_projects="\"$project\""
104+ else
105+ matched_projects="$matched_projects,\"$project\""
106+ fi
107+ break
108+ fi
109+ done
110+ done < <(echo "$projects_json" | jq -r '.[]')
111+
112+ # Return as JSON array
113+ echo "[$matched_projects]"
114+ }
115+
116+ # Filter each project type
117+ NODE_FILTERED=$(filter_projects '${{ steps.find-projects.outputs.node-projects }}')
118+ POETRY_FILTERED=$(filter_projects '${{ steps.find-projects.outputs.poetry-projects }}')
119+ UV_FILTERED=$(filter_projects '${{ steps.find-projects.outputs.uv-projects }}')
120+ PIP_FILTERED=$(filter_projects '${{ steps.find-projects.outputs.pip-projects }}')
121+
122+ echo "node-projects=$NODE_FILTERED" >> $GITHUB_OUTPUT
123+ echo "poetry-projects=$POETRY_FILTERED" >> $GITHUB_OUTPUT
124+ echo "uv-projects=$UV_FILTERED" >> $GITHUB_OUTPUT
125+ echo "pip-projects=$PIP_FILTERED" >> $GITHUB_OUTPUT
126+
44127 # Debug output
45- echo "Node.js projects: $NODE_PROJECTS "
46- echo "Poetry projects: $POETRY_PROJECTS "
47- echo "uv projects: $UV_PROJECTS "
48- echo "pip projects: $PIP_PROJECTS "
128+ echo "Filtered Node.js projects: $NODE_FILTERED "
129+ echo "Filtered Poetry projects: $POETRY_FILTERED "
130+ echo "Filtered uv projects: $UV_FILTERED "
131+ echo "Filtered pip projects: $PIP_FILTERED "
49132
50133 # Build and lint Node.js projects
51134 node :
@@ -266,10 +349,22 @@ jobs:
266349 steps :
267350 - name : Check all jobs passed
268351 run : |
269- if [ "${{ needs.node.result }}" == "failure" ] || \
270- [ "${{ needs.poetry.result }}" == "failure" ] || \
271- [ "${{ needs.uv.result }}" == "failure" ] || \
272- [ "${{ needs.pip.result }}" == "failure" ]; then
352+ # Check each job result - 'skipped' is OK (no projects to build)
353+ # 'success' is OK, 'failure' is not OK
354+ NODE_RESULT="${{ needs.node.result }}"
355+ POETRY_RESULT="${{ needs.poetry.result }}"
356+ UV_RESULT="${{ needs.uv.result }}"
357+ PIP_RESULT="${{ needs.pip.result }}"
358+
359+ echo "Node job result: $NODE_RESULT"
360+ echo "Poetry job result: $POETRY_RESULT"
361+ echo "uv job result: $UV_RESULT"
362+ echo "pip job result: $PIP_RESULT"
363+
364+ if [ "$NODE_RESULT" == "failure" ] || \
365+ [ "$POETRY_RESULT" == "failure" ] || \
366+ [ "$UV_RESULT" == "failure" ] || \
367+ [ "$PIP_RESULT" == "failure" ]; then
273368 echo "One or more jobs failed"
274369 exit 1
275370 fi
0 commit comments