feat(channel): add experimental WhatsApp channel support #1856
Workflow file for this run
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: Docker | |
| on: | |
| push: | |
| branches: [main, "v*.*"] | |
| tags: ["v*"] | |
| paths-ignore: | |
| - "**.md" | |
| - "devenv/**" | |
| release: | |
| types: [published] | |
| pull_request: | |
| branches: [main, "v*.*"] | |
| paths-ignore: | |
| - "**.md" | |
| - "devenv/**" | |
| workflow_dispatch: | |
| concurrency: | |
| group: docker-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| PUSH: ${{ github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v') || startsWith(github.ref, 'refs/tags/') || github.event_name == 'release') }} | |
| REGISTRY: ghcr.io | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| jobs: | |
| detect-changes: | |
| name: Detect changes | |
| runs-on: ubuntu-latest | |
| outputs: | |
| server: ${{ steps.filter.outputs.server }} | |
| web: ${{ steps.filter.outputs.web }} | |
| sparse: ${{ steps.filter.outputs.sparse }} | |
| workspace: ${{ steps.filter.outputs.workspace }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: dorny/paths-filter@v3 | |
| id: filter | |
| with: | |
| # Tags, releases, and workflow_dispatch always build everything | |
| predicate-quantifier: some | |
| filters: | | |
| server: | |
| - '**/*.go' | |
| - 'go.mod' | |
| - 'go.sum' | |
| - 'cmd/**' | |
| - 'internal/**' | |
| - 'crates/**' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| - 'docker/Dockerfile.server' | |
| - 'docker/server-entrypoint.sh' | |
| - 'docker/toolkit/**' | |
| - 'conf/providers/**' | |
| - 'spec/**' | |
| web: | |
| - 'apps/web/**' | |
| - 'packages/**' | |
| - 'pnpm-lock.yaml' | |
| - 'pnpm-workspace.yaml' | |
| - 'docker/Dockerfile.web' | |
| - 'docker/nginx.conf' | |
| sparse: | |
| - 'internal/memory/sparse/service/**' | |
| - 'docker/Dockerfile.sparse' | |
| workspace: | |
| - 'docker/Dockerfile.workspace' | |
| - 'scripts/desktop-install.sh' | |
| build: | |
| name: build ${{ matrix.image }}${{ matrix.variant != '' && format(' ({0})', matrix.variant) || '' }} ${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} | |
| needs: detect-changes | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| image: [server, web, sparse, workspace] | |
| platform: [linux/amd64, linux/arm64] | |
| variant: ["", debian] | |
| exclude: | |
| - image: server | |
| variant: debian | |
| - image: web | |
| variant: debian | |
| - image: sparse | |
| variant: debian | |
| - image: workspace | |
| variant: "" | |
| include: | |
| - image: server | |
| dockerfile: docker/Dockerfile.server | |
| - image: web | |
| dockerfile: docker/Dockerfile.web | |
| - image: sparse | |
| dockerfile: docker/Dockerfile.sparse | |
| - image: workspace | |
| dockerfile: docker/Dockerfile.workspace | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - name: Check if build is needed | |
| id: should-build | |
| run: | | |
| FORCE="false" | |
| if [[ "${{ github.ref }}" == refs/tags/* ]] || \ | |
| [[ "${{ github.event_name }}" == "release" ]] || \ | |
| [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| FORCE="true" | |
| fi | |
| IMAGE="${{ matrix.image }}" | |
| CHANGED="false" | |
| case "$IMAGE" in | |
| server) CHANGED="${{ needs.detect-changes.outputs.server }}" ;; | |
| web) CHANGED="${{ needs.detect-changes.outputs.web }}" ;; | |
| sparse) CHANGED="${{ needs.detect-changes.outputs.sparse }}" ;; | |
| workspace) CHANGED="${{ needs.detect-changes.outputs.workspace }}" ;; | |
| esac | |
| if [[ "$FORCE" == "true" || "$CHANGED" == "true" ]]; then | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| echo "Skipping $IMAGE build — no relevant files changed" | |
| fi | |
| - name: Checkout | |
| if: steps.should-build.outputs.skip != 'true' | |
| uses: actions/checkout@v4 | |
| - name: Set up Docker Buildx | |
| if: steps.should-build.outputs.skip != 'true' | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Set up Go | |
| if: steps.should-build.outputs.skip != 'true' && matrix.image == 'server' | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: '1.25' | |
| cache: true | |
| - name: Pre-warm Go mod cache | |
| if: steps.should-build.outputs.skip != 'true' && matrix.image == 'server' | |
| run: | | |
| mkdir -p .go-cache | |
| GOMODCACHE=$(pwd)/.go-cache go mod download | |
| - name: Login to Docker Hub | |
| if: steps.should-build.outputs.skip != 'true' && env.PUSH == 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Login to GitHub Container Registry | |
| if: steps.should-build.outputs.skip != 'true' && env.PUSH == 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Resolve artifact key | |
| id: resolve | |
| if: steps.should-build.outputs.skip != 'true' | |
| run: | | |
| VARIANT="${{ matrix.variant }}" | |
| if [ -n "$VARIANT" ]; then | |
| ARTIFACT_KEY="${{ matrix.image }}-${VARIANT}" | |
| else | |
| ARTIFACT_KEY="${{ matrix.image }}" | |
| fi | |
| echo "artifact_key=${ARTIFACT_KEY}" >> "$GITHUB_OUTPUT" | |
| - name: Build and push by digest | |
| id: build | |
| if: steps.should-build.outputs.skip != 'true' | |
| uses: docker/build-push-action@v6 | |
| with: | |
| context: . | |
| file: ${{ matrix.dockerfile }} | |
| platforms: ${{ matrix.platform }} | |
| outputs: ${{ env.PUSH == 'true' && format('type=image,"name={0}/{1}/{2}",push-by-digest=true,name-canonical=true,push=true,compression=zstd', env.REGISTRY, github.repository_owner, matrix.image) || '' }} | |
| build-contexts: ${{ matrix.image == 'server' && format('gomodcache={0}/.go-cache', github.workspace) || '' }} | |
| build-args: | | |
| VERSION=${{ github.ref_name }} | |
| COMMIT_HASH=${{ github.sha }} | |
| VITE_API_URL=/api | |
| VITE_AGENT_URL=/agent | |
| cache-from: | | |
| type=gha,scope=${{ steps.resolve.outputs.artifact_key }}-${{ matrix.platform }} | |
| type=registry,ref=${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.image }}:buildcache-${{ steps.resolve.outputs.artifact_key }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }} | |
| cache-to: | | |
| type=gha,scope=${{ steps.resolve.outputs.artifact_key }}-${{ matrix.platform }},mode=max | |
| ${{ env.PUSH == 'true' && format('type=registry,ref={0}/{1}/{2}:buildcache-{3}-{4},mode=max,compression=zstd', env.REGISTRY, github.repository_owner, matrix.image, steps.resolve.outputs.artifact_key, matrix.platform == 'linux/amd64' && 'amd64' || 'arm64') || '' }} | |
| - name: Export digest | |
| if: steps.should-build.outputs.skip != 'true' && env.PUSH == 'true' | |
| run: | | |
| mkdir -p /tmp/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "/tmp/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| if: steps.should-build.outputs.skip != 'true' && env.PUSH == 'true' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: digests__${{ steps.resolve.outputs.artifact_key }}__${{ strategy.job-index }} | |
| path: /tmp/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge: | |
| name: publish ${{ matrix.image }}${{ matrix.variant != '' && format(' ({0})', matrix.variant) || '' }} | |
| runs-on: ubuntu-latest | |
| if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/v') || startsWith(github.ref, 'refs/tags/') || github.event_name == 'release') | |
| needs: [detect-changes, build] | |
| strategy: | |
| matrix: | |
| include: | |
| - image: server | |
| artifact_key: server | |
| variant: "" | |
| - image: web | |
| artifact_key: web | |
| variant: "" | |
| - image: sparse | |
| artifact_key: sparse | |
| variant: "" | |
| - image: workspace | |
| artifact_key: workspace-debian | |
| variant: debian | |
| steps: | |
| - name: Check if publish is needed | |
| id: should-publish | |
| run: | | |
| FORCE="false" | |
| if [[ "${{ github.ref }}" == refs/tags/* ]] || \ | |
| [[ "${{ github.event_name }}" == "release" ]] || \ | |
| [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
| FORCE="true" | |
| fi | |
| IMAGE="${{ matrix.image }}" | |
| CHANGED="false" | |
| case "$IMAGE" in | |
| server) CHANGED="${{ needs.detect-changes.outputs.server }}" ;; | |
| web) CHANGED="${{ needs.detect-changes.outputs.web }}" ;; | |
| sparse) CHANGED="${{ needs.detect-changes.outputs.sparse }}" ;; | |
| workspace) CHANGED="${{ needs.detect-changes.outputs.workspace }}" ;; | |
| esac | |
| if [[ "$FORCE" == "true" || "$CHANGED" == "true" ]]; then | |
| echo "skip=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "skip=true" >> "$GITHUB_OUTPUT" | |
| echo "Skipping $IMAGE publish — no relevant files changed" | |
| fi | |
| - name: Download digests | |
| if: steps.should-publish.outputs.skip != 'true' | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: /tmp/digests | |
| pattern: digests__${{ matrix.artifact_key }}__* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| if: steps.should-publish.outputs.skip != 'true' | |
| uses: docker/setup-buildx-action@v3 | |
| - name: Login to Docker Hub | |
| if: steps.should-publish.outputs.skip != 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Login to GitHub Container Registry | |
| if: steps.should-publish.outputs.skip != 'true' | |
| uses: docker/login-action@v3 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Resolve publish config | |
| if: steps.should-publish.outputs.skip != 'true' | |
| id: publish | |
| run: | | |
| IMAGE="memohai/${{ matrix.image }}" | |
| GHCR_IMAGE="ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}" | |
| REF_NAME="${{ github.event_name == 'release' && github.event.release.tag_name || github.ref_name }}" | |
| VERSION="${REF_NAME#v}" | |
| BASE_VERSION="${VERSION%%-*}" | |
| MAJOR_MINOR="${BASE_VERSION%.*}" | |
| MAJOR="${BASE_VERSION%%.*}" | |
| VARIANT="${{ matrix.variant }}" | |
| TAG_ARGS="" | |
| add_tag() { | |
| local tag="$1" | |
| TAG_ARGS="$TAG_ARGS -t ${IMAGE}:${tag} -t ${GHCR_IMAGE}:${tag}" | |
| } | |
| if [ -n "$VARIANT" ]; then | |
| VERSION_TAG_SUFFIX="-$VARIANT" | |
| DEV_TAG="${VARIANT}-dev" | |
| BRANCH_DEV_TAG="${VARIANT}-${REF_NAME}-dev" | |
| LATEST_TAG="${VARIANT}-latest" | |
| else | |
| VERSION_TAG_SUFFIX="" | |
| DEV_TAG="dev" | |
| BRANCH_DEV_TAG="${REF_NAME}-dev" | |
| LATEST_TAG="latest" | |
| fi | |
| if [ "$GITHUB_REF" = "refs/heads/main" ]; then | |
| add_tag "$DEV_TAG" | |
| if [ "${{ matrix.image }}" = "workspace" ] && [ -n "$VARIANT" ]; then | |
| add_tag "$VARIANT" | |
| fi | |
| fi | |
| if [[ "$GITHUB_REF" == refs/heads/v* ]]; then | |
| add_tag "$BRANCH_DEV_TAG" | |
| fi | |
| if [ "${{ github.event_name }}" = "release" ] || [[ "$GITHUB_REF" == refs/tags/* ]]; then | |
| add_tag "${VERSION}${VERSION_TAG_SUFFIX}" | |
| if [ "$VERSION" = "$BASE_VERSION" ]; then | |
| add_tag "$LATEST_TAG" | |
| add_tag "${MAJOR_MINOR}${VERSION_TAG_SUFFIX}" | |
| add_tag "${MAJOR}${VERSION_TAG_SUFFIX}" | |
| if [ "${{ matrix.image }}" = "workspace" ] && [ -n "$VARIANT" ]; then | |
| add_tag "$VARIANT" | |
| fi | |
| fi | |
| fi | |
| echo "tag_args=${TAG_ARGS# }" >> "$GITHUB_OUTPUT" | |
| - name: Create manifest list and push | |
| if: steps.should-publish.outputs.skip != 'true' | |
| working-directory: /tmp/digests | |
| run: | | |
| docker buildx imagetools create \ | |
| ${{ steps.publish.outputs.tag_args }} \ | |
| $(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.image }}@sha256:%s ' *) |