Langflow Release by @erichare #1686
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Langflow Release | |
| run-name: Langflow Release by @${{ github.actor }} | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| release_tag: | |
| description: "Tag to release from. This is the tag that contains the source code for the release." | |
| required: true | |
| type: string | |
| release_package_base: | |
| description: "Release Langflow Base" | |
| required: true | |
| type: boolean | |
| default: false | |
| release_package_main: | |
| description: "Release Langflow" | |
| required: true | |
| type: boolean | |
| default: false | |
| release_lfx: | |
| description: "Release LFX package (manually triggered)" | |
| required: false | |
| type: boolean | |
| default: false | |
| release_sdk: | |
| description: "Release langflow-sdk package (required when releasing LFX)" | |
| required: false | |
| type: boolean | |
| default: false | |
| release_bundles: | |
| description: "Release every src/bundles/* package (required when releasing main, since main pins exact bundle versions)" | |
| required: false | |
| type: boolean | |
| default: false | |
| build_docker_base: | |
| description: "Build Docker Image for Langflow Base" | |
| required: true | |
| type: boolean | |
| default: false | |
| build_docker_main: | |
| description: "Build Docker Image for Langflow" | |
| required: true | |
| type: boolean | |
| default: false | |
| pre_release: | |
| description: "Pre-release" | |
| required: false | |
| type: boolean | |
| default: false | |
| create_release: | |
| description: "Whether to create a gh release" | |
| required: false | |
| type: boolean | |
| default: false | |
| dry_run: | |
| description: "Dry run mode - disables all pushes to external services (PyPI, Docker, GitHub releases)" | |
| required: false | |
| type: boolean | |
| default: true | |
| run_pip_check: | |
| description: "Whether to run pip check - ONLY SET TO FALSE ONCE YOU HAVE ALREADY ATTEMPTED AND FAILED A RUN THEN MADE SURE DEPS DO NOT CAUSE FAILURES" | |
| required: false | |
| type: boolean | |
| default: true | |
| jobs: | |
| echo-inputs: | |
| name: Echo Workflow Inputs | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Echo workflow inputs | |
| run: | | |
| echo "release_tag: ${{ inputs.release_tag }}" | |
| 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 "release_bundles: ${{ inputs.release_bundles }}" | |
| echo "build_docker_base: ${{ inputs.build_docker_base }}" | |
| echo "build_docker_main: ${{ inputs.build_docker_main }}" | |
| echo "pre_release: ${{ inputs.pre_release }}" | |
| echo "create_release: ${{ inputs.create_release }}" | |
| echo "dry_run: ${{ inputs.dry_run }}" | |
| validate-tag: | |
| name: Validate Tag Input | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 # Fetch all history - required for tags (?) | |
| - name: Validate that input is a tag, not a branch | |
| run: | | |
| # Check if the input exists as a tag | |
| if ! git tag -l | grep -q "^${{ inputs.release_tag }}$"; then | |
| echo "Error: '${{ inputs.release_tag }}' is not a valid tag." | |
| echo "Available tags:" | |
| git tag -l | head -20 | |
| exit 1 | |
| fi | |
| # Check if the input also exists as a branch (warn if so, but don't fail) | |
| if git branch -r | grep -q "origin/${{ inputs.release_tag }}$"; then | |
| echo "Tag '${{ inputs.release_tag }}' also exists as a branch. Exiting out of caution." | |
| exit 1 | |
| fi | |
| echo "Validated: '${{ inputs.release_tag }}' is a valid tag." | |
| validate-tag-format: | |
| name: Validate Tag Format and Check for Duplicates | |
| runs-on: ubuntu-latest | |
| needs: [validate-tag] | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Validate Tag Has v Prefix | |
| run: | | |
| TAG="${{ inputs.release_tag }}" | |
| if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "❌ Error: Tag must start with 'v' and follow semver format (v1.2.3)" | |
| echo " Got: $TAG" | |
| echo "" | |
| echo "This is required to ensure GitHub's generateReleaseNotes uses the correct base comparison." | |
| exit 1 | |
| fi | |
| echo "✅ Tag format is valid: $TAG" | |
| - name: Check for Duplicate Tag Without v Prefix | |
| run: | | |
| TAG="${{ inputs.release_tag }}" | |
| TAG_WITHOUT_V="${TAG#v}" | |
| if git rev-parse "$TAG_WITHOUT_V" >/dev/null 2>&1; then | |
| echo "❌ Error: Duplicate tag without 'v' prefix exists: $TAG_WITHOUT_V" | |
| echo " This will cause release notes to use the wrong base comparison." | |
| echo "" | |
| echo " The tag '$TAG_WITHOUT_V' points to commit: $(git rev-parse --short $TAG_WITHOUT_V)" | |
| echo " The tag '$TAG' points to commit: $(git rev-parse --short $TAG)" | |
| echo "" | |
| echo " To fix this, delete the duplicate tag:" | |
| echo " git push origin :refs/tags/$TAG_WITHOUT_V" | |
| exit 1 | |
| fi | |
| echo "✅ No duplicate tag found" | |
| validate-dependencies: | |
| name: Validate Release Dependencies | |
| runs-on: ubuntu-latest | |
| 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 | |
| run: | | |
| if [ "${{ inputs.release_package_main }}" = "true" ] && [ "${{ inputs.release_package_base }}" = "false" ]; then | |
| echo "Error: Cannot release Langflow Main without releasing Langflow Base." | |
| echo "Please enable 'release_package_base' or disable 'release_package_main'." | |
| 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 | |
| if [ "${{ inputs.release_package_main }}" = "true" ] && [ "${{ inputs.release_bundles }}" = "false" ]; then | |
| echo "Error: Cannot release Langflow Main without releasing bundles." | |
| echo "Langflow Main pins exact bundle versions (lfx-arxiv, lfx-duckduckgo, ...). Please enable 'release_bundles' or disable 'release_package_main'." | |
| exit 1 | |
| fi | |
| echo "✅ Release dependencies validated successfully." | |
| determine-base-version: | |
| name: Determine Base Version | |
| needs: [validate-tag, validate-dependencies] | |
| 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: Install the project | |
| run: uv sync | |
| - name: Determine version | |
| id: version | |
| run: | | |
| version=$(python3 -c " | |
| import tomllib, pathlib | |
| data = tomllib.loads(pathlib.Path('src/backend/base/pyproject.toml').read_text()) | |
| print(data['project']['version']) | |
| ") | |
| echo "Base version from pyproject.toml: $version" | |
| if [ ${{inputs.pre_release}} == "true" ]; then | |
| last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/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 base pre-release version: $last_released_version" | |
| echo "Base pre-release version to be released: $version" | |
| else | |
| last_released_version=$(curl -s "https://pypi.org/pypi/langflow-base/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1) | |
| echo "Latest base release version: $last_released_version" | |
| fi | |
| if [ "$version" = "$last_released_version" ]; then | |
| echo "Base 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 | |
| determine-main-version: | |
| name: Determine Main Version | |
| needs: [validate-tag, validate-dependencies] | |
| 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: Install the project | |
| run: uv sync | |
| - name: Determine version | |
| id: version | |
| run: | | |
| version=$(uv tree | grep -E '^langflow(-nightly)?[[:space:]]' | awk '{print $2}' | sed 's/^v//') | |
| echo "Main version from pyproject.toml: $version" | |
| if [ ${{inputs.pre_release}} == "true" ]; then | |
| last_released_version=$(curl -s "https://pypi.org/pypi/langflow/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 main pre-release version: $last_released_version" | |
| echo "Main pre-release version to be released: $version" | |
| else | |
| last_released_version=$(curl -s "https://pypi.org/pypi/langflow/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1) | |
| echo "Latest main release version: $last_released_version" | |
| fi | |
| if [ "$version" = "$last_released_version" ]; then | |
| echo "Main 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 | |
| determine-lfx-version: | |
| name: Determine LFX Version | |
| needs: [validate-tag, validate-dependencies] | |
| 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: Install LFX dependencies | |
| run: uv sync --dev --package lfx | |
| - name: Determine version | |
| id: version | |
| run: | | |
| version=$(uv tree | grep 'lfx' | awk '{print $3}' | sed 's/^v//' | head -n 2 | xargs) | |
| echo "LFX version from pyproject.toml: $version" | |
| if [ ${{inputs.pre_release}} == "true" ]; then | |
| last_released_version=$(curl -s "https://pypi.org/pypi/lfx/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 LFX pre-release version: $last_released_version" | |
| echo "LFX pre-release version to be released: $version" | |
| else | |
| last_released_version=$(curl -s "https://pypi.org/pypi/lfx/json" | jq -r '.releases | keys | .[]' | grep -vE '(a|b|rc|dev|alpha|beta)' | sort -V | tail -n 1) | |
| echo "Latest LFX release version: $last_released_version" | |
| fi | |
| if [ "$version" = "$last_released_version" ]; then | |
| echo "LFX 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 | |
| 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: Install SDK dependencies | |
| run: uv sync --dev --package langflow-sdk | |
| - 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] | |
| uses: ./.github/workflows/ci.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| python-versions: "['3.10', '3.11', '3.12', '3.13', '3.14']" | |
| frontend-tests-folder: "tests" | |
| release: true | |
| run-all-tests: true | |
| runs-on: ubuntu-latest | |
| secrets: inherit | |
| 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 | |
| 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: 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 }}" | |
| # importlib.metadata returns the PEP 440 canonical form, so normalize | |
| # the expected version the same way the wheel filename check does. | |
| NORMALIZED_VERSION=$(echo "$EXPECTED_VERSION" | sed 's/\.rc/rc/g; s/\.a/a/g; s/\.b/b/g; s/\.dev/dev/g') | |
| ./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 == '$NORMALIZED_VERSION', f'Installed version {installed_version} does not match expected version $NORMALIZED_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 | |
| if: ${{ inputs.pre_release }} | |
| run: | | |
| VERSION="${{ needs.determine-lfx-version.outputs.version }}" | |
| echo "Setting pre-release version to: $VERSION" | |
| cd src/lfx | |
| # Update version in lfx pyproject.toml | |
| sed -i.bak "s/^version = .*/version = \"$VERSION\"/" pyproject.toml | |
| # 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 | |
| rm -rf dist/ | |
| uv build --wheel --out-dir dist | |
| - name: Verify built version | |
| run: | | |
| EXPECTED_VERSION="${{ needs.determine-lfx-version.outputs.version }}" | |
| WHEEL_FILE=$(ls src/lfx/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 CLI | |
| run: | | |
| cd src/lfx | |
| # 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: | |
| name: dist-lfx | |
| path: src/lfx/dist | |
| build-base: | |
| name: Build Langflow Base | |
| 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 | |
| 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.12" | |
| prune-cache: false | |
| - name: Download LFX artifact | |
| uses: actions/download-artifact@v7 | |
| 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: Install dependencies with local LFX and SDK wheels | |
| run: | | |
| # Create virtual environment | |
| uv venv | |
| # 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 | |
| if: ${{ inputs.run_pip_check }} | |
| run: uv pip check | |
| - name: Set version for pre-release | |
| if: ${{ inputs.pre_release }} | |
| run: | | |
| VERSION="${{ needs.determine-base-version.outputs.version }}" | |
| echo "Setting pre-release version to: $VERSION" | |
| cd src/backend/base | |
| # Update version in pyproject.toml | |
| sed -i.bak "s/^version = .*/version = \"$VERSION\"/" pyproject.toml | |
| # Verify the change | |
| echo "Updated pyproject.toml version:" | |
| grep "^version" pyproject.toml | |
| - name: Update lfx dependency for pre-release | |
| if: ${{ inputs.pre_release }} | |
| run: | | |
| LFX_VERSION="${{ needs.determine-lfx-version.outputs.version }}" | |
| echo "Updating lfx dependency to allow pre-release version: $LFX_VERSION" | |
| cd src/backend/base | |
| # Extract current lfx constraint from pyproject.toml | |
| CURRENT_CONSTRAINT=$(grep -E '^\s*"lfx' pyproject.toml | head -1) | |
| echo "Current constraint: $CURRENT_CONSTRAINT" | |
| # Extract the major.minor version (e.g., "1.10" from "~=1.10.0", or from the | |
| # lower bound of the range form ">=1.10.0,<1.11.dev0"). Anchor to the FIRST | |
| # version in the line so a greedy match can't pick up the range's upper bound. | |
| MAJOR_MINOR=$(echo "$CURRENT_CONSTRAINT" | sed -E 's/^[^0-9]*([0-9]+\.[0-9]+).*/\1/') | |
| MAJOR=${MAJOR_MINOR%.*} | |
| MINOR=${MAJOR_MINOR#*.} | |
| NEXT_MINOR=$((MINOR + 1)) | |
| # Create new constraint: >=LFX_VERSION,<MAJOR.(MINOR+1).dev0 | |
| NEW_CONSTRAINT="\"lfx>=$LFX_VERSION,<$MAJOR.$NEXT_MINOR.dev0\"" | |
| echo "New constraint: $NEW_CONSTRAINT" | |
| # Replace the constraint | |
| sed -i.bak "s|\"lfx[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml | |
| # Verify the change | |
| echo "Updated lfx dependency:" | |
| grep "lfx" pyproject.toml | |
| - name: Build project for distribution | |
| run: make build base=true args="--wheel" | |
| - name: Verify built version | |
| run: | | |
| EXPECTED_VERSION="${{ needs.determine-base-version.outputs.version }}" | |
| WHEEL_FILE=$(ls dist/*.whl 2>/dev/null || ls src/backend/base/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 CLI | |
| run: | | |
| # TODO: Unsure why the whl is not built in src/backend/base/dist | |
| mkdir src/backend/base/dist | |
| mv dist/*.whl src/backend/base/dist | |
| uv pip install src/backend/base/dist/*.whl | |
| uv run python -m langflow run --host localhost --port 7860 --backend-only & | |
| SERVER_PID=$! | |
| # Wait for the server to start | |
| timeout 120 bash -c 'until curl -f http://localhost:7860/api/v1/auto_login; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1) | |
| # Terminate the server | |
| kill $SERVER_PID || (echo "Failed to terminate the server" && exit 1) | |
| sleep 20 # give the server some time to terminate | |
| # Check if the server is still running | |
| if kill -0 $SERVER_PID 2>/dev/null; then | |
| echo "Failed to terminate the server" | |
| exit 0 | |
| else | |
| echo "Server terminated successfully" | |
| fi | |
| # PyPI publishing moved to after cross-platform testing | |
| - name: Upload Artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: dist-base | |
| path: src/backend/base/dist | |
| build-main: | |
| name: Build Langflow Main | |
| needs: | |
| [ | |
| build-base, | |
| build-lfx, | |
| build-sdk, | |
| determine-base-version, | |
| determine-main-version, | |
| determine-lfx-version, | |
| ] | |
| 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 | |
| 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.12" | |
| prune-cache: false | |
| - name: Download LFX artifact | |
| uses: actions/download-artifact@v7 | |
| 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: | |
| name: dist-base | |
| path: ./base-dist | |
| - name: Install dependencies with local wheels | |
| run: | | |
| # Create virtual environment | |
| uv venv | |
| # Install using pip with local wheel directories as find-links | |
| 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 | |
| if: ${{ inputs.run_pip_check }} | |
| run: uv pip check | |
| - name: Set version for pre-release | |
| if: ${{ inputs.pre_release }} | |
| run: | | |
| VERSION="${{ needs.determine-main-version.outputs.version }}" | |
| echo "Setting main pre-release version to: $VERSION" | |
| # Update version in main pyproject.toml | |
| sed -i.bak "s/^version = .*/version = \"$VERSION\"/" pyproject.toml | |
| # Verify the change | |
| echo "Updated pyproject.toml version:" | |
| grep "^version" pyproject.toml | |
| - name: Update langflow-base dependency for pre-release | |
| if: ${{ inputs.pre_release }} | |
| run: | | |
| BASE_VERSION="${{ needs.determine-base-version.outputs.version }}" | |
| echo "Base version for pre-release: $BASE_VERSION" | |
| # Extract current langflow-base constraint from pyproject.toml | |
| CURRENT_CONSTRAINT=$(grep -E '^\s*"langflow-base' pyproject.toml | head -1) | |
| echo "Current constraint: $CURRENT_CONSTRAINT" | |
| # Extract the major.minor version (e.g., "0.8" from "~=0.8.0") | |
| MAJOR_MINOR=$(echo "$CURRENT_CONSTRAINT" | sed -E 's/.*[~>=<]+([0-9]+\.[0-9]+).*/\1/') | |
| NEXT_MAJOR=$((${MAJOR_MINOR%.*} + 1)) | |
| # Create new constraint: >=BASE_VERSION,<NEXT_MAJOR.dev0 (preserve [complete] extra) | |
| NEW_CONSTRAINT="\"langflow-base[complete]>=$BASE_VERSION,<$NEXT_MAJOR.dev0\"" | |
| echo "New constraint: $NEW_CONSTRAINT" | |
| # Replace the constraint | |
| sed -i.bak "s|\"langflow-base[^\"]*\"|$NEW_CONSTRAINT|" pyproject.toml | |
| # Verify the change | |
| echo "Updated dependency:" | |
| grep "langflow-base" pyproject.toml | |
| - name: Build project for pre-release distribution | |
| if: ${{ inputs.pre_release }} | |
| run: make build pre=true args="--no-sources --wheel" | |
| - name: Build project for distribution | |
| if: ${{ !inputs.pre_release }} | |
| run: make build main=true args="--no-sources --wheel" | |
| - name: Verify built version | |
| run: | | |
| EXPECTED_VERSION="${{ needs.determine-main-version.outputs.version }}" | |
| WHEEL_FILE=$(ls 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 CLI | |
| run: | | |
| uv pip install dist/*.whl | |
| uv run python -m langflow run --host localhost --port 7860 --backend-only & | |
| SERVER_PID=$! | |
| # Wait for the server to start | |
| timeout 120 bash -c 'until curl -f http://localhost:7860/health_check; do sleep 2; done' || (echo "Server did not start in time" && kill $SERVER_PID && exit 1) | |
| # Terminate the server | |
| kill $SERVER_PID || (echo "Failed to terminate the server" && exit 1) | |
| sleep 20 # give the server some time to terminate | |
| # Check if the server is still running | |
| if kill -0 $SERVER_PID 2>/dev/null; then | |
| echo "Failed to terminate the server" | |
| exit 0 | |
| else | |
| echo "Server terminated successfully" | |
| fi | |
| # PyPI publishing moved to after cross-platform testing | |
| - name: Upload Artifact | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: dist-main | |
| path: dist | |
| build-bundles: | |
| name: Build Langflow Bundles | |
| needs: [build-lfx, determine-lfx-version] | |
| if: | | |
| always() && | |
| !cancelled() && | |
| inputs.release_bundles && | |
| needs.build-lfx.result == 'success' | |
| 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 }} | |
| - 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: Install the project | |
| run: uv sync | |
| - name: Relax bundle lfx floor for pre-release | |
| if: ${{ inputs.pre_release }} | |
| run: | | |
| # Bundles floor lfx at the release line (e.g. lfx>=1.10.0). A pre-release | |
| # such as 1.10.0rc0 sorts BELOW 1.10.0 under PEP 440, so it fails that | |
| # floor and the cross-platform install test cannot resolve. Mirror what | |
| # build-base / build-main / build-lfx already do for pre-release: rewrite | |
| # the floor to the exact pre-release lfx version, preserving the bundle's | |
| # wide <2.0.0 BUNDLE_API cap. Stable source stays at >=1.10.0 -- only the | |
| # RC wheels are relaxed, at build time. | |
| LFX_VERSION="${{ needs.determine-lfx-version.outputs.version }}" | |
| echo "Relaxing bundle lfx floor to pre-release version: $LFX_VERSION" | |
| for pyproject in src/bundles/*/pyproject.toml; do | |
| sed -i.bak -E "s|\"lfx>=[^\"]*\"|\"lfx>=${LFX_VERSION},<2.0.0\"|" "$pyproject" | |
| rm -f "${pyproject}.bak" | |
| grep -E '"lfx>=' "$pyproject" | sed "s|^| ${pyproject}: |" | |
| done | |
| - 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/ | |
| - name: Upload bundles artifact | |
| if: steps.build.outputs.bundles-found == '1' | |
| uses: actions/upload-artifact@v6 | |
| with: | |
| name: dist-bundles | |
| path: bundles-dist | |
| test-cross-platform: | |
| name: Test Cross-Platform Installation | |
| needs: [build-base, build-main, build-lfx, build-sdk, build-bundles] | |
| if: | | |
| always() && | |
| !cancelled() && | |
| (needs.build-base.result == 'success' || needs.build-main.result == 'success' || needs.build-lfx.result == 'success') | |
| uses: ./.github/workflows/cross-platform-test.yml | |
| with: | |
| 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' || '' }} | |
| bundles-artifact-name: ${{ needs.build-bundles.result == 'success' && needs.build-bundles.outputs.bundles-found == '1' && 'dist-bundles' || '' }} | |
| pre_release: ${{ inputs.pre_release }} | |
| publish-base: | |
| name: Publish Langflow Base to PyPI | |
| 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 | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: dist-base | |
| path: src/backend/base/dist | |
| - name: Setup Environment | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: false | |
| python-version: "3.13" | |
| - name: Publish base to PyPI | |
| if: ${{ !inputs.dry_run }} | |
| env: | |
| UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} | |
| run: | | |
| cd src/backend/base && uv publish dist/*.whl | |
| publish-bundles: | |
| name: Publish Bundles to PyPI | |
| needs: [build-bundles, test-cross-platform, ci, publish-lfx] | |
| if: | | |
| always() && | |
| !cancelled() && | |
| inputs.release_bundles && | |
| needs.build-bundles.result == 'success' && | |
| needs.build-bundles.outputs.bundles-found == '1' && | |
| needs.test-cross-platform.result == 'success' && | |
| needs.ci.result == 'success' && | |
| (needs.publish-lfx.result == 'success' || needs.publish-lfx.result == 'skipped') | |
| 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: "3.13" | |
| - name: Publish bundles to PyPI | |
| if: ${{ !inputs.dry_run }} | |
| 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" | |
| # Tolerate "already exists" so reruns -- or a bundle whose version is | |
| # unchanged and already on PyPI -- do not fail the job. Matches the | |
| # duplicate-tolerant publish in release_bundles.yml. | |
| 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 | |
| publish-main: | |
| name: Publish Langflow Main to PyPI | |
| if: | | |
| always() && | |
| !cancelled() && | |
| inputs.release_package_main && | |
| needs.build-main.result == 'success' && | |
| needs.test-cross-platform.result == 'success' && | |
| needs.publish-base.result == 'success' && | |
| needs.ci.result == 'success' && | |
| (needs.publish-bundles.result == 'success' || needs.publish-bundles.result == 'skipped') | |
| needs: [build-main, test-cross-platform, publish-base, publish-bundles, ci] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Download main artifact | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: dist-main | |
| path: dist | |
| - name: Setup Environment | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: false | |
| python-version: "3.13" | |
| - name: Publish main to PyPI | |
| if: ${{ !inputs.dry_run }} | |
| env: | |
| UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} | |
| 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 | |
| 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 | |
| uses: actions/download-artifact@v7 | |
| with: | |
| name: dist-lfx | |
| path: src/lfx/dist | |
| - name: Setup Environment | |
| uses: astral-sh/setup-uv@v6 | |
| with: | |
| enable-cache: false | |
| python-version: "3.13" | |
| - name: Publish LFX to PyPI | |
| if: ${{ !inputs.dry_run }} | |
| env: | |
| UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} | |
| run: | | |
| cd src/lfx && uv publish dist/*.whl | |
| call_docker_build_base: | |
| name: Call Docker Build Workflow for Langflow Base | |
| if: ${{ inputs.build_docker_base }} | |
| needs: [ci] | |
| uses: ./.github/workflows/docker-build-v2.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| release_type: base | |
| pre_release: ${{ inputs.pre_release }} | |
| push_to_registry: ${{ !inputs.dry_run }} | |
| secrets: inherit | |
| call_docker_build_main: | |
| name: Call Docker Build Workflow for Langflow | |
| if: ${{ inputs.build_docker_main }} | |
| needs: [ci] | |
| uses: ./.github/workflows/docker-build-v2.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| release_type: main | |
| pre_release: ${{ inputs.pre_release }} | |
| push_to_registry: ${{ !inputs.dry_run }} | |
| secrets: inherit | |
| call_docker_build_main_backend: | |
| name: Call Docker Build Workflow for Langflow Backend | |
| if: ${{ inputs.build_docker_main && !inputs.dry_run }} | |
| needs: [call_docker_build_main] | |
| uses: ./.github/workflows/docker-build-v2.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| release_type: main-backend | |
| pre_release: ${{ inputs.pre_release }} | |
| push_to_registry: ${{ !inputs.dry_run }} | |
| secrets: inherit | |
| call_docker_build_main_frontend: | |
| name: Call Docker Build Workflow for Langflow Frontend | |
| if: ${{ inputs.build_docker_main && !inputs.dry_run }} | |
| needs: [call_docker_build_main] | |
| uses: ./.github/workflows/docker-build-v2.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| release_type: main-frontend | |
| pre_release: ${{ inputs.pre_release }} | |
| push_to_registry: ${{ !inputs.dry_run }} | |
| secrets: inherit | |
| call_docker_build_main_ep: | |
| name: Call Docker Build Workflow for Langflow with Entrypoint | |
| if: ${{ inputs.build_docker_main }} | |
| needs: [ci] | |
| uses: ./.github/workflows/docker-build-v2.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| release_type: main-ep | |
| pre_release: ${{ inputs.pre_release }} | |
| push_to_registry: ${{ !inputs.dry_run }} | |
| secrets: inherit | |
| call_docker_build_main_all: | |
| name: Call Docker Build Workflow for langflow-all | |
| if: ${{ inputs.build_docker_main }} | |
| needs: [ci] | |
| uses: ./.github/workflows/docker-build-v2.yml | |
| with: | |
| ref: ${{ inputs.release_tag }} | |
| release_type: main-all | |
| pre_release: ${{ inputs.pre_release }} | |
| push_to_registry: ${{ !inputs.dry_run }} | |
| secrets: inherit | |
| create_release: | |
| name: Create Release | |
| runs-on: ubuntu-latest | |
| needs: | |
| [determine-main-version, build-main, publish-main, validate-tag-format] | |
| if: | | |
| always() && | |
| !cancelled() && | |
| !inputs.dry_run && | |
| inputs.create_release && | |
| needs.build-main.result == 'success' && | |
| needs.publish-main.result == 'success' && | |
| needs.validate-tag-format.result == 'success' | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| name: dist-main | |
| path: dist | |
| # The release must attach to the dispatched v-prefixed tag. Passing the | |
| # bare version as `tag` made GitHub mint a new lightweight tag at the | |
| # default-branch HEAD — the wrong commit, still carrying the previous | |
| # version (main only adopts the new version via the post-release | |
| # back-merge). Pre-releases keep their computed tag (e.g. 1.10.0rc1), | |
| # but `commit` pins any newly minted tag to the release commit. | |
| - name: Resolve release commit | |
| id: release_commit | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| sha=$(gh api "repos/${{ github.repository }}/commits/${{ inputs.release_tag }}" --jq '.sha') | |
| echo "Release tag '${{ inputs.release_tag }}' resolves to commit $sha" | |
| echo "sha=$sha" >> "$GITHUB_OUTPUT" | |
| - name: Create Release | |
| uses: ncipollo/release-action@v1 | |
| with: | |
| artifacts: dist/* | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| draft: false | |
| generateReleaseNotes: true | |
| prerelease: ${{ inputs.pre_release }} | |
| tag: ${{ inputs.pre_release && needs.determine-main-version.outputs.version || inputs.release_tag }} | |
| name: ${{ needs.determine-main-version.outputs.version }} | |
| commit: ${{ steps.release_commit.outputs.sha }} | |
| allowUpdates: true | |
| updateOnlyUnreleased: false |