name: Docker Build and Push run-name: Docker Build and Push @${{ inputs.release_type }} by @${{ github.actor }} on: workflow_call: inputs: main_version: required: true type: string description: "Main version to tag images with. Required for both main and base releases." base_version: required: false type: string description: "Base version to tag images with. Required for base release type." release_type: required: true type: string description: "Release type. One of 'main', 'main-ep', 'base', 'nightly-main', 'nightly-base'." pre_release: required: false type: boolean default: false ref: required: false type: string description: "Ref to check out. If not specified, will default to the main version or current branch." workflow_dispatch: inputs: main_version: description: "Main version to tag images with. Required for both main and base releases." required: false type: string base_version: description: "Base version to tag images with. Required for base release type." required: false type: string release_type: description: "Type of release. One of 'main', 'main-ep', 'base', 'nightly-main', 'nightly-base'." required: true type: string pre_release: required: false type: boolean default: false ref: required: false type: string description: "Ref to check out. If not specified, will default to the main version or current branch." env: POETRY_VERSION: "1.8.2" TEST_TAG: "langflowai/langflow:test" jobs: get-version: name: Get Version runs-on: ubuntu-latest outputs: version: ${{ steps.get-version-input.outputs.version || steps.get-version-base.outputs.version || steps.get-version-main.outputs.version }} steps: - name: Verify a main version exists if: ${{ inputs.main_version == '' }} run: | # due to our how we split packages, we need to have a main version to check out. echo "Must specify a main version to check out." exit 1 - name: Check out the code at a specific ref uses: actions/checkout@v4 with: ref: ${{ inputs.ref || inputs.main_version || github.ref }} persist-credentials: true - name: Get Version to Tag if: ${{ inputs.main_version != '' }} id: get-version-input run: | # Produces the versions we will use to tag the docker images with. if [[ "${{ inputs.release_type }}" == "base" && "${{ inputs.base_version }}" == '' ]]; then echo "Must specify a base version for base release type." exit 1 fi if [[ "${{ inputs.release_type }}" == "nightly-base" && "${{ inputs.base_version }}" == '' ]]; then echo "Must specify a base version for nightly-base release type." exit 1 fi if [[ "${{ inputs.release_type }}" == "main" && "${{ inputs.main_version }}" == '' ]]; then echo "Must specify a main version for main release type." exit 1 fi if [[ "${{ inputs.release_type }}" == "main-ep" && "${{ inputs.main_version }}" == '' ]]; then echo "Must specify a main version for main-ep release type." exit 1 fi if [[ "${{ inputs.release_type }}" == "nightly-main" && "${{ inputs.main_version }}" == '' ]]; then echo "Must specify a main version for nightly-main release type." exit 1 fi if [[ "${{ inputs.release_type }}" == "base" || "${{ inputs.release_type }}" == "nightly-base" ]]; then version=${{ inputs.base_version }} echo "base version=${{ inputs.base_version }}" echo version=$version echo version=$version >> $GITHUB_OUTPUT elif [[ "${{ inputs.release_type }}" == "main" || "${{ inputs.release_type }}" == "main-ep" || "${{ inputs.release_type }}" == "nightly-main" ]]; then version=${{ inputs.main_version }} echo version=$version echo version=$version >> $GITHUB_OUTPUT else echo "No version or ref specified. Exiting the workflow." exit 1 fi - name: Get Version Base if: ${{ inputs.base_version == '' && (inputs.release_type == 'base' || inputs.release_type == 'nightly-base') }} id: get-version-base run: | version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//') if [ -z "$version" ]; then echo "Failed to extract version from uv tree output" exit 1 fi echo version=$version echo version=$version >> $GITHUB_OUTPUT - name: Get Version Main if: ${{ inputs.main_version == '' && (inputs.release_type == 'main' || inputs.release_type == 'main-ep' || inputs.release_type == 'nightly-main') }} id: get-version-main run: | version=$(uv tree | grep 'langflow' | grep -v 'langflow-base' | awk '{print $2}' | sed 's/^v//') echo version=$version echo version=$version >> $GITHUB_OUTPUT setup: runs-on: ubuntu-latest needs: get-version outputs: docker_tags: ${{ steps.set-vars.outputs.docker_tags }} ghcr_tags: ${{ steps.set-vars.outputs.ghcr_tags }} file: ${{ steps.set-vars.outputs.file }} steps: - name: Set Dockerfile and Tags id: set-vars run: | nightly_suffix='' if [[ "${{ inputs.release_type }}" == "nightly-base" || "${{ inputs.release_type }}" == "nightly-main" ]]; then nightly_suffix="-nightly" fi if [[ "${{ inputs.release_type }}" == "base" || "${{ inputs.release_type }}" == "nightly-base" ]]; then # LANGFLOW-BASE RELEASE echo "docker_tags=langflowai/langflow${nightly_suffix}:base-${{ needs.get-version.outputs.version }},langflowai/langflow${nightly_suffix}:base-latest" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow${nightly_suffix}:base-${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow${nightly_suffix}:base-latest" >> $GITHUB_OUTPUT echo "file=./docker/build_and_push_base.Dockerfile" >> $GITHUB_OUTPUT else if [[ "${{ inputs.pre_release }}" == "true" ]]; then # LANGFLOW-MAIN PRE-RELEASE echo "docker_tags=langflowai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }}" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }}" >> $GITHUB_OUTPUT echo "file=./docker/build_and_push.Dockerfile" >> $GITHUB_OUTPUT elif [[ "${{ inputs.release_type }}" == "main-ep" ]]; then # LANGFLOW-MAIN (ENTRYPOINT) RELEASE echo "docker_tags=langflowai/langflow-ep${nightly_suffix}:${{ needs.get-version.outputs.version }},langflowai/langflow-ep${nightly_suffix}:latest" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow-ep${nightly_suffix}:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow-ep${nightly_suffix}:latest" >> $GITHUB_OUTPUT echo "file=./docker/build_and_push_ep.Dockerfile" >> $GITHUB_OUTPUT elif [[ "${{ inputs.release_type }}" == "main" || "${{ inputs.release_type }}" == "nightly-main" ]]; then # LANGFLOW-MAIN RELEASE echo "docker_tags=langflowai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }},langflowai/langflow${nightly_suffix}:latest" >> $GITHUB_OUTPUT echo "ghcr_tags=ghcr.io/langflow-ai/langflow${nightly_suffix}:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow${nightly_suffix}:latest" >> $GITHUB_OUTPUT echo "file=./docker/build_and_push.Dockerfile" >> $GITHUB_OUTPUT else echo "Invalid release type. Exiting the workflow." exit 1 fi fi build: runs-on: ubuntu-latest needs: [get-version, setup] steps: - name: Check out the code at a specific ref uses: actions/checkout@v4 with: ref: ${{ inputs.ref || inputs.main_version || github.ref }} persist-credentials: true - name: "Setup Environment" uses: ./.github/actions/setup-uv - name: Install the project run: | if [[ "${{ inputs.release_type }}" == "base" || "${{ inputs.release_type }}" == "nightly-base" ]]; then uv sync --directory src/backend/base --no-dev --no-sources else uv sync --no-dev --no-sources fi - 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@v6 with: context: . push: true file: ${{ needs.setup.outputs.file }} tags: ${{ needs.setup.outputs.docker_tags }} platforms: linux/amd64,linux/arm64 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@v6 with: context: . push: true file: ${{ needs.setup.outputs.file }} tags: ${{ needs.setup.outputs.ghcr_tags }} platforms: linux/amd64,linux/arm64 cache-from: type=gha cache-to: type=gha,mode=max build_components: if: ${{ inputs.release_type == 'main' }} runs-on: ubuntu-latest permissions: packages: write needs: [build, get-version] strategy: matrix: component: [docker-backend, docker-frontend, ghcr-backend, ghcr-frontend] include: - component: docker-backend dockerfile: ./docker/build_and_push_backend.Dockerfile tags: langflowai/langflow-backend:${{ needs.get-version.outputs.version }},langflowai/langflow-backend:latest langflow_image: langflowai/langflow:${{ needs.get-version.outputs.version }} - component: docker-frontend dockerfile: ./docker/frontend/build_and_push_frontend.Dockerfile tags: langflowai/langflow-frontend:${{ needs.get-version.outputs.version }},langflowai/langflow-frontend:latest langflow_image: langflowai/langflow:${{ needs.get-version.outputs.version }} - component: ghcr-backend dockerfile: ./docker/build_and_push_backend.Dockerfile tags: ghcr.io/langflow-ai/langflow-backend:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow-backend:latest langflow_image: ghcr.io/langflow-ai/langflow:${{ needs.get-version.outputs.version }} - component: ghcr-frontend dockerfile: ./docker/frontend/build_and_push_frontend.Dockerfile tags: ghcr.io/langflow-ai/langflow-frontend:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow-frontend:latest langflow_image: ghcr.io/langflow-ai/langflow:${{ needs.get-version.outputs.version }} steps: - name: Check out the code at a specific ref uses: actions/checkout@v4 with: ref: ${{ inputs.ref || inputs.main_version || github.ref }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Login to Docker Hub if: ${{ matrix.component == 'docker-backend' }} || ${{ matrix.component == 'docker-frontend' }} uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Login to Github Container Registry if: ${{ matrix.component == 'ghcr-backend' }} || ${{ matrix.component == 'ghcr-frontend' }} uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.TEMP_GHCR_TOKEN}} - name: Wait for propagation (for backend) run: sleep 120 - name: Build and push ${{ matrix.component }} uses: docker/build-push-action@v6 with: context: . push: true build-args: | LANGFLOW_IMAGE=${{ matrix.langflow_image }} file: ${{ matrix.dockerfile }} tags: ${{ matrix.tags }} # provenance: false will result in a single manifest for all platforms which makes the image pullable from arm64 machines via the emulation (e.g. Apple Silicon machines) provenance: false restart-space: name: Restart HuggingFace Spaces if: ${{ inputs.release_type == 'main' }} runs-on: ubuntu-latest needs: [build, get-version] strategy: matrix: python-version: - "3.12" steps: - name: Check out the code at a specific ref uses: actions/checkout@v4 with: ref: ${{ inputs.ref || inputs.main_version || github.ref }} - name: "Setup Environment" uses: ./.github/actions/setup-uv - name: Restart HuggingFace Spaces Build run: | uv run ./scripts/factory_restart_space.py --space "Langflow/Langflow" --token ${{ secrets.HUGGINGFACE_API_TOKEN }}