mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-23 17:58:35 +08:00
fix(ci): rename bundles to -nightly during nightly build (#13193)
fix: rename bundles for nightly build
This commit is contained in:
4
.github/workflows/nightly_build.yml
vendored
4
.github/workflows/nightly_build.yml
vendored
@ -163,6 +163,8 @@ jobs:
|
||||
uv run --no-sync ./scripts/ci/update_sdk_version.py $SDK_TAG
|
||||
echo "Updating LFX project version to $LFX_TAG"
|
||||
uv run --no-sync ./scripts/ci/update_lfx_version.py $LFX_TAG $SDK_TAG
|
||||
echo "Renaming bundle packages to their -nightly counterparts (lfx dev suffix: $LFX_TAG)"
|
||||
uv run --no-sync ./scripts/ci/update_bundle_versions.py $LFX_TAG
|
||||
echo "Updating base project version to $BASE_TAG and updating main project version to $RELEASE_TAG"
|
||||
uv run --no-sync ./scripts/ci/update_pyproject_combined.py main $RELEASE_TAG $BASE_TAG $LFX_TAG
|
||||
|
||||
@ -170,7 +172,7 @@ jobs:
|
||||
cd src/backend/base && uv lock && cd ../../..
|
||||
cd src/lfx && uv lock && cd ../..
|
||||
|
||||
git add pyproject.toml src/backend/base/pyproject.toml src/lfx/pyproject.toml src/sdk/pyproject.toml uv.lock src/backend/base/uv.lock
|
||||
git add pyproject.toml src/backend/base/pyproject.toml src/lfx/pyproject.toml src/sdk/pyproject.toml src/bundles/*/pyproject.toml uv.lock src/backend/base/uv.lock
|
||||
git commit -m "Update version and project name"
|
||||
|
||||
echo "Tagging main with $RELEASE_TAG"
|
||||
|
||||
@ -187,7 +187,7 @@
|
||||
"filename": ".github/workflows/nightly_build.yml",
|
||||
"hashed_secret": "3e26d6750975d678acb8fa35a0f69237881576b0",
|
||||
"is_verified": false,
|
||||
"line_number": 297,
|
||||
"line_number": 299,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@ -9031,5 +9031,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2026-05-18T23:09:06Z"
|
||||
"generated_at": "2026-05-19T01:17:22Z"
|
||||
}
|
||||
|
||||
181
scripts/ci/update_bundle_versions.py
Normal file
181
scripts/ci/update_bundle_versions.py
Normal file
@ -0,0 +1,181 @@
|
||||
"""Rename ``lfx-*`` bundle packages to their ``-nightly`` counterparts.
|
||||
|
||||
Bundles under ``src/bundles/*`` follow the same package-rename convention as
|
||||
``langflow``, ``langflow-base``, ``lfx``, and ``langflow-sdk``: for nightly
|
||||
builds, the distribution is published as ``<name>-nightly`` so the regular
|
||||
(non-nightly) PyPI name stays untouched.
|
||||
|
||||
This script (a) renames each bundle's ``[project] name`` to
|
||||
``<name>-nightly``, (b) bumps its version to ``<base>.dev<N>``, (c) rewrites
|
||||
its ``lfx`` runtime dep so it resolves against the renamed ``lfx-nightly``
|
||||
workspace member, and (d) updates the root ``pyproject.toml`` so its bundle
|
||||
deps and ``[tool.uv.sources]`` entries reference the renamed packages.
|
||||
|
||||
All operations are idempotent — running twice is a no-op.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
BASE_DIR = Path(__file__).parent.parent.parent
|
||||
|
||||
# Matches the lfx dep specifier inside a bundle pyproject's dependencies list.
|
||||
# Accepts the bundle default ("lfx>=X.Y.Z,<A.B.C"), legacy ~=/==, and the
|
||||
# already-rewritten "lfx-nightly==X.Y.Z" form (idempotent).
|
||||
_LFX_DEP_PATTERN = re.compile(
|
||||
r'"lfx(?:-nightly)?'
|
||||
r"(?:"
|
||||
r"(?:~=|==)[\d.]+(?:\.(?:post|dev|a|b|rc)\d+)*"
|
||||
r"|"
|
||||
r">=[\d.]+(?:\.(?:post|dev|a|b|rc)\d+)*"
|
||||
r",\s*<[\d.]+(?:\.(?:post|dev|a|b|rc)\d+)*"
|
||||
r')"'
|
||||
)
|
||||
|
||||
_PROJECT_NAME_PATTERN = re.compile(r'(\[project\][^\[]*?\nname = ")([^"]+)(")', re.DOTALL)
|
||||
_PROJECT_VERSION_PATTERN = re.compile(r'(\[project\][^\[]*?\nversion = ")([^"]+)(")', re.DOTALL)
|
||||
|
||||
|
||||
def _strip_nightly(name: str) -> str:
|
||||
"""Return the base name with a trailing ``-nightly`` stripped (for idempotency)."""
|
||||
return name.removesuffix("-nightly")
|
||||
|
||||
|
||||
def _strip_dev_suffix(version: str) -> str:
|
||||
"""Return the base version with any trailing PEP 440 dev segment stripped."""
|
||||
return re.sub(r"\.dev\d+$", "", version)
|
||||
|
||||
|
||||
def _extract_dev_n(tag: str) -> str:
|
||||
"""Extract ``N`` from a tag like ``v0.5.0.dev38`` or ``0.5.0.dev38``."""
|
||||
match = re.search(r"\.dev(\d+)$", tag)
|
||||
if not match:
|
||||
msg = f"Tag does not end in .devN: {tag!r}"
|
||||
raise ValueError(msg)
|
||||
return match.group(1)
|
||||
|
||||
|
||||
def rename_bundle_pyproject(pyproject_path: Path, lfx_version: str, dev_n: str) -> tuple[str, str, str] | None:
|
||||
"""Rewrite a single bundle ``pyproject.toml`` for nightly publication.
|
||||
|
||||
- ``[project] name`` → ``<base_name>-nightly``
|
||||
- ``[project] version`` → ``<base_version>.dev<N>``
|
||||
- entry-point key → ``<base_name>-nightly``
|
||||
- ``"lfx>=...,<..."`` dep → ``"lfx-nightly==<lfx_version>"``
|
||||
|
||||
Returns ``(base_name, nightly_name, nightly_version)`` so the caller can
|
||||
update the root pyproject. Returns ``None`` if the file has no
|
||||
``[project]`` name/version (shouldn't happen, but we skip rather than fail).
|
||||
"""
|
||||
content = pyproject_path.read_text(encoding="utf-8")
|
||||
|
||||
name_match = _PROJECT_NAME_PATTERN.search(content)
|
||||
version_match = _PROJECT_VERSION_PATTERN.search(content)
|
||||
if not name_match or not version_match:
|
||||
return None
|
||||
|
||||
base_name = _strip_nightly(name_match.group(2))
|
||||
nightly_name = f"{base_name}-nightly"
|
||||
base_version = _strip_dev_suffix(version_match.group(2))
|
||||
nightly_version = f"{base_version}.dev{dev_n}"
|
||||
|
||||
content = _PROJECT_NAME_PATTERN.sub(rf"\g<1>{nightly_name}\g<3>", content, count=1)
|
||||
content = _PROJECT_VERSION_PATTERN.sub(rf"\g<1>{nightly_version}\g<3>", content, count=1)
|
||||
|
||||
# Entry-point key. The key may already be the nightly form on a re-run.
|
||||
entry_point_pattern = re.compile(
|
||||
rf'(\[project\.entry-points\."langflow\.extensions"\]\s*\n)'
|
||||
rf"{re.escape(base_name)}(?:-nightly)?"
|
||||
rf'(\s*=\s*"[^"]+")'
|
||||
)
|
||||
content = entry_point_pattern.sub(rf"\g<1>{nightly_name}\g<2>", content, count=1)
|
||||
|
||||
# Rewrite the lfx dep regardless of which form it's in.
|
||||
content = _LFX_DEP_PATTERN.sub(f'"lfx-nightly=={lfx_version}"', content)
|
||||
|
||||
pyproject_path.write_text(content, encoding="utf-8")
|
||||
return base_name, nightly_name, nightly_version
|
||||
|
||||
|
||||
def update_root_pyproject_for_bundle(
|
||||
root_pyproject: Path,
|
||||
base_name: str,
|
||||
nightly_name: str,
|
||||
nightly_version: str,
|
||||
) -> None:
|
||||
"""Update root ``pyproject.toml`` to reference the nightly bundle.
|
||||
|
||||
- dependency line ``"<base_name>[..]"`` → ``"<nightly_name>==<version>"``
|
||||
- uv.sources entry ``<base_name> = { workspace = true }`` → ``<nightly_name> = ...``
|
||||
|
||||
Idempotent: also matches the already-nightly form.
|
||||
"""
|
||||
content = root_pyproject.read_text(encoding="utf-8")
|
||||
|
||||
# Dependency in [project.dependencies] (any PEP 440 specifier or range form).
|
||||
dep_pattern = re.compile(
|
||||
rf'"{re.escape(base_name)}(?:-nightly)?'
|
||||
r"(?:"
|
||||
r"(?:~=|==|>=)[\d.]+(?:\.(?:post|dev|a|b|rc)\d+)*"
|
||||
r"(?:,\s*<[\d.]+(?:\.(?:post|dev|a|b|rc)\d+)*)?"
|
||||
r')"'
|
||||
)
|
||||
content = dep_pattern.sub(f'"{nightly_name}=={nightly_version}"', content)
|
||||
|
||||
# uv.sources entry — only the workspace = true form is used by bundles today.
|
||||
source_pattern = re.compile(
|
||||
rf"^{re.escape(base_name)}(?:-nightly)?(\s*=\s*\{{\s*workspace\s*=\s*true\s*\}})",
|
||||
re.MULTILINE,
|
||||
)
|
||||
content = source_pattern.sub(rf"{nightly_name}\g<1>", content)
|
||||
|
||||
root_pyproject.write_text(content, encoding="utf-8")
|
||||
|
||||
|
||||
def update_bundles_for_nightly(lfx_tag: str) -> list[tuple[str, str, str]]:
|
||||
"""Rename every ``src/bundles/*`` package to its ``-nightly`` counterpart.
|
||||
|
||||
Returns a list of ``(base_name, nightly_name, nightly_version)`` tuples
|
||||
for the bundles that were rewritten.
|
||||
"""
|
||||
bundles_dir = BASE_DIR / "src" / "bundles"
|
||||
if not bundles_dir.is_dir():
|
||||
return []
|
||||
|
||||
lfx_version = lfx_tag.lstrip("v")
|
||||
dev_n = _extract_dev_n(lfx_version)
|
||||
root_pyproject = BASE_DIR / "pyproject.toml"
|
||||
|
||||
results: list[tuple[str, str, str]] = []
|
||||
for bundle_pyproject in sorted(bundles_dir.glob("*/pyproject.toml")):
|
||||
renamed = rename_bundle_pyproject(bundle_pyproject, lfx_version, dev_n)
|
||||
if renamed is None:
|
||||
continue
|
||||
base_name, nightly_name, nightly_version = renamed
|
||||
update_root_pyproject_for_bundle(root_pyproject, base_name, nightly_name, nightly_version)
|
||||
results.append(renamed)
|
||||
print(f"Renamed {base_name} -> {nightly_name} ({nightly_version}) in {bundle_pyproject.relative_to(BASE_DIR)}")
|
||||
return results
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Entry point.
|
||||
|
||||
Usage:
|
||||
update_bundle_versions.py <lfx_tag>
|
||||
|
||||
``lfx_tag`` is the LFX nightly tag (e.g., ``v0.5.0.dev38``); its ``.devN``
|
||||
suffix is reused for all bundles so they share a single nightly cadence.
|
||||
"""
|
||||
expected_args = 2
|
||||
if len(sys.argv) != expected_args:
|
||||
print("Usage: update_bundle_versions.py <lfx_tag>")
|
||||
sys.exit(1)
|
||||
update_bundles_for_nightly(sys.argv[1])
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user