mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 13:09:09 +08:00
* ci: stop publishing -nightly bundle variants; release bundles on demand (#13206) Bundles (lfx-arxiv, lfx-duckduckgo) change infrequently enough that a nightly cadence is overkill. Drop the rename-to-`-nightly` and bundle publish lanes from the nightly pipeline and add a dedicated workflow_dispatch-only release_bundles.yml for purposeful releases. - nightly_build.yml: drop update_bundle_versions.py invocation and the src/bundles/*/pyproject.toml git-add guard. - release_nightly.yml: remove build-nightly-bundles and publish-nightly-bundles jobs; untether test-cross-platform and publish-nightly-main from them. - release_bundles.yml (new): build all src/bundles/* wheels, run a cross-OS install smoke test, then publish to PyPI under their stable names. Tolerates already-published versions so re-runs without a version bump are no-ops. release.yml still owns bundle publishing as part of main releases. Manual follow-up (PyPI admin): delete the lfx-arxiv-nightly and lfx-duckduckgo-nightly projects from PyPI. * ci(release_bundles): build lfx wheel locally for smoke test (#13207) The release_bundles.yml smoke test installs bundle wheels into a fresh venv, which makes uv resolve their `lfx>=X.Y,<Z` pin against PyPI. When bundles are released ahead of a matching lfx (typical case — bundles ship more often than lfx bumps land on PyPI), the resolve fails: Because only lfx<=0.4.3 is available and lfx-arxiv==0.1.0 depends on lfx>=0.5.0,<0.6.0, we can conclude that lfx-arxiv==0.1.0 cannot be used. Build the lfx wheel from the current ref in the build-bundles job and install it alongside the bundle wheels in the smoke test. The lfx wheel ships as a separate `dist-lfx-smoketest` artifact and is NOT included in the publish-bundles step — only the `dist-bundles` artifact gets pushed to PyPI. * ci(nightly): re-pin bundle lfx deps to lfx-nightly during nightly build (#13208) The nightly pipeline renames the workspace `lfx` package to `lfx-nightly` in `src/lfx/pyproject.toml` and the root workspace dep, but leaves each `src/bundles/*/pyproject.toml`'s `"lfx>=X.Y,<Z"` pin unchanged. With the workspace `lfx` gone and PyPI still on lfx 0.4.3, the create-nightly-tag job's `uv lock` fails: × No solution found when resolving dependencies for split [...] ╰─▶ Because only lfx<=0.4.3 is available and lfx-arxiv depends on lfx>=0.5.0,<0.6.0, we can conclude that lfx-arxiv's requirements are unsatisfiable. `update_lfx_version.py` now also rewrites the `lfx` (or already-rewritten `lfx-nightly`) specifier in every `src/bundles/*/pyproject.toml` to `lfx-nightly==<dev version>`, mirroring how `update_lf_base_dependency` re-pins the lfx dep inside `langflow-base`. The lookahead in the regex prevents matching sibling packages like `lfx-arxiv` / `lfx-duckduckgo`. No-op when no bundle pyprojects exist (e.g. on main today), so this is safe to merge ahead of the bundle extraction landing on main. Restored the guarded `git add src/bundles/*/pyproject.toml` step so the modified bundle pyprojects ride the same commit/tag as the rest of the nightly version bumps. Cherry-pick to release-1.10.0 to unblock nightlies cut from that branch.
224 lines
7.6 KiB
YAML
224 lines
7.6 KiB
YAML
name: Release Bundles
|
|
|
|
# Manually-triggered workflow for publishing stable `lfx-<name>` bundle wheels
|
|
# from src/bundles/* to PyPI. Bundles change infrequently, so we release them
|
|
# on demand rather than on a schedule. Re-running the workflow without a
|
|
# version bump is a no-op (PyPI rejects the duplicate upload and we tolerate
|
|
# the conflict).
|
|
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
release_tag:
|
|
description: "Git ref to build from (branch, tag, or SHA). Defaults to the workflow's checked-out ref."
|
|
required: false
|
|
type: string
|
|
default: ""
|
|
dry_run:
|
|
description: "Build and test only; skip the PyPI publish step."
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
env:
|
|
PYTHON_VERSION: "3.13"
|
|
|
|
jobs:
|
|
build-bundles:
|
|
name: Build Langflow Bundles
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
shell: bash
|
|
outputs:
|
|
bundles-found: ${{ steps.build.outputs.bundles-found }}
|
|
steps:
|
|
- name: Checkout code
|
|
uses: actions/checkout@v6
|
|
with:
|
|
ref: ${{ inputs.release_tag || github.ref }}
|
|
- name: Setup Environment
|
|
uses: astral-sh/setup-uv@v6
|
|
with:
|
|
enable-cache: true
|
|
cache-dependency-glob: "uv.lock"
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
prune-cache: false
|
|
- name: Install the project
|
|
run: uv sync
|
|
- name: Build bundle wheels
|
|
id: build
|
|
run: |
|
|
shopt -s nullglob
|
|
bundles=(src/bundles/*/pyproject.toml)
|
|
if [ ${#bundles[@]} -eq 0 ]; then
|
|
echo "No bundles found under src/bundles/*/"
|
|
echo "bundles-found=0" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
mkdir -p bundles-dist
|
|
BUNDLES_DIST="$PWD/bundles-dist"
|
|
for bundle_pyproject in "${bundles[@]}"; do
|
|
bundle_dir=$(dirname "$bundle_pyproject")
|
|
echo "Building wheel for $bundle_dir"
|
|
(cd "$bundle_dir" && uv build --wheel --out-dir "$BUNDLES_DIST")
|
|
done
|
|
echo "bundles-found=1" >> $GITHUB_OUTPUT
|
|
ls -la bundles-dist/
|
|
# Bundles pin lfx (e.g. lfx>=0.5.0,<0.6.0). The smoke test below
|
|
# installs the bundles in a fresh venv, so it needs an lfx wheel that
|
|
# satisfies the pin available locally — PyPI may not yet have a
|
|
# matching lfx published when bundles are released ahead of a main
|
|
# release. We build the lfx wheel from the current ref so the smoke
|
|
# test resolves against it; this artifact is not published.
|
|
- name: Build lfx wheel for smoke test
|
|
if: steps.build.outputs.bundles-found == '1'
|
|
run: |
|
|
mkdir -p lfx-dist
|
|
LFX_DIST="$PWD/lfx-dist"
|
|
(cd src/lfx && uv build --wheel --out-dir "$LFX_DIST")
|
|
ls -la lfx-dist/
|
|
- name: Upload bundles artifact
|
|
if: steps.build.outputs.bundles-found == '1'
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: dist-bundles
|
|
path: bundles-dist
|
|
- name: Upload lfx artifact (smoke-test only; not published)
|
|
if: steps.build.outputs.bundles-found == '1'
|
|
uses: actions/upload-artifact@v6
|
|
with:
|
|
name: dist-lfx-smoketest
|
|
path: lfx-dist
|
|
|
|
test-install:
|
|
name: Install Smoke Test - ${{ matrix.os }} ${{ matrix.python-version }}
|
|
needs: [build-bundles]
|
|
if: needs.build-bundles.outputs.bundles-found == '1'
|
|
runs-on: ${{ matrix.runner }}
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- os: linux
|
|
runner: ubuntu-latest
|
|
python-version: "3.10"
|
|
- os: linux
|
|
runner: ubuntu-latest
|
|
python-version: "3.12"
|
|
- os: macos
|
|
runner: macos-latest
|
|
python-version: "3.12"
|
|
- os: windows
|
|
runner: windows-latest
|
|
python-version: "3.12"
|
|
steps:
|
|
- name: Setup Python
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
- name: Setup UV
|
|
uses: astral-sh/setup-uv@v6
|
|
with:
|
|
enable-cache: false
|
|
ignore-empty-workdir: true
|
|
- name: Download bundles artifact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: dist-bundles
|
|
path: ./bundles-dist
|
|
- name: Download lfx artifact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: dist-lfx-smoketest
|
|
path: ./lfx-dist
|
|
- name: Create fresh virtual environment
|
|
run: uv venv test-env --seed
|
|
shell: bash
|
|
- name: Install lfx + bundle wheels (Unix)
|
|
if: matrix.os != 'windows'
|
|
run: |
|
|
shopt -s nullglob
|
|
BUNDLE_WHEELS=(./bundles-dist/*.whl)
|
|
LFX_WHEELS=(./lfx-dist/*.whl)
|
|
if [ ${#BUNDLE_WHEELS[@]} -eq 0 ]; then
|
|
echo "No bundle wheels found in ./bundles-dist/"
|
|
exit 1
|
|
fi
|
|
if [ ${#LFX_WHEELS[@]} -eq 0 ]; then
|
|
echo "No lfx wheel found in ./lfx-dist/"
|
|
exit 1
|
|
fi
|
|
printf 'Installing: %s\n' "${LFX_WHEELS[@]}" "${BUNDLE_WHEELS[@]}"
|
|
uv pip install --prerelease=allow --python ./test-env/bin/python "${LFX_WHEELS[@]}" "${BUNDLE_WHEELS[@]}"
|
|
shell: bash
|
|
- name: Install lfx + bundle wheels (Windows)
|
|
if: matrix.os == 'windows'
|
|
run: |
|
|
shopt -s nullglob
|
|
BUNDLE_WHEELS=(./bundles-dist/*.whl)
|
|
LFX_WHEELS=(./lfx-dist/*.whl)
|
|
if [ ${#BUNDLE_WHEELS[@]} -eq 0 ]; then
|
|
echo "No bundle wheels found in ./bundles-dist/"
|
|
exit 1
|
|
fi
|
|
if [ ${#LFX_WHEELS[@]} -eq 0 ]; then
|
|
echo "No lfx wheel found in ./lfx-dist/"
|
|
exit 1
|
|
fi
|
|
printf 'Installing: %s\n' "${LFX_WHEELS[@]}" "${BUNDLE_WHEELS[@]}"
|
|
uv pip install --prerelease=allow --python ./test-env/Scripts/python.exe "${LFX_WHEELS[@]}" "${BUNDLE_WHEELS[@]}"
|
|
shell: bash
|
|
|
|
publish-bundles:
|
|
name: Publish Bundles to PyPI
|
|
needs: [build-bundles, test-install]
|
|
if: |
|
|
always() &&
|
|
!cancelled() &&
|
|
!inputs.dry_run &&
|
|
needs.build-bundles.result == 'success' &&
|
|
needs.build-bundles.outputs.bundles-found == '1' &&
|
|
needs.test-install.result == 'success'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Download bundles artifact
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: dist-bundles
|
|
path: bundles-dist
|
|
- name: Setup Environment
|
|
uses: astral-sh/setup-uv@v6
|
|
with:
|
|
enable-cache: false
|
|
python-version: ${{ env.PYTHON_VERSION }}
|
|
- name: Publish bundles to PyPI
|
|
env:
|
|
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
|
run: |
|
|
shopt -s nullglob
|
|
wheels=(bundles-dist/*.whl)
|
|
if [ ${#wheels[@]} -eq 0 ]; then
|
|
echo "No bundle wheels to publish."
|
|
exit 0
|
|
fi
|
|
failed=0
|
|
for wheel in "${wheels[@]}"; do
|
|
echo "Publishing $wheel"
|
|
# Capture stderr so we can tolerate "already exists" without failing
|
|
# the whole run — re-running this workflow without bumping a bundle
|
|
# version should be a no-op for that bundle.
|
|
if ! err=$(uv publish "$wheel" 2>&1); then
|
|
echo "$err"
|
|
if echo "$err" | grep -qiE 'already exists|file already exists|HTTP 400|duplicate'; then
|
|
echo "Skipping $wheel: already published."
|
|
else
|
|
echo "Publish failed for $wheel"
|
|
failed=1
|
|
fi
|
|
fi
|
|
done
|
|
if [ "$failed" = "1" ]; then
|
|
exit 1
|
|
fi
|