mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 06:10:49 +08:00
* feat(lfx): synchronize LFX onto Langflow major.minor version line (Phase 1) - Bump src/lfx/pyproject.toml from 0.5.0 to 1.10.0 - Tighten langflow-base lfx pin: ~=0.5.0 → ~=1.10.0 - Fix release.yml pre-release boundary from next-major to next-minor (<X.(Y+1).dev0) - Add minor-parity soft check to scripts/release-lfx.sh - Extend make patch to sync lfx version alongside langflow/base/frontend - Document LFX compatibility contract in RELEASE.md Contract: LFX X.Y.N is compatible with any Flow from Langflow X.Y.M. * feat(lfx/upgrade): add compatibility checker (Phase 2) * fix(lfx/upgrade): fix registry_code guard and types order-sensitivity in checker * feat(lfx/upgrade): implement safe-upgrade applier (Phase 2) * feat(lfx): add lfx upgrade command (Phase 2) * feat(lfx/run): add --upgrade-flow option (Phase 2) * feat(lfx/serve): add --upgrade-flow option (Phase 2) * update lfx pyproject version * [autofix.ci] apply automated fixes * test(lfx/upgrade): add v1.9.0 starter flow fixtures for upgrade integration tests * test(lfx/upgrade): add v1.9.0 starter flow fixtures and real-flow integration tests * [autofix.ci] apply automated fixes * fix(lfx/upgrade): use alias-aware registry lookup so renamed components are not falsely blocked * fix(lfx/upgrade): handle outer flow envelope and file-path inputs in upgrade checks * fix(lfx/upgrade): fail-fast on upgrade_flow errors; add regression tests for Bugs 1-3 * chore(tests): remove bug-number labels from test comments * [autofix.ci] apply automated fixes * fix(lfx/upgrade): address PR review comments - Reject .py files early in serve --upgrade-flow with a clear error message - Preserve outer flow envelope metadata (name, description, etc.) when lfx upgrade --write rewrites a file - Move Mapping import under TYPE_CHECKING to satisfy Ruff TC003 - Assert fixture flows and registry are non-empty so parametrized tests cannot pass vacuously - Remove unused capsys arg and replace print with sys.stderr.write (Ruff T201/ARG001) - Add upgrade_flow param to run command docstring * fix(lfx/upgrade): preserve envelope on run, apply nested upgrades (#13200) * fix(lfx/upgrade): preserve envelope on run, apply nested upgrades Three follow-ups on top of the upgrade tooling: - run --upgrade-flow: re-attach the inner graph to the outer envelope before handing the flow to aload_flow_from_json. Previously the upgrade path unwrapped {"data": ...} and passed the inner dict to the loader, which raised KeyError: 'data'. Adds happy-path tests for envelope and flat file inputs. - applier: recurse into one level of nested flow nodes (node.data.node.flow.data.nodes), matching the checker. Without this, outdated_safe nodes inside grouped components were reported but never written. Adds a regression test. - upgrade --write test: assert the envelope is preserved (name, description, endpoint_name, etc.) instead of the previous unwrapped-output expectation, so the test matches the actual fix in this PR. - Drive-by ruff cleanup: D417 docstring, SIM103, SIM108, E501, RUF059. * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix(lfx/upgrade): fix loader KeyError, outer-envelope checker gap, and nested-node applier Three bugs from ogabrielluiz's PR review: 1. run/base.py loader KeyError: file-path branch unwrapped the outer envelope for the checker but passed the inner dict to aload_flow_from_json, which does flow_graph["data"] unconditionally. Re-wrap as {"data": flow_dict} before the loader call. Applied consistently to all three input paths (--flow-json, --stdin, file-path). 2. run/base.py zero-node checker for --flow-json/--stdin: those paths stored the raw parsed JSON without unwrapping, so a caller passing an exported flow {"name":..., "data":{...}} caused the checker to see zero nodes and silently pass. Now unwrap with raw.get("data", raw) matching the file-path branch. 3. applier.py nested flows never upgraded: the early `continue` on top-level nodes not in safe_ids prevented the nested-node loop from running. Restructured so the nested check fires unconditionally for every top-level node, mirroring checker.py:160-165. * fix(lfx/run): unify outer-envelope unwrap across all --upgrade-flow input paths File-path reads now call raw.get("data", raw) matching --flow-json and --stdin, so the upgrade checker always sees the inner graph. This also removes the has_envelope/re-wrap machinery that was double-wrapping outer-envelope files when passing to aload_flow_from_json. Fix two test assertions that described the old double-wrapped shape. * fix(lfx/upgrade): inject registry into upgrade_command; fix Makefile lfx pin regex - upgrade_command now accepts an optional registry parameter so tests can pass the dict directly instead of mocking load_registry_from_index - Makefile sed regex broadened from \"lfx~=.*\" to match both ~= and >= forms so make patch works after release.yml rewrites the pin - Echo label changed to LFX (synced) to clarify the variable is the shared Langflow version, not a separate LFX-specific value * fix(make/patch): fix langflow-base sed regex and validation grep The dependency in pyproject.toml is "langflow-base[complete]>=X.Y.Z", not the "langflow-base==X" form the original regex expected, so make patch silently left the pin unchanged and the validation step always failed. The sed pattern now matches any extras/operator combination and rewrites to the canonical [complete]>= form; the grep uses -F so the [complete] brackets are treated literally. * test(lfx): add patch regex tests and symmetric safe-mode envelope tests test_patch_regexes.py — 15 tests covering the Python regexes embedded in the Makefile patch target. Exercises all three substitutions (langflow-base pin, lfx pin, version field) against every realistic pin format including the >=X.Y.Z,<dev0 form that release.yml writes. Would have caught the langflow-base==.* vs [complete]>= mismatch before manual testing. test_base.py — two new TestUpgradeFlowOption tests: test_upgrade_flow_safe_envelope_inline_json_loads_successfully test_upgrade_flow_safe_envelope_stdin_loads_successfully Symmetric to the existing file-path envelope test; verifies that --flow-json and --stdin with an outer-envelope flow also pass {"data": inner} to the loader after safe upgrades, not a double-wrapped {"data": outer_envelope}. * fix(lfx/upgrade): address review: compat checker, shared gate, fail-fast registry Checker correctness: - _outputs_are_compatible: drop cosmetic display_name from the breaking check; treat widened output types as safe (flow types must be a subset of registry types), only narrowing breaks downstream edges. - _input_types_contained: stop flagging widened input_types as breaking; keep narrowing as the only breaking case; fix misleading comments. - check_flow_compatibility now recurses fully into nested grouped components (symmetric with the applier) and accepts a pre-built registry lookup. CLI/run/serve: - New lfx.upgrade.cli_gate (UpgradeFlowMode enum, UpgradeFlowError, apply_upgrade_gate) shared by run_flow and serve_command so the two --upgrade-flow paths can't diverge. - run_flow: extract _materialize_flow_dict and route gating through the shared helper. - run/serve --upgrade-flow options typed as UpgradeFlowMode (check|safe choices). - lfx upgrade: load_registry_from_index fails fast when the bundled registry is empty/missing instead of silently marking every node blocked; ASCII-only report output; new --strict flag; build the registry lookup once and reuse it. Docs/tests: - RELEASE.md: migration note for the lfx 0.5.0 -> 1.10.0 version jump. - Regression tests for the checker fixes, the shared gate, fail-fast registry, --strict, and serve --upgrade-flow parity. * [autofix.ci] apply automated fixes * [autofix.ci] apply automated fixes (attempt 2/3) * fix(lfx): consolidate flow-envelope handling and fix version-ceiling regex Extract the outer-envelope unwrap/rewrap logic (previously hand-rolled as raw.get("data", raw) with subtly different rules across serve, run, and upgrade) into a single lfx.utils.flow_envelope module with split/merge helpers. This fixes a serve bug where an enveloped flow had its inner graph written bare to the temp file, making the loader's flow_graph["data"] raise KeyError. Also fix release.yml's major.minor extraction: the greedy sed grabbed the upper bound from a range pin (>=1.10.0,<1.11.dev0), drifting the version ceiling up one minor each release cycle. Anchor to the first version instead. * fix(lfx): upgrade-flow gate reads bundled component index, not empty cache The --upgrade-flow=check|safe gate on lfx run and lfx serve rejected every flow as 'blocked'. Both call sites passed component_cache.all_types_dict to apply_upgrade_gate, but that cache is populated lazily after services start, so at gate time it is empty -- an empty registry classifies every node as blocked. The standalone lfx upgrade command was unaffected because it reads the bundled _assets/component_index.json instead. Make the gate own registry loading: apply_upgrade_gate now defaults all_types_dict to None and loads the bundled index (the same source lfx upgrade uses) via a new _load_bundled_registry helper, raising UpgradeFlowError on a missing/empty index so a broken install fails loudly instead of silently blocking every component. Both call sites pass mode= and let the gate load the registry. Existing gate tests mocked component_cache with a populated registry, which is exactly what hid the bug; repoint them at the new _load_bundled_registry seam and add regression tests that do not mock the registry, including an end-to-end run_flow check against a real clean v1.9.0 starter flow. --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@logspace.ai>
231 lines
6.7 KiB
Bash
Executable File
231 lines
6.7 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Colors for output
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m' # No Color
|
|
|
|
# Default values
|
|
DRY_RUN=false
|
|
|
|
# Function to print colored output
|
|
print_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
print_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
print_warning() {
|
|
echo -e "${YELLOW}[WARNING]${NC} $1"
|
|
}
|
|
|
|
print_dry_run() {
|
|
echo -e "${BLUE}[DRY RUN]${NC} $1"
|
|
}
|
|
|
|
# Function to show usage
|
|
show_usage() {
|
|
echo "Usage: $0 [OPTIONS] [VERSION]"
|
|
echo ""
|
|
echo "Options:"
|
|
echo " --dry-run Run the script without making actual changes"
|
|
echo " --help Show this help message"
|
|
echo ""
|
|
echo "Arguments:"
|
|
echo " VERSION The new version to release (e.g., 0.1.0)"
|
|
echo ""
|
|
echo "Examples:"
|
|
echo " $0 0.1.0 # Release version 0.1.0"
|
|
echo " $0 --dry-run 0.1.0 # Dry run for version 0.1.0"
|
|
echo " $0 --dry-run # Dry run with interactive version prompt"
|
|
}
|
|
|
|
# Parse command line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--dry-run)
|
|
DRY_RUN=true
|
|
shift
|
|
;;
|
|
--help|-h)
|
|
show_usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
if [ -z "$NEW_VERSION" ]; then
|
|
NEW_VERSION=$1
|
|
fi
|
|
shift
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Check if we're in the right directory
|
|
if [ ! -f "src/lfx/pyproject.toml" ]; then
|
|
print_error "This script must be run from the root of the langflow repository"
|
|
exit 1
|
|
fi
|
|
|
|
# Get current version
|
|
CURRENT_VERSION=$(grep '^version = ' src/lfx/pyproject.toml | cut -d'"' -f2)
|
|
print_info "Current LFX version: $CURRENT_VERSION"
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_dry_run "Running in dry run mode - no changes will be made"
|
|
fi
|
|
|
|
# Check for uncommitted changes (skip in dry run)
|
|
if [ "$DRY_RUN" = false ]; then
|
|
if ! git diff-index --quiet HEAD --; then
|
|
print_warning "You have uncommitted changes. Please commit or stash them before releasing."
|
|
exit 1
|
|
fi
|
|
else
|
|
if ! git diff-index --quiet HEAD --; then
|
|
print_warning "Uncommitted changes detected (ignored in dry run mode)"
|
|
fi
|
|
fi
|
|
|
|
# Get new version from argument or prompt
|
|
if [ -z "$NEW_VERSION" ]; then
|
|
echo -n "Enter new version (current: $CURRENT_VERSION): "
|
|
read NEW_VERSION
|
|
fi
|
|
|
|
# Validate version format
|
|
if ! [[ $NEW_VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9]+)?$ ]]; then
|
|
print_error "Invalid version format. Use semantic versioning (e.g., 0.1.0 or 0.1.0-alpha)"
|
|
exit 1
|
|
fi
|
|
|
|
print_info "Preparing to release LFX version $NEW_VERSION"
|
|
|
|
# Soft check: warn if LFX minor doesn't match Langflow minor
|
|
LANGFLOW_VERSION=$(grep '^version = ' pyproject.toml | cut -d'"' -f2)
|
|
LFX_MINOR=$(echo "$NEW_VERSION" | cut -d. -f1-2)
|
|
LANGFLOW_MINOR=$(echo "$LANGFLOW_VERSION" | cut -d. -f1-2)
|
|
if [ "$LFX_MINOR" != "$LANGFLOW_MINOR" ]; then
|
|
print_warning "LFX minor version ($LFX_MINOR) does not match Langflow minor version ($LANGFLOW_MINOR)."
|
|
print_warning "Per the compatibility policy, LFX X.Y.N must align with Langflow X.Y.M."
|
|
print_warning "Proceed only if this is intentional (e.g., a patch-only LFX release)."
|
|
fi
|
|
|
|
# Update version in pyproject.toml
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_dry_run "Would update version in pyproject.toml to $NEW_VERSION"
|
|
else
|
|
print_info "Updating version in pyproject.toml..."
|
|
sed -i.bak "s/^version = \".*\"/version = \"$NEW_VERSION\"/" src/lfx/pyproject.toml
|
|
rm src/lfx/pyproject.toml.bak
|
|
fi
|
|
|
|
# Update version in Dockerfiles if they have ARG LFX_VERSION
|
|
if grep -q "ARG LFX_VERSION" src/lfx/docker/Dockerfile 2>/dev/null; then
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_dry_run "Would update version in Dockerfiles to $NEW_VERSION"
|
|
else
|
|
print_info "Updating version in Dockerfiles..."
|
|
sed -i.bak "s/ARG LFX_VERSION=.*/ARG LFX_VERSION=$NEW_VERSION/" src/lfx/docker/Dockerfile*
|
|
rm src/lfx/docker/Dockerfile*.bak
|
|
fi
|
|
fi
|
|
|
|
# Run tests
|
|
print_info "Running tests..."
|
|
cd src/lfx
|
|
if ! make test; then
|
|
print_error "Tests failed!"
|
|
if [ "$DRY_RUN" = false ]; then
|
|
print_info "Rolling back changes..."
|
|
git checkout -- .
|
|
fi
|
|
exit 1
|
|
fi
|
|
cd ../..
|
|
|
|
# Build package to verify
|
|
print_info "Building package..."
|
|
cd src/lfx
|
|
if ! uv build; then
|
|
print_error "Build failed!"
|
|
if [ "$DRY_RUN" = false ]; then
|
|
print_info "Rolling back changes..."
|
|
cd ../..
|
|
git checkout -- .
|
|
fi
|
|
exit 1
|
|
fi
|
|
cd ../..
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_dry_run "Skipping cleanup of build artifacts in dry run mode"
|
|
else
|
|
# Clean up build artifacts
|
|
rm -rf src/lfx/dist/
|
|
fi
|
|
|
|
# Create git commit
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_dry_run "Would create git commit: 'chore(lfx): bump version to $NEW_VERSION'"
|
|
else
|
|
print_info "Creating git commit..."
|
|
git add src/lfx/pyproject.toml src/lfx/docker/Dockerfile* 2>/dev/null || true
|
|
git commit -m "chore(lfx): bump version to $NEW_VERSION
|
|
|
|
- Update version in pyproject.toml
|
|
- Prepare for PyPI and Docker release"
|
|
fi
|
|
|
|
# Create git tag
|
|
TAG_NAME="lfx-v$NEW_VERSION"
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_dry_run "Would create git tag: $TAG_NAME"
|
|
else
|
|
print_info "Creating git tag: $TAG_NAME"
|
|
git tag -a "$TAG_NAME" -m "LFX Release $NEW_VERSION"
|
|
fi
|
|
|
|
if [ "$DRY_RUN" = true ]; then
|
|
print_info "✅ Dry run complete!"
|
|
echo ""
|
|
echo "Dry run performed:"
|
|
echo "✅ Validated version format"
|
|
echo "✅ Ran tests successfully"
|
|
echo "✅ Built package successfully"
|
|
echo ""
|
|
echo "What would happen in a real run:"
|
|
echo "1. Update version in pyproject.toml to $NEW_VERSION"
|
|
echo "2. Update version in Dockerfiles (if applicable)"
|
|
echo "3. Create git commit with message: 'chore(lfx): bump version to $NEW_VERSION'"
|
|
echo "4. Create git tag: $TAG_NAME"
|
|
echo ""
|
|
echo "To perform the actual release, run without --dry-run:"
|
|
echo " $0 $NEW_VERSION"
|
|
else
|
|
print_info "✅ Release preparation complete!"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo "1. Push the commit and tag:"
|
|
echo " git push origin HEAD"
|
|
echo " git push origin $TAG_NAME"
|
|
echo ""
|
|
echo "2. Go to GitHub Actions and run the 'LFX Release' workflow:"
|
|
echo " https://github.com/langflow-ai/langflow/actions/workflows/release-lfx.yml"
|
|
echo ""
|
|
echo "3. Enter version: $NEW_VERSION"
|
|
echo ""
|
|
echo "4. Select options:"
|
|
echo " - Publish to PyPI: Yes"
|
|
echo " - Build Docker images: Yes"
|
|
echo " - Create GitHub release: Yes"
|
|
echo ""
|
|
echo "The workflow will:"
|
|
echo "- Run tests on all Python versions"
|
|
echo "- Build and publish to PyPI"
|
|
echo "- Build and push Docker images (standard and alpine)"
|
|
echo "- Create a GitHub release with artifacts"
|
|
fi |