diff --git a/.base-image-digest b/.base-image-digest deleted file mode 100644 index 67f3281..0000000 --- a/.base-image-digest +++ /dev/null @@ -1 +0,0 @@ -sha256:3ad34ca6292aec4a91d8ddeb9229e29d9c2f689efd0dd242860889ac71842eba diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index f71518a..73bc6f7 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -1,75 +1,35 @@ name: Build and Push Docker Image on: - schedule: - - cron: '0 8 * * *' + push: + branches: [master] + paths: + - 'Dockerfile' + - '.opencode-version' + - 'docker-entrypoint.sh' + - 'config/opencode.json' + pull_request: + paths: + - 'Dockerfile' + - '.opencode-version' + - 'docker-entrypoint.sh' + - 'config/opencode.json' workflow_dispatch: inputs: - force: - description: 'Force build even if no changes detected' + push_image: + description: 'Push the built image to Docker Hub' required: false - default: false + default: true type: boolean + concurrency: - group: docker-build + group: docker-build-${{ github.ref }} cancel-in-progress: false -permissions: - contents: write -jobs: - check-for-updates: - runs-on: ubuntu-latest - outputs: - should_build: ${{ steps.check.outputs.changed }} - force_build: ${{ github.event.inputs.force == 'true' }} - steps: - - name: Checkout - uses: actions/checkout@v5 - with: - persist-credentials: false - - name: Check for updates - id: check - run: | - CHANGED="false" - COMMIT_MSG="" - - # Check base image digest - CURRENT_DIGEST=$(curl -s "https://registry.hub.docker.com/v2/repositories/library/node/tags/alpine" | jq -r '.digest') - STORED_DIGEST=$(cat .base-image-digest 2>/dev/null || echo "") - if [ "$CURRENT_DIGEST" != "$STORED_DIGEST" ]; then - echo "Base image changed: $STORED_DIGEST -> $CURRENT_DIGEST" - echo "$CURRENT_DIGEST" > .base-image-digest - CHANGED="true" - COMMIT_MSG="Update base image digest" - fi - - # Check opencode-ai version - CURRENT_OPENCODE=$(curl -s https://registry.npmjs.org/opencode-ai/latest | jq -r '.version') - STORED_OPENCODE=$(cat .opencode-version 2>/dev/null || echo "") - - if [ "$CURRENT_OPENCODE" != "$STORED_OPENCODE" ]; then - echo "opencode-ai changed: $STORED_OPENCODE -> $CURRENT_OPENCODE" - echo "$CURRENT_OPENCODE" > .opencode-version - CHANGED="true" - if [ -n "$COMMIT_MSG" ]; then - COMMIT_MSG="$COMMIT_MSG and opencode-ai to v$CURRENT_OPENCODE" - else - COMMIT_MSG="Update opencode-ai to v$CURRENT_OPENCODE" - fi - fi +permissions: + contents: read - echo "changed=$CHANGED" >> $GITHUB_OUTPUT - echo "commit_msg=$COMMIT_MSG" >> $GITHUB_OUTPUT - - name: Update version files - if: steps.check.outputs.changed == 'true' - run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git add .base-image-digest .opencode-version - git commit -m "${{ steps.check.outputs.commit_msg }}" - git push https://x-access-token:${{ secrets.PAT_TOKEN }}@github.com/${{ github.repository }}.git HEAD:master +jobs: build-and-push: - needs: check-for-updates - if: needs.check-for-updates.outputs.should_build == 'true' || needs.check-for-updates.outputs.force_build == 'true' runs-on: ubuntu-latest steps: - name: Checkout @@ -78,20 +38,31 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 + - name: Resolve push flag + id: cfg + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "push=false" >> "$GITHUB_OUTPUT" + elif [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "push=${{ inputs.push_image }}" >> "$GITHUB_OUTPUT" + else + echo "push=true" >> "$GITHUB_OUTPUT" + fi - name: Login to Docker Hub + if: steps.cfg.outputs.push == 'true' uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Generate date tag id: date - run: echo "tag=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + run: echo "tag=$(date +'%Y-%m-%d')" >> "$GITHUB_OUTPUT" - name: Build and Push uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64,linux/arm64 - push: true + push: ${{ steps.cfg.outputs.push }} no-cache: true tags: | vinnyahh/opencode-box:${{ steps.date.outputs.tag }} diff --git a/Dockerfile b/Dockerfile index 00e6930..c625efb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,23 +1,33 @@ FROM node:alpine +# Populated automatically by Docker Buildx per target platform (amd64 / arm64). +ARG TARGETARCH + LABEL org.opencontainers.image.title="opencode-box" \ org.opencontainers.image.description="OpenCode AI coding agent in a container, with Node (npx) and Python (uvx) MCP support" \ org.opencontainers.image.source="https://github.com/vinnyang/opencode-box" \ org.opencontainers.image.licenses="MIT" -# Pin opencode to the tracked version for reproducible builds (the installer reads $VERSION). +# Pin opencode to the tracked version for reproducible builds. # Copied first so a version bump invalidates the install layer cache. COPY .opencode-version /tmp/oc-version RUN apk upgrade --no-cache && \ apk add --no-cache git ripgrep jq python3 py3-pip curl bash tar && \ pip3 install --break-system-packages uv && \ - curl -fsSL https://opencode.ai/install | VERSION="$(cat /tmp/oc-version)" bash && \ - rm /tmp/oc-version + OC_VER="$(cat /tmp/oc-version)" && \ + case "$TARGETARCH" in \ + amd64) OC_ARCH="x64" ;; \ + arm64) OC_ARCH="arm64" ;; \ + *) echo "unsupported TARGETARCH: '$TARGETARCH'" >&2; exit 1 ;; \ + esac && \ + curl -fsSL -o /tmp/oc.tar.gz \ + "https://github.com/anomalyco/opencode/releases/download/v${OC_VER}/opencode-linux-${OC_ARCH}-musl.tar.gz" && \ + tar -xzf /tmp/oc.tar.gz -C /usr/local/bin opencode && \ + chmod 755 /usr/local/bin/opencode && \ + rm /tmp/oc.tar.gz /tmp/oc-version # Need to compile native MCP deps (Python wheels / node-gyp)? add: build-base python3-dev -ENV PATH="/root/.opencode/bin:$PATH" - RUN mkdir -p /config /data/sessions /data/snapshots /data/log /projects COPY docker-entrypoint.sh /usr/local/bin/ diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..24003b4 --- /dev/null +++ b/renovate.json @@ -0,0 +1,56 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:recommended", + "docker:enableMajor", + "docker:pinDigests", + "helpers:pinGitHubActionDigests" + ], + "labels": ["dependencies"], + "schedule": ["before 4am"], + "timezone": "America/New_York", + "packageRules": [ + { + "description": "Auto-merge Docker digest updates (very low risk)", + "matchDatasources": ["docker"], + "matchUpdateTypes": ["digest"], + "automerge": true, + "automergeType": "branch" + }, + { + "description": "Auto-merge Docker minor/patch", + "matchDatasources": ["docker"], + "matchUpdateTypes": ["minor", "patch"], + "automerge": true + }, + { + "description": "Auto-merge npm patch updates", + "matchDatasources": ["npm"], + "matchUpdateTypes": ["patch"], + "automerge": true + }, + { + "description": "Auto-merge GitHub Actions updates", + "matchManagers": ["github-actions"], + "automerge": true + }, + { + "description": "Auto-merge opencode patch releases", + "matchDatasources": ["github-releases"], + "matchPackageNames": ["anomalyco/opencode"], + "matchUpdateTypes": ["patch"], + "automerge": true + } + ], + "customManagers": [ + { + "customType": "regex", + "description": "Track opencode from GitHub releases (same source as the installed binary)", + "managerFilePatterns": ["/(^|/)\\.opencode-version$/"], + "matchStrings": ["(?\\S+)"], + "depNameTemplate": "anomalyco/opencode", + "datasourceTemplate": "github-releases", + "extractVersionTemplate": "^v(?.+)$" + } + ] +}