mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 04:47:23 +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>
192 lines
8.0 KiB
Markdown
192 lines
8.0 KiB
Markdown
# Releasing Langflow
|
||
|
||
Langflow follows a **release-when-ready** cadence, with each cycle typically lasting 4–6 weeks depending on QA and stabilization needs.
|
||
|
||
## Goals
|
||
|
||
* Keep `main` fast-moving for everyday work while ensuring stable release builds when features mature.
|
||
* Provide an isolated branch for QA and last-minute fixes (the release candidate, RC).
|
||
* Preserve a linear, readable history wherever possible.
|
||
* Ensure released code is extensively tested before publication.
|
||
* Minimize time to resolution of critical bugs.
|
||
|
||
## Process Overview
|
||
|
||
### 1. OSS QA
|
||
|
||
Create an OSS release candidate (RC) branch containing `langflow` and any associated PyPI packages (e.g. `lfx`).
|
||
During this period:
|
||
|
||
* QA is performed manually.
|
||
* Bug fixes are merged into the RC branch.
|
||
* New features continue development on `main`.
|
||
|
||
This step usually lasts about a week.
|
||
|
||
### 2. Desktop QA
|
||
|
||
Once OSS QA and bugfixing are complete, create a Desktop release candidate.
|
||
|
||
* The Desktop RC is based on the final OSS RC.
|
||
* Manual QA is performed.
|
||
* Bug fixes are merged into the Desktop RC.
|
||
* New features continue on `main`.
|
||
|
||
This step also usually lasts about a week.
|
||
|
||
### 3. Release
|
||
|
||
After QA and bugfixing are complete for both OSS and Desktop:
|
||
|
||
* Final releases are cut from their respective RC branches.
|
||
* Release timing is coordinated with Langflow's DevRel team.
|
||
* For at least 24 hours after release, Discord, GitHub, and other support channels should be monitored for critical bug reports.
|
||
|
||
### 4. Release Artifacts
|
||
|
||
The release workflow automatically publishes the following artifacts:
|
||
|
||
* **PyPI Packages:**
|
||
* `langflow` - Main package with all integrations
|
||
* `langflow-base` - Core framework without integrations
|
||
* `lfx` - Lightweight executor CLI
|
||
* `langflow-sdk` - SDK for programmatic access (when updated)
|
||
|
||
* **Docker Images:**
|
||
* `langflowai/langflow` - Full Langflow image
|
||
* `langflowai/langflow-backend` - Backend-only image (published independently)
|
||
* `langflowai/langflow-frontend` - Frontend-only image (published independently)
|
||
* `langflowai/langflow-ep` - Enterprise edition image (published independently)
|
||
* `langflowai/langflow-base` - Base image without integrations
|
||
|
||
**Note:** Backend, frontend, and enterprise images are published separately from the main image and will be built even if the main version already exists on Docker Hub.
|
||
|
||
## Branch Model
|
||
|
||
| Branch | Purpose | Merge Policy |
|
||
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
|
||
| **`main`** | Integration branch. All feature PRs target this by default. | **Squash & Merge** (linear history) |
|
||
| **`release-X.Y.Z`**<br>(e.g. `release-1.4.3`) | Temporary RC branch. Active only for the release cycle. Accepts QA and blocking-bug PRs labeled `type:release`. | **Squash & Merge** within the branch.<br>Rebased onto **`main`** before final merge. |
|
||
|
||
## Release Steps
|
||
|
||
### 1. Cut Release Candidate
|
||
|
||
```sh
|
||
git checkout main && git pull # Ensure local main is up to date
|
||
git checkout -b release-X.Y.Z # Create new release candidate branch
|
||
git push -u origin release-X.Y.Z # Push RC branch to remote
|
||
```
|
||
|
||
### 2. Apply a Bugfix to RC
|
||
|
||
1. Create a feature branch as usual.
|
||
2. Open a GitHub PR targeting `release-X.Y.Z`.
|
||
3. Review and approve as normal.
|
||
4. Merge into the RC branch after review.
|
||
|
||
### 3. Review Regression Log
|
||
|
||
Before tagging, review `regressions/X.Y.x.yaml` to confirm no unresolved `blocking` entries exist.
|
||
If `blocking` entries exist, they should be signed off on.
|
||
|
||
See [regressions/README.md](./regressions/README.md) for the full schema and entry instructions.
|
||
|
||
### 4. Final Release
|
||
|
||
```sh
|
||
git checkout release-X.Y.Z && git pull # Ensure RC branch is up to date
|
||
git tag vX.Y.Z # Create final release tag
|
||
git push origin vX.Y.Z # Push tag to remote
|
||
```
|
||
|
||
### 5. Merge RC Back into Main
|
||
|
||
```sh
|
||
git checkout main
|
||
git merge --ff-only release-X.Y.Z # Fast-forward main to include RC changes
|
||
```
|
||
|
||
## Merge Strategy
|
||
|
||
1. **Squash & Merge** everywhere for atomic commits and clean history.
|
||
|
||
2. While RC is open, periodically re-sync with main:
|
||
|
||
```sh
|
||
git checkout release-X.Y.Z
|
||
git fetch origin
|
||
git rebase origin/main
|
||
```
|
||
|
||
*This resolves conflicts early while keeping history linear.*
|
||
|
||
3. Final merge back must be fast-forward only. If not possible, rebase the RC onto `main` before merging.
|
||
|
||
## Versioning & Tags
|
||
|
||
* Follows [Semantic Versioning](https://semver.org): `MAJOR.MINOR.PATCH`.
|
||
* RC tags use `-rc.N`, e.g. `v1.8.0-rc.1`.
|
||
* **All tags MUST start with `v` prefix** (e.g., `v1.9.1`, not `1.9.1`).
|
||
* The release workflow validates this format and rejects tags without the `v` prefix.
|
||
* Duplicate tags (e.g., both `1.8.3` and `v1.8.3`) cause GitHub's release notes generation to use the wrong base comparison, resulting in incomplete changelogs.
|
||
* The workflow automatically checks for and prevents duplicate tags.
|
||
|
||
## LFX Compatibility
|
||
|
||
Langflow and LFX share a **major.minor version line**. The compatibility contract is:
|
||
|
||
> **LFX X.Y.N is guaranteed compatible with any Flow exported from Langflow X.Y.M.**
|
||
|
||
Patch releases (`N` and `M`) are independent — a patch to LFX does not require a Langflow patch release, and vice versa.
|
||
|
||
### Version management
|
||
|
||
`make patch v=X.Y.Z` updates all four artifacts together:
|
||
|
||
| Artifact | Version set |
|
||
|---|---|
|
||
| `langflow` | `X.Y.Z` |
|
||
| `langflow-base` | `0.Y.Z` |
|
||
| `lfx` | `X.Y.Z` |
|
||
| frontend | `X.Y.Z` |
|
||
|
||
### Cutting an LFX patch release
|
||
|
||
Use `scripts/release-lfx.sh <version>`. The script warns if the LFX minor version does not match the current Langflow minor version, which would violate the compatibility contract. A warning is not a hard block — patch-only LFX releases within the same minor are expected and fine.
|
||
|
||
### Implications for users
|
||
|
||
Users can pin `lfx~=X.Y.0` in their `requirements.txt` to receive all compatible LFX patch releases for a given Langflow minor.
|
||
|
||
### Migrating from lfx 0.5.x to 1.10.0
|
||
|
||
LFX was realigned from its standalone `0.5.x` line onto Langflow's `major.minor` line, so the version jumps from `0.5.0` to `1.10.0` in a single step. This is a version-numbering change, not 95 minors of feature churn. The jump affects downstream pins, and neither pip nor uv will flag it — so it must be called out in the release announcement, not just here:
|
||
|
||
- `lfx==0.5.x` or `lfx<1.0` pins will **not** upgrade (intentional — those deployments stay put).
|
||
- `lfx>=0.5,<1` pins will **not** upgrade.
|
||
- `lfx>=0.5` with no upper bound **will** pull `1.10.0` on the next install — a major jump with no warning.
|
||
|
||
Going forward, pin `lfx~=X.Y.0` (e.g. `lfx~=1.10.0`) so you track compatible patches for a given Langflow minor without silently crossing minor lines.
|
||
|
||
## Roles
|
||
|
||
| Role | Responsibility |
|
||
| --------------------------------------- | ----------------------------------------------------------------- |
|
||
| **Release Captain** (rotates per cycle) | Owns timeline, branch cut, tagging, merge-back. |
|
||
| **PR Author** | Ensures tests pass; flags PR with `type:release` if needed in RC. |
|
||
| **CI** | Blocks merges on failing tests or missing labels. |
|
||
|
||
## FAQ
|
||
|
||
### Do we ever merge main into the RC?
|
||
|
||
No. Always rebase the RC onto `main` to preserve linear history.
|
||
|
||
### Can we automate branch deletion?
|
||
|
||
Not yet — merge-back and cleanup are manual.
|
||
|
||
### How flexible is the timeline?
|
||
|
||
Very flexible. QA and stabilization phases can be extended as needed for quality. |