341 lines
16 KiB
YAML
341 lines
16 KiB
YAML
name: Docker Build and Push
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
version:
|
|
required: false
|
|
type: string
|
|
description: "Main version to build. Does not support base version."
|
|
release_type:
|
|
required: true
|
|
type: string
|
|
pre_release:
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
nightly_tag_main:
|
|
description: "Tag for the nightly main build"
|
|
required: false
|
|
type: string
|
|
default: ''
|
|
nightly_tag_base:
|
|
description: "Tag for the nightly base build"
|
|
required: false
|
|
type: string
|
|
default: ''
|
|
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: "Main version to build. Does not support base version."
|
|
required: false
|
|
type: string
|
|
release_type:
|
|
description: "Type of release"
|
|
required: true
|
|
type: string
|
|
pre_release:
|
|
description: "Pre-release"
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
nightly_tag_main:
|
|
description: "Tag for the nightly main build"
|
|
required: false
|
|
type: string
|
|
default: ''
|
|
nightly_tag_base:
|
|
description: "Tag for the nightly base build"
|
|
required: false
|
|
type: string
|
|
default: ''
|
|
|
|
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 }}
|
|
nightly-tag: ${{ steps.resolve-nightly-tag.outputs.nightly_tag }}
|
|
nightly-build: ${{ steps.resolve-nightly-tag.outputs.nightly_build }}
|
|
steps:
|
|
- name: Resolve nightly tag
|
|
id: resolve-nightly-tag
|
|
run: |
|
|
# Note - this is more complex than I'd like. For `main` builds, we just pass the `main` tag.
|
|
# For `base` builds, we pass both the `base` and `main` tags. This is because the `main` tag is the
|
|
# version we need to check out for the build, but the `base` tag is the version we need to build.
|
|
#
|
|
# So, you need to check for `base` existence before `main`.
|
|
|
|
if [[ "${{ inputs.nightly_tag_base }}" != '' ]]; then
|
|
if [[ "${{ inputs.release_type }}" != "base" ]]; then
|
|
echo "Release type is not 'base'. Exiting the workflow."
|
|
exit 1
|
|
fi
|
|
|
|
# Main tag must not be empty, otherwise we have no valid tag to check out.
|
|
if [[ "${{ inputs.nightly_tag_main }}" == '' ]]; then
|
|
echo "Nightly tag main is empty. Exiting the workflow."
|
|
exit 1
|
|
fi
|
|
|
|
echo "nightly_tag=${{ inputs.nightly_tag_base }}" >> $GITHUB_OUTPUT
|
|
echo "nightly_build=true" >> $GITHUB_OUTPUT
|
|
elif [[ "${{ inputs.nightly_tag_main }}" != '' ]]; then
|
|
if [[ "${{ inputs.release_type }}" != "main" ]]; then
|
|
echo "Release type is not 'main'. Exiting the workflow."
|
|
exit 1
|
|
fi
|
|
echo "nightly_tag=${{ inputs.nightly_tag_main }}" >> $GITHUB_OUTPUT
|
|
echo "nightly_build=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "nightly_tag=" >> $GITHUB_OUTPUT
|
|
echo "nightly_build=false" >> $GITHUB_OUTPUT
|
|
fi
|
|
- name: Check out the code at a specific ref
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ inputs.nightly_tag_main || github.ref }}
|
|
persist-credentials: true
|
|
|
|
- name: Get Version from Input
|
|
if: ${{ inputs.version != '' }}
|
|
id: get-version-input
|
|
run: |
|
|
# Base version cannot have a version input, since you have to specify a valid main tag to checkout.
|
|
if [[ "${{ inputs.release_type }}" == "base" && "${{ inputs.version }}" != '' ]]; then
|
|
echo "Cannot specify version for base release."
|
|
echo "Build type is 'base' and version is non-empty. Exiting the workflow."
|
|
exit 1
|
|
fi
|
|
|
|
# If doing a nightly release, just specify the nightly tag.
|
|
if [[ "${{ inputs.version }}" != '' && "${{ steps.resolve-nightly-tag.outputs.nightly-tag }}" != '' ]]; then
|
|
echo "Cannot specify both version and nightly version."
|
|
echo "Version is specified and nightly tag is non-empty. Exiting the workflow."
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${{ steps.resolve-nightly-tag.outputs.nightly-tag }}" != '' ]]; then
|
|
if [[ "${{ inputs.nightly_tag_main }}" == '' ]]; then
|
|
echo "Must specify a main nightly tag to check out when building base image."
|
|
echo "Nightly tag main is empty. Exiting the workflow."
|
|
exit 1
|
|
fi
|
|
echo "main nightly version=${{ inputs.nightly_tag_main }}"
|
|
echo "base nightly version=${{ inputs.nightly_tag_base }}"
|
|
echo "building image for nightly_version=${{ steps.resolve-nightly-tag.outputs.nightly-tag }}"
|
|
|
|
# Strip leading v from nightly tag main if present
|
|
version=${{ inputs.nightly_tag_main }}
|
|
version=${version#v}
|
|
echo version=$version >> $GITHUB_OUTPUT
|
|
elif [[ "${{ inputs.version }}" != '' ]]; then
|
|
# strip leading v if present
|
|
version=${{ inputs.version }}
|
|
version=${version#v}
|
|
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.version == '' && inputs.release_type == 'base' }}
|
|
id: get-version-base
|
|
run: |
|
|
version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//')
|
|
echo version=$version
|
|
echo version=$version >> $GITHUB_OUTPUT
|
|
- name: Get Version Main
|
|
if: ${{ inputs.version == '' && (inputs.release_type == 'main' || inputs.release_type == 'main-ep') }}
|
|
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 [[ "${{ needs.get-version.outputs.nightly-build }}" == "true" ]]; then
|
|
nightly_suffix="-nightly"
|
|
fi
|
|
|
|
if [[ "${{ inputs.release_type }}" == "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" ]]; 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: ${{ needs.get-version.outputs.version || github.ref }}
|
|
persist-credentials: true
|
|
- name: "Setup Environment"
|
|
uses: ./.github/actions/setup-uv
|
|
- name: Install the project
|
|
run: |
|
|
if [[ "${{ inputs.release_type }}" == "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 }}
|
|
# 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
|
|
|
|
- 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 }}
|
|
# 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
|
|
|
|
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: ${{ inputs.pre_release == 'true' && format('langflowai/langflow-backend{0}:{1}', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) || format('langflowai/langflow-backend{0}:{1},langflowai/langflow-backend{0}:latest', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) }}
|
|
langflow_image: langflowai/langflow${{ needs.get-version.outputs.nightly-build && '-nightly' || '' }}:${{ needs.get-version.outputs.version }}
|
|
- component: docker-frontend
|
|
dockerfile: ./docker/frontend/build_and_push_frontend.Dockerfile
|
|
tags: ${{ inputs.pre_release == 'true' && format('langflowai/langflow-frontend{0}:{1}', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) || format('langflowai/langflow-frontend{0}:{1},langflowai/langflow-frontend{0}:latest', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) }}
|
|
langflow_image: langflowai/langflow${{ needs.get-version.outputs.nightly-build && '-nightly' || '' }}:${{ needs.get-version.outputs.version }}
|
|
- component: ghcr-backend
|
|
dockerfile: ./docker/build_and_push_backend.Dockerfile
|
|
tags: ${{ format('ghcr.io/langflow-ai/langflow-backend{0}:{1},ghcr.io/langflow-ai/langflow-backend{0}:latest', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) }}
|
|
langflow_image: ghcr.io/langflow-ai/langflow${{ needs.get-version.outputs.nightly-build && '-nightly' || '' }}:${{ needs.get-version.outputs.version }}
|
|
- component: ghcr-frontend
|
|
dockerfile: ./docker/frontend/build_and_push_frontend.Dockerfile
|
|
tags: ${{ format('ghcr.io/langflow-ai/langflow-frontend{0}:{1},ghcr.io/langflow-ai/langflow-frontend{0}:latest', needs.get-version.outputs.nightly-build && '-nightly' || '', needs.get-version.outputs.version) }}
|
|
langflow_image: ghcr.io/langflow-ai/langflow${{ needs.get-version.outputs.nightly-build && '-nightly' || '' }}:${{ needs.get-version.outputs.version }}
|
|
steps:
|
|
- name: Check out the code at a specific ref
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: ${{ needs.get-version.outputs.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' && needs.get-version.outputs.nightly-build == 'false' }}
|
|
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: ${{ needs.get-version.outputs.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 }}
|