name: Build OpenCode CLI and Docker Image on: push: branches: - main - master paths: - opencode/** - Dockerfile - .github/workflows/build-opencode-cli-docker.yml workflow_dispatch: inputs: image_name: description: "Docker image name (including registry if desired)" required: false push_image: description: "Push the image to the registry" type: boolean default: false permissions: contents: read packages: write actions: read jobs: build-cli: name: Build OpenCode CLI (${{ matrix.arch }}) runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: include: - arch: amd64 runner: ubuntu-24.04 cli_dir: opencode-linux-x64 - arch: arm64 runner: ubuntu-24.04-arm64 cli_dir: opencode-linux-arm64 steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version-file: opencode/package.json - name: Install dependencies run: bun install working-directory: opencode - name: Build CLI run: ./packages/opencode/script/build.ts --single working-directory: opencode - name: Upload CLI artifact uses: actions/upload-artifact@v4 with: name: opencode-cli-${{ matrix.arch }} path: opencode/packages/opencode/dist/${{ matrix.cli_dir }} build-image: name: Build Docker image needs: build-cli runs-on: ubuntu-24.04 env: IMAGE_NAME: ${{ inputs.image_name || format('ghcr.io/{0}/shopify-ai-builder', github.repository_owner) }} PUSH_IMAGE: ${{ inputs.push_image || false }} steps: - name: Checkout uses: actions/checkout@v4 - name: Download CLI artifacts uses: actions/download-artifact@v4 with: pattern: opencode-cli-* path: opencode/packages/opencode/dist merge-multiple: true - name: Set up QEMU uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 with: driver-opts: | image=moby/buildkit:latest buildkitd-flags: --debug - name: Cache Docker layers uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ github.sha }} restore-keys: | ${{ runner.os }}-buildx- - name: Login to GHCR if: ${{ env.PUSH_IMAGE == 'true' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build image (multi-arch push) if: ${{ env.PUSH_IMAGE == 'true' }} run: | docker buildx build \ --platform linux/amd64,linux/arm64 \ --cache-from type=local,src=/tmp/.buildx-cache \ --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ -t "$IMAGE_NAME" \ --push \ . - name: Move cache if: ${{ env.PUSH_IMAGE == 'true' }} run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache - name: Build image (amd64) and verify CLI if: ${{ env.PUSH_IMAGE != 'true' }} run: | docker buildx build \ --platform linux/amd64 \ --cache-from type=local,src=/tmp/.buildx-cache \ --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ -t "$IMAGE_NAME" \ --load \ . docker run --rm "$IMAGE_NAME" opencode --version - name: Move cache if: ${{ env.PUSH_IMAGE != 'true' }} run: | rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache - name: Cleanup old package versions if: ${{ env.PUSH_IMAGE == 'true' && github.event_name == 'push' }} uses: actions/github-script@v7 with: script: | const packageName = 'shopify-ai-builder'; const packageType = 'container'; // List all versions of the package const { data: versions } = await github.rest.packages.getAllPackageVersionsForPackageOwnedByOrg({ package_type: packageType, package_name: packageName, org: context.repo.owner, per_page: 100 }); // Keep only the most recent version, delete the rest if (versions.length > 1) { const versionsToDelete = versions.slice(1); for (const version of versionsToDelete) { await github.rest.packages.deletePackageVersionForOrg({ package_type: packageType, package_name: packageName, org: context.repo.owner, package_version_id: version.id }); console.log(`Deleted package version ${version.id}`); } }