Feat: session recording agent's browser sessions #7098
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --- | |
| name: Agent Server | |
| on: | |
| push: | |
| branches: [main] | |
| tags: | |
| - '*' # Trigger on any tag (e.g., 1.0.0, 1.0.0a5, build-docker) | |
| pull_request: | |
| branches: [main] | |
| workflow_dispatch: | |
| inputs: | |
| base_image: | |
| description: Base runtime image | |
| type: string | |
| default: nikolaik/python-nodejs:python3.12-nodejs22-slim | |
| image: | |
| description: GHCR image name | |
| type: string | |
| default: ghcr.io/openhands/agent-server | |
| platforms: | |
| description: Target platforms | |
| type: string | |
| default: linux/amd64,linux/arm64 | |
| permissions: | |
| contents: read | |
| packages: write | |
| jobs: | |
| build-binary-and-test: | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| os: [ubuntu-latest, macos-latest] | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: latest | |
| - name: Install dependencies | |
| run: uv sync --dev | |
| - name: Build binary | |
| run: | | |
| make build-server | |
| # FIXME: windows-latest not working due to | |
| # Run if [[ "windows-latest" == "windows-latest" ]]; then | |
| # [PYI-2160:ERROR] Failed to load Python DLL 'C:\Users\RUNNER~1\AppData\Local\Temp\_MEI5602\python312.dll'. | |
| # LoadLibrary: Invalid access to memory location. | |
| # - name: Test binary (Windows) | |
| # if: matrix.os == 'windows-latest' | |
| # shell: pwsh | |
| # run: | | |
| # Get-ChildItem dist | |
| # .\dist\openhands-agent-server.exe --help | |
| - name: Test binary (Linux and macOS) | |
| if: matrix.os != 'windows-latest' | |
| shell: bash | |
| run: | | |
| # Test help command | |
| ./dist/openhands-agent-server --help | |
| # Test server startup and template loading | |
| echo "Testing server startup and template loading..." | |
| ./dist/openhands-agent-server --port 8002 > server_test.log 2>&1 & | |
| SERVER_PID=$! | |
| # Wait for server to start | |
| sleep 5 | |
| # Check if server started successfully (no template errors) | |
| if grep -q "system_prompt.j2.*not found" server_test.log; then | |
| echo "ERROR: Template files not found in binary!" | |
| cat server_test.log | |
| kill $SERVER_PID 2>/dev/null || true | |
| exit 1 | |
| fi | |
| # Check if server is running | |
| if ! kill -0 $SERVER_PID 2>/dev/null; then | |
| echo "ERROR: Server failed to start!" | |
| cat server_test.log | |
| exit 1 | |
| fi | |
| # Test basic API endpoint | |
| if command -v curl >/dev/null 2>&1; then | |
| echo "Testing basic API endpoint..." | |
| if curl -f -s http://localhost:8002/health >/dev/null 2>&1; then | |
| echo "✓ Health endpoint accessible" | |
| else | |
| echo "⚠ Health endpoint not accessible (may be expected)" | |
| fi | |
| fi | |
| # Clean up | |
| kill $SERVER_PID 2>/dev/null || true | |
| wait $SERVER_PID 2>/dev/null || true | |
| rm -f server_test.log | |
| echo "✓ Binary test completed successfully" | |
| - name: Upload binary artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: openhands-server-${{ matrix.os }} | |
| path: | | |
| dist/openhands-server* | |
| retention-days: 7 | |
| check-openapi-schema: | |
| name: Check OpenAPI Schema | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| steps: | |
| - name: Checkout PR branch | |
| uses: actions/checkout@v5 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: latest | |
| - name: Install Node.js (for npx) | |
| uses: actions/setup-node@v6 | |
| with: | |
| node-version: 22 | |
| - name: Install dependencies | |
| run: | | |
| uv sync --frozen --dev | |
| - name: Check OpenAPI JSON and build client | |
| env: | |
| PYTHONPATH: . | |
| run: | | |
| make test-server-schema | |
| build-and-push-image: | |
| name: Build & Push (${{ matrix.variant }}-${{ matrix.arch }}) | |
| # Run on push events and pull requests from the same repository (not forks) | |
| # Fork PRs cannot push to GHCR and would fail authentication | |
| if: > | |
| github.event_name == 'push' || | |
| (github.event_name == 'pull_request' && | |
| !github.event.pull_request.head.repo.fork) | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| # Explicit matrix: 3 variants × 2 architectures = 6 jobs | |
| # Each job specifies exactly what it builds and where it runs | |
| include: | |
| # Python variant | |
| - variant: python | |
| arch: amd64 | |
| base_image: nikolaik/python-nodejs:python3.12-nodejs22 | |
| runner: blacksmith-8vcpu-ubuntu-2404 | |
| platform: linux/amd64 | |
| - variant: python | |
| arch: arm64 | |
| base_image: nikolaik/python-nodejs:python3.12-nodejs22 | |
| runner: blacksmith-8vcpu-ubuntu-2404-arm | |
| platform: linux/arm64 | |
| # Java variant | |
| - variant: java | |
| arch: amd64 | |
| base_image: eclipse-temurin:17-jdk | |
| runner: blacksmith-8vcpu-ubuntu-2404 | |
| platform: linux/amd64 | |
| - variant: java | |
| arch: arm64 | |
| base_image: eclipse-temurin:17-jdk | |
| runner: blacksmith-8vcpu-ubuntu-2404-arm | |
| platform: linux/arm64 | |
| # Golang variant | |
| - variant: golang | |
| arch: amd64 | |
| base_image: golang:1.21-bookworm | |
| runner: blacksmith-8vcpu-ubuntu-2404 | |
| platform: linux/amd64 | |
| - variant: golang | |
| arch: arm64 | |
| base_image: golang:1.21-bookworm | |
| runner: blacksmith-8vcpu-ubuntu-2404-arm | |
| platform: linux/arm64 | |
| runs-on: ${{ matrix.runner }} | |
| env: | |
| IMAGE: ${{ inputs.image != '' && inputs.image || 'ghcr.io/openhands/agent-server' }} | |
| BASE_IMAGE: ${{ inputs.base_image != '' && inputs.base_image || matrix.base_image }} | |
| CUSTOM_TAGS: ${{ matrix.variant }} | |
| VARIANT: ${{ matrix.variant }} | |
| ARCH: ${{ matrix.arch }} | |
| TARGET: binary | |
| PLATFORM: ${{ matrix.platform }} | |
| GITHUB_SHA: ${{ github.sha }} | |
| GITHUB_REF: ${{ github.ref }} | |
| CI: 'true' | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v5 | |
| - name: Install uv | |
| uses: astral-sh/setup-uv@v7 | |
| with: | |
| version: latest | |
| - name: Set up Docker Buildx with Blacksmith | |
| uses: useblacksmith/setup-docker-builder@v1 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Prepare build context and metadata | |
| id: prep | |
| run: | | |
| uv sync --frozen | |
| # Generate build context and tags with arch suffix | |
| # build.py now handles architecture tagging internally via --arch flag | |
| # Add --versioned-tag when triggered by a git tag (e.g., v1.0.0) | |
| BUILD_CMD="uv run ./openhands-agent-server/openhands/agent_server/docker/build.py --build-ctx-only --arch ${{ matrix.arch }}" | |
| if [[ "${{ github.ref }}" == refs/tags/* ]]; then | |
| BUILD_CMD="$BUILD_CMD --versioned-tag" | |
| fi | |
| eval "$BUILD_CMD" | |
| # Alias tags_csv output to tags for the build action | |
| TAGS=$(grep '^tags_csv=' $GITHUB_OUTPUT | cut -d= -f2-) | |
| echo "tags=$TAGS" >> $GITHUB_OUTPUT | |
| # Extract short SHA for consolidation | |
| SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7) | |
| echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT | |
| # Extract versioned tags CSV for consolidation | |
| VERSIONED_TAGS_CSV=$(grep '^versioned_tags_csv=' $GITHUB_OUTPUT | cut -d= -f2- || echo "") | |
| echo "versioned_tags_csv=$VERSIONED_TAGS_CSV" >> $GITHUB_OUTPUT | |
| # Verify outputs | |
| echo "=== Build outputs ===" | |
| echo "Build context: $(grep '^build_context=' $GITHUB_OUTPUT | cut -d= -f2-)" | |
| echo "Tags: $TAGS" | |
| echo "Short SHA: $SHORT_SHA" | |
| echo "Versioned tags: $VERSIONED_TAGS_CSV" | |
| echo "====================" | |
| - name: Build & Push with Blacksmith (${{ matrix.variant }}-${{ matrix.arch }}) | |
| id: build | |
| uses: useblacksmith/build-push-action@v2 | |
| with: | |
| context: ${{ steps.prep.outputs.build_context }} | |
| file: ${{ steps.prep.outputs.dockerfile }} | |
| target: ${{ env.TARGET }} | |
| platforms: ${{ env.PLATFORM }} | |
| push: true | |
| tags: ${{ steps.prep.outputs.tags }} | |
| build-args: | | |
| BASE_IMAGE=${{ env.BASE_IMAGE }} | |
| - name: Cleanup build context | |
| if: always() | |
| run: | | |
| if [ -n "${{ steps.prep.outputs.build_context }}" ] && [ -d "${{ steps.prep.outputs.build_context }}" ]; then | |
| echo "Cleaning up build context: ${{ steps.prep.outputs.build_context }}" | |
| rm -rf "${{ steps.prep.outputs.build_context }}" | |
| fi | |
| - name: Summary (${{ matrix.variant }}-${{ matrix.arch }}) - outputs | |
| run: | | |
| echo "Image: ${{ env.IMAGE }}" | |
| echo "Variant: ${{ env.VARIANT }}" | |
| echo "Architecture: ${{ env.ARCH }}" | |
| echo "Platform: ${{ env.PLATFORM }}" | |
| echo "Short SHA: ${{ steps.prep.outputs.short_sha }}" | |
| echo "Tags: ${{ steps.prep.outputs.tags }}" | |
| echo "Build digest: ${{ steps.build.outputs.digest }}" | |
| - name: Save build info for consolidation | |
| run: | | |
| mkdir -p build-info | |
| cat > "build-info/${{ matrix.variant }}-${{ matrix.arch }}.json" << EOF | |
| { | |
| "variant": "${{ matrix.variant }}", | |
| "arch": "${{ matrix.arch }}", | |
| "base_image": "${{ matrix.base_image }}", | |
| "image": "${{ env.IMAGE }}", | |
| "short_sha": "${{ steps.prep.outputs.short_sha }}", | |
| "tags": "${{ steps.prep.outputs.tags }}", | |
| "versioned_tags_csv": "${{ steps.prep.outputs.versioned_tags_csv }}", | |
| "platform": "${{ env.PLATFORM }}" | |
| } | |
| EOF | |
| - name: Upload build info artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: build-info-${{ matrix.variant }}-${{ matrix.arch }} | |
| path: build-info/${{ matrix.variant }}-${{ matrix.arch }}.json | |
| retention-days: 1 | |
| merge-manifests: | |
| name: Merge Multi-Arch Manifests | |
| needs: build-and-push-image | |
| if: > | |
| github.event_name == 'push' || | |
| (github.event_name == 'pull_request' && | |
| !github.event.pull_request.head.repo.fork) | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| strategy: | |
| matrix: | |
| variant: [python, java, golang] | |
| env: | |
| IMAGE: ${{ inputs.image != '' && inputs.image || 'ghcr.io/openhands/agent-server' }} | |
| steps: | |
| - name: Download build info to extract SHORT_SHA | |
| uses: actions/download-artifact@v6 | |
| with: | |
| pattern: build-info-${{ matrix.variant }}-* | |
| merge-multiple: true | |
| path: build-info | |
| - name: Extract SHORT_SHA from build info | |
| id: get_sha | |
| run: | | |
| # Get SHORT_SHA from any build info artifact for this variant | |
| SHORT_SHA=$(jq -r '.short_sha' build-info/${{ matrix.variant }}-amd64.json) | |
| echo "short_sha=$SHORT_SHA" >> $GITHUB_OUTPUT | |
| echo "Using SHORT_SHA: $SHORT_SHA" | |
| - name: Set up Docker Buildx with Blacksmith | |
| uses: useblacksmith/setup-docker-builder@v1 | |
| - name: Log in to GHCR | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create and push multi-arch manifest for ${{ matrix.variant }} | |
| id: create_manifest | |
| run: | | |
| SHORT_SHA=${{ steps.get_sha.outputs.short_sha }} | |
| VARIANT=${{ matrix.variant }} | |
| MANIFEST_TAG="${SHORT_SHA}-${VARIANT}" | |
| # Create multi-arch manifest combining amd64 and arm64 using buildx imagetools | |
| # This properly handles manifest lists from Blacksmith builds | |
| echo "Creating multi-arch manifest: ${IMAGE}:${MANIFEST_TAG}" | |
| docker buildx imagetools create -t ${IMAGE}:${MANIFEST_TAG} \ | |
| ${IMAGE}:${SHORT_SHA}-${VARIANT}-amd64 \ | |
| ${IMAGE}:${SHORT_SHA}-${VARIANT}-arm64 | |
| # Verify the multi-arch manifest | |
| echo "Inspecting multi-arch manifest:" | |
| docker buildx imagetools inspect ${IMAGE}:${MANIFEST_TAG} | |
| echo "✓ Multi-arch manifest created: ${IMAGE}:${MANIFEST_TAG}" | |
| # Create latest manifest if on main branch | |
| if [ "${{ github.ref }}" == "refs/heads/main" ]; then | |
| LATEST_TAG="latest-${VARIANT}" | |
| echo "Creating latest multi-arch manifest: ${IMAGE}:${LATEST_TAG}" | |
| docker buildx imagetools create -t ${IMAGE}:${LATEST_TAG} \ | |
| ${IMAGE}:main-${VARIANT}-amd64 \ | |
| ${IMAGE}:main-${VARIANT}-arm64 | |
| echo "Inspecting latest multi-arch manifest:" | |
| docker buildx imagetools inspect ${IMAGE}:${LATEST_TAG} | |
| echo "✓ Latest multi-arch manifest created: ${IMAGE}:${LATEST_TAG}" | |
| MANIFEST_TAG="${MANIFEST_TAG},${LATEST_TAG}" | |
| fi | |
| # Create versioned manifests if triggered by a git tag | |
| # Extract versioned tags from build info (format: "1.2.0-python,1.2.0-java") | |
| VERSIONED_TAGS_CSV=$(jq -r '.versioned_tags_csv' build-info/${VARIANT}-amd64.json) | |
| if [ -n "$VERSIONED_TAGS_CSV" ] && [ "$VERSIONED_TAGS_CSV" != "null" ] && [ "$VERSIONED_TAGS_CSV" != "" ]; then | |
| echo "Found versioned tags: $VERSIONED_TAGS_CSV" | |
| # Split CSV and create manifest for each versioned tag | |
| IFS=',' read -ra VERSIONED_TAGS <<< "$VERSIONED_TAGS_CSV" | |
| for VERSIONED_TAG in "${VERSIONED_TAGS[@]}"; do | |
| if [ -n "$VERSIONED_TAG" ]; then | |
| echo "Creating versioned multi-arch manifest: ${IMAGE}:${VERSIONED_TAG}" | |
| docker buildx imagetools create -t ${IMAGE}:${VERSIONED_TAG} \ | |
| ${IMAGE}:${VERSIONED_TAG}-amd64 \ | |
| ${IMAGE}:${VERSIONED_TAG}-arm64 | |
| echo "Inspecting versioned multi-arch manifest:" | |
| docker buildx imagetools inspect ${IMAGE}:${VERSIONED_TAG} | |
| echo "✓ Versioned multi-arch manifest created: ${IMAGE}:${VERSIONED_TAG}" | |
| MANIFEST_TAG="${MANIFEST_TAG},${VERSIONED_TAG}" | |
| fi | |
| done | |
| fi | |
| # Save manifest info for consolidation | |
| mkdir -p manifest-info | |
| cat > "manifest-info/${VARIANT}.json" << EOF | |
| { | |
| "variant": "${VARIANT}", | |
| "image": "${IMAGE}", | |
| "short_sha": "${SHORT_SHA}", | |
| "manifest_tag": "${MANIFEST_TAG}" | |
| } | |
| EOF | |
| - name: Upload manifest info artifact | |
| uses: actions/upload-artifact@v5 | |
| with: | |
| name: manifest-info-${{ matrix.variant }} | |
| path: manifest-info/${{ matrix.variant }}.json | |
| retention-days: 1 | |
| consolidate-build-info: | |
| name: Consolidate Build Information | |
| needs: [build-and-push-image, merge-manifests] | |
| # Run if it's a PR and the matrix job completed (even if some variants failed) | |
| if: github.event_name == 'pull_request' && always() && (needs.build-and-push-image.result == 'success' || needs.build-and-push-image.result == | |
| 'failure') | |
| runs-on: blacksmith-4vcpu-ubuntu-2404 | |
| outputs: | |
| build_summary: ${{ steps.consolidate.outputs.build_summary }} | |
| steps: | |
| - name: Download build info artifacts | |
| uses: actions/download-artifact@v6 | |
| with: | |
| pattern: build-info-* | |
| merge-multiple: true | |
| path: build-info | |
| - name: Download manifest info artifacts | |
| uses: actions/download-artifact@v6 | |
| with: | |
| pattern: manifest-info-* | |
| merge-multiple: true | |
| path: manifest-info | |
| - name: Consolidate build information from artifacts | |
| id: consolidate | |
| run: | | |
| echo "Processing build info artifacts..." | |
| ls -la build-info/ | |
| echo "Found $(ls build-info/*.json 2>/dev/null | wc -l) JSON files" | |
| # Initialize variables | |
| IMAGE="" | |
| SHORT_SHA="" | |
| ALL_TAGS="" | |
| # Use associative arrays to track variants (bash 4+) | |
| declare -A VARIANT_BASE_IMAGE | |
| declare -A VARIANT_ARCHS | |
| # Process each build info | |
| for info_file in build-info/*.json; do | |
| if [[ ! -f "$info_file" ]]; then | |
| echo "Skipping $info_file - not a file" | |
| continue | |
| fi | |
| echo "=== Processing $info_file ===" | |
| cat "$info_file" | |
| echo "=== End of $info_file ===" | |
| # Extract information from JSON | |
| VARIANT=$(jq -r '.variant' "$info_file") | |
| ARCH=$(jq -r '.arch' "$info_file") | |
| BASE_IMAGE=$(jq -r '.base_image' "$info_file") | |
| VARIANT_IMAGE=$(jq -r '.image' "$info_file") | |
| VARIANT_SHA=$(jq -r '.short_sha' "$info_file") | |
| VARIANT_TAGS=$(jq -r '.tags' "$info_file") | |
| # Set common values (same across all builds) | |
| if [[ -z "$IMAGE" ]]; then | |
| IMAGE="$VARIANT_IMAGE" | |
| SHORT_SHA="$VARIANT_SHA" | |
| fi | |
| # Store variant information | |
| VARIANT_BASE_IMAGE[$VARIANT]=$BASE_IMAGE | |
| if [[ -z "${VARIANT_ARCHS[$VARIANT]}" ]]; then | |
| VARIANT_ARCHS[$VARIANT]=$ARCH | |
| else | |
| VARIANT_ARCHS[$VARIANT]="${VARIANT_ARCHS[$VARIANT]}, $ARCH" | |
| fi | |
| # Collect tags (comma-separated to newline-separated) | |
| if [[ -n "$VARIANT_TAGS" ]]; then | |
| VARIANT_TAG_LIST=$(echo "$VARIANT_TAGS" | tr ',' '\n') | |
| if [[ -n "$ALL_TAGS" ]]; then | |
| ALL_TAGS="${ALL_TAGS}"$'\n'"${VARIANT_TAG_LIST}" | |
| else | |
| ALL_TAGS="$VARIANT_TAG_LIST" | |
| fi | |
| fi | |
| done | |
| # Build variants JSON array from collected data | |
| VARIANTS_JSON="[]" | |
| for VARIANT in "${!VARIANT_BASE_IMAGE[@]}"; do | |
| BASE_IMG="${VARIANT_BASE_IMAGE[$VARIANT]}" | |
| ARCHS="${VARIANT_ARCHS[$VARIANT]}" | |
| VARIANTS_JSON=$(echo "$VARIANTS_JSON" | jq \ | |
| --arg variant "$VARIANT" \ | |
| --arg base_image "$BASE_IMG" \ | |
| --arg archs "$ARCHS" \ | |
| '. += [{custom_tags: $variant, base_image: $base_image, architectures: $archs}]') | |
| echo "Added variant $VARIANT ($ARCHS), current variants JSON:" | |
| echo "$VARIANTS_JSON" | jq . | |
| done | |
| # Process manifest info artifacts | |
| echo "Processing manifest info artifacts..." | |
| if [[ -d "manifest-info" ]]; then | |
| ls -la manifest-info/ | |
| MANIFEST_TAGS="" | |
| for manifest_file in manifest-info/*.json; do | |
| if [[ -f "$manifest_file" ]]; then | |
| echo "=== Processing $manifest_file ===" | |
| cat "$manifest_file" | |
| MANIFEST_TAG_CSV=$(jq -r '.manifest_tag' "$manifest_file") | |
| # Convert comma-separated tags to newline-separated | |
| MANIFEST_TAG_LIST=$(echo "$MANIFEST_TAG_CSV" | tr ',' '\n' | sed "s|^|${IMAGE}:|") | |
| if [[ -n "$MANIFEST_TAGS" ]]; then | |
| MANIFEST_TAGS="${MANIFEST_TAGS}"$'\n'"${MANIFEST_TAG_LIST}" | |
| else | |
| MANIFEST_TAGS="$MANIFEST_TAG_LIST" | |
| fi | |
| fi | |
| done | |
| # Add manifest tags to ALL_TAGS | |
| if [[ -n "$MANIFEST_TAGS" ]]; then | |
| echo "Adding manifest tags to output" | |
| if [[ -n "$ALL_TAGS" ]]; then | |
| ALL_TAGS="${ALL_TAGS}"$'\n'"${MANIFEST_TAGS}" | |
| else | |
| ALL_TAGS="$MANIFEST_TAGS" | |
| fi | |
| fi | |
| else | |
| echo "No manifest-info directory found (merge-manifests may not have run)" | |
| fi | |
| # Create consolidated build summary | |
| BUILD_SUMMARY=$(jq -n \ | |
| --arg image "$IMAGE" \ | |
| --arg short_sha "$SHORT_SHA" \ | |
| --arg ghcr_url "https://github.com/OpenHands/agent-sdk/pkgs/container/agent-server" \ | |
| --arg all_tags "$ALL_TAGS" \ | |
| --argjson variants "$VARIANTS_JSON" \ | |
| '{ | |
| image: $image, | |
| short_sha: $short_sha, | |
| ghcr_package_url: $ghcr_url, | |
| all_tags: $all_tags, | |
| variants: $variants | |
| }') | |
| echo "Consolidated build summary:" | |
| echo "$BUILD_SUMMARY" | jq . | |
| echo "DEBUG: Final variants count: $(echo "$VARIANTS_JSON" | jq 'length')" | |
| echo "DEBUG: Final variants: $(echo "$VARIANTS_JSON" | jq -c '.')" | |
| # Set output | |
| { | |
| echo 'build_summary<<EOF' | |
| echo "$BUILD_SUMMARY" | |
| echo 'EOF' | |
| } >> $GITHUB_OUTPUT | |
| update-pr-description: | |
| name: Update PR description with agent server image | |
| needs: consolidate-build-info | |
| # Only on PRs, and only if the consolidation succeeded | |
| if: github.event_name == 'pull_request' && needs.consolidate-build-info.result == 'success' | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| permissions: | |
| contents: read | |
| pull-requests: write | |
| steps: | |
| - name: Generate PR description from build summary | |
| id: generate_description | |
| run: | | |
| echo "Event: ${{ github.event_name }}" | |
| echo "PR number: ${{ github.event.number }}" | |
| echo "Run attempt: ${{ github.run_attempt }}" | |
| # Parse the build summary JSON | |
| BUILD_SUMMARY='${{ needs.consolidate-build-info.outputs.build_summary }}' | |
| echo "Build summary received:" | |
| echo "$BUILD_SUMMARY" | jq . | |
| # Extract basic information | |
| IMAGE=$(echo "$BUILD_SUMMARY" | jq -r '.image') | |
| SHORT_SHA=$(echo "$BUILD_SUMMARY" | jq -r '.short_sha') | |
| GHCR_URL=$(echo "$BUILD_SUMMARY" | jq -r '.ghcr_package_url') | |
| ALL_TAGS=$(echo "$BUILD_SUMMARY" | jq -r '.all_tags') | |
| # Build the variants table dynamically | |
| VARIANTS_TABLE="" | |
| # Process each build | |
| VARIANTS=$(echo "$BUILD_SUMMARY" | jq -r '.variants[] | @base64') | |
| echo "DEBUG: Found builds (base64 encoded):" | |
| echo "$VARIANTS" | |
| echo "DEBUG: Number of builds: $(echo "$VARIANTS" | wc -l)" | |
| for variant_data in $VARIANTS; do | |
| # Decode base64 and extract build info | |
| VARIANT_JSON=$(echo "$variant_data" | base64 --decode) | |
| echo "DEBUG: Processing build JSON: $VARIANT_JSON" | |
| CUSTOM_TAGS=$(echo "$VARIANT_JSON" | jq -r '.custom_tags') | |
| BASE_IMAGE=$(echo "$VARIANT_JSON" | jq -r '.base_image') | |
| ARCHS=$(echo "$VARIANT_JSON" | jq -r '.architectures // "amd64, arm64"') | |
| echo "DEBUG: Adding variant $CUSTOM_TAGS with base image $BASE_IMAGE (archs: $ARCHS)" | |
| # Add to variants table with architecture info | |
| VARIANTS_TABLE="${VARIANTS_TABLE}| ${CUSTOM_TAGS} | ${ARCHS} | \`${BASE_IMAGE}\` | [Link](https://hub.docker.com/_/${BASE_IMAGE}) |"$'\n' | |
| done | |
| echo "DEBUG: Final variants table:" | |
| echo "$VARIANTS_TABLE" | |
| # Create the complete PR description with the requested format | |
| PR_CONTENT=$(cat << EOF | |
| <!-- AGENT_SERVER_IMAGES_START --> | |
| --- | |
| **Agent Server images for this PR** | |
| • **GHCR package:** ${GHCR_URL} | |
| **Variants & Base Images** | |
| | Variant | Architectures | Base Image | Docs / Tags | | |
| |---|---|---|---| | |
| ${VARIANTS_TABLE} | |
| **Pull (multi-arch manifest)** | |
| \`\`\`bash | |
| # Each variant is a multi-arch manifest supporting both amd64 and arm64 | |
| docker pull ${IMAGE}:${SHORT_SHA}-python | |
| \`\`\` | |
| **Run** | |
| \`\`\`bash | |
| docker run -it --rm \\ | |
| -p 8000:8000 \\ | |
| --name agent-server-${SHORT_SHA}-python \\ | |
| ${IMAGE}:${SHORT_SHA}-python | |
| \`\`\` | |
| **All tags pushed for this build** | |
| \`\`\` | |
| ${ALL_TAGS} | |
| \`\`\` | |
| **About Multi-Architecture Support** | |
| - Each variant tag (e.g., \`${SHORT_SHA}-python\`) is a **multi-arch manifest** supporting both **amd64** and **arm64** | |
| - Docker automatically pulls the correct architecture for your platform | |
| - Individual architecture tags (e.g., \`${SHORT_SHA}-python-amd64\`) are also available if needed | |
| <!-- AGENT_SERVER_IMAGES_END --> | |
| EOF | |
| ) | |
| # Set output for the next step | |
| { | |
| echo 'pr_content<<EOF' | |
| echo "$PR_CONTENT" | |
| echo 'EOF' | |
| } >> $GITHUB_OUTPUT | |
| - name: Update PR description with comprehensive docker information | |
| uses: nefrob/[email protected] | |
| with: | |
| content: ${{ steps.generate_description.outputs.pr_content }} | |
| regex: <!-- AGENT_SERVER_IMAGES_START -->.*?<!-- AGENT_SERVER_IMAGES_END --> | |
| regexFlags: s | |
| token: ${{ secrets.GITHUB_TOKEN }} |