mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-23 20:22:46 +08:00
Merge remote-tracking branch 'origin/release-1.10.1' into release-1.11.0
# Conflicts: # .secrets.baseline # pyproject.toml # src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json # src/backend/base/langflow/initial_setup/starter_projects/Structured Data Analysis Agent.json # src/backend/base/langflow/services/auth/service.py # src/backend/base/langflow/services/job_queue/service.py # src/backend/base/pyproject.toml # src/backend/tests/unit/components/models_and_agents/test_cuga_agent.py # src/backend/tests/unit/test_redis_job_queue_service.py # src/bundles/lfx-bundles/src/lfx_bundles/deepseek/deepseek.py # src/bundles/lfx-bundles/src/lfx_bundles/glean/glean_search_api.py # src/bundles/lfx-bundles/src/lfx_bundles/homeassistant/home_assistant_control.py # src/bundles/lfx-bundles/src/lfx_bundles/homeassistant/list_home_assistant_states.py # src/bundles/lfx-bundles/src/lfx_bundles/huggingface/huggingface_inference_api.py # src/bundles/lfx-bundles/src/lfx_bundles/lmstudio/lmstudioembeddings.py # src/bundles/lfx-bundles/src/lfx_bundles/xai/xai.py # src/frontend/package-lock.json # src/frontend/package.json # src/lfx/pyproject.toml # src/lfx/src/lfx/_assets/component_index.json # src/lfx/src/lfx/components/files_and_knowledge/filesystem.py # src/lfx/tests/unit/components/tools/test_filesystem_deny_list.py # uv.lock
This commit is contained in:
23
.github/workflows/cross-platform-test.md
vendored
23
.github/workflows/cross-platform-test.md
vendored
@ -58,9 +58,14 @@ jobs:
|
||||
- **macOS**: Intel (AMD64), Apple Silicon (ARM64)
|
||||
- **Windows**: AMD64
|
||||
- **Python versions**:
|
||||
- **All platforms**: 3.10, 3.12, and 3.13
|
||||
- **Stability**: 3.10 and 3.12 are required to pass (blocking)
|
||||
- **Preview**: 3.13 testing is optional (non-blocking) to monitor ecosystem readiness
|
||||
- **All platforms**: 3.10, 3.12, 3.13, and 3.14
|
||||
- **Stability**: 3.10, 3.12, and 3.13 are required to pass (blocking)
|
||||
- **Preview**: 3.14 testing is optional (non-blocking) to monitor ecosystem readiness
|
||||
- **Note**: macOS Intel (x86_64) is tested only on Python 3.12. macOS x86_64 is
|
||||
being dropped across the ecosystem — PyTorch ships no x86_64 wheels for py>=3.13
|
||||
and onnxruntime shipped none after 1.23 — and langflow requires `onnxruntime>=1.26`
|
||||
on py>=3.14, so macOS Intel + py>=3.14 cannot resolve. The 3.13 (blocking) and
|
||||
3.14 (preview) sets therefore run on Linux, Windows, and macOS arm64 only
|
||||
|
||||
## What Gets Tested
|
||||
|
||||
@ -103,8 +108,8 @@ gh workflow run cross-platform-test.yml \
|
||||
- **Timeout**: Configurable timeout with proper cross-platform handling
|
||||
|
||||
### Platform-Specific Optimizations
|
||||
- **Stable versions**: Python 3.10 and 3.12 provide reliable package ecosystem support
|
||||
- **Preview testing**: Python 3.13 runs as non-blocking to monitor when it becomes viable
|
||||
- **Stable versions**: Python 3.10, 3.12, and 3.13 provide reliable package ecosystem support
|
||||
- **Preview testing**: Python 3.14 runs as non-blocking to monitor when it becomes viable
|
||||
- **Virtual Environments**: Uses `uv venv --seed` for consistent pip availability
|
||||
|
||||
### Workflow Architecture
|
||||
@ -187,9 +192,11 @@ error: command '/usr/bin/clang++' failed with exit code 1
|
||||
3. **macOS clang** doesn't support `-march=native` flag used by `chroma-hnswlib` compilation
|
||||
|
||||
**Current Status**:
|
||||
- **Stable testing**: Python 3.10 and 3.12 are required to pass (blocking jobs)
|
||||
- **Preview testing**: Python 3.13 runs as non-blocking to monitor ecosystem readiness
|
||||
- **Compilation issues**: Python 3.13 may still fail due to `chroma-hnswlib` but won't block releases
|
||||
- **Stable testing**: Python 3.10, 3.12, and 3.13 are required to pass (blocking jobs)
|
||||
- **Preview testing**: Python 3.14 runs as non-blocking to monitor ecosystem readiness
|
||||
- **Compilation issues**: the historical `chroma-hnswlib` failure is avoided on the tested install
|
||||
paths (workspace/source builds exclude `chromadb`); a similar upstream issue surfacing on the
|
||||
preview (3.14) tier stays non-blocking
|
||||
- **Manual testing**: Source builds now use the same dependency transformation as nightly builds for testing parity
|
||||
|
||||
**Files Involved**:
|
||||
|
||||
82
.github/workflows/cross-platform-test.yml
vendored
82
.github/workflows/cross-platform-test.yml
vendored
@ -178,6 +178,23 @@ jobs:
|
||||
arch: amd64
|
||||
runner: windows-latest
|
||||
python-version: "3.12"
|
||||
# Python 3.13 - graduated from experimental to stable (blocking).
|
||||
# macOS Intel (amd64) is intentionally omitted here: like 3.10/3.12 above
|
||||
# it stays on the costly macos-latest-large runner only at 3.12. Intel
|
||||
# coverage for newer Python continues (non-blocking) in the experimental
|
||||
# 3.14 set below.
|
||||
- os: linux
|
||||
arch: amd64
|
||||
runner: ubuntu-latest
|
||||
python-version: "3.13"
|
||||
- os: macos
|
||||
arch: arm64
|
||||
runner: macos-latest
|
||||
python-version: "3.13"
|
||||
- os: windows
|
||||
arch: amd64
|
||||
runner: windows-latest
|
||||
python-version: "3.13"
|
||||
|
||||
steps:
|
||||
- name: Determine install method
|
||||
@ -454,23 +471,26 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Python 3.13 - Experimental
|
||||
# Python 3.14 - Experimental (non-blocking) to monitor ecosystem readiness.
|
||||
# macOS Intel (x86_64) is intentionally omitted: langflow requires
|
||||
# onnxruntime>=1.26 on Python >=3.14 (pyproject.toml), but onnxruntime
|
||||
# dropped macOS x86_64 wheels at 1.24 — so macOS Intel + py3.14 is
|
||||
# permanently unsatisfiable (older onnxruntime that still ships macOS
|
||||
# x86_64 wheels has no cp314 ABI). macOS Intel resolves fine through 3.13;
|
||||
# arm64 has cp314 wheels. Running it would only burn the costly
|
||||
# macos-latest-large runner on a guaranteed, no-signal failure.
|
||||
- os: linux
|
||||
arch: amd64
|
||||
runner: ubuntu-latest
|
||||
python-version: "3.13"
|
||||
python-version: "3.14"
|
||||
- os: windows
|
||||
arch: amd64
|
||||
runner: windows-latest
|
||||
python-version: "3.13"
|
||||
- os: macos
|
||||
arch: amd64
|
||||
runner: macos-latest-large
|
||||
python-version: "3.13"
|
||||
python-version: "3.14"
|
||||
- os: macos
|
||||
arch: arm64
|
||||
runner: macos-latest
|
||||
python-version: "3.13"
|
||||
python-version: "3.14"
|
||||
|
||||
steps:
|
||||
- name: Determine install method
|
||||
@ -615,6 +635,19 @@ jobs:
|
||||
- name: Force reinstall local wheels to prevent downgrades (Windows)
|
||||
if: steps.install-method.outputs.method == 'wheel' && matrix.os == 'windows'
|
||||
run: |
|
||||
# Expose the local wheel dirs so dependency re-resolution (the
|
||||
# pre-release path below drops --no-deps) can find the local
|
||||
# pre-release lfx/base wheels. Without these, uv re-resolves
|
||||
# langflow-base's `lfx>=X.Y.Zrc0` constraint against PyPI only, where
|
||||
# the matching rc/dev wheel is not published yet, and fails with
|
||||
# "No solution found when resolving dependencies".
|
||||
FIND_LINKS=()
|
||||
for wheel_dir in ./sdk-dist ./lfx-dist ./base-dist ./bundles-dist; do
|
||||
if [ -d "$wheel_dir" ]; then
|
||||
FIND_LINKS+=(--find-links "$wheel_dir")
|
||||
fi
|
||||
done
|
||||
|
||||
# Reinstall LFX if it was provided
|
||||
if [ -n "${{ inputs.lfx-artifact-name || needs.build-if-needed.outputs.lfx-artifact-name }}" ]; then
|
||||
LFX_WHEEL=$(find ./lfx-dist -name "*.whl" -type f | head -1)
|
||||
@ -633,7 +666,7 @@ jobs:
|
||||
if [ "${{ inputs.pre_release }}" = "true" ]; then
|
||||
NO_DEPS=""
|
||||
fi
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit --python ./test-env/Scripts/python.exe "${INSTALL_WHEELS[@]}"
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit "${FIND_LINKS[@]}" --python ./test-env/Scripts/python.exe "${INSTALL_WHEELS[@]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -645,13 +678,26 @@ jobs:
|
||||
if [ "${{ inputs.pre_release }}" = "true" ]; then
|
||||
NO_DEPS=""
|
||||
fi
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit --python ./test-env/Scripts/python.exe "$BASE_WHEEL"
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit "${FIND_LINKS[@]}" --python ./test-env/Scripts/python.exe "$BASE_WHEEL"
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
- name: Force reinstall local wheels to prevent downgrades (Unix)
|
||||
if: steps.install-method.outputs.method == 'wheel' && matrix.os != 'windows'
|
||||
run: |
|
||||
# Expose the local wheel dirs so dependency re-resolution (the
|
||||
# pre-release path below drops --no-deps) can find the local
|
||||
# pre-release lfx/base wheels. Without these, uv re-resolves
|
||||
# langflow-base's `lfx>=X.Y.Zrc0` constraint against PyPI only, where
|
||||
# the matching rc/dev wheel is not published yet, and fails with
|
||||
# "No solution found when resolving dependencies".
|
||||
FIND_LINKS=()
|
||||
for wheel_dir in ./sdk-dist ./lfx-dist ./base-dist ./bundles-dist; do
|
||||
if [ -d "$wheel_dir" ]; then
|
||||
FIND_LINKS+=(--find-links "$wheel_dir")
|
||||
fi
|
||||
done
|
||||
|
||||
# Reinstall LFX if it was provided
|
||||
if [ -n "${{ inputs.lfx-artifact-name || needs.build-if-needed.outputs.lfx-artifact-name }}" ]; then
|
||||
LFX_WHEEL=$(find ./lfx-dist -name "*.whl" -type f | head -1)
|
||||
@ -670,7 +716,7 @@ jobs:
|
||||
if [ "${{ inputs.pre_release }}" = "true" ]; then
|
||||
NO_DEPS=""
|
||||
fi
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit --python ./test-env/bin/python "${INSTALL_WHEELS[@]}"
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit "${FIND_LINKS[@]}" --python ./test-env/bin/python "${INSTALL_WHEELS[@]}"
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -682,7 +728,7 @@ jobs:
|
||||
if [ "${{ inputs.pre_release }}" = "true" ]; then
|
||||
NO_DEPS=""
|
||||
fi
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit --python ./test-env/bin/python "$BASE_WHEEL"
|
||||
uv pip install --force-reinstall $NO_DEPS --prerelease=if-necessary-or-explicit "${FIND_LINKS[@]}" --python ./test-env/bin/python "$BASE_WHEEL"
|
||||
fi
|
||||
shell: bash
|
||||
|
||||
@ -826,9 +872,9 @@ jobs:
|
||||
if [ "$experimental_result" = "success" ]; then
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
if [ -n "${{ inputs.langflow-version }}" ]; then
|
||||
echo "✅ All PyPI installation tests passed (including Python 3.13)"
|
||||
echo "✅ All PyPI installation tests passed (including Python 3.14)"
|
||||
else
|
||||
echo "✅ All source build and installation tests passed (including Python 3.13)"
|
||||
echo "✅ All source build and installation tests passed (including Python 3.14)"
|
||||
fi
|
||||
else
|
||||
echo "✅ All cross-platform tests passed - PyPI upload can proceed"
|
||||
@ -836,17 +882,17 @@ jobs:
|
||||
else
|
||||
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
|
||||
if [ -n "${{ inputs.langflow-version }}" ]; then
|
||||
echo "✅ PyPI installation tests passed (Python 3.13 experimental failures are acceptable)"
|
||||
echo "✅ PyPI installation tests passed (Python 3.14 experimental failures are acceptable)"
|
||||
else
|
||||
echo "✅ Source build and installation tests passed (Python 3.13 experimental failures are acceptable)"
|
||||
echo "✅ Source build and installation tests passed (Python 3.14 experimental failures are acceptable)"
|
||||
fi
|
||||
else
|
||||
echo "✅ Cross-platform tests passed - Python 3.13 experimental failures are acceptable - PyPI upload can proceed"
|
||||
echo "✅ Cross-platform tests passed - Python 3.14 experimental failures are acceptable - PyPI upload can proceed"
|
||||
fi
|
||||
fi
|
||||
elif [ "$stable_result" = "failure" ]; then
|
||||
echo "❌ Critical platform tests failed - blocking release"
|
||||
echo "Stable platforms (Python 3.10, 3.12) must pass for release"
|
||||
echo "Stable platforms (Python 3.10, 3.12, 3.13) must pass for release"
|
||||
exit 1
|
||||
elif [ "$stable_result" = "cancelled" ]; then
|
||||
echo "❌ Critical platform tests were cancelled"
|
||||
|
||||
42
.github/workflows/docker-build-v2.yml
vendored
42
.github/workflows/docker-build-v2.yml
vendored
@ -16,6 +16,11 @@ on:
|
||||
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."
|
||||
version_override:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
description: "Resolved version to use for image tags. When omitted, the workflow computes the version from the checked-out ref and registry history."
|
||||
push_to_registry:
|
||||
required: false
|
||||
type: boolean
|
||||
@ -44,6 +49,11 @@ on:
|
||||
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."
|
||||
version_override:
|
||||
description: "Resolved version to use for image tags. Leave blank to compute from the checked-out ref and registry history."
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
push_to_registry:
|
||||
description: "Whether to push images to registries. Set to false for testing builds without publishing."
|
||||
required: false
|
||||
@ -81,10 +91,16 @@ jobs:
|
||||
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"
|
||||
if [ -n "${{ inputs.version_override }}" ]; then
|
||||
version="${{ inputs.version_override }}"
|
||||
echo "Using version override: $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-' | grep -vE '\-(amd64|arm64)$' | grep -v 'latest' | sed 's/^base-//' | sort -V | tail -n 1)
|
||||
echo "Latest base release version: $last_released_version"
|
||||
fi
|
||||
elif [ ${{inputs.pre_release}} == "true" ]; then
|
||||
released_versions=$(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)$' | sed 's/^base-//' || true)
|
||||
version="$(printf '%s\n' "$released_versions" | uv run ./scripts/ci/langflow_pre_release_tag.py "$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)
|
||||
@ -127,10 +143,16 @@ jobs:
|
||||
version=$(uv tree 2>/dev/null | grep -E '^langflow(-nightly)?[[:space:]]' | 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"
|
||||
if [ -n "${{ inputs.version_override }}" ]; then
|
||||
version="${{ inputs.version_override }}"
|
||||
echo "Using version override: $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 -v '^base-' | grep -vE '\-(amd64|arm64)$' | grep -v 'latest' | sort -V | tail -n 1)
|
||||
echo "Latest main release version: $last_released_version"
|
||||
fi
|
||||
elif [ ${{inputs.pre_release}} == "true" ]; then
|
||||
released_versions=$(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)$' || true)
|
||||
version="$(printf '%s\n' "$released_versions" | uv run ./scripts/ci/langflow_pre_release_tag.py "$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)
|
||||
@ -335,7 +357,7 @@ jobs:
|
||||
context: .
|
||||
push: ${{ inputs.push_to_registry }}
|
||||
build-args: |
|
||||
LANGFLOW_IMAGE=langflowai/langflow:${{ steps.version.outputs.version }}-${{ matrix.arch }}
|
||||
LANGFLOW_IMAGE=langflowai/langflow:${{ needs.determine-main-version.outputs.version }}-${{ matrix.arch }}
|
||||
file: ./docker/build_and_push_backend.Dockerfile
|
||||
tags: ${{ steps.tags.outputs.docker_tags }}
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
@ -356,7 +378,7 @@ jobs:
|
||||
context: .
|
||||
push: ${{ inputs.push_to_registry }}
|
||||
build-args: |
|
||||
LANGFLOW_IMAGE=ghcr.io/langflow-ai/langflow:${{ steps.version.outputs.version }}-${{ matrix.arch }}
|
||||
LANGFLOW_IMAGE=ghcr.io/langflow-ai/langflow:${{ needs.determine-main-version.outputs.version }}-${{ matrix.arch }}
|
||||
file: ./docker/build_and_push_backend.Dockerfile
|
||||
tags: ${{ steps.tags.outputs.ghcr_tags }}
|
||||
platforms: linux/${{ matrix.arch }}
|
||||
|
||||
237
.github/workflows/release.yml
vendored
237
.github/workflows/release.yml
vendored
@ -177,9 +177,164 @@ jobs:
|
||||
|
||||
echo "✅ Release dependencies validated successfully."
|
||||
|
||||
determine-rc-number:
|
||||
name: Determine Shared RC Number
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
rc_number: ${{ steps.rc.outputs.rc_number || steps.stable.outputs.rc_number }}
|
||||
steps:
|
||||
- name: Use stable RC number
|
||||
id: stable
|
||||
if: ${{ !inputs.pre_release }}
|
||||
run: |
|
||||
echo "rc_number=0" >> "$GITHUB_OUTPUT"
|
||||
echo "Not a pre-release; shared rc number is 0."
|
||||
|
||||
- name: Checkout code
|
||||
if: ${{ inputs.pre_release }}
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
|
||||
- name: Setup Environment
|
||||
if: ${{ inputs.pre_release }}
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: true
|
||||
cache-dependency-glob: "uv.lock"
|
||||
python-version: "3.13"
|
||||
prune-cache: false
|
||||
|
||||
- name: Determine shared pre-release RC number
|
||||
id: rc
|
||||
if: ${{ inputs.pre_release }}
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
read_pyproject_version() {
|
||||
python3 - "$1" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
import tomllib
|
||||
|
||||
data = tomllib.loads(pathlib.Path(sys.argv[1]).read_text())
|
||||
print(data["project"]["version"])
|
||||
PY
|
||||
}
|
||||
|
||||
fetch_pypi_versions() {
|
||||
local package_name="$1"
|
||||
local output_file="$2"
|
||||
local response_file
|
||||
response_file="$(mktemp)"
|
||||
local status
|
||||
status=$(curl --retry 3 --retry-delay 2 --retry-connrefused -sS -o "$response_file" -w "%{http_code}" "https://pypi.org/pypi/${package_name}/json")
|
||||
if [ "$status" = "404" ]; then
|
||||
: > "$output_file"
|
||||
return
|
||||
fi
|
||||
if [ "$status" != "200" ]; then
|
||||
echo "Failed to fetch PyPI releases for ${package_name}: HTTP ${status}" >&2
|
||||
cat "$response_file" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
jq -r '.releases | keys[]' "$response_file" > "$output_file"
|
||||
}
|
||||
|
||||
fetch_docker_tags() {
|
||||
local repository="$1"
|
||||
local output_file="$2"
|
||||
local response_file
|
||||
response_file="$(mktemp)"
|
||||
local status
|
||||
status=$(curl --retry 3 --retry-delay 2 --retry-connrefused -sS -o "$response_file" -w "%{http_code}" "https://registry.hub.docker.com/v2/repositories/${repository}/tags?page_size=100")
|
||||
if [ "$status" != "200" ]; then
|
||||
echo "Failed to fetch Docker tags for ${repository}: HTTP ${status}" >&2
|
||||
cat "$response_file" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
jq -r '.results[].name' "$response_file" > "$output_file"
|
||||
}
|
||||
|
||||
max_rc=0
|
||||
consider_versions() {
|
||||
local label="$1"
|
||||
local base_version="$2"
|
||||
local versions_file="$3"
|
||||
local rc_number
|
||||
rc_number=$(uv run ./scripts/ci/langflow_pre_release_tag.py "$base_version" --print-rc-number - < "$versions_file")
|
||||
echo "${label}: next rc number for ${base_version} is ${rc_number}"
|
||||
if [ "$rc_number" -gt "$max_rc" ]; then
|
||||
max_rc="$rc_number"
|
||||
fi
|
||||
}
|
||||
|
||||
tmp_dir="$(mktemp -d)"
|
||||
|
||||
if [ "${{ inputs.release_package_main }}" = "true" ]; then
|
||||
version="$(read_pyproject_version pyproject.toml)"
|
||||
fetch_pypi_versions "langflow" "$tmp_dir/langflow-pypi.txt"
|
||||
consider_versions "PyPI langflow" "$version" "$tmp_dir/langflow-pypi.txt"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.release_package_base }}" = "true" ]; then
|
||||
version="$(read_pyproject_version src/backend/base/pyproject.toml)"
|
||||
fetch_pypi_versions "langflow-base" "$tmp_dir/langflow-base-pypi.txt"
|
||||
consider_versions "PyPI langflow-base" "$version" "$tmp_dir/langflow-base-pypi.txt"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.release_lfx }}" = "true" ]; then
|
||||
version="$(read_pyproject_version src/lfx/pyproject.toml)"
|
||||
fetch_pypi_versions "lfx" "$tmp_dir/lfx-pypi.txt"
|
||||
consider_versions "PyPI lfx" "$version" "$tmp_dir/lfx-pypi.txt"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.release_sdk || inputs.release_lfx }}" = "true" ]; then
|
||||
version="$(read_pyproject_version src/sdk/pyproject.toml)"
|
||||
fetch_pypi_versions "langflow-sdk" "$tmp_dir/langflow-sdk-pypi.txt"
|
||||
consider_versions "PyPI langflow-sdk" "$version" "$tmp_dir/langflow-sdk-pypi.txt"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.release_bundles }}" = "true" ]; then
|
||||
for pyproject in src/bundles/*/pyproject.toml; do
|
||||
package_name=$(python3 - "$pyproject" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
import tomllib
|
||||
|
||||
data = tomllib.loads(pathlib.Path(sys.argv[1]).read_text())
|
||||
print(data["project"]["name"])
|
||||
PY
|
||||
)
|
||||
version="$(read_pyproject_version "$pyproject")"
|
||||
output_file="$tmp_dir/${package_name}-pypi.txt"
|
||||
fetch_pypi_versions "$package_name" "$output_file"
|
||||
consider_versions "PyPI ${package_name}" "$version" "$output_file"
|
||||
done
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.build_docker_main }}" = "true" ]; then
|
||||
version="$(read_pyproject_version pyproject.toml)"
|
||||
fetch_docker_tags "langflowai/langflow" "$tmp_dir/langflow-docker.txt"
|
||||
grep -v '^base-' "$tmp_dir/langflow-docker.txt" | grep -vE '\-(amd64|arm64)$' > "$tmp_dir/langflow-docker-release-tags.txt" || true
|
||||
consider_versions "Docker langflowai/langflow" "$version" "$tmp_dir/langflow-docker-release-tags.txt"
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.build_docker_base }}" = "true" ]; then
|
||||
version="$(read_pyproject_version src/backend/base/pyproject.toml)"
|
||||
fetch_docker_tags "langflowai/langflow" "$tmp_dir/langflow-base-docker.txt"
|
||||
grep -E '^base-' "$tmp_dir/langflow-base-docker.txt" | grep -vE '\-(amd64|arm64)$' | sed 's/^base-//' > "$tmp_dir/langflow-base-docker-release-tags.txt" || true
|
||||
consider_versions "Docker langflowai/langflow base" "$version" "$tmp_dir/langflow-base-docker-release-tags.txt"
|
||||
fi
|
||||
|
||||
echo "Shared pre-release rc number: ${max_rc}"
|
||||
echo "rc_number=${max_rc}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
determine-base-version:
|
||||
name: Determine Base Version
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
needs: [validate-tag, validate-dependencies, determine-rc-number]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
@ -212,16 +367,16 @@ jobs:
|
||||
echo "Base version from pyproject.toml: $version"
|
||||
|
||||
if [ ${{inputs.pre_release}} == "true" ]; then
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | 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"
|
||||
rc_number="${{ needs.determine-rc-number.outputs.rc_number }}"
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" --rc-number "$rc_number")"
|
||||
echo "Shared release candidate number: rc$rc_number"
|
||||
echo "Base pre-release version to be released: $version"
|
||||
else
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
|
||||
echo "Latest base release version: $last_released_version"
|
||||
fi
|
||||
|
||||
if [ "$version" = "$last_released_version" ]; then
|
||||
if [ "$version" = "$last_released_version" ] && [ "${{ inputs.release_package_base }}" = "true" ]; then
|
||||
echo "Base pypi version $version is already released. Skipping release."
|
||||
echo skipped=true >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
@ -232,7 +387,7 @@ jobs:
|
||||
|
||||
determine-main-version:
|
||||
name: Determine Main Version
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
needs: [validate-tag, validate-dependencies, determine-rc-number]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
@ -261,16 +416,16 @@ jobs:
|
||||
echo "Main version from pyproject.toml: $version"
|
||||
|
||||
if [ ${{inputs.pre_release}} == "true" ]; then
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/langflow/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | 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"
|
||||
rc_number="${{ needs.determine-rc-number.outputs.rc_number }}"
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" --rc-number "$rc_number")"
|
||||
echo "Shared release candidate number: rc$rc_number"
|
||||
echo "Main pre-release version to be released: $version"
|
||||
else
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/langflow/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
|
||||
echo "Latest main release version: $last_released_version"
|
||||
fi
|
||||
|
||||
if [ "$version" = "$last_released_version" ]; then
|
||||
if [ "$version" = "$last_released_version" ] && [ "${{ inputs.release_package_main }}" = "true" ]; then
|
||||
echo "Main pypi version $version is already released. Skipping release."
|
||||
echo skipped=true >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
@ -281,7 +436,7 @@ jobs:
|
||||
|
||||
determine-lfx-version:
|
||||
name: Determine LFX Version
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
needs: [validate-tag, validate-dependencies, determine-rc-number]
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
@ -310,9 +465,9 @@ jobs:
|
||||
echo "LFX version from pyproject.toml: $version"
|
||||
|
||||
if [ ${{inputs.pre_release}} == "true" ]; then
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/lfx/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")"
|
||||
echo "Latest LFX pre-release version: $last_released_version"
|
||||
rc_number="${{ needs.determine-rc-number.outputs.rc_number }}"
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" --rc-number "$rc_number")"
|
||||
echo "Shared release candidate number: rc$rc_number"
|
||||
echo "LFX pre-release version to be released: $version"
|
||||
else
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/lfx/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
|
||||
@ -330,7 +485,7 @@ jobs:
|
||||
|
||||
determine-sdk-version:
|
||||
name: Determine SDK Version
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
needs: [validate-tag, validate-dependencies, determine-rc-number]
|
||||
if: ${{ inputs.release_sdk || inputs.release_lfx }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
@ -368,11 +523,17 @@ jobs:
|
||||
if [ "$pypi_response" = "404" ]; then
|
||||
echo "langflow-sdk has never been published to PyPI. This will be the first release."
|
||||
last_released_version=""
|
||||
if [ ${{inputs.pre_release}} == "true" ]; then
|
||||
rc_number="${{ needs.determine-rc-number.outputs.rc_number }}"
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" --rc-number "$rc_number")"
|
||||
echo "Shared release candidate number: rc$rc_number"
|
||||
echo "SDK pre-release version to be released: $version"
|
||||
fi
|
||||
else
|
||||
if [ ${{inputs.pre_release}} == "true" ]; then
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-sdk/json" | jq -r '.releases | keys | .[]' | grep -E '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" "$last_released_version")"
|
||||
echo "Latest SDK pre-release version: $last_released_version"
|
||||
rc_number="${{ needs.determine-rc-number.outputs.rc_number }}"
|
||||
version="$(uv run ./scripts/ci/langflow_pre_release_tag.py "$version" --rc-number "$rc_number")"
|
||||
echo "Shared release candidate number: rc$rc_number"
|
||||
echo "SDK pre-release version to be released: $version"
|
||||
else
|
||||
last_released_version=$(curl -s "https://pypi.org/pypi/langflow-sdk/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1)
|
||||
@ -862,7 +1023,7 @@ jobs:
|
||||
|
||||
build-bundles:
|
||||
name: Build Langflow Bundles
|
||||
needs: [build-lfx, determine-lfx-version]
|
||||
needs: [build-lfx, determine-lfx-version, determine-rc-number]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
@ -888,6 +1049,26 @@ jobs:
|
||||
prune-cache: false
|
||||
- name: Install the project
|
||||
run: uv sync
|
||||
- name: Set bundle versions for pre-release
|
||||
if: ${{ inputs.pre_release }}
|
||||
run: |
|
||||
RC_NUMBER="${{ needs.determine-rc-number.outputs.rc_number }}"
|
||||
echo "Setting bundle pre-release versions with shared rc number: rc$RC_NUMBER"
|
||||
for pyproject in src/bundles/*/pyproject.toml; do
|
||||
CURRENT_VERSION=$(python3 - "$pyproject" <<'PY'
|
||||
import pathlib
|
||||
import sys
|
||||
import tomllib
|
||||
|
||||
data = tomllib.loads(pathlib.Path(sys.argv[1]).read_text())
|
||||
print(data["project"]["version"])
|
||||
PY
|
||||
)
|
||||
VERSION=$(uv run ./scripts/ci/langflow_pre_release_tag.py "$CURRENT_VERSION" --rc-number "$RC_NUMBER")
|
||||
sed -i.bak "0,/^version = /s|^version = .*|version = \"$VERSION\"|" "$pyproject"
|
||||
rm -f "${pyproject}.bak"
|
||||
grep "^version" "$pyproject" | sed "s|^| ${pyproject}: |"
|
||||
done
|
||||
- name: Relax bundle lfx floor for pre-release
|
||||
if: ${{ inputs.pre_release }}
|
||||
run: |
|
||||
@ -1154,72 +1335,78 @@ jobs:
|
||||
call_docker_build_base:
|
||||
name: Call Docker Build Workflow for Langflow Base
|
||||
if: ${{ inputs.build_docker_base }}
|
||||
needs: [ci]
|
||||
needs: [ci, determine-base-version]
|
||||
uses: ./.github/workflows/docker-build-v2.yml
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
release_type: base
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
version_override: ${{ needs.determine-base-version.outputs.version }}
|
||||
push_to_registry: ${{ !inputs.dry_run }}
|
||||
secrets: inherit
|
||||
|
||||
call_docker_build_main:
|
||||
name: Call Docker Build Workflow for Langflow
|
||||
if: ${{ inputs.build_docker_main }}
|
||||
needs: [ci]
|
||||
needs: [ci, determine-main-version]
|
||||
uses: ./.github/workflows/docker-build-v2.yml
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
release_type: main
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
version_override: ${{ needs.determine-main-version.outputs.version }}
|
||||
push_to_registry: ${{ !inputs.dry_run }}
|
||||
secrets: inherit
|
||||
|
||||
call_docker_build_main_backend:
|
||||
name: Call Docker Build Workflow for Langflow Backend
|
||||
if: ${{ inputs.build_docker_main && !inputs.dry_run }}
|
||||
needs: [call_docker_build_main]
|
||||
needs: [call_docker_build_main, determine-main-version]
|
||||
uses: ./.github/workflows/docker-build-v2.yml
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
release_type: main-backend
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
version_override: ${{ needs.determine-main-version.outputs.version }}
|
||||
push_to_registry: ${{ !inputs.dry_run }}
|
||||
secrets: inherit
|
||||
|
||||
call_docker_build_main_frontend:
|
||||
name: Call Docker Build Workflow for Langflow Frontend
|
||||
if: ${{ inputs.build_docker_main && !inputs.dry_run }}
|
||||
needs: [call_docker_build_main]
|
||||
needs: [call_docker_build_main, determine-main-version]
|
||||
uses: ./.github/workflows/docker-build-v2.yml
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
release_type: main-frontend
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
version_override: ${{ needs.determine-main-version.outputs.version }}
|
||||
push_to_registry: ${{ !inputs.dry_run }}
|
||||
secrets: inherit
|
||||
|
||||
call_docker_build_main_ep:
|
||||
name: Call Docker Build Workflow for Langflow with Entrypoint
|
||||
if: ${{ inputs.build_docker_main }}
|
||||
needs: [ci]
|
||||
needs: [ci, determine-main-version]
|
||||
uses: ./.github/workflows/docker-build-v2.yml
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
release_type: main-ep
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
version_override: ${{ needs.determine-main-version.outputs.version }}
|
||||
push_to_registry: ${{ !inputs.dry_run }}
|
||||
secrets: inherit
|
||||
|
||||
call_docker_build_main_all:
|
||||
name: Call Docker Build Workflow for langflow-all
|
||||
if: ${{ inputs.build_docker_main }}
|
||||
needs: [ci]
|
||||
needs: [ci, determine-main-version]
|
||||
uses: ./.github/workflows/docker-build-v2.yml
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
release_type: main-all
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
version_override: ${{ needs.determine-main-version.outputs.version }}
|
||||
push_to_registry: ${{ !inputs.dry_run }}
|
||||
secrets: inherit
|
||||
|
||||
|
||||
Reference in New Issue
Block a user