poseidon.yml 10 KB

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