name: Docker Build and Push v2 run-name: Docker Build and Push @${{ inputs.release_type }} by @${{ github.actor }} on: workflow_call: inputs: release_type: required: true type: string description: "Release type. One of 'main', 'main-backend', 'main-frontend', 'main-ep', 'base', 'main-all'." pre_release: required: false type: boolean default: false ref: required: true type: string description: "Ref to check out (branch, tag, or commit). This is required -- it specifies where the source code for the release is located." push_to_registry: required: false type: boolean default: true description: "Whether to push images to registries. Set to false for testing builds without publishing." workflow_dispatch: inputs: release_type: description: "Type of release. One of 'main', 'main-backend', 'main-frontend', 'main-ep', 'base', 'main-all'." required: true type: choice options: - main - main-backend - main-frontend - main-ep - base - main-all pre_release: description: "Whether this is a pre-release." required: false type: boolean default: false ref: required: true type: string description: "Ref to check out (branch, tag, or commit). This is required -- it specifies where the source code for the release is located." push_to_registry: description: "Whether to push images to registries. Set to false for testing builds without publishing." required: false type: boolean default: false env: PYTHON_VERSION: "3.13" jobs: determine-base-version: name: Determine Base Version if: ${{ inputs.release_type == 'base' }} runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.version }} skipped: ${{ steps.version.outputs.skipped }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Setup Environment uses: astral-sh/setup-uv@v6 with: enable-cache: true cache-dependency-glob: "uv.lock" python-version: "3.13" prune-cache: false - name: Determine version id: version run: | version=$(uv tree 2>/dev/null | grep '^langflow-base' | cut -d' ' -f2 | sed 's/^v//') echo "Base version from pyproject.toml: $version" if [ ${{inputs.pre_release}} == "true" ]; then last_released_version=$(curl -s "https://registry.hub.docker.com/v2/repositories/langflowai/langflow/tags?page_size=100" | jq -r '.results[].name' | grep -E '^base-.*\.rc[0-9]+' | grep -vE '\-(amd64|arm64)$' | sed 's/^base-//' | sort -V | tail -n 1) version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")" echo "Latest base pre-release version: $last_released_version" echo "Base pre-release version to be released: $version" else last_released_version=$(curl -s "https://registry.hub.docker.com/v2/repositories/langflowai/langflow/tags?page_size=100" | jq -r '.results[].name' | grep -E '^base-' | grep -vE '\-(amd64|arm64)$' | grep -v 'latest' | sed 's/^base-//' | sort -V | tail -n 1) echo "Latest base release version: $last_released_version" fi if [ "$version" = "$last_released_version" ]; then echo "Base docker version $version is already released. Skipping release." echo skipped=true >> $GITHUB_OUTPUT exit 0 else echo version=$version >> $GITHUB_OUTPUT echo skipped=false >> $GITHUB_OUTPUT fi determine-main-version: name: Determine Main Version if: ${{ inputs.release_type != 'base' }} runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.version }} skipped: ${{ steps.version.outputs.skipped }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Setup Environment uses: astral-sh/setup-uv@v6 with: enable-cache: true cache-dependency-glob: "uv.lock" python-version: "3.13" prune-cache: false - name: Determine version id: version run: | version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//') echo "Main version from pyproject.toml: $version" if [ ${{inputs.pre_release}} == "true" ]; then last_released_version=$(curl -s "https://registry.hub.docker.com/v2/repositories/langflowai/langflow/tags?page_size=100" | jq -r '.results[].name' | grep -E '\.rc[0-9]+' | grep -v '^base-' | grep -vE '\-(amd64|arm64)$' | sort -V | tail -n 1) version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")" echo "Latest main pre-release version: $last_released_version" echo "Main pre-release version to be released: $version" else last_released_version=$(curl -s "https://registry.hub.docker.com/v2/repositories/langflowai/langflow/tags?page_size=100" | jq -r '.results[].name' | grep -v '^base-' | grep -vE '\-(amd64|arm64)$' | grep -v 'latest' | sort -V | tail -n 1) echo "Latest main release version: $last_released_version" fi if [ "$version" = "$last_released_version" ]; then echo "Main docker version $version is already released. Skipping release." echo skipped=true >> $GITHUB_OUTPUT exit 0 else echo version=$version >> $GITHUB_OUTPUT echo skipped=false >> $GITHUB_OUTPUT fi build-base: name: Build Base Package needs: [determine-base-version] if: ${{ inputs.release_type == 'base' && needs.determine-base-version.outputs.skipped == 'false' }} strategy: matrix: include: - arch: amd64 runner: [Langflow-runner] - arch: arm64 runner: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral] runs-on: ${{ matrix.runner }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Set tags id: tags run: | version="${{ needs.determine-base-version.outputs.version }}" echo "docker_tags=langflowai/langflow:base-${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow:base-${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - name: Docker cleanup run: | docker system prune -af --volumes || true docker buildx prune -af || true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Build and push to Docker Hub uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push_base.Dockerfile tags: ${{ steps.tags.outputs.docker_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push to GitHub Container Registry uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push_base.Dockerfile tags: ${{ steps.tags.outputs.ghcr_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max build-main: name: Build Main Package needs: [determine-main-version] if: ${{ inputs.release_type == 'main' && needs.determine-main-version.outputs.skipped == 'false' }} strategy: matrix: include: - arch: amd64 runner: [Langflow-runner] - arch: arm64 runner: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral] runs-on: ${{ matrix.runner }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Set tags id: tags run: | version="${{ needs.determine-main-version.outputs.version }}" echo "docker_tags=langflowai/langflow:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - name: Docker cleanup run: | docker system prune -af --volumes || true docker buildx prune -af || true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Build and push to Docker Hub uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push.Dockerfile tags: ${{ steps.tags.outputs.docker_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push to GitHub Container Registry uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push.Dockerfile tags: ${{ steps.tags.outputs.ghcr_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max build-main-backend: name: Build Main Backend Package needs: [determine-main-version] if: ${{ inputs.release_type == 'main-backend' && needs.determine-main-version.outputs.skipped == 'false' }} strategy: matrix: include: - arch: amd64 runner: [Langflow-runner] - arch: arm64 runner: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral] runs-on: ${{ matrix.runner }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Set tags id: tags run: | version="${{ needs.determine-main-version.outputs.version }}" echo "docker_tags=langflowai/langflow-backend:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow-backend:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - name: Docker cleanup run: | docker system prune -af --volumes || true docker buildx prune -af || true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push to Docker Hub uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} build-args: | LANGFLOW_IMAGE=langflowai/langflow:${{ steps.version.outputs.version }}-${{ matrix.arch }} file: ./docker/build_and_push_backend.Dockerfile tags: ${{ steps.tags.outputs.docker_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Build and push to GitHub Container Registry uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} build-args: | LANGFLOW_IMAGE=ghcr.io/langflow-ai/langflow:${{ steps.version.outputs.version }}-${{ matrix.arch }} file: ./docker/build_and_push_backend.Dockerfile tags: ${{ steps.tags.outputs.ghcr_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max build-main-frontend: name: Build Main Frontend Package needs: [determine-main-version] if: ${{ inputs.release_type == 'main-frontend' && needs.determine-main-version.outputs.skipped == 'false' }} strategy: matrix: include: - arch: amd64 runner: [Langflow-runner] - arch: arm64 runner: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral] runs-on: ${{ matrix.runner }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Set tags id: tags run: | version="${{ needs.determine-main-version.outputs.version }}" echo "docker_tags=langflowai/langflow-frontend:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow-frontend:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - name: Docker cleanup run: | docker system prune -af --volumes || true docker buildx prune -af || true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push to Docker Hub uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/frontend/build_and_push_frontend.Dockerfile tags: ${{ steps.tags.outputs.docker_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Build and push to GitHub Container Registry uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/frontend/build_and_push_frontend.Dockerfile tags: ${{ steps.tags.outputs.ghcr_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max build-main-ep: name: Build Main EP Package needs: [determine-main-version] if: ${{ inputs.release_type == 'main-ep' && needs.determine-main-version.outputs.skipped == 'false' }} strategy: matrix: include: - arch: amd64 runner: [Langflow-runner] - arch: arm64 runner: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral] runs-on: ${{ matrix.runner }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Set tags id: tags run: | version="${{ needs.determine-main-version.outputs.version }}" echo "docker_tags=langflowai/langflow-ep:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow-ep:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - name: Docker cleanup run: | docker system prune -af --volumes || true docker buildx prune -af || true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Build and push to Docker Hub uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push_ep.Dockerfile tags: ${{ steps.tags.outputs.docker_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push to GitHub Container Registry uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push_ep.Dockerfile tags: ${{ steps.tags.outputs.ghcr_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max build-main-all: name: Build Main All Package needs: [determine-main-version] if: ${{ inputs.release_type == 'main-all' && needs.determine-main-version.outputs.skipped == 'false' }} strategy: matrix: include: - arch: amd64 runner: [Langflow-runner] - arch: arm64 runner: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb-ephemeral] runs-on: ${{ matrix.runner }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Set tags id: tags run: | version="${{ needs.determine-main-version.outputs.version }}" echo "docker_tags=langflowai/langflow-all:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow-all:${version}-${{ matrix.arch }}" >> $GITHUB_OUTPUT - name: Docker cleanup run: | docker system prune -af --volumes || true docker buildx prune -af || true - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Build and push to Docker Hub uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push_with_extras.Dockerfile tags: ${{ steps.tags.outputs.docker_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push to GitHub Container Registry uses: docker/build-push-action@v7 with: context: . push: ${{ inputs.push_to_registry }} file: ./docker/build_and_push_with_extras.Dockerfile tags: ${{ steps.tags.outputs.ghcr_tags }} platforms: linux/${{ matrix.arch }} provenance: false cache-from: type=gha cache-to: type=gha,mode=max create-manifest: name: Create Multi-Arch Manifest needs: [ build-base, build-main, build-main-backend, build-main-frontend, build-main-ep, build-main-all, determine-base-version, determine-main-version, ] runs-on: ubuntu-latest if: ${{ always() && inputs.push_to_registry && (needs.build-base.result == 'success' || needs.build-main.result == 'success' || needs.build-main-backend.result == 'success' || needs.build-main-frontend.result == 'success' || needs.build-main-ep.result == 'success' || needs.build-main-all.result == 'success') }} steps: - name: Check out the code uses: actions/checkout@v6 with: ref: ${{ inputs.ref }} - name: Get version id: version run: | if [[ "${{ inputs.release_type }}" == "base" ]]; then version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1) else version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//') fi echo "Using version: $version" echo version=$version >> $GITHUB_OUTPUT - name: Set tags id: tags run: | version="${{ needs.determine-main-version.outputs.version }}" case "${{ inputs.release_type }}" in "base") version="${{ needs.determine-base-version.outputs.version }}" if [[ "${{ inputs.pre_release }}" == "true" ]]; then echo "final_tags=langflowai/langflow:base-${version},ghcr.io/langflow-ai/langflow:base-${version}" >> $GITHUB_OUTPUT else echo "final_tags=langflowai/langflow:base-${version},langflowai/langflow:base-latest,ghcr.io/langflow-ai/langflow:base-${version},ghcr.io/langflow-ai/langflow:base-latest" >> $GITHUB_OUTPUT fi echo "arch_base=langflowai/langflow:base-${version}" >> $GITHUB_OUTPUT echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow:base-${version}" >> $GITHUB_OUTPUT ;; "main") if [[ "${{ inputs.pre_release }}" == "true" ]]; then echo "final_tags=langflowai/langflow:${version},ghcr.io/langflow-ai/langflow:${version}" >> $GITHUB_OUTPUT else echo "final_tags=langflowai/langflow:${version},langflowai/langflow:latest,ghcr.io/langflow-ai/langflow:${version},ghcr.io/langflow-ai/langflow:latest" >> $GITHUB_OUTPUT fi echo "arch_base=langflowai/langflow:${version}" >> $GITHUB_OUTPUT echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow:${version}" >> $GITHUB_OUTPUT ;; "main-backend") if [[ "${{ inputs.pre_release }}" == "true" ]]; then echo "final_tags=langflowai/langflow-backend:${version},ghcr.io/langflow-ai/langflow-backend:${version}" >> $GITHUB_OUTPUT else echo "final_tags=langflowai/langflow-backend:${version},langflowai/langflow-backend:latest,ghcr.io/langflow-ai/langflow-backend:${version},ghcr.io/langflow-ai/langflow-backend:latest" >> $GITHUB_OUTPUT fi echo "arch_base=langflowai/langflow-backend:${version}" >> $GITHUB_OUTPUT echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-backend:${version}" >> $GITHUB_OUTPUT ;; "main-frontend") if [[ "${{ inputs.pre_release }}" == "true" ]]; then echo "final_tags=langflowai/langflow-frontend:${version},ghcr.io/langflow-ai/langflow-frontend:${version}" >> $GITHUB_OUTPUT else echo "final_tags=langflowai/langflow-frontend:${version},langflowai/langflow-frontend:latest,ghcr.io/langflow-ai/langflow-frontend:${version},ghcr.io/langflow-ai/langflow-frontend:latest" >> $GITHUB_OUTPUT fi echo "arch_base=langflowai/langflow-frontend:${version}" >> $GITHUB_OUTPUT echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-frontend:${version}" >> $GITHUB_OUTPUT ;; "main-ep") if [[ "${{ inputs.pre_release }}" == "true" ]]; then echo "final_tags=langflowai/langflow-ep:${version},ghcr.io/langflow-ai/langflow-ep:${version}" >> $GITHUB_OUTPUT else echo "final_tags=langflowai/langflow-ep:${version},langflowai/langflow-ep:latest,ghcr.io/langflow-ai/langflow-ep:${version},ghcr.io/langflow-ai/langflow-ep:latest" >> $GITHUB_OUTPUT fi echo "arch_base=langflowai/langflow-ep:${version}" >> $GITHUB_OUTPUT echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-ep:${version}" >> $GITHUB_OUTPUT ;; "main-all") if [[ "${{ inputs.pre_release }}" == "true" ]]; then echo "final_tags=langflowai/langflow-all:${version},ghcr.io/langflow-ai/langflow-all:${version}" >> $GITHUB_OUTPUT else echo "final_tags=langflowai/langflow-all:${version},langflowai/langflow-all:latest,ghcr.io/langflow-ai/langflow-all:${version},ghcr.io/langflow-ai/langflow-all:latest" >> $GITHUB_OUTPUT fi echo "arch_base=langflowai/langflow-all:${version}" >> $GITHUB_OUTPUT echo "ghcr_arch_base=ghcr.io/langflow-ai/langflow-all:${version}" >> $GITHUB_OUTPUT ;; *) echo "Error: Invalid release_type: ${{ inputs.release_type }}" >&2 exit 1 ;; esac - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Create and push multi-arch manifests run: | # Split tags and create manifests for each IFS=',' read -ra TAGS <<< "${{ steps.tags.outputs.final_tags }}" for tag in "${TAGS[@]}"; do echo "Creating manifest for $tag" # Determine architecture-specific tags if [[ "$tag" == *"langflowai"* ]]; then amd64_tag="${{ steps.tags.outputs.arch_base }}-amd64" arm64_tag="${{ steps.tags.outputs.arch_base }}-arm64" else amd64_tag="${{ steps.tags.outputs.ghcr_arch_base }}-amd64" arm64_tag="${{ steps.tags.outputs.ghcr_arch_base }}-arm64" fi docker buildx imagetools create \ --tag "$tag" \ "$amd64_tag" \ "$arm64_tag" done