ghcr.yml 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. name: Build Publish and Test Docker Image
  2. concurrency:
  3. group: ${{ github.workflow }}-${{ github.ref }}
  4. cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
  5. on:
  6. push:
  7. branches:
  8. - main
  9. tags:
  10. - '*'
  11. pull_request:
  12. workflow_dispatch:
  13. inputs:
  14. reason:
  15. description: 'Reason for manual trigger'
  16. required: true
  17. default: ''
  18. jobs:
  19. ghcr_build:
  20. runs-on: ubuntu-latest
  21. outputs:
  22. tags: ${{ steps.capture-tags.outputs.tags }}
  23. permissions:
  24. contents: read
  25. packages: write
  26. strategy:
  27. matrix:
  28. image: ["sandbox", "opendevin"]
  29. platform: ["amd64", "arm64"]
  30. steps:
  31. - name: Checkout
  32. uses: actions/checkout@v4
  33. - name: Free Disk Space (Ubuntu)
  34. uses: jlumbroso/free-disk-space@main
  35. with:
  36. # this might remove tools that are actually needed,
  37. # if set to "true" but frees about 6 GB
  38. tool-cache: true
  39. # all of these default to true, but feel free to set to
  40. # "false" if necessary for your workflow
  41. android: true
  42. dotnet: true
  43. haskell: true
  44. large-packages: true
  45. docker-images: false
  46. swap-storage: true
  47. - name: Set up QEMU
  48. uses: docker/setup-qemu-action@v3
  49. - name: Set up Docker Buildx
  50. id: buildx
  51. uses: docker/setup-buildx-action@v3
  52. - name: Build and export image
  53. id: build
  54. run: ./containers/build.sh ${{ matrix.image }} ${{ github.repository_owner }} ${{ matrix.platform }}
  55. - name: Capture tags
  56. id: capture-tags
  57. run: |
  58. tags=$(cat tags.txt)
  59. echo "tags=$tags"
  60. echo "tags=$tags" >> $GITHUB_OUTPUT
  61. - name: Upload Docker image as artifact
  62. uses: actions/upload-artifact@v4
  63. with:
  64. name: ${{ matrix.image }}-docker-image-${{ matrix.platform }}
  65. path: /tmp/${{ matrix.image }}_image_${{ matrix.platform }}.tar
  66. test-for-sandbox:
  67. name: Test for Sandbox
  68. runs-on: ubuntu-latest
  69. needs: ghcr_build
  70. env:
  71. PERSIST_SANDBOX: "false"
  72. steps:
  73. - uses: actions/checkout@v4
  74. - name: Install poetry via pipx
  75. run: pipx install poetry
  76. - name: Set up Python
  77. uses: actions/setup-python@v5
  78. with:
  79. python-version: "3.11"
  80. cache: "poetry"
  81. - name: Install Python dependencies using Poetry
  82. run: make install-python-dependencies
  83. - name: Download sandbox Docker image
  84. uses: actions/download-artifact@v4
  85. with:
  86. name: sandbox-docker-image-amd64
  87. path: /tmp/
  88. - name: Load sandbox image and run sandbox tests
  89. run: |
  90. # Load the Docker image and capture the output
  91. output=$(docker load -i /tmp/sandbox_image_amd64.tar)
  92. # Extract the first image name from the output
  93. image_name=$(echo "$output" | grep -oP 'Loaded image: \K.*' | head -n 1)
  94. # Print the full name of the image
  95. echo "Loaded Docker image: $image_name"
  96. SANDBOX_CONTAINER_IMAGE=$image_name TEST_IN_CI=true poetry run pytest --cov=agenthub --cov=opendevin --cov-report=xml -s ./tests/unit/test_sandbox.py
  97. - name: Upload coverage to Codecov
  98. uses: codecov/codecov-action@v4
  99. env:
  100. CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
  101. integration-tests-on-linux:
  102. name: Integration Tests on Linux
  103. runs-on: ubuntu-latest
  104. needs: ghcr_build
  105. env:
  106. PERSIST_SANDBOX: "false"
  107. strategy:
  108. fail-fast: false
  109. matrix:
  110. python-version: ["3.11"]
  111. sandbox: ["ssh", "local"]
  112. steps:
  113. - uses: actions/checkout@v4
  114. - name: Install poetry via pipx
  115. run: pipx install poetry
  116. - name: Set up Python
  117. uses: actions/setup-python@v5
  118. with:
  119. python-version: ${{ matrix.python-version }}
  120. cache: 'poetry'
  121. - name: Install Python dependencies using Poetry
  122. run: make install-python-dependencies
  123. - name: Download sandbox Docker image
  124. uses: actions/download-artifact@v4
  125. with:
  126. name: sandbox-docker-image-amd64
  127. path: /tmp/
  128. - name: Load sandbox image and run integration tests
  129. env:
  130. SANDBOX_TYPE: ${{ matrix.sandbox }}
  131. run: |
  132. # Load the Docker image and capture the output
  133. output=$(docker load -i /tmp/sandbox_image_amd64.tar)
  134. # Extract the first image name from the output
  135. image_name=$(echo "$output" | grep -oP 'Loaded image: \K.*' | head -n 1)
  136. # Print the full name of the image
  137. echo "Loaded Docker image: $image_name"
  138. SANDBOX_CONTAINER_IMAGE=$image_name TEST_IN_CI=true TEST_ONLY=true ./tests/integration/regenerate.sh
  139. - name: Upload coverage to Codecov
  140. uses: codecov/codecov-action@v4
  141. env:
  142. CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
  143. ghcr_push:
  144. runs-on: ubuntu-latest
  145. # don't push if integration tests or sandbox tests fail
  146. needs: [ghcr_build, integration-tests-on-linux, test-for-sandbox]
  147. if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
  148. env:
  149. tags: ${{ needs.ghcr_build.outputs.tags }}
  150. permissions:
  151. contents: read
  152. packages: write
  153. strategy:
  154. matrix:
  155. image: ["sandbox", "opendevin"]
  156. platform: ["amd64", "arm64"]
  157. steps:
  158. - name: Checkout code
  159. uses: actions/checkout@v4
  160. - name: Login to GHCR
  161. uses: docker/login-action@v2
  162. with:
  163. registry: ghcr.io
  164. username: ${{ github.repository_owner }}
  165. password: ${{ secrets.GITHUB_TOKEN }}
  166. - name: Download Docker images
  167. uses: actions/download-artifact@v4
  168. with:
  169. name: ${{ matrix.image }}-docker-image-${{ matrix.platform }}
  170. path: /tmp/${{ matrix.platform }}
  171. - name: Load images and push to registry
  172. run: |
  173. mv /tmp/${{ matrix.platform }}/${{ matrix.image }}_image_${{ matrix.platform }}.tar .
  174. loaded_image=$(docker load -i ${{ matrix.image }}_image_${{ matrix.platform }}.tar | grep "Loaded image:" | head -n 1 | awk '{print $3}')
  175. echo "loaded image = $loaded_image"
  176. tags=$(echo ${tags} | tr ' ' '\n')
  177. image_name=$(echo "ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}" | tr '[:upper:]' '[:lower:]')
  178. echo "image name = $image_name"
  179. for tag in $tags; do
  180. echo "tag = $tag"
  181. docker tag $loaded_image $image_name:${tag}_${{ matrix.platform }}
  182. docker push $image_name:${tag}_${{ matrix.platform }}
  183. done
  184. create_manifest:
  185. runs-on: ubuntu-latest
  186. needs: [ghcr_build, ghcr_push]
  187. if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/')
  188. env:
  189. tags: ${{ needs.ghcr_build.outputs.tags }}
  190. strategy:
  191. matrix:
  192. image: ["sandbox", "opendevin"]
  193. permissions:
  194. contents: read
  195. packages: write
  196. steps:
  197. - name: Checkout code
  198. uses: actions/checkout@v4
  199. - name: Login to GHCR
  200. uses: docker/login-action@v2
  201. with:
  202. registry: ghcr.io
  203. username: ${{ github.repository_owner }}
  204. password: ${{ secrets.GITHUB_TOKEN }}
  205. - name: Create and push multi-platform manifest
  206. run: |
  207. image_name=$(echo "ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}" | tr '[:upper:]' '[:lower:]')
  208. echo "image name = $image_name"
  209. tags=$(echo ${tags} | tr ' ' '\n')
  210. for tag in $tags; do
  211. echo 'tag = $tag'
  212. docker buildx imagetools create --tag $image_name:$tag \
  213. $image_name:${tag}_amd64 \
  214. $image_name:${tag}_arm64
  215. done
  216. # FIXME: an admin needs to mark this as non-mandatory, and then we can remove it
  217. docker_build_success:
  218. name: Docker Build Success
  219. runs-on: ubuntu-latest
  220. needs: ghcr_build
  221. steps:
  222. - run: echo Done!