1
+ name : Poseidon
2
+
3
+ on :
4
+ schedule :
5
+ - cron : " 0 0 * * *"
6
+ push :
7
+ branches :
8
+ - main
9
+ pull_request :
10
+ types : [opened, synchronize, reopened]
11
+ branches :
12
+ - main
13
+
14
+ env :
15
+ MAX_JOBS : 64
16
+ MIN_PROJECTS_PER_JOB : 4
17
+ MIN_PROJECTS_FOR_MATRIX : 4
18
+
19
+ jobs :
20
+ changes :
21
+ runs-on : ubuntu-latest
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 }}
28
+ steps :
29
+ - uses : actions/checkout@v4
30
+ - uses : dorny/paths-filter@v3
31
+ id : changes
32
+ if : github.event_name == 'pull_request'
33
+ with :
34
+ list-files : shell
35
+ filters : |
36
+ poseidon:
37
+ - added|modified: '**/poseidon/**'
38
+ workflow:
39
+ - added|modified: '.github/workflows/poseidon.yml'
40
+ - name : Analyze Changes
41
+ id : analyze
42
+ run : |
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 "poseidon" | 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.poseidon }}" == "true" ]]; then
55
+ changed_files=(${{ steps.changes.outputs.poseidon_files }})
56
+ projects=$(for file in "${changed_files[@]}"; do dirname "${file}" | grep poseidon | sed 's#/poseidon/.*#/poseidon#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
76
+ run : |
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
+ # Generate matrix based on number of projects
83
+ if [ "$total_projects" -lt "$min_projects_for_matrix" ]; then
84
+ echo "matrix=[0]" >> $GITHUB_OUTPUT
85
+ else
86
+ projects_per_job=$(( (total_projects + max_jobs - 1) / max_jobs ))
87
+ projects_per_job=$(( projects_per_job > min_projects_per_job ? projects_per_job : min_projects_per_job ))
88
+ num_jobs=$(( (total_projects + projects_per_job - 1) / projects_per_job ))
89
+
90
+ indices=$(seq 0 $(( num_jobs - 1 )))
91
+ echo "matrix=[$(echo $indices | tr ' ' ',')]" >> $GITHUB_OUTPUT
92
+ fi
93
+
94
+ build-and-test :
95
+ needs : changes
96
+ if : needs.changes.outputs.total_projects != '0'
97
+ runs-on : ubuntu-latest
98
+ strategy :
99
+ fail-fast : false
100
+ matrix :
101
+ index : ${{ fromJson(needs.changes.outputs.matrix) }}
102
+ name : build-and-test-group-${{ matrix.index }}
103
+ outputs :
104
+ failed_projects : ${{ steps.set-failed.outputs.failed_projects }}
105
+ steps :
106
+ - uses : actions/checkout@v4
107
+ -
uses :
heyAyushh/[email protected]
108
+ with :
109
+ anchor-version : 0.30.1
110
+ solana-cli-version : stable
111
+ node-version : 20.x
112
+ use-avm : false
113
+
114
+ # Get Poseidon repo commit SHA for cache key
115
+ - name : Get Poseidon commit SHA
116
+ id : poseidon-sha
117
+ run : |
118
+ POSEIDON_SHA=$(git ls-remote https://github.com/Turbin3/poseidon HEAD | cut -f1)
119
+ echo "sha=$POSEIDON_SHA" >> $GITHUB_OUTPUT
120
+
121
+ # Setup Rust cache
122
+ - name : Setup Rust cache
123
+ uses : Swatinem/rust-cache@v2
124
+ with :
125
+ shared-key : " poseidon-cli"
126
+ cache-on-failure : true
127
+ workspaces : |
128
+ ~/.cargo/bin/poseidon -> Cargo.lock
129
+
130
+ # Cache Poseidon binary
131
+ - name : Cache Poseidon binary
132
+ id : cache-poseidon
133
+ uses : actions/cache@v3
134
+ with :
135
+ path : ~/.cargo/bin/poseidon
136
+ key : poseidon-${{ runner.os }}-${{ steps.poseidon-sha.outputs.sha }}
137
+
138
+ # Install Poseidon CLI only if not cached
139
+ - name : Install Poseidon CLI
140
+ if : steps.cache-poseidon.outputs.cache-hit != 'true'
141
+ run : |
142
+ cargo install --git https://github.com/Turbin3/poseidon
143
+ - name : Display Versions and Install pnpm
144
+ run : |
145
+ solana -V
146
+ solana-keygen new --no-bip39-passphrase
147
+ rustc -V
148
+ poseidon --version
149
+ npm i -g pnpm
150
+ - name : Build and Test
151
+ env :
152
+ TOTAL_PROJECTS : ${{ needs.changes.outputs.total_projects }}
153
+ PROJECTS_PER_JOB : ${{ env.MIN_PROJECTS_PER_JOB }}
154
+ run : |
155
+ function build_and_test() {
156
+ local project=$1
157
+ echo "Building and Testing $project"
158
+ cd "$project" || return 1
159
+
160
+ # Install dependencies
161
+ if ! pnpm install --frozen-lockfile; then
162
+ echo "::error::pnpm install failed for $project"
163
+ echo "$project: pnpm install failed" >> $GITHUB_WORKSPACE/failed_projects.txt
164
+ cd - > /dev/null
165
+ return 1
166
+ fi
167
+
168
+ # Run poseidon build
169
+ if ! poseidon build; then
170
+ echo "::error::poseidon build failed for $project"
171
+ echo "$project: poseidon build failed" >> $GITHUB_WORKSPACE/failed_projects.txt
172
+ rm -rf target
173
+ cd - > /dev/null
174
+ return 1
175
+ fi
176
+
177
+
178
+ # Run poseidon test
179
+ if ! poseidon test; then
180
+ echo "::error::poseidon test failed for $project"
181
+ echo "$project: poseidon test failed" >> $GITHUB_WORKSPACE/failed_projects.txt
182
+ rm -rf target node_modules
183
+ cd - > /dev/null
184
+ return 1
185
+ fi
186
+
187
+ echo "Build and tests succeeded for $project."
188
+ rm -rf target node_modules
189
+ cd - > /dev/null
190
+ return 0
191
+ }
192
+
193
+ # Determine which projects to build in this job
194
+ readarray -t all_projects < <(echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]?')
195
+ start_index=$(( ${{ matrix.index }} * PROJECTS_PER_JOB ))
196
+ end_index=$(( start_index + PROJECTS_PER_JOB ))
197
+ end_index=$(( end_index > TOTAL_PROJECTS ? TOTAL_PROJECTS : end_index ))
198
+
199
+ echo "Projects to build and test in this job"
200
+ for i in $(seq $start_index $(( end_index - 1 ))); do
201
+ echo "${all_projects[$i]}"
202
+ done
203
+
204
+ # Build and test projects
205
+ failed=false
206
+ failed_projects=()
207
+ for i in $(seq $start_index $(( end_index - 1 ))); do
208
+ echo "::group::Building and testing ${all_projects[$i]}"
209
+ if ! build_and_test "${all_projects[$i]}"; then
210
+ failed=true
211
+ failed_projects+=("${all_projects[$i]}")
212
+ fi
213
+ echo "::endgroup::"
214
+ done
215
+
216
+ if [[ "$failed" == "true" ]]; then
217
+ echo "::group::Failed projects"
218
+ cat $GITHUB_WORKSPACE/failed_projects.txt
219
+ echo "::endgroup::"
220
+ echo "failed_projects=${failed_projects[@]}" >> $GITHUB_OUTPUT
221
+ exit 1
222
+ else
223
+ echo "failed_projects=" >> $GITHUB_OUTPUT
224
+ fi
225
+
226
+ - name : Set failed projects output
227
+ id : set-failed
228
+ if : failure()
229
+ run : |
230
+ # Prepare failed projects list for output
231
+ failed_projects=$(cat $GITHUB_WORKSPACE/failed_projects.txt | jq -R -s -c 'split("\n")[:-1]')
232
+ echo "failed_projects=$failed_projects" >> $GITHUB_OUTPUT
233
+
234
+ summary :
235
+ needs : [changes, build-and-test]
236
+ if : always()
237
+ runs-on : ubuntu-latest
238
+ steps :
239
+ - uses : actions/checkout@v4
240
+ - name : Create job summary
241
+ run : |
242
+ echo "## Poseidon Workflow Summary" >> $GITHUB_STEP_SUMMARY
243
+ echo "- Total projects: ${{ needs.changes.outputs.total_projects }}" >> $GITHUB_STEP_SUMMARY
244
+
245
+ # List all processed projects
246
+ echo "<details>" >> $GITHUB_STEP_SUMMARY
247
+ echo "<summary>Projects processed (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
248
+ echo "" >> $GITHUB_STEP_SUMMARY
249
+ echo '${{ needs.changes.outputs.changed_projects }}' | jq -r '.[]' | while read project; do
250
+ echo "- $project" >> $GITHUB_STEP_SUMMARY
251
+ done
252
+ echo "" >> $GITHUB_STEP_SUMMARY
253
+ echo "</details>" >> $GITHUB_STEP_SUMMARY
254
+
255
+ # Report build and test results
256
+ if [[ "${{ needs.build-and-test.result }}" == "failure" ]]; then
257
+ echo "## :x: Build or tests failed" >> $GITHUB_STEP_SUMMARY
258
+ echo "<details>" >> $GITHUB_STEP_SUMMARY
259
+ echo "<summary>Failed projects (click to expand)</summary>" >> $GITHUB_STEP_SUMMARY
260
+ echo "" >> $GITHUB_STEP_SUMMARY
261
+ failed_projects='${{ needs.build-and-test.outputs.failed_projects }}'
262
+ if [[ -n "$failed_projects" ]]; then
263
+ echo "$failed_projects" | jq -r '.[]' | while IFS=: read -r project failure_reason; do
264
+ echo "- **$project**" >> $GITHUB_STEP_SUMMARY
265
+ echo " - Failure reason: $failure_reason" >> $GITHUB_STEP_SUMMARY
266
+ done
267
+ else
268
+ echo "No failed projects reported. This might indicate an unexpected error in the workflow." >> $GITHUB_STEP_SUMMARY
269
+ fi
270
+ echo "" >> $GITHUB_STEP_SUMMARY
271
+ echo "</details>" >> $GITHUB_STEP_SUMMARY
272
+ elif [[ "${{ needs.build-and-test.result }}" == "success" ]]; then
273
+ echo "## :white_check_mark: All builds and tests passed" >> $GITHUB_STEP_SUMMARY
274
+ else
275
+ echo "## :warning: Build and test job was skipped or canceled" >> $GITHUB_STEP_SUMMARY
276
+ fi
0 commit comments