Docker Build and Push @nightly-main by @jordanrfrazier #102
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 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', 'main-all', 'nightly-main-all'." | |
| 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', 'main-all', 'nightly-main-all'." | |
| required: true | |
| type: string | |
| pre_release: | |
| description: "Whether this is a 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: | |
| PYTHON_VERSION: "3.13" | |
| 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@v5 | |
| 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.release_type }}" == "main-all") && "${{ 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.release_type }}" == "nightly-main-all") && "${{ 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" || "${{ inputs.release_type }}" == "nightly-main-all" ]]; 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//' | head -n 1) | |
| 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' || inputs.release_type == 'main-all' || inputs.release_type == 'nightly-main-all') }} | |
| 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" || "${{ inputs.release_type }}" == "nightly-main-all" ]]; 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 | |
| elif [[ "${{ inputs.release_type }}" == "main-all" || "${{ inputs.release_type }}" == "nightly-main-all" ]]; then | |
| # LANGFLOW-MAIN (ALL OPTIONAL DEPS) RELEASE | |
| echo "docker_tags=langflowai/langflow-all${nightly_suffix}:${{ needs.get-version.outputs.version }},langflowai/langflow-all${nightly_suffix}:latest" >> $GITHUB_OUTPUT | |
| echo "ghcr_tags=ghcr.io/langflow-ai/langflow-all${nightly_suffix}:${{ needs.get-version.outputs.version }},ghcr.io/langflow-ai/langflow-all${nightly_suffix}:latest" >> $GITHUB_OUTPUT | |
| echo "file=./docker/build_and_push_with_extras.Dockerfile" >> $GITHUB_OUTPUT | |
| else | |
| echo "Invalid release type. Exiting the workflow." | |
| exit 1 | |
| fi | |
| fi | |
| build: | |
| runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb] | |
| needs: [get-version, setup] | |
| steps: | |
| - name: Check out the code at a specific ref | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.ref || inputs.main_version || github.ref }} | |
| persist-credentials: true | |
| - name: "Setup Environment" | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "uv.lock" | |
| python-version: ${{ env.PYTHON_VERSION }} | |
| prune-cache: false | |
| - 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: Docker System Info and Cleanup | |
| run: | | |
| echo "=== Docker System Usage Before Cleanup ===" | |
| docker system df || true | |
| docker buildx du || true | |
| echo "=== Cleaning up Docker System ===" | |
| docker system prune -af --volumes || true | |
| docker buildx prune -af || true | |
| echo "=== Docker System Usage After Cleanup ===" | |
| docker system df || true | |
| docker buildx du || true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| version: latest | |
| driver: docker-container | |
| driver-opts: | | |
| image=moby/buildkit:v0.22.0 | |
| network=host | |
| - 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: Wandalen/wretry.action@master | |
| with: | |
| action: 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: Wandalen/wretry.action@master | |
| with: | |
| action: 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: [self-hosted, linux, ARM64, langflow-ai-arm64-40gb] | |
| 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@v5 | |
| with: | |
| ref: ${{ inputs.ref || inputs.main_version || github.ref }} | |
| - name: Docker System Info and Cleanup | |
| run: | | |
| echo "=== Docker System Usage Before Cleanup ===" | |
| docker system df || true | |
| docker buildx du || true | |
| echo "=== Cleaning up Docker System ===" | |
| docker system prune -af --volumes || true | |
| docker buildx prune -af || true | |
| echo "=== Docker System Usage After Cleanup ===" | |
| docker system df || true | |
| docker buildx du || true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v3 | |
| with: | |
| version: latest | |
| driver: docker-container | |
| driver-opts: | | |
| image=moby/buildkit:v0.22.0 | |
| network=host | |
| - 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: Wandalen/wretry.action@master | |
| with: | |
| action: 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.13" | |
| steps: | |
| - name: Check out the code at a specific ref | |
| uses: actions/checkout@v5 | |
| with: | |
| ref: ${{ inputs.ref || inputs.main_version || github.ref }} | |
| - name: "Setup Environment" | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: true | |
| cache-dependency-glob: "uv.lock" | |
| python-version: ${{ matrix.python-version }} | |
| prune-cache: false | |
| - name: Restart HuggingFace Spaces Build | |
| run: | | |
| uv run ./scripts/factory_restart_space.py --space "Langflow/Langflow" --token ${{ secrets.HUGGINGFACE_API_TOKEN }} | |