mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-24 02:05:11 +08:00
feat: add langflow-sdk support to release workflow (#12679)
* feat: add langflow-sdk build and publish support to release workflow Add support for building and publishing the langflow-sdk package in the release workflow, mirroring the nightly build support added in #12491. Changes: - Add `release_sdk` workflow input for controlling SDK release - Add `determine-sdk-version` job with first-release PyPI handling - Add `build-sdk` job with version verification and import testing - Add `publish-sdk` job that publishes SDK to PyPI before LFX - Update `build-lfx` to download SDK artifact and test both wheels together - Update `build-base` and `build-main` to use SDK wheel as find-links - Pass SDK artifact to cross-platform tests - Add validation: releasing LFX requires releasing SDK - Add pre-release version handling for SDK and LFX's SDK dependency * Update release.yml * Update release.yml * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
295
.github/workflows/release.yml
vendored
295
.github/workflows/release.yml
vendored
@ -23,6 +23,11 @@ on:
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
release_sdk:
|
||||
description: "Release langflow-sdk package (required when releasing LFX)"
|
||||
required: false
|
||||
type: boolean
|
||||
default: false
|
||||
build_docker_base:
|
||||
description: "Build Docker Image for Langflow Base"
|
||||
required: true
|
||||
@ -60,6 +65,7 @@ jobs:
|
||||
echo "release_package_base: ${{ inputs.release_package_base }}"
|
||||
echo "release_package_main: ${{ inputs.release_package_main }}"
|
||||
echo "release_lfx: ${{ inputs.release_lfx }}"
|
||||
echo "release_sdk: ${{ inputs.release_sdk }}"
|
||||
echo "build_docker_base: ${{ inputs.build_docker_base }}"
|
||||
echo "build_docker_main: ${{ inputs.build_docker_main }}"
|
||||
echo "pre_release: ${{ inputs.pre_release }}"
|
||||
@ -95,7 +101,7 @@ jobs:
|
||||
validate-dependencies:
|
||||
name: Validate Release Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ inputs.release_package_base || inputs.release_package_main || inputs.release_lfx || inputs.build_docker_base || inputs.build_docker_main }}
|
||||
if: ${{ inputs.release_package_base || inputs.release_package_main || inputs.release_lfx || inputs.release_sdk || inputs.build_docker_base || inputs.build_docker_main }}
|
||||
needs: [validate-tag]
|
||||
steps:
|
||||
- name: Validate that build-base is enabled if build-main is enabled
|
||||
@ -106,6 +112,12 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ "${{ inputs.release_lfx }}" = "true" ] && [ "${{ inputs.release_sdk }}" = "false" ]; then
|
||||
echo "Error: Cannot release LFX without releasing langflow-sdk."
|
||||
echo "LFX depends on langflow-sdk. Please enable 'release_sdk' or disable 'release_lfx'."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Release dependencies validated successfully."
|
||||
|
||||
determine-base-version:
|
||||
@ -259,6 +271,64 @@ jobs:
|
||||
echo skipped=false >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
determine-sdk-version:
|
||||
name: Determine SDK Version
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
if: ${{ inputs.release_sdk || inputs.release_lfx }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
skipped: ${{ steps.version.outputs.skipped }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
|
||||
- name: Setup Environment
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: true
|
||||
cache-dependency-glob: "uv.lock"
|
||||
python-version: "3.13"
|
||||
prune-cache: false
|
||||
|
||||
- name: Determine version
|
||||
id: version
|
||||
run: |
|
||||
version=$(python3 -c "
|
||||
import tomllib, pathlib
|
||||
data = tomllib.loads(pathlib.Path('src/sdk/pyproject.toml').read_text())
|
||||
print(data['project']['version'])
|
||||
")
|
||||
echo "SDK version from pyproject.toml: $version"
|
||||
|
||||
# Check if langflow-sdk exists on PyPI (may be first release)
|
||||
pypi_response=$(curl -s -o /dev/null -w "%{http_code}" "https://pypi.org/pypi/langflow-sdk/json")
|
||||
if [ "$pypi_response" = "404" ]; then
|
||||
echo "langflow-sdk has never been published to PyPI. This will be the first release."
|
||||
last_released_version=""
|
||||
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"
|
||||
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)
|
||||
echo "Latest SDK release version: $last_released_version"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$version" = "$last_released_version" ]; then
|
||||
echo "SDK pypi version $version is already released. Skipping release."
|
||||
echo skipped=true >> $GITHUB_OUTPUT
|
||||
exit 1
|
||||
else
|
||||
echo version=$version >> $GITHUB_OUTPUT
|
||||
echo skipped=false >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
ci:
|
||||
name: CI
|
||||
needs: [validate-tag, validate-dependencies]
|
||||
@ -272,10 +342,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
secrets: inherit
|
||||
|
||||
build-lfx:
|
||||
name: Build LFX
|
||||
needs: [determine-lfx-version]
|
||||
if: ${{ needs.determine-lfx-version.outputs.skipped == 'false' }}
|
||||
build-sdk:
|
||||
name: Build langflow-sdk
|
||||
needs: [determine-sdk-version]
|
||||
if: ${{ needs.determine-sdk-version.outputs.skipped == 'false' }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -289,6 +359,78 @@ jobs:
|
||||
cache-dependency-glob: "uv.lock"
|
||||
python-version: "3.13"
|
||||
prune-cache: false
|
||||
- name: Set version for pre-release
|
||||
if: ${{ inputs.pre_release }}
|
||||
run: |
|
||||
VERSION="${{ needs.determine-sdk-version.outputs.version }}"
|
||||
echo "Setting SDK pre-release version to: $VERSION"
|
||||
cd src/sdk
|
||||
|
||||
# Update version in SDK pyproject.toml
|
||||
sed -i.bak "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
|
||||
|
||||
# Verify the change
|
||||
echo "Updated pyproject.toml version:"
|
||||
grep "^version" pyproject.toml
|
||||
- name: Build project for distribution
|
||||
run: make sdk_build args="--wheel"
|
||||
- name: Verify built version
|
||||
run: |
|
||||
EXPECTED_VERSION="${{ needs.determine-sdk-version.outputs.version }}"
|
||||
WHEEL_FILE=$(ls src/sdk/dist/*.whl)
|
||||
echo "Built wheel: $WHEEL_FILE"
|
||||
|
||||
NORMALIZED_VERSION=$(echo "$EXPECTED_VERSION" | sed 's/\.rc/rc/g; s/\.a/a/g; s/\.b/b/g; s/\.dev/dev/g')
|
||||
echo "Expected version: $EXPECTED_VERSION"
|
||||
echo "Normalized for wheel: $NORMALIZED_VERSION"
|
||||
|
||||
if [[ ! "$WHEEL_FILE" =~ $NORMALIZED_VERSION ]]; then
|
||||
echo "❌ Error: Wheel version doesn't match expected version"
|
||||
echo "Expected: $EXPECTED_VERSION (normalized: $NORMALIZED_VERSION)"
|
||||
echo "Wheel file: $WHEEL_FILE"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ Version verified: $EXPECTED_VERSION"
|
||||
- name: Test SDK import
|
||||
run: |
|
||||
cd src/sdk
|
||||
uv venv test-env --seed
|
||||
uv pip install --python ./test-env/bin/python dist/*.whl
|
||||
EXPECTED_VERSION="${{ needs.determine-sdk-version.outputs.version }}"
|
||||
./test-env/bin/python -c "from importlib.metadata import version; import langflow_sdk; installed_version = version('langflow-sdk'); print(f'langflow-sdk {installed_version} imported successfully'); assert installed_version == '$EXPECTED_VERSION', f'Installed version {installed_version} does not match expected version $EXPECTED_VERSION'"
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: dist-sdk
|
||||
path: src/sdk/dist
|
||||
|
||||
build-lfx:
|
||||
name: Build LFX
|
||||
needs: [determine-lfx-version, determine-sdk-version, build-sdk]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
needs.determine-lfx-version.result == 'success' &&
|
||||
needs.determine-lfx-version.outputs.skipped == 'false'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
- name: Setup Environment
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: true
|
||||
cache-dependency-glob: "uv.lock"
|
||||
python-version: "3.13"
|
||||
prune-cache: false
|
||||
- name: Download SDK artifact
|
||||
if: needs.build-sdk.result == 'success'
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: dist-sdk
|
||||
path: ./sdk-dist
|
||||
- name: Install LFX dependencies
|
||||
run: uv sync --dev --package lfx
|
||||
- name: Set version for pre-release
|
||||
@ -304,6 +446,31 @@ jobs:
|
||||
# Verify the change
|
||||
echo "Updated pyproject.toml version:"
|
||||
grep "^version" pyproject.toml
|
||||
- name: Update langflow-sdk dependency for pre-release
|
||||
if: ${{ inputs.pre_release && needs.build-sdk.result == 'success' }}
|
||||
run: |
|
||||
SDK_VERSION="${{ needs.determine-sdk-version.outputs.version }}"
|
||||
echo "Updating langflow-sdk dependency to allow pre-release version: $SDK_VERSION"
|
||||
cd src/lfx
|
||||
|
||||
# Extract current langflow-sdk constraint from pyproject.toml
|
||||
CURRENT_CONSTRAINT=$(grep -E '^\s*"langflow-sdk' pyproject.toml | head -1)
|
||||
echo "Current constraint: $CURRENT_CONSTRAINT"
|
||||
|
||||
# Create new constraint using the next major derived from SDK_VERSION
|
||||
SDK_BASE_VERSION=$(echo "$SDK_VERSION" | sed 's/[^0-9.].*$//')
|
||||
SDK_MAJOR=$(echo "$SDK_BASE_VERSION" | cut -d. -f1)
|
||||
NEXT_MAJOR=$((SDK_MAJOR + 1))
|
||||
NEW_CONSTRAINT="\"langflow-sdk>=$SDK_VERSION,<$NEXT_MAJOR.dev0\""
|
||||
|
||||
echo "New constraint: $NEW_CONSTRAINT"
|
||||
|
||||
# Replace the constraint
|
||||
sed -i.bak "s|\"langflow-sdk[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml
|
||||
|
||||
# Verify the change
|
||||
echo "Updated langflow-sdk dependency:"
|
||||
grep "langflow-sdk" pyproject.toml
|
||||
- name: Build project for distribution
|
||||
run: |
|
||||
cd src/lfx
|
||||
@ -329,8 +496,16 @@ jobs:
|
||||
- name: Test CLI
|
||||
run: |
|
||||
cd src/lfx
|
||||
uv pip install dist/*.whl --force-reinstall
|
||||
uv run lfx --help
|
||||
# Use a clean venv and install both SDK and LFX wheels together
|
||||
# so uv can resolve the local SDK dependency without falling back to PyPI.
|
||||
uv venv test-env --seed
|
||||
if [ -d "../../sdk-dist" ]; then
|
||||
SDK_WHEEL=$(find ../../sdk-dist -name "*.whl" -type f | head -1)
|
||||
uv pip install --python ./test-env/bin/python --force-reinstall "$SDK_WHEEL" dist/*.whl
|
||||
else
|
||||
uv pip install --python ./test-env/bin/python --force-reinstall dist/*.whl
|
||||
fi
|
||||
./test-env/bin/lfx --help
|
||||
- name: Upload Artifact
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
@ -339,8 +514,14 @@ jobs:
|
||||
|
||||
build-base:
|
||||
name: Build Langflow Base
|
||||
needs: [build-lfx, determine-base-version, determine-lfx-version]
|
||||
if: ${{ inputs.release_package_base && needs.determine-base-version.outputs.skipped == 'false' }}
|
||||
needs: [build-lfx, build-sdk, determine-base-version, determine-lfx-version]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
inputs.release_package_base &&
|
||||
needs.determine-base-version.result == 'success' &&
|
||||
needs.determine-base-version.outputs.skipped == 'false' &&
|
||||
needs.build-lfx.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -359,12 +540,22 @@ jobs:
|
||||
with:
|
||||
name: dist-lfx
|
||||
path: ./lfx-dist
|
||||
- name: Install dependencies with local LFX wheel
|
||||
- name: Download SDK artifact
|
||||
if: needs.build-sdk.result == 'success'
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: dist-sdk
|
||||
path: ./sdk-dist
|
||||
- name: Install dependencies with local LFX and SDK wheels
|
||||
run: |
|
||||
# Create virtual environment
|
||||
uv venv
|
||||
# Install using pip with local wheel directory as find-links
|
||||
uv pip install --find-links ./lfx-dist --prerelease=allow -e src/backend/base
|
||||
# Install using pip with local wheel directories as find-links
|
||||
FIND_LINKS="--find-links ./lfx-dist"
|
||||
if [ -d "./sdk-dist" ]; then
|
||||
FIND_LINKS="$FIND_LINKS --find-links ./sdk-dist"
|
||||
fi
|
||||
uv pip install $FIND_LINKS --prerelease=allow -e src/backend/base
|
||||
- name: Check for dependency incompatibility
|
||||
run: uv pip check
|
||||
- name: Set version for pre-release
|
||||
@ -460,11 +651,19 @@ jobs:
|
||||
[
|
||||
build-base,
|
||||
build-lfx,
|
||||
build-sdk,
|
||||
determine-base-version,
|
||||
determine-main-version,
|
||||
determine-lfx-version,
|
||||
]
|
||||
if: ${{ inputs.release_package_main && needs.determine-main-version.outputs.skipped == 'false' }}
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
inputs.release_package_main &&
|
||||
needs.determine-main-version.result == 'success' &&
|
||||
needs.determine-main-version.outputs.skipped == 'false' &&
|
||||
needs.build-base.result == 'success' &&
|
||||
needs.build-lfx.result == 'success'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
@ -483,6 +682,12 @@ jobs:
|
||||
with:
|
||||
name: dist-lfx
|
||||
path: ./lfx-dist
|
||||
- name: Download SDK artifact
|
||||
if: needs.build-sdk.result == 'success'
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: dist-sdk
|
||||
path: ./sdk-dist
|
||||
- name: Download base artifact
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
@ -493,7 +698,11 @@ jobs:
|
||||
# Create virtual environment
|
||||
uv venv
|
||||
# Install using pip with local wheel directories as find-links
|
||||
uv pip install --find-links ./lfx-dist --find-links ./base-dist --prerelease=allow -e .
|
||||
FIND_LINKS="--find-links ./lfx-dist --find-links ./base-dist"
|
||||
if [ -d "./sdk-dist" ]; then
|
||||
FIND_LINKS="$FIND_LINKS --find-links ./sdk-dist"
|
||||
fi
|
||||
uv pip install $FIND_LINKS --prerelease=allow -e .
|
||||
- name: Check for dependency incompatibility
|
||||
run: uv pip check
|
||||
- name: Set version for pre-release
|
||||
@ -584,7 +793,7 @@ jobs:
|
||||
|
||||
test-cross-platform:
|
||||
name: Test Cross-Platform Installation
|
||||
needs: [build-base, build-main, build-lfx]
|
||||
needs: [build-base, build-main, build-lfx, build-sdk]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
@ -594,12 +803,20 @@ jobs:
|
||||
base-artifact-name: "dist-base"
|
||||
main-artifact-name: "dist-main"
|
||||
lfx-artifact-name: "dist-lfx"
|
||||
sdk-artifact-name: ${{ needs.build-sdk.result == 'success' && 'dist-sdk' || '' }}
|
||||
pre_release: ${{ inputs.pre_release }}
|
||||
|
||||
publish-base:
|
||||
name: Publish Langflow Base to PyPI
|
||||
if: ${{ inputs.release_package_base }}
|
||||
needs: [build-base, test-cross-platform, ci]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
inputs.release_package_base &&
|
||||
needs.build-base.result == 'success' &&
|
||||
needs.test-cross-platform.result == 'success' &&
|
||||
needs.ci.result == 'success' &&
|
||||
(needs.publish-lfx.result == 'success' || needs.publish-lfx.result == 'skipped')
|
||||
needs: [build-base, test-cross-platform, ci, publish-lfx]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download base artifact
|
||||
@ -642,10 +859,50 @@ jobs:
|
||||
run: |
|
||||
uv publish dist/*.whl
|
||||
|
||||
publish-sdk:
|
||||
name: Publish langflow-sdk to PyPI
|
||||
needs: [build-sdk, test-cross-platform, ci]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
inputs.release_sdk &&
|
||||
needs.build-sdk.result == 'success' &&
|
||||
needs.ci.result == 'success' &&
|
||||
(needs.test-cross-platform.result == 'success' || needs.test-cross-platform.result == 'skipped')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ inputs.release_tag }}
|
||||
- name: Download SDK artifact
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: dist-sdk
|
||||
path: src/sdk/dist
|
||||
- name: Setup Environment
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
enable-cache: false
|
||||
python-version: "3.13"
|
||||
- name: Publish SDK to PyPI
|
||||
if: ${{ !inputs.dry_run }}
|
||||
env:
|
||||
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
|
||||
run: |
|
||||
make sdk_publish
|
||||
|
||||
publish-lfx:
|
||||
name: Publish LFX to PyPI
|
||||
if: ${{ inputs.release_lfx }}
|
||||
needs: [build-lfx, test-cross-platform, ci]
|
||||
needs: [build-lfx, test-cross-platform, ci, publish-sdk]
|
||||
if: |
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
inputs.release_lfx &&
|
||||
needs.build-lfx.result == 'success' &&
|
||||
needs.test-cross-platform.result == 'success' &&
|
||||
needs.ci.result == 'success' &&
|
||||
(needs.publish-sdk.result == 'success' || needs.publish-sdk.result == 'skipped')
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download LFX artifact
|
||||
|
||||
@ -197,7 +197,7 @@
|
||||
"filename": ".github/workflows/release.yml",
|
||||
"hashed_secret": "3e26d6750975d678acb8fa35a0f69237881576b0",
|
||||
"is_verified": false,
|
||||
"line_number": 273,
|
||||
"line_number": 342,
|
||||
"is_secret": false
|
||||
}
|
||||
],
|
||||
@ -8405,5 +8405,5 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
"generated_at": "2026-04-10T17:09:16Z"
|
||||
"generated_at": "2026-04-14T00:28:39Z"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user