ghcr_runtime.yml 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # Workflow that builds, tests and then pushes the runtime docker images to the ghcr.io repository
  2. name: Build, Test and Publish Runtime Image
  3. # Only run one workflow of the same group at a time.
  4. # There can be at most one running and one pending job in a concurrency group at any time.
  5. concurrency:
  6. group: ${{ github.workflow }}-${{ github.ref }}
  7. cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
  8. # Always run on "main"
  9. # Always run on tags
  10. # Always run on PRs
  11. # Can also be triggered manually
  12. on:
  13. push:
  14. branches:
  15. - main
  16. tags:
  17. - '*'
  18. pull_request:
  19. workflow_dispatch:
  20. inputs:
  21. reason:
  22. description: 'Reason for manual trigger'
  23. required: true
  24. default: ''
  25. jobs:
  26. # Builds the runtime Docker images
  27. ghcr_build_runtime:
  28. name: Build Image
  29. runs-on: ubuntu-latest
  30. permissions:
  31. contents: read
  32. packages: write
  33. strategy:
  34. matrix:
  35. base_image:
  36. - image: 'nikolaik/python-nodejs:python3.11-nodejs22'
  37. tag: nikolaik
  38. - image: 'python:3.11-bookworm'
  39. tag: python
  40. - image: 'node:22-bookworm'
  41. tag: node
  42. steps:
  43. - name: Checkout
  44. uses: actions/checkout@v4
  45. - name: Free Disk Space (Ubuntu)
  46. uses: jlumbroso/free-disk-space@main
  47. with:
  48. # this might remove tools that are actually needed,
  49. # if set to "true" but frees about 6 GB
  50. tool-cache: true
  51. # all of these default to true, but feel free to set to
  52. # "false" if necessary for your workflow
  53. android: true
  54. dotnet: true
  55. haskell: true
  56. large-packages: true
  57. docker-images: false
  58. swap-storage: true
  59. - name: Set up QEMU
  60. uses: docker/setup-qemu-action@v3
  61. - name: Login to GHCR
  62. uses: docker/login-action@v3
  63. with:
  64. registry: ghcr.io
  65. username: ${{ github.repository_owner }}
  66. password: ${{ secrets.GITHUB_TOKEN }}
  67. - name: Set up Docker Buildx
  68. id: buildx
  69. uses: docker/setup-buildx-action@v3
  70. - name: Install poetry via pipx
  71. run: pipx install poetry
  72. - name: Set up Python
  73. uses: actions/setup-python@v5
  74. with:
  75. python-version: '3.11'
  76. cache: 'poetry'
  77. - name: Install Python dependencies using Poetry
  78. run: make install-python-dependencies
  79. - name: Create source distribution and Dockerfile
  80. run: poetry run python3 openhands/runtime/utils/runtime_build.py --base_image ${{ matrix.base_image.image }} --build_folder containers/runtime --force_rebuild
  81. - name: Build and push runtime image ${{ matrix.base_image.image }}
  82. if: "!github.event.pull_request.head.repo.fork"
  83. run: |
  84. ./containers/build.sh runtime ${{ github.repository_owner }} --push ${{ matrix.base_image.tag }}
  85. # Forked repos can't push to GHCR, so we need to upload the image as an artifact
  86. - name: Build runtime image ${{ matrix.base_image.image }} for fork
  87. if: "github.event.pull_request.head.repo.fork"
  88. uses: docker/build-push-action@v6
  89. with:
  90. tags: ghcr.io/all-hands-ai/runtime:${{ github.sha }}-${{ matrix.base_image.tag }}
  91. outputs: type=docker,dest=/tmp/runtime-${{ matrix.base_image.tag }}.tar
  92. context: containers/runtime
  93. - name: Upload runtime image for fork
  94. if: "github.event.pull_request.head.repo.fork"
  95. uses: actions/upload-artifact@v4
  96. with:
  97. name: runtime-${{ matrix.base_image.tag }}
  98. path: /tmp/runtime-${{ matrix.base_image.tag }}.tar
  99. # Run unit tests with the EventStream runtime Docker images
  100. test_runtime:
  101. name: Test Runtime
  102. runs-on: ubuntu-latest
  103. needs: [ghcr_build_runtime]
  104. strategy:
  105. matrix:
  106. base_image: ['nikolaik', 'python', 'node']
  107. steps:
  108. - uses: actions/checkout@v4
  109. - name: Free Disk Space (Ubuntu)
  110. uses: jlumbroso/free-disk-space@main
  111. with:
  112. tool-cache: true
  113. android: true
  114. dotnet: true
  115. haskell: true
  116. large-packages: true
  117. swap-storage: true
  118. # Forked repos can't push to GHCR, so we need to download the image as an artifact
  119. - name: Download runtime image for fork
  120. if: "github.event.pull_request.head.repo.fork"
  121. uses: actions/download-artifact@v4
  122. with:
  123. name: runtime-${{ matrix.base_image }}
  124. path: /tmp
  125. - name: Load runtime image for fork
  126. if: "github.event.pull_request.head.repo.fork"
  127. run: |
  128. docker load --input /tmp/runtime-${{ matrix.base_image }}.tar
  129. - name: Install poetry via pipx
  130. run: pipx install poetry
  131. - name: Set up Python
  132. uses: actions/setup-python@v5
  133. with:
  134. python-version: '3.11'
  135. cache: 'poetry'
  136. - name: Install Python dependencies using Poetry
  137. run: make install-python-dependencies
  138. - name: Run runtime tests
  139. run: |
  140. image_name=ghcr.io/${{ github.repository_owner }}/runtime:${{ github.sha }}-${{ matrix.base_image }}
  141. image_name=$(echo $image_name | tr '[:upper:]' '[:lower:]')
  142. TEST_RUNTIME=eventstream \
  143. SANDBOX_USER_ID=$(id -u) \
  144. SANDBOX_BASE_CONTAINER_IMAGE=$image_name \
  145. TEST_IN_CI=true \
  146. poetry run pytest --cov=agenthub --cov=openhands --cov-report=xml -s ./tests/runtime
  147. - name: Upload coverage to Codecov
  148. uses: codecov/codecov-action@v4
  149. env:
  150. CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
  151. # Run integration tests with the eventstream runtime Docker image
  152. runtime_integration_tests_on_linux:
  153. name: Runtime Integration Tests on Linux
  154. runs-on: ubuntu-latest
  155. needs: [ghcr_build_runtime]
  156. strategy:
  157. fail-fast: false
  158. matrix:
  159. base_image: ['nikolaik', 'python', 'node']
  160. steps:
  161. - uses: actions/checkout@v4
  162. # Forked repos can't push to GHCR, so we need to download the image as an artifact
  163. - name: Download runtime image for fork
  164. if: "github.event.pull_request.head.repo.fork"
  165. uses: actions/download-artifact@v4
  166. with:
  167. name: runtime-${{ matrix.base_image }}
  168. path: /tmp
  169. - name: Load runtime image for fork
  170. if: "github.event.pull_request.head.repo.fork"
  171. run: |
  172. docker load --input /tmp/runtime-${{ matrix.base_image }}.tar
  173. - name: Install poetry via pipx
  174. run: pipx install poetry
  175. - name: Set up Python
  176. uses: actions/setup-python@v5
  177. with:
  178. python-version: '3.11'
  179. cache: 'poetry'
  180. - name: Install Python dependencies using Poetry
  181. run: make install-python-dependencies
  182. - name: Run integration tests
  183. run: |
  184. image_name=ghcr.io/${{ github.repository_owner }}/runtime:${{ github.sha }}-${{ matrix.base_image }}
  185. image_name=$(echo $image_name | tr '[:upper:]' '[:lower:]')
  186. TEST_RUNTIME=eventstream \
  187. SANDBOX_USER_ID=$(id -u) \
  188. SANDBOX_BASE_CONTAINER_IMAGE=$image_name \
  189. TEST_IN_CI=true \
  190. TEST_ONLY=true \
  191. ./tests/integration/regenerate.sh
  192. - name: Upload coverage to Codecov
  193. uses: codecov/codecov-action@v4
  194. env:
  195. CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
  196. # Checks that all runtime tests have passed
  197. all_runtime_tests_passed:
  198. name: All Runtime Tests Passed
  199. runs-on: ubuntu-latest
  200. needs: [test_runtime, runtime_integration_tests_on_linux]
  201. steps:
  202. - name: All tests passed
  203. run: echo "All runtime tests have passed successfully!"