@@ -11,107 +11,246 @@ 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+
1419jobs :
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
30+ - uses : dorny/paths-filter@v3
31+ id : changes
32+ if : github.event_name == 'pull_request'
2533 with :
26- node-version : ${{ matrix.node-version }}
27- check-latest : true
28- - uses : heyAyushh/[email protected] 29- 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 :
69- node-version : [20.x]
70- solana-version : [1.18.17, stable]
100+ index : ${{ fromJson(needs.changes.outputs.matrix) }}
101+ name : build-and-test-group-${{ matrix.index }}
102+ outputs :
103+ failed_projects : ${{ steps.set-failed.outputs.failed_projects }}
71104 steps :
72105 - uses : actions/checkout@v4
73- - name : Use Node.js ${{ matrix.node-version }}
106+ - name : Use Node.js
74107 uses : actions/setup-node@v4
75108 with :
76- node-version : ${{ matrix.node-version }}
109+ node-version : 20.x
77110 check-latest : true
78- -
uses :
heyAyushh/[email protected] 79- with :
80- solana-cli-version : ${{ matrix.solana-version }}
81- - run : solana block
82- shell : bash
83- - name : Install pnpm
111+ - name : Setup build environment
112+ id : setup
84113 run : |
114+ # Create the build and test function
115+ cat << 'EOF' > build_and_test.sh
116+ function build_and_test() {
117+ local project=$1
118+ local solana_version=$2
119+ echo "Building and Testing $project with Solana $solana_version"
120+ cd "$project" || return 1
121+
122+ # Install dependencies
123+ if ! pnpm install --frozen-lockfile; then
124+ echo "::error::pnpm install failed for $project"
125+ echo "$project: pnpm install failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
126+ cd - > /dev/null
127+ return 1
128+ fi
129+
130+ # Build
131+ if ! pnpm build; then
132+ echo "::error::build failed for $project"
133+ echo "$project: build failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
134+ cd - > /dev/null
135+ return 1
136+ fi
137+
138+ # Test
139+ if ! pnpm build-and-test; then
140+ echo "::error::tests failed for $project"
141+ echo "$project: tests failed with $solana_version" >> $GITHUB_WORKSPACE/failed_projects.txt
142+ cd - > /dev/null
143+ return 1
144+ fi
145+
146+ echo "Build and tests succeeded for $project with $solana_version version."
147+ cd - > /dev/null
148+ return 0
149+ }
150+
151+ function process_projects() {
152+ local solana_version=$1
153+
154+ readarray -t all_projects < <(echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]?')
155+ start_index=$(( ${{ matrix.index }} * ${{ env.MIN_PROJECTS_PER_JOB }} ))
156+ end_index=$(( start_index + ${{ env.MIN_PROJECTS_PER_JOB }} ))
157+ end_index=$(( end_index > ${{ needs.changes.outputs.total_projects }} ? ${{ needs.changes.outputs.total_projects }} : end_index ))
158+
159+ echo "Projects to build and test in this job"
160+ for i in $(seq $start_index $(( end_index - 1 ))); do
161+ echo "${all_projects[$i]}"
162+ done
163+
164+ failed=false
165+ for i in $(seq $start_index $(( end_index - 1 ))); do
166+ echo "::group::Building and testing ${all_projects[$i]}"
167+ if ! build_and_test "${all_projects[$i]}" "$solana_version"; then
168+ failed=true
169+ fi
170+ echo "::endgroup::"
171+ done
172+
173+ return $([ "$failed" = true ] && echo 1 || echo 0)
174+ }
175+ EOF
176+
177+ # Make the script executable
178+ chmod +x build_and_test.sh
179+
180+ # Install pnpm
85181 npm install --global pnpm
86- - name : Test solana native programs
182+ - name : Setup Solana stable
183+ 184+ with :
185+ solana-cli-version : stable
186+ - name : Build and Test with Stable
187+ run : |
188+ source build_and_test.sh
189+ solana -V
190+ rustc -V
191+ process_projects "stable"
192+ - name : Setup Solana 1.18.17
193+ 194+ with :
195+ solana-cli-version : 1.18.17
196+ - name : Build and Test with 1.18.17
87197 run : |
198+ source build_and_test.sh
88199 solana -V
89200 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."
201+ process_projects "1.18.17"
202+
203+ - name : Set failed projects output
204+ id : set-failed
205+ if : failure()
206+ run : |
207+ if [ -f "$GITHUB_WORKSPACE/failed_projects.txt" ]; then
208+ failed_projects=$(cat $GITHUB_WORKSPACE/failed_projects.txt | jq -R -s -c 'split("\n")[:-1]')
209+ echo "failed_projects=$failed_projects" >> $GITHUB_OUTPUT
210+ else
211+ echo "failed_projects=[]" >> $GITHUB_OUTPUT
212+ fi
213+
214+ summary :
215+ needs : [changes, build-and-test]
216+ if : always()
217+ runs-on : ubuntu-latest
218+ steps :
219+ - uses : actions/checkout@v4
220+ - name : Create job summary
221+ run : |
222+ echo "## Native Workflow Summary" >> $GITHUB_STEP_SUMMARY
223+ echo "- Total projects: ${{ needs.changes.outputs.total_projects }}" >> $GITHUB_STEP_SUMMARY
224+
225+ # List all processed projects
226+ echo "<details>" >> $GITHUB_STEP_SUMMARY
227+ echo "<summary>Projects processed (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
228+ echo "" >> $GITHUB_STEP_SUMMARY
229+ echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]' | while read project; do
230+ echo "- $project" >> $GITHUB_STEP_SUMMARY
231+ done
232+ echo "" >> $GITHUB_STEP_SUMMARY
233+ echo "</details>" >> $GITHUB_STEP_SUMMARY
234+
235+ # Report build and test results
236+ if [[ "${{ needs.build-and-test.result }}" == "failure" ]]; then
237+ echo "## :x: Build or tests failed" >> $GITHUB_STEP_SUMMARY
238+ echo "<details>" >> $GITHUB_STEP_SUMMARY
239+ echo "<summary>Failed projects (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
240+ echo "" >> $GITHUB_STEP_SUMMARY
241+ failed_projects='${{ needs.build-and-test.outputs.failed_projects }}'
242+ if [[ -n "$failed_projects" ]]; then
243+ echo "$failed_projects" | jq -r '.[]' | while IFS=: read -r project failure_reason; do
244+ echo "- **$project**" >> $GITHUB_STEP_SUMMARY
245+ echo " - Failure reason: $failure_reason" >> $GITHUB_STEP_SUMMARY
246+ done
102247 else
103- failed=true
104- failed_tests+=($projectDir)
105- echo "Tests failed for $projectDir. Continuing with the next program."
248+ echo "No failed projects reported. This might indicate an unexpected error in the workflow." >> $GITHUB_STEP_SUMMARY
106249 fi
107- cd - > /dev/null
108- done
109- if [ "$failed" = true ]; then
110- echo "*****************************"
111- echo "Programs that failed testing:"
112- printf "%s\n" "${failed_tests[@]}"
113- exit 1
250+ echo "" >> $GITHUB_STEP_SUMMARY
251+ echo "</details>" >> $GITHUB_STEP_SUMMARY
252+ elif [[ "${{ needs.build-and-test.result }}" == "success" ]]; then
253+ echo "## :white_check_mark: All builds and tests passed" >> $GITHUB_STEP_SUMMARY
114254 else
115- echo "All tests passed."
255+ echo "## :warning: Build and test job was skipped or canceled" >> $GITHUB_STEP_SUMMARY
116256 fi
117- shell : bash
0 commit comments