Skip to content

Commit f6d70c2

Browse files
committed
run actions only when project is added or changed
1 parent 45e302a commit f6d70c2

File tree

4 files changed

+391
-145
lines changed

4 files changed

+391
-145
lines changed

.github/workflows/solana-native.yml

Lines changed: 197 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -11,107 +11,233 @@ on:
1111
branches:
1212
- main
1313

14+
env:
15+
MAX_JOBS: 64
16+
MIN_PROJECTS_PER_JOB: 4
17+
MIN_PROJECTS_FOR_MATRIX: 4
18+
1419
jobs:
15-
build:
20+
changes:
1621
runs-on: ubuntu-latest
17-
strategy:
18-
matrix:
19-
node-version: [20.x]
20-
solana-version: [stable]
22+
permissions:
23+
pull-requests: read
24+
outputs:
25+
changed_projects: ${{ steps.analyze.outputs.changed_projects }}
26+
total_projects: ${{ steps.analyze.outputs.total_projects }}
27+
matrix: ${{ steps.matrix.outputs.matrix }}
2128
steps:
2229
- uses: actions/checkout@v4
23-
- name: Use Node.js ${{ matrix.node-version }}
24-
uses: actions/setup-node@v4
25-
with:
26-
node-version: ${{ matrix.node-version }}
27-
check-latest: true
28-
- uses: heyAyushh/[email protected]
30+
- uses: dorny/paths-filter@v3
31+
id: changes
32+
if: github.event_name == 'pull_request'
2933
with:
30-
solana-cli-version: ${{ matrix.solana-version }}
31-
- run: solana -V
32-
shell: bash
33-
- name: Install pnpm
34+
list-files: shell
35+
filters: |
36+
native:
37+
- added|modified: '**/native/**'
38+
workflow:
39+
- added|modified: '.github/workflows/solana-native.yml'
40+
- name: Analyze Changes
41+
id: analyze
3442
run: |
35-
npm install --global pnpm
36-
- name: Build Native programs
43+
# Generate ignore pattern, excluding comments
44+
ignore_pattern=$(grep -v '^#' .github/.ghaignore | grep -v '^$' | tr '\n' '|' | sed 's/|$//')
45+
echo "Ignore pattern: $ignore_pattern"
46+
47+
function get_projects() {
48+
find . -type d -name "native" | grep -vE "$ignore_pattern" | sort
49+
}
50+
51+
# Determine which projects to build and test
52+
if [[ "${{ github.event_name }}" == "push" || "${{ github.event_name }}" == "schedule" || "${{ steps.changes.outputs.workflow }}" == "true" ]]; then
53+
projects=$(get_projects)
54+
elif [[ "${{ steps.changes.outputs.native }}" == "true" ]]; then
55+
changed_files=(${{ steps.changes.outputs.native_files }})
56+
projects=$(for file in "${changed_files[@]}"; do dirname "${file}" | grep native | sed 's#/native/.*#/native#g'; done | grep -vE "$ignore_pattern" | sort -u)
57+
else
58+
projects=""
59+
fi
60+
61+
# Output project information
62+
if [[ -n "$projects" ]]; then
63+
echo "Projects to build and test"
64+
echo "$projects"
65+
total_projects=$(echo "$projects" | wc -l)
66+
echo "Total projects: $total_projects"
67+
echo "total_projects=$total_projects" >> $GITHUB_OUTPUT
68+
echo "changed_projects=$(echo "$projects" | jq -R -s -c 'split("\n")[:-1]')" >> $GITHUB_OUTPUT
69+
else
70+
echo "No projects to build and test."
71+
echo "total_projects=0" >> $GITHUB_OUTPUT
72+
echo "changed_projects=[]" >> $GITHUB_OUTPUT
73+
fi
74+
- name: Generate matrix
75+
id: matrix
3776
run: |
38-
declare -a ProjectDirs=($(find . -type d -name "native"| grep -v -f <(grep . .github/.ghaignore | grep -v '^$')))
39-
echo "Projects to Build:"
40-
printf "%s\n" "${ProjectDirs[@]}"
41-
for projectDir in "${ProjectDirs[@]}"; do
42-
echo "
43-
********
44-
Building $projectDir
45-
********"
46-
cd $projectDir
47-
if pnpm build; then
48-
echo "Build succeeded for $projectDir."
49-
else
50-
failed=true
51-
failed_builds+=($projectDir)
52-
echo "Build failed for $projectDir. Continuing with the next program."
53-
fi
54-
cd - > /dev/null
55-
done
56-
if [ "$failed" = true ]; then
57-
echo "Programs that failed building:"
58-
printf "%s\n" "${failed_builds[@]}"
59-
exit 1
77+
total_projects=${{ steps.analyze.outputs.total_projects }}
78+
max_jobs=${{ env.MAX_JOBS }}
79+
min_projects_per_job=${{ env.MIN_PROJECTS_PER_JOB }}
80+
min_projects_for_matrix=${{ env.MIN_PROJECTS_FOR_MATRIX }}
81+
82+
if [ "$total_projects" -lt "$min_projects_for_matrix" ]; then
83+
echo "matrix=[0]" >> $GITHUB_OUTPUT
6084
else
61-
echo "All programs built successfully."
85+
projects_per_job=$(( (total_projects + max_jobs - 1) / max_jobs ))
86+
projects_per_job=$(( projects_per_job > min_projects_per_job ? projects_per_job : min_projects_per_job ))
87+
num_jobs=$(( (total_projects + projects_per_job - 1) / projects_per_job ))
88+
89+
indices=$(seq 0 $(( num_jobs - 1 )))
90+
echo "matrix=[$(echo $indices | tr ' ' ',')]" >> $GITHUB_OUTPUT
6291
fi
63-
shell: bash
6492
65-
test:
93+
build-and-test:
94+
needs: changes
95+
if: needs.changes.outputs.total_projects != '0'
6696
runs-on: ubuntu-latest
6797
strategy:
98+
fail-fast: false
6899
matrix:
69100
node-version: [20.x]
70101
solana-version: [1.18.17, stable]
102+
index: ${{ fromJson(needs.changes.outputs.matrix) }}
103+
name: build-and-test-group-${{ matrix.index }}
104+
outputs:
105+
failed_projects: ${{ steps.set-failed.outputs.failed_projects }}
71106
steps:
72107
- uses: actions/checkout@v4
73108
- name: Use Node.js ${{ matrix.node-version }}
74109
uses: actions/setup-node@v4
75110
with:
76111
node-version: ${{ matrix.node-version }}
77112
check-latest: true
78-
- uses: heyAyushh/setup-solana@v5.4
113+
- uses: heyAyushh/setup-solana@v5.5
79114
with:
80115
solana-cli-version: ${{ matrix.solana-version }}
81-
- run: solana block
116+
- run: |
117+
solana -V
118+
rustc -V
82119
shell: bash
83120
- name: Install pnpm
121+
run: npm install --global pnpm
122+
- name: Build and Test
123+
env:
124+
TOTAL_PROJECTS: ${{ needs.changes.outputs.total_projects }}
125+
PROJECTS_PER_JOB: ${{ env.MIN_PROJECTS_PER_JOB }}
84126
run: |
85-
npm install --global pnpm
86-
- name: Test solana native programs
87-
run: |
88-
solana -V
89-
rustc -V
90-
declare -a ProjectDirs=($(find . -type d -name "native"| grep -v -f <(grep . .github/.ghaignore | grep -v '^$')))
91-
echo "Projects to Test:"
92-
printf "%s\n" "${ProjectDirs[@]}"
93-
for projectDir in "${ProjectDirs[@]}"; do
94-
echo "
95-
********
96-
Testing $projectDir
97-
********"
98-
cd $projectDir
99-
pnpm install --frozen-lockfile
100-
if pnpm build-and-test; then
101-
echo "Tests succeeded for $projectDir."
102-
else
127+
function build_and_test() {
128+
local project=$1
129+
echo "Building and Testing $project"
130+
cd "$project" || return 1
131+
132+
# Install dependencies
133+
if ! pnpm install --frozen-lockfile; then
134+
echo "::error::pnpm install failed for $project"
135+
echo "$project: pnpm install failed" >> $GITHUB_WORKSPACE/failed_projects.txt
136+
cd - > /dev/null
137+
return 1
138+
fi
139+
140+
# Build
141+
if ! pnpm build; then
142+
echo "::error::build failed for $project"
143+
echo "$project: build failed" >> $GITHUB_WORKSPACE/failed_projects.txt
144+
cd - > /dev/null
145+
return 1
146+
fi
147+
148+
# Test
149+
if ! pnpm build-and-test; then
150+
echo "::error::tests failed for $project"
151+
echo "$project: tests failed" >> $GITHUB_WORKSPACE/failed_projects.txt
152+
cd - > /dev/null
153+
return 1
154+
fi
155+
156+
echo "Build and tests succeeded for $project."
157+
cd - > /dev/null
158+
return 0
159+
}
160+
161+
# Determine which projects to build in this job
162+
readarray -t all_projects < <(echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]?')
163+
start_index=$(( ${{ matrix.index }} * PROJECTS_PER_JOB ))
164+
end_index=$(( start_index + PROJECTS_PER_JOB ))
165+
end_index=$(( end_index > TOTAL_PROJECTS ? TOTAL_PROJECTS : end_index ))
166+
167+
echo "Projects to build and test in this job"
168+
for i in $(seq $start_index $(( end_index - 1 ))); do
169+
echo "${all_projects[$i]}"
170+
done
171+
172+
# Build and test projects
173+
failed=false
174+
failed_projects=()
175+
for i in $(seq $start_index $(( end_index - 1 ))); do
176+
echo "::group::Building and testing ${all_projects[$i]}"
177+
if ! build_and_test "${all_projects[$i]}"; then
103178
failed=true
104-
failed_tests+=($projectDir)
105-
echo "Tests failed for $projectDir. Continuing with the next program."
179+
failed_projects+=("${all_projects[$i]}")
106180
fi
107-
cd - > /dev/null
181+
echo "::endgroup::"
108182
done
109-
if [ "$failed" = true ]; then
110-
echo "*****************************"
111-
echo "Programs that failed testing:"
112-
printf "%s\n" "${failed_tests[@]}"
183+
184+
if [[ "$failed" == "true" ]]; then
185+
echo "::group::Failed projects"
186+
cat $GITHUB_WORKSPACE/failed_projects.txt
187+
echo "::endgroup::"
188+
echo "failed_projects=${failed_projects[@]}" >> $GITHUB_OUTPUT
113189
exit 1
114190
else
115-
echo "All tests passed."
191+
echo "failed_projects=" >> $GITHUB_OUTPUT
192+
fi
193+
194+
- name: Set failed projects output
195+
id: set-failed
196+
if: failure()
197+
run: |
198+
failed_projects=$(cat $GITHUB_WORKSPACE/failed_projects.txt | jq -R -s -c 'split("\n")[:-1]')
199+
echo "failed_projects=$failed_projects" >> $GITHUB_OUTPUT
200+
201+
summary:
202+
needs: [changes, build-and-test]
203+
if: always()
204+
runs-on: ubuntu-latest
205+
steps:
206+
- uses: actions/checkout@v4
207+
- name: Create job summary
208+
run: |
209+
echo "## Native Workflow Summary" >> $GITHUB_STEP_SUMMARY
210+
echo "- Total projects: ${{ needs.changes.outputs.total_projects }}" >> $GITHUB_STEP_SUMMARY
211+
212+
# List all processed projects
213+
echo "<details>" >> $GITHUB_STEP_SUMMARY
214+
echo "<summary>Projects processed (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
215+
echo "" >> $GITHUB_STEP_SUMMARY
216+
echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]' | while read project; do
217+
echo "- $project" >> $GITHUB_STEP_SUMMARY
218+
done
219+
echo "" >> $GITHUB_STEP_SUMMARY
220+
echo "</details>" >> $GITHUB_STEP_SUMMARY
221+
222+
# Report build and test results
223+
if [[ "${{ needs.build-and-test.result }}" == "failure" ]]; then
224+
echo "## :x: Build or tests failed" >> $GITHUB_STEP_SUMMARY
225+
echo "<details>" >> $GITHUB_STEP_SUMMARY
226+
echo "<summary>Failed projects (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
227+
echo "" >> $GITHUB_STEP_SUMMARY
228+
failed_projects='${{ needs.build-and-test.outputs.failed_projects }}'
229+
if [[ -n "$failed_projects" ]]; then
230+
echo "$failed_projects" | jq -r '.[]' | while IFS=: read -r project failure_reason; do
231+
echo "- **$project**" >> $GITHUB_STEP_SUMMARY
232+
echo " - Failure reason: $failure_reason" >> $GITHUB_STEP_SUMMARY
233+
done
234+
else
235+
echo "No failed projects reported. This might indicate an unexpected error in the workflow." >> $GITHUB_STEP_SUMMARY
236+
fi
237+
echo "" >> $GITHUB_STEP_SUMMARY
238+
echo "</details>" >> $GITHUB_STEP_SUMMARY
239+
elif [[ "${{ needs.build-and-test.result }}" == "success" ]]; then
240+
echo "## :white_check_mark: All builds and tests passed" >> $GITHUB_STEP_SUMMARY
241+
else
242+
echo "## :warning: Build and test job was skipped or canceled" >> $GITHUB_STEP_SUMMARY
116243
fi
117-
shell: bash

0 commit comments

Comments
 (0)