name: Build Publish and Test Runtime Image concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} on: push: branches: - main tags: - '*' pull_request: workflow_dispatch: inputs: reason: description: 'Reason for manual trigger' required: true default: '' jobs: ghcr_build_runtime: runs-on: ubuntu-latest outputs: tags: ${{ steps.capture-tags.outputs.tags }} permissions: contents: read packages: write strategy: matrix: image: ["od_runtime"] base_image: ["ubuntu:22.04"] platform: ["amd64", "arm64"] steps: - name: Checkout uses: actions/checkout@v4 - name: Free Disk Space (Ubuntu) uses: jlumbroso/free-disk-space@main with: # this might remove tools that are actually needed, # if set to "true" but frees about 6 GB tool-cache: true # all of these default to true, but feel free to set to # "false" if necessary for your workflow android: true dotnet: true haskell: true large-packages: true docker-images: false swap-storage: true - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v3 - name: Install poetry via pipx run: pipx install poetry - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" cache: "poetry" - name: Install Python dependencies using Poetry run: make install-python-dependencies - name: Create source distribution and Dockerfile run: poetry run python3 opendevin/runtime/utils/runtime_build.py --base_image ${{ matrix.base_image }} --build_folder containers/runtime - name: Build and export image id: build run: ./containers/build.sh ${{ matrix.image }} ${{ github.repository_owner }} ${{ matrix.platform }} - name: Capture tags id: capture-tags run: | tags=$(cat tags.txt) echo "tags=$tags" echo "tags=$tags" >> $GITHUB_OUTPUT - name: Upload Docker image as artifact uses: actions/upload-artifact@v4 with: name: ${{ matrix.image }}-docker-image-${{ matrix.platform }} path: /tmp/${{ matrix.image }}_image_${{ matrix.platform }}.tar test-for-runtime: name: Test for Runtime runs-on: ubuntu-latest needs: ghcr_build_runtime env: PERSIST_SANDBOX: "false" steps: - uses: actions/checkout@v4 - name: Free Disk Space (Ubuntu) uses: jlumbroso/free-disk-space@main with: # this might remove tools that are actually needed, # when set to "true" but frees about 6 GB tool-cache: true # all of these default to true, but feel free to set to # "false" if necessary for your workflow android: true dotnet: true haskell: true large-packages: true swap-storage: true - name: Install poetry via pipx run: pipx install poetry - name: Set up Python uses: actions/setup-python@v5 with: python-version: "3.11" cache: "poetry" - name: Install Python dependencies using Poetry run: make install-python-dependencies - name: Download Runtime Docker image uses: actions/download-artifact@v4 with: name: od_runtime-docker-image-amd64 path: /tmp/ - name: Load Runtime image and run runtime tests run: | # Load the Docker image and capture the output output=$(docker load -i /tmp/od_runtime_image_amd64.tar) # Extract the first image name from the output image_name=$(echo "$output" | grep -oP 'Loaded image: \K.*' | head -n 1) # Print the full name of the image echo "Loaded Docker image: $image_name" SANDBOX_CONTAINER_IMAGE=$image_name TEST_IN_CI=true poetry run pytest --cov=agenthub --cov=opendevin --cov-report=xml -s ./tests/unit/test_runtime.py - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} ghcr_push: runs-on: ubuntu-latest # don't push if runtime tests fail needs: [ghcr_build_runtime, test-for-runtime] if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') env: tags: ${{ needs.ghcr_build_runtime.outputs.tags }} permissions: contents: read packages: write strategy: matrix: image: ["od_runtime"] platform: ["amd64", "arm64"] steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to GHCR uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Download Docker images uses: actions/download-artifact@v4 with: name: ${{ matrix.image }}-docker-image-${{ matrix.platform }} path: /tmp/${{ matrix.platform }} - name: Load images and push to registry run: | mv /tmp/${{ matrix.platform }}/${{ matrix.image }}_image_${{ matrix.platform }}.tar . loaded_image=$(docker load -i ${{ matrix.image }}_image_${{ matrix.platform }}.tar | grep "Loaded image:" | head -n 1 | awk '{print $3}') echo "loaded image = $loaded_image" tags=$(echo ${tags} | tr ' ' '\n') image_name=$(echo "ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}" | tr '[:upper:]' '[:lower:]') echo "image name = $image_name" for tag in $tags; do echo "tag = $tag" docker tag $loaded_image $image_name:${tag}_${{ matrix.platform }} docker push $image_name:${tag}_${{ matrix.platform }} done create_manifest: runs-on: ubuntu-latest needs: [ghcr_build_runtime, ghcr_push] if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') env: tags: ${{ needs.ghcr_build_runtime.outputs.tags }} strategy: matrix: image: ["od_runtime"] permissions: contents: read packages: write steps: - name: Checkout code uses: actions/checkout@v4 - name: Login to GHCR uses: docker/login-action@v2 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Create and push multi-platform manifest run: | image_name=$(echo "ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}" | tr '[:upper:]' '[:lower:]') echo "image name = $image_name" tags=$(echo ${tags} | tr ' ' '\n') for tag in $tags; do echo 'tag = $tag' docker buildx imagetools create --tag $image_name:$tag \ $image_name:${tag}_amd64 \ $image_name:${tag}_arm64 done