integration-testing.yaml 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. name: Run OpenCost Integration Tests
  2. on:
  3. schedule:
  4. - cron: '0 14 * * *'
  5. push:
  6. branches:
  7. - develop
  8. pull_request:
  9. branches:
  10. - develop
  11. merge_group:
  12. types: [checks_requested]
  13. concurrency:
  14. group: ${{ github.event.merge_group.head.sha || github.ref }}-intg-tests
  15. cancel-in-progress: false
  16. jobs:
  17. check_actor_permissions:
  18. runs-on: ubuntu-latest
  19. outputs:
  20. ismaintainer: ${{ steps.teamAffiliation.outputs.isTeamMember }}
  21. steps:
  22. - name: Check if actor is a maintainer
  23. uses: tspascoal/get-user-teams-membership@v2
  24. id: teamAffiliation
  25. with:
  26. GITHUB_TOKEN: ${{ secrets.ORG_READER_PAT }}
  27. username: ${{ github.actor }}
  28. team: 'OpenCost Maintainers'
  29. noop-tests:
  30. needs: check_actor_permissions
  31. permissions: {}
  32. runs-on: Kubecost-Linux-Small-x86
  33. if: ${{ always() && !cancelled() && github.event_name != 'merge_group' && github.ref != 'refs/heads/develop' && needs.check_actor_permissions.outputs.ismaintainer == 'false' }}
  34. outputs:
  35. is_noop: ${{ steps.noop-tests.outputs.is_noop }}
  36. steps:
  37. - name: Tests Not Needed
  38. id: noop-tests
  39. run: |
  40. echo "integration tests not running because you are not a maintainer. they will run automatically when a PR is merged."
  41. echo "is_noop=true" >> $GITHUB_OUTPUT
  42. wait_for_image_ready:
  43. runs-on: ubuntu-latest
  44. permissions: {}
  45. needs: check_actor_permissions
  46. if: ${{ (always() && !cancelled()) && ( github.event_name == 'merge_group' || github.ref != 'refs/heads/develop' || needs.check_actor_permissions.outputs.ismaintainer == 'true') }}
  47. outputs:
  48. IMAGE_TAG: ${{ steps.set_image_tags.outputs.IMAGE_TAG }}
  49. NAMESPACE: ${{ steps.set_image_tags.outputs.NAMESPACE }}
  50. MAINBRANCH: ${{ steps.set_image_tags.outputs.mainbranch }}
  51. passed: ${{ steps.wait_for_image_ready.outputs.passed }}
  52. steps:
  53. - uses: actions/checkout@v4
  54. with:
  55. ref: ${{ github.event.merge_group.head.sha || github.ref }}
  56. - name: Set OC SHA
  57. run: |
  58. echo "OC_SHORTHASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
  59. - name: Set image tags
  60. id: set_image_tags
  61. run: |
  62. echo "github.event_name: ${{ github.event_name }}"
  63. if [[ "${{ github.event_name }}" == "merge_group" ]]; then
  64. echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost:test-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
  65. echo "NAMESPACE=merge-queue-${{ github.event.number }}-oc-${{ env.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
  66. echo "mainbranch=false" >> $GITHUB_OUTPUT
  67. else
  68. echo "building on develop branch"
  69. echo "IMAGE_TAG=ghcr.io/${{ github.repository_owner }}/opencost:develop-${{ steps.sha.outputs.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
  70. echo "NAMESPACE=develop-oc-${{ env.OC_SHORTHASH }}" >> $GITHUB_OUTPUT
  71. echo "mainbranch=true" >> $GITHUB_OUTPUT
  72. fi
  73. - name: Log into ghcr.io
  74. uses: docker/login-action@v3
  75. with:
  76. registry: ghcr.io
  77. username: ${{ github.actor }}
  78. password: ${{ secrets.GITHUB_TOKEN }}
  79. - name: wait for docker image to be ready
  80. id: wait_for_image_ready
  81. run: |
  82. max_attempts=100
  83. # Loop until the Docker image can be pulled
  84. until docker manifest inspect ${{ steps.set_image_tags.outputs.IMAGE_TAG }}; do
  85. echo "Waiting for Docker image ${{ steps.set_image_tags.outputs.IMAGE_TAG }} to be available, $max_attempts tries remain..."
  86. sleep 6
  87. max_attempts=$((max_attempts - 1))
  88. if [[ $max_attempts -eq 0 ]]; then
  89. echo "Docker image ${{ steps.set_image_tags.outputs.IMAGE_TAG }} is not available after 10 minutes. Exiting..."
  90. exit 1
  91. fi
  92. done
  93. echo "Docker image ${{ steps.set_image_tags.outputs.IMAGE_TAG }} is ready!"
  94. echo "passed=true" >> $GITHUB_OUTPUT
  95. build-test-stack:
  96. needs: wait_for_image_ready
  97. uses: opencost/opencost-infra/.github/workflows/build-stack.yaml@main
  98. secrets: inherit
  99. with:
  100. oc-container-version: "${{ needs.wait_for_image_ready.outputs.IMAGE_TAG }}"
  101. namespace: "${{ needs.wait_for_image_ready.outputs.NAMESPACE }}"
  102. wait-for-dns:
  103. needs: [wait_for_image_ready, build-test-stack]
  104. runs-on: ubuntu-latest
  105. permissions: {}
  106. steps:
  107. - name: Wait for DNS to resolve
  108. run: |
  109. echo "Waiting for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io to resolve in DNS..."
  110. max_attempts=60
  111. until host ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io; do
  112. echo "DNS not yet resolved for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io, $max_attempts tries remain..."
  113. sleep 10
  114. max_attempts=$((max_attempts - 1))
  115. if [[ $max_attempts -eq 0 ]]; then
  116. echo "DNS resolution failed for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io after 10 minutes. Exiting..."
  117. exit 1
  118. fi
  119. done
  120. echo "DNS resolved successfully for ${{ needs.wait_for_image_ready.outputs.NAMESPACE }}.infra.opencost.io!"
  121. run-tests:
  122. needs: [wait_for_image_ready, build-test-stack, wait-for-dns]
  123. permissions: {}
  124. uses: opencost/opencost-infra/.github/workflows/test-stack.yaml@main
  125. secrets: inherit
  126. with:
  127. namespace: "${{ needs.wait_for_image_ready.outputs.NAMESPACE }}"
  128. target_branch: "${{ github.event.pull_request.head.ref || 'main' }}"
  129. teardown-test-stack:
  130. needs: [wait_for_image_ready, run-tests]
  131. permissions: {}
  132. uses: opencost/opencost-infra/.github/workflows/destroy-stack.yaml@main
  133. if: always()
  134. secrets: inherit
  135. with:
  136. namespace: "${{ needs.wait_for_image_ready.outputs.NAMESPACE }}"
  137. check-success:
  138. needs: [noop-tests, run-tests]
  139. permissions: {}
  140. runs-on: ubuntu-latest
  141. if: ${{ always() }}
  142. steps:
  143. - name: Check success
  144. run: |
  145. if [[ "${{ needs.noop-tests.outputs.is_noop }}" == "true" ]]; then
  146. echo "No-op tests, skipping success check"
  147. exit 0
  148. fi
  149. if [[ "${{ needs.run-tests.outputs.passed }}" != "true" ]]; then
  150. echo "One or more integration tests failed"
  151. exit 1
  152. fi
  153. echo "All integration tests passed"
  154. exit 0
  155. set-labels:
  156. needs: [wait_for_image_ready, run-tests]
  157. runs-on: ubuntu-latest
  158. permissions: {}
  159. steps:
  160. - name: label integration tests failing
  161. if: ${{ always() && contains(needs.*.result, 'failure') && !cancelled()}}
  162. uses: andymckay/labeler@1.0.4
  163. with:
  164. add-labels: "integration tests failed"
  165. - uses: mondeja/remove-labels-gh-action@v2
  166. if: ${{ always() && contains(needs.*.result, 'failure') && !cancelled()}}
  167. with:
  168. token: ${{ secrets.GITHUB_TOKEN }}
  169. labels: |
  170. integration tests passed
  171. - name: Label integration tests passing
  172. if: ${{ always() && !contains(needs.*.result, 'failure') && !cancelled()}}
  173. uses: andymckay/labeler@1.0.4
  174. with:
  175. add-labels: "integration tests passed"
  176. - uses: mondeja/remove-labels-gh-action@v2
  177. if: ${{ always() && !contains(needs.*.result, 'failure') && !cancelled()}}
  178. with:
  179. token: ${{ secrets.GITHUB_TOKEN }}
  180. labels: |
  181. integration tests failed