Files
langflow/.github/workflows/release-lfx.yml
Eric Hare 2df7c221f4 fix(ci): resolve validate-version output in release-lfx changelog link (1.10.1) (#13611)
fix(ci): resolve validate-version output in release-lfx changelog link

The create-release job references
needs.validate-version.outputs.current_version in its generated release
notes (the Full Changelog compare link), but validate-version was not in
the job's needs array, so the expression evaluated empty and the link
rendered as compare/v...lfx-vX.Y.Z (broken base).

Add validate-version to the create-release needs. This adds no real
serialization: create-release already waits on release-lfx, which
transitively requires validate-version via run-tests, and the job's
always() if-condition is unaffected.

Flagged by actionlint: property "validate-version" is not defined in
object type {build-docker, release-lfx}.
2026-06-10 08:42:21 -07:00

406 lines
13 KiB
YAML

name: LFX Release
run-name: LFX Release ${{ github.event.inputs.version || 'dev' }} by @${{ github.actor }}
on:
workflow_dispatch:
inputs:
version:
description: "Version to release (e.g., 0.1.0)"
required: true
type: string
publish_pypi:
description: "Publish to PyPI"
required: true
type: boolean
default: true
build_docker:
description: "Build and publish Docker images"
required: true
type: boolean
default: true
pre_release:
description: "Mark as pre-release"
required: false
type: boolean
default: false
create_github_release:
description: "Create GitHub release"
required: true
type: boolean
default: true
env:
PYTHON_VERSION: "3.13"
permissions:
contents: write
packages: write
jobs:
validate-version:
name: Validate Version
runs-on: ubuntu-latest
outputs:
should_release: ${{ steps.check.outputs.should_release }}
current_version: ${{ steps.check.outputs.current_version }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- 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: Check version
id: check
run: |
cd src/lfx
# Use uv tree to get package info, consistent with nightly workflow
name=$(uv tree | grep 'lfx' | head -n 1 | awk '{print $1}')
version=$(uv tree | grep 'lfx' | head -n 1 | awk '{print $2}')
# Strip leading 'v' if present
version=$(echo $version | sed 's/^v//')
echo "current_version=$version" >> $GITHUB_OUTPUT
if [ "$version" != "${{ github.event.inputs.version }}" ]; then
echo "❌ Version mismatch: package has $version but input is ${{ github.event.inputs.version }}"
echo "Please update the version in pyproject.toml first"
echo "should_release=false" >> $GITHUB_OUTPUT
exit 1
fi
# Check if version already exists on PyPI
if curl -s "https://pypi.org/pypi/lfx/json" | jq -r '.releases | keys[]' | grep -q "^${{ github.event.inputs.version }}$"; then
echo "❌ Version ${{ github.event.inputs.version }} already exists on PyPI"
echo "should_release=false" >> $GITHUB_OUTPUT
exit 1
fi
echo "✅ Version ${{ github.event.inputs.version }} is valid and not yet released"
echo "should_release=true" >> $GITHUB_OUTPUT
run-tests:
name: Run Tests
needs: validate-version
if: needs.validate-version.outputs.should_release == 'true'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Setup Environment
uses: astral-sh/setup-uv@v6
with:
enable-cache: true
cache-dependency-glob: "uv.lock"
python-version: ${{ matrix.python-version }}
prune-cache: false
- name: Run LFX tests
run: |
cd src/lfx
make test
- name: Test CLI installation
run: |
cd src/lfx
uv pip install .
uv run lfx --help
uv run lfx run --help
uv run lfx serve --help
release-lfx:
name: Build and Release LFX
needs: [validate-version, run-tests]
runs-on: ubuntu-latest
outputs:
version: ${{ steps.check-version.outputs.version }}
steps:
- name: Checkout code
uses: actions/checkout@v6
- 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 LFX dependencies
run: uv sync --dev --package lfx
- name: Verify Version
id: check-version
run: |
cd src/lfx
# Use uv tree to get package info, consistent with nightly workflow
name=$(uv tree | grep 'lfx' | head -n 1 | awk '{print $1}')
version=$(uv tree | grep 'lfx' | head -n 1 | awk '{print $2}')
# Verify package name
if [ "$name" != "lfx" ]; then
echo "Package name $name does not match lfx. Exiting the workflow."
exit 1
fi
# Strip leading 'v' if present
version=$(echo $version | sed 's/^v//')
# Verify version matches input
if [ "$version" != "${{ github.event.inputs.version }}" ]; then
echo "Version $version does not match input ${{ github.event.inputs.version }}. Exiting the workflow."
exit 1
fi
echo "version=$version" >> $GITHUB_OUTPUT
- name: Build distribution
run: |
cd src/lfx
rm -rf dist/
uv build --wheel --out-dir dist
- name: Check build artifacts
run: |
cd src/lfx
ls -la dist/
# Verify wheel contents
unzip -l dist/*.whl | grep -E "(lfx/__main__.py|lfx/cli/run.py|lfx/cli/commands.py)"
- name: Test installation from wheel
run: |
cd src/lfx
uv pip install dist/*.whl --force-reinstall
uv run lfx --help
echo "LFX CLI test completed successfully"
- name: Upload artifacts
uses: actions/upload-artifact@v6
with:
name: lfx-dist
path: src/lfx/dist/
retention-days: 5
- name: Publish to PyPI
if: github.event.inputs.publish_pypi == 'true'
env:
UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
run: |
cd src/lfx
uv publish dist/*.whl
build-docker:
name: Build Docker Images
needs: [validate-version, run-tests]
if: github.event.inputs.build_docker == 'true'
runs-on: ubuntu-latest
strategy:
matrix:
variant: [production, alpine]
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Docker System Info and Cleanup
run: |
echo "=== Docker System Usage Before Cleanup ==="
docker system df || true
docker buildx du || true
echo "=== Cleaning up Docker System ==="
docker system prune -af --volumes || true
docker buildx prune -af || true
echo "=== Docker System Usage After Cleanup ==="
docker system df || true
docker buildx du || true
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
langflowai/lfx
ghcr.io/langflow-ai/lfx
tags: |
type=raw,value=${{ github.event.inputs.version }}${{ matrix.variant == 'alpine' && '-alpine' || '' }}
type=raw,value=latest${{ matrix.variant == 'alpine' && '-alpine' || '' }},enable=${{ github.event.inputs.pre_release == 'false' }}
labels: |
org.opencontainers.image.title=LFX
org.opencontainers.image.description=Langflow Executor - CLI tool for running Langflow AI workflows
org.opencontainers.image.vendor=Langflow
org.opencontainers.image.version=${{ github.event.inputs.version }}
- name: Build and push Docker image
uses: docker/build-push-action@v6
with:
context: .
file: src/lfx/docker/Dockerfile${{ matrix.variant == 'alpine' && '.alpine' || '' }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
LFX_VERSION=${{ github.event.inputs.version }}
create-release:
name: Create GitHub Release
needs: [validate-version, release-lfx, build-docker]
if: always() && github.event.inputs.create_github_release == 'true' && needs.release-lfx.result == 'success'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Download artifacts
uses: actions/download-artifact@v7
with:
name: lfx-dist
path: dist/
- name: Generate release notes
id: notes
run: |
cat > release_notes.md << EOF
# LFX ${{ github.event.inputs.version }}
## 🚀 Installation
### PyPI
\`\`\`bash
pip install lfx==${{ github.event.inputs.version }}
# or
uv pip install lfx==${{ github.event.inputs.version }}
# or run without installing
uvx lfx@${{ github.event.inputs.version }} --help
\`\`\`
### Docker
\`\`\`bash
# Standard image
docker pull langflowai/lfx:${{ github.event.inputs.version }}
# Alpine image (smaller)
docker pull langflowai/lfx:${{ github.event.inputs.version }}-alpine
# Run a flow
docker run --rm -v \$(pwd):/app/data langflowai/lfx:${{ github.event.inputs.version }} lfx run flow.json --input-value "Hello"
\`\`\`
## 📦 What's New
<!-- Add release notes here -->
## 📋 Checksums
\`\`\`
$(cd dist && sha256sum *)
\`\`\`
---
**Full Changelog**: https://github.com/${{ github.repository }}/compare/v${{ needs.validate-version.outputs.current_version }}...lfx-v${{ github.event.inputs.version }}
EOF
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: lfx-v${{ github.event.inputs.version }}
# Pin the minted tag to the commit this release was built from;
# without it GitHub creates the tag at the default-branch HEAD.
target_commitish: ${{ github.sha }}
name: LFX ${{ github.event.inputs.version }}
body_path: release_notes.md
draft: false
prerelease: ${{ github.event.inputs.pre_release }}
files: |
dist/*
generate_release_notes: true
test-release:
name: Test Release
needs: [release-lfx, build-docker]
if: always() && (needs.release-lfx.result == 'success' || needs.build-docker.result == 'success')
runs-on: ubuntu-latest
steps:
- name: Wait for PyPI propagation
if: needs.release-lfx.result == 'success'
run: sleep 60
- name: Test PyPI installation
if: needs.release-lfx.result == 'success'
run: |
# Test installation using uv
uv pip install lfx==${{ github.event.inputs.version }}
uv run lfx --help
- name: Test Docker image
if: needs.build-docker.result == 'success'
run: |
# Test standard image
docker run --rm langflowai/lfx:${{ github.event.inputs.version }} lfx --help
# Test alpine image
docker run --rm langflowai/lfx:${{ github.event.inputs.version }}-alpine lfx --help
# Test with a simple flow
cat > test_flow.json << 'EOF'
{
"nodes": [],
"edges": []
}
EOF
docker run --rm -v $(pwd):/app/data langflowai/lfx:${{ github.event.inputs.version }} \
lfx run /app/data/test_flow.json --input-value "test" || true
notify:
name: Notify Release Status
needs: [create-release, test-release]
if: always()
runs-on: ubuntu-latest
steps:
- name: Notify success
if: needs.create-release.result == 'success'
run: |
echo "✅ LFX ${{ github.event.inputs.version }} released successfully!"
echo "PyPI: https://pypi.org/project/lfx/${{ github.event.inputs.version }}/"
echo "Docker Hub: https://hub.docker.com/r/langflowai/lfx/tags"
echo "GitHub Release: https://github.com/${{ github.repository }}/releases/tag/lfx-v${{ github.event.inputs.version }}"
- name: Notify failure
if: needs.create-release.result != 'success'
run: |
echo "❌ LFX ${{ github.event.inputs.version }} release failed!"
exit 1