langflow/Makefile
Gabriel Luiz Freitas Almeida 43ad226ddb
chore: update docker images to use uv (#3916)
* fix dev dependencies

* fix dev dependencies

* update lock

* Add langchain-unstructured dependency to pyproject.toml

* Switch to uv-based Docker image and streamline build process

- Use `ghcr.io/astral-sh/uv:python3.12-bookworm-slim` as the base image
- Simplify environment variable setup and remove unnecessary ones
- Install project dependencies using `uv sync` with cache mounts
- Add and copy necessary files for the build process
- Update npm installation and frontend build steps
- Adjust entrypoint and runtime configurations
- Remove redundant user setup and streamline CMD execution

* Refactor Dockerfile to use multi-stage builds for optimized image size

- Introduce a builder stage to install dependencies and build the frontend.
- Use npm ci instead of npm install for more reliable builds.
- Copy built frontend assets to the final image.
- Transition to a runtime stage with a slimmer Python base image.
- Ensure the final image only contains necessary runtime dependencies.

* Switch base image to `ghcr.io/astral-sh/uv:python3.12-bookworm-slim` and update Dockerfile

- Replace `python:3.12.3-slim` with `ghcr.io/astral-sh/uv:python3.12-bookworm-slim` as the base image.
- Enable bytecode compilation and set link mode to copy.
- Update dependency installation process using `uv sync`.
- Simplify frontend build and copy process.
- Add OCI labels for image metadata.
- Update CMD to use `langflow-base` for running the application.

* Update Dockerfile to use uv base image and optimize dependency installation

- Switch base image to `ghcr.io/astral-sh/uv:python3.12-bookworm-slim`
- Combine apt-get commands and clean up to reduce image size
- Replace Poetry with uv for dependency management and caching

* Refactor Dockerfile to use multi-stage build for optimized image size

- Introduce a builder stage using `ghcr.io/astral-sh/uv:python3.12-bookworm-slim`
- Add a runtime stage using `python:3.12.3-slim`
- Copy the virtual environment from the builder stage to the runtime stage
- Remove the `uv` entrypoint to avoid invoking it by default

* Update Dockerfile: Fix indentation and remove redundant ENTRYPOINT reset

* ci: update release workflows to use uv (#3919)

* Update nightly build workflow to use 'uv' for dependency management and caching

- Replace Poetry with 'uv' for dependency installation and project setup
- Add steps to install 'uv' and set up caching for 'uv.lock'
- Modify Python setup to use version specified in 'pyproject.toml'
- Remove Node.js setup steps

* Update release workflow to use uv for dependency management

- Replace Poetry with uv for dependency installation and caching
- Update Python setup to use version specified in pyproject.toml
- Add steps to restore uv cache and install project dependencies using uv
- Adjust publish steps to maintain functionality with new setup

* Replace 'poetry publish' with 'uv publish' in Makefile for consistency

* Update nightly build workflow to use 'uv' for dependency management and caching

* Set up Node.js 20 in release_nightly workflow and update version verification logic

* Update Makefile to use `uv sync --frozen` for backend dependencies installation

* Update Makefile to pass arguments to 'uv build' and remove '--skip-existing' from publish commands

- Modified 'build_langflow' target to accept arguments.
- Removed '--skip-existing' from 'publish_base' and 'publish_base_testpypi' commands.
- Added TODO comments for updating test-pypi repository usage.

* Remove --skip-existing flag from uv publish commands and add TODO comments for test-pypi updates

* new lock

* Update CI workflow to remove version prefix and add build args

- Removed 'v' prefix from version extraction in nightly release workflow.
- Added '--no-sources' argument to the build command in the distribution step.

* Update CI workflow to use 'uv' for versioning and publishing

- Replace 'poetry' with 'uv' for version extraction in release checks

* Update CI workflow to use UV_PUBLISH_TOKEN for PyPI publishing

* Add verification step for 'langflow-nightly' name and version in CI workflow

- Corrected awk commands for extracting 'langflow-base' name and version.
- Added a new step to verify 'langflow-nightly' name and version against expected values.

* feat: Update dev.Dockerfile to use 'uv' for dependency management and caching

* update dockerfiles with --no-editable

---------

Co-authored-by: phact <estevezsebastian@gmail.com>
Co-authored-by: Jordan Frazier <jordan.frazier@datastax.com>
2024-09-30 22:49:25 +00:00

442 lines
12 KiB
Makefile

.PHONY: all init format lint build build_frontend install_frontend run_frontend run_backend dev help tests coverage clean_python_cache clean_npm_cache clean_all
# Configurations
VERSION=$(shell grep "^version" pyproject.toml | sed 's/.*\"\(.*\)\"$$/\1/')
DOCKERFILE=docker/build_and_push.Dockerfile
DOCKERFILE_BACKEND=docker/build_and_push_backend.Dockerfile
DOCKERFILE_FRONTEND=docker/frontend/build_and_push_frontend.Dockerfile
DOCKER_COMPOSE=docker_example/docker-compose.yml
PYTHON_REQUIRED=$(shell grep '^python[[:space:]]*=' pyproject.toml | sed -n 's/.*"\([^"]*\)".*/\1/p')
RED=\033[0;31m
NC=\033[0m # No Color
GREEN=\033[0;32m
log_level ?= debug
host ?= 0.0.0.0
port ?= 7860
env ?= .env
open_browser ?= true
path = src/backend/base/langflow/frontend
workers ?= 1
async ?= true
all: help
######################
# UTILITIES
######################
# increment the patch version of the current package
patch: ## bump the version in langflow and langflow-base
@echo 'Patching the version'
@poetry version patch
@echo 'Patching the version in langflow-base'
@cd src/backend/base && poetry version patch
@make lock
# check for required tools
check_tools:
@command -v uv >/dev/null 2>&1 || { echo >&2 "$(RED)uv is not installed. Aborting.$(NC)"; exit 1; }
@command -v npm >/dev/null 2>&1 || { echo >&2 "$(RED)NPM is not installed. Aborting.$(NC)"; exit 1; }
@command -v pipx >/dev/null 2>&1 || { echo >&2 "$(RED)pipx is not installed. Aborting.$(NC)"; exit 1; }
@$(MAKE) check_env
@echo "$(GREEN)All required tools are installed.$(NC)"
# check if Python version is compatible
check_env: ## check if Python version is compatible
@chmod +x scripts/setup/check_env.sh
@PYTHON_INSTALLED=$$(scripts/setup/check_env.sh python --version 2>&1 | awk '{print $$2}'); \
if ! scripts/setup/check_env.sh python -c "import sys; from packaging.specifiers import SpecifierSet; from packaging.version import Version; sys.exit(not SpecifierSet('$(PYTHON_REQUIRED)').contains(Version('$$PYTHON_INSTALLED')))" 2>/dev/null; then \
echo "$(RED)Error: Python version $$PYTHON_INSTALLED is not compatible with the required version $(PYTHON_REQUIRED). Aborting.$(NC)"; exit 1; \
fi
help: ## show this help message
@echo '----'
@grep -hE '^\S+:.*##' $(MAKEFILE_LIST) | \
awk -F ':.*##' '{printf "\033[36mmake %s\033[0m: %s\n", $$1, $$2}' | \
column -c2 -t -s :
@echo '----'
######################
# INSTALL PROJECT
######################
reinstall_backend: ## forces reinstall all dependencies (no caching)
@echo 'Installing backend dependencies'
@uv sync -n --reinstall --frozen
install_backend: ## install the backend dependencies
@echo 'Installing backend dependencies'
@uv sync --frozen
install_frontend: ## install the frontend dependencies
@echo 'Installing frontend dependencies'
@cd src/frontend && npm install > /dev/null 2>&1
build_frontend: ## build the frontend static files
@echo 'Building frontend static files'
@cd src/frontend && CI='' npm run build > /dev/null 2>&1
@rm -rf src/backend/base/langflow/frontend
@cp -r src/frontend/build src/backend/base/langflow/frontend
init: check_tools clean_python_cache clean_npm_cache ## initialize the project
@make install_backend
@make install_frontend
@make build_frontend
@echo "$(GREEN)All requirements are installed.$(NC)"
@uv run langflow run
######################
# CLEAN PROJECT
######################
clean_python_cache:
@echo "Cleaning Python cache..."
find . -type d -name '__pycache__' -exec rm -r {} +
find . -type f -name '*.py[cod]' -exec rm -f {} +
find . -type f -name '*~' -exec rm -f {} +
find . -type f -name '.*~' -exec rm -f {} +
find . -type d -empty -delete
@echo "$(GREEN)Python cache cleaned.$(NC)"
clean_npm_cache:
@echo "Cleaning npm cache..."
cd src/frontend && npm cache clean --force
rm -rf src/frontend/node_modules src/frontend/build src/backend/base/langflow/frontend src/frontend/package-lock.json
@echo "$(GREEN)NPM cache and frontend directories cleaned.$(NC)"
clean_all: clean_python_cache clean_npm_cache # clean all caches and temporary directories
@echo "$(GREEN)All caches and temporary directories cleaned.$(NC)"
setup_uv: ## install poetry using pipx
pipx install uv
add:
@echo 'Adding dependencies'
ifdef devel
@cd src/backend/base && uv add --group dev $(devel)
endif
ifdef main
@uv add $(main)
endif
ifdef base
@cd src/backend/base && uv add $(base)
endif
######################
# CODE TESTS
######################
coverage: ## run the tests and generate a coverage report
@uv run coverage run
@uv run coverage erase
#@poetry run coverage run
#@poetry run coverage erase
unit_tests: ## run unit tests
@uv sync --extra dev --frozen
ifeq ($(async), true)
uv run pytest src/backend/tests \
--ignore=src/backend/tests/integration \
--instafail -n auto -ra -m "not api_key_required" \
--durations-path src/backend/tests/.test_durations \
--splitting-algorithm least_duration \
$(args)
else
uv run pytest src/backend/tests \
--ignore=src/backend/tests/integration \
--instafail -ra -m "not api_key_required" \
--durations-path src/backend/tests/.test_durations \
--splitting-algorithm least_duration \
$(args)
endif
unit_tests_looponfail:
@make unit_tests args="-f"
integration_tests:
uv run pytest src/backend/tests/integration \
--instafail -ra \
$(args)
integration_tests_no_api_keys:
uv run pytest src/backend/tests/integration \
--instafail -ra -m "not api_key_required" \
$(args)
integration_tests_api_keys:
uv run pytest src/backend/tests/integration \
--instafail -ra -m "api_key_required" \
$(args)
tests: ## run unit, integration, coverage tests
@echo 'Running Unit Tests...'
make unit_tests
@echo 'Running Integration Tests...'
make integration_tests
@echo 'Running Coverage Tests...'
make coverage
######################
# CODE QUALITY
######################
codespell: ## run codespell to check spelling
@poetry install --with spelling
poetry run codespell --toml pyproject.toml
fix_codespell: ## run codespell to fix spelling errors
@poetry install --with spelling
poetry run codespell --toml pyproject.toml --write
format: ## run code formatters
@uv run ruff check . --fix
@uv run ruff format .
@cd src/frontend && npm run format
lint: install_backend ## run linters
@uv run mypy --namespace-packages -p "langflow"
install_frontendci:
@cd src/frontend && npm ci > /dev/null 2>&1
install_frontendc:
@cd src/frontend && rm -rf node_modules package-lock.json && npm install > /dev/null 2>&1
run_frontend: ## run the frontend
@-kill -9 `lsof -t -i:3000`
@cd src/frontend && npm start
tests_frontend: ## run frontend tests
ifeq ($(UI), true)
@cd src/frontend && npx playwright test --ui --project=chromium
else
@cd src/frontend && npx playwright test --project=chromium
endif
run_cli: install_frontend install_backend build_frontend ## run the CLI
@echo 'Running the CLI'
ifdef env
@make start env=$(env) host=$(host) port=$(port) log_level=$(log_level)
else
@make start host=$(host) port=$(port) log_level=$(log_level)
endif
run_cli_debug:
@echo 'Running the CLI in debug mode'
@make install_frontend > /dev/null
@echo 'Building the frontend'
@make build_frontend > /dev/null
@echo 'Install backend dependencies'
@make install_backend > /dev/null
ifdef env
@make start env=$(env) host=$(host) port=$(port) log_level=debug
else
@make start host=$(host) port=$(port) log_level=debug
endif
start:
@echo 'Running the CLI'
ifeq ($(open_browser),false)
@make install_backend && uv run langflow run \
--path $(path) \
--log-level $(log_level) \
--host $(host) \
--port $(port) \
--env-file $(env) \
--no-open-browser
else
@make install_backend && uv run langflow run \
--path $(path) \
--log-level $(log_level) \
--host $(host) \
--port $(port) \
--env-file $(env)
endif
setup_devcontainer: ## set up the development container
make install_backend
make install_frontend
make build_frontend
uv run langflow --path src/frontend/build
setup_env: ## set up the environment
@sh ./scripts/setup/setup_env.sh
frontend: install_frontend ## run the frontend in development mode
make run_frontend
frontendc: install_frontendc
make run_frontend
backend: setup_env install_backend ## run the backend in development mode
@-kill -9 $$(lsof -t -i:7860) || true
ifdef login
@echo "Running backend autologin is $(login)";
LANGFLOW_AUTO_LOGIN=$(login) uv run uvicorn \
--factory langflow.main:create_app \
--host 0.0.0.0 \
--port $(port) \
$(if $(filter-out 1,$(workers)),, --reload) \
--env-file $(env) \
--loop asyncio \
$(if $(workers),--workers $(workers),)
else
@echo "Running backend respecting the $(env) file";
uv run uvicorn \
--factory langflow.main:create_app \
--host 0.0.0.0 \
--port $(port) \
$(if $(filter-out 1,$(workers)),, --reload) \
--env-file $(env) \
--loop asyncio \
$(if $(workers),--workers $(workers),)
endif
build_and_run: setup_env ## build the project and run it
rm -rf dist
rm -rf src/backend/base/dist
make build
uv run pip install dist/*.tar.gz
uv run langflow run
build_and_install: ## build the project and install it
@echo 'Removing dist folder'
rm -rf dist
rm -rf src/backend/base/dist
make build && uv run pip install dist/*.whl && pip install src/backend/base/dist/*.whl --force-reinstall
build: setup_env ## build the frontend static files and package the project
ifdef base
make install_frontendci
make build_frontend
make build_langflow_base
endif
ifdef main
make install_frontendci
make build_frontend
make build_langflow_base
make build_langflow args="$(args)"
endif
build_langflow_base:
cd src/backend/base && uv build
rm -rf src/backend/base/langflow/frontend
build_langflow_backup:
uv lock && uv build
build_langflow:
uv lock --no-upgrade
uv build $(args)
ifdef restore
mv pyproject.toml.bak pyproject.toml
mv uv.lock.bak uv.lock
endif
docker_build: dockerfile_build clear_dockerimage ## build DockerFile
docker_build_backend: dockerfile_build_be clear_dockerimage ## build Backend DockerFile
docker_build_frontend: dockerfile_build_fe clear_dockerimage ## build Frontend Dockerfile
dockerfile_build:
@echo 'BUILDING DOCKER IMAGE: ${DOCKERFILE}'
@docker build --rm \
-f ${DOCKERFILE} \
-t langflow:${VERSION} .
dockerfile_build_be: dockerfile_build
@echo 'BUILDING DOCKER IMAGE BACKEND: ${DOCKERFILE_BACKEND}'
@docker build --rm \
--build-arg LANGFLOW_IMAGE=langflow:${VERSION} \
-f ${DOCKERFILE_BACKEND} \
-t langflow_backend:${VERSION} .
dockerfile_build_fe: dockerfile_build
@echo 'BUILDING DOCKER IMAGE FRONTEND: ${DOCKERFILE_FRONTEND}'
@docker build --rm \
--build-arg LANGFLOW_IMAGE=langflow:${VERSION} \
-f ${DOCKERFILE_FRONTEND} \
-t langflow_frontend:${VERSION} .
clear_dockerimage:
@echo 'Clearing the docker build'
@if docker images -f "dangling=true" -q | grep -q '.*'; then \
docker rmi $$(docker images -f "dangling=true" -q); \
fi
docker_compose_up: docker_build docker_compose_down
@echo 'Running docker compose up'
docker compose -f $(DOCKER_COMPOSE) up --remove-orphans
docker_compose_down:
@echo 'Running docker compose down'
docker compose -f $(DOCKER_COMPOSE) down || true
dcdev_up:
@echo 'Running docker compose up'
docker compose -f docker/dev.docker-compose.yml down || true
docker compose -f docker/dev.docker-compose.yml up --remove-orphans
lock_base:
cd src/backend/base && uv lock
lock_langflow:
uv lock
lock: ## lock dependencies
@echo 'Locking dependencies'
cd src/backend/base && uv lock --no-update
uv lock --no-update
update: ## update dependencies
@echo 'Updating dependencies'
cd src/backend/base && uv sync --upgrade
uv sync --upgrade
publish_base:
cd src/backend/base && uv publish
publish_langflow:
uv publish
publish_base_testpypi:
# TODO: update this to use the test-pypi repository
cd src/backend/base && uv publish -r test-pypi
publish_langflow_testpypi:
# TODO: update this to use the test-pypi repository
uv publish -r test-pypi
publish: ## build the frontend static files and package the project and publish it to PyPI
@echo 'Publishing the project'
ifdef base
make publish_base
endif
ifdef main
make publish_langflow
endif
publish_testpypi: ## build the frontend static files and package the project and publish it to PyPI
@echo 'Publishing the project'
ifdef base
#TODO: replace with uvx twine upload dist/*
poetry config repositories.test-pypi https://test.pypi.org/legacy/
make publish_base_testpypi
endif
ifdef main
#TODO: replace with uvx twine upload dist/*
poetry config repositories.test-pypi https://test.pypi.org/legacy/
make publish_langflow_testpypi
endif