diff --git a/.github/workflows/cross-platform-test-manual.yml b/.github/workflows/cross-platform-test-manual.yml new file mode 100644 index 000000000..1aa767fea --- /dev/null +++ b/.github/workflows/cross-platform-test-manual.yml @@ -0,0 +1,55 @@ +name: Manual Cross-Platform Test + +on: + workflow_dispatch: + inputs: + test-from-pypi: + description: "Test from PyPI instead of building from source" + type: boolean + default: false + langflow-version: + description: "Langflow version to test from PyPI (leave empty for latest)" + required: false + type: string + default: "" + test-timeout: + description: "Timeout for langflow server startup test (minutes)" + required: false + type: number + default: 5 + +jobs: + test-pypi-installation: + if: inputs.test-from-pypi == true + name: Test PyPI Installation + uses: ./.github/workflows/cross-platform-test-shared.yml + with: + install-method: "pypi" + test-timeout: ${{ inputs.test-timeout }} + langflow-version: ${{ inputs.langflow-version }} + + test-source-build: + if: inputs.test-from-pypi == false + name: Test Source Build and Install + uses: ./.github/workflows/cross-platform-test.yml + with: + base-artifact-name: "" + main-artifact-name: "" + test-timeout: ${{ inputs.test-timeout }} + + test-summary: + name: Test Summary + needs: [test-pypi-installation, test-source-build] + runs-on: ubuntu-latest + if: always() + steps: + - name: Check test results + run: | + if [ "${{ needs.test-pypi-installation.result }}" = "failure" ] || [ "${{ needs.test-source-build.result }}" = "failure" ]; then + echo "❌ Cross-platform tests failed" + exit 1 + elif [ "${{ needs.test-pypi-installation.result }}" = "success" ] || [ "${{ needs.test-source-build.result }}" = "success" ]; then + echo "✅ Cross-platform tests passed" + else + echo "ℹ️ No tests were run" + fi \ No newline at end of file diff --git a/.github/workflows/cross-platform-test-shared.yml b/.github/workflows/cross-platform-test-shared.yml new file mode 100644 index 000000000..86d12b7e4 --- /dev/null +++ b/.github/workflows/cross-platform-test-shared.yml @@ -0,0 +1,319 @@ +name: Shared Cross-Platform Test Logic + +on: + workflow_call: + inputs: + test-timeout: + description: "Timeout for langflow server startup test (minutes)" + required: false + type: number + default: 5 + install-method: + description: "Installation method: 'wheel' for local wheels, 'pypi' for PyPI packages" + required: true + type: string + langflow-version: + description: "Langflow version to install from PyPI (only used if install-method is 'pypi')" + required: false + type: string + default: "" + base-artifact-name: + description: "Name of the base package artifact (only used if install-method is 'wheel')" + required: false + type: string + default: "" + main-artifact-name: + description: "Name of the main package artifact (only used if install-method is 'wheel')" + required: false + type: string + default: "" + run-id: + description: "GitHub run ID to download artifacts from (leave empty for current run)" + required: false + type: string + default: "" + +jobs: + test-installation: + name: Install & Run - ${{ matrix.os }} ${{ matrix.arch }} ${{ matrix.python-version }} + runs-on: ${{ matrix.runner }} + strategy: + fail-fast: false + matrix: + include: + # Linux AMD64 + - os: linux + arch: amd64 + runner: ubuntu-latest + python-version: "3.10" + - os: linux + arch: amd64 + runner: ubuntu-latest + python-version: "3.13" + # macOS AMD64 + - os: macos + arch: amd64 + runner: macos-13 + python-version: "3.10" + - os: macos + arch: amd64 + runner: macos-13 + python-version: "3.13" + # macOS ARM64 (Apple Silicon) + - os: macos + arch: arm64 + runner: macos-latest + python-version: "3.10" + - os: macos + arch: arm64 + runner: macos-latest + python-version: "3.13" + # Windows AMD64 + - os: windows + arch: amd64 + runner: windows-latest + python-version: "3.10" + - os: windows + arch: amd64 + runner: windows-latest + python-version: "3.12" + + steps: + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + architecture: ${{ matrix.arch == 'amd64' && 'x64' || matrix.arch }} + + - name: Setup UV + uses: astral-sh/setup-uv@v6 + with: + enable-cache: false + + # Download artifacts for wheel installation + - name: Download base package artifact + if: inputs.install-method == 'wheel' + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.base-artifact-name }} + path: ./base-dist + + - name: Download main package artifact + if: inputs.install-method == 'wheel' + uses: actions/download-artifact@v4 + with: + name: ${{ inputs.main-artifact-name }} + path: ./main-dist + + - name: Create fresh virtual environment + run: | + uv venv test-env --seed + shell: bash + + # Wheel installation steps + - name: Install base package from wheel (Windows) + if: inputs.install-method == 'wheel' && matrix.os == 'windows' + run: | + ls -la ./base-dist/ + find ./base-dist -name "*.whl" -type f + WHEEL_FILE=$(find ./base-dist -name "*.whl" -type f | head -1) + if [ -n "$WHEEL_FILE" ]; then + uv pip install --python ./test-env/Scripts/python.exe "$WHEEL_FILE" + else + echo "No wheel file found in ./base-dist/" + exit 1 + fi + shell: bash + + - name: Install main package from wheel (Windows) + if: inputs.install-method == 'wheel' && matrix.os == 'windows' + run: | + ls -la ./main-dist/ + find ./main-dist -name "*.whl" -type f + WHEEL_FILE=$(find ./main-dist -name "*.whl" -type f | head -1) + if [ -n "$WHEEL_FILE" ]; then + uv pip install --python ./test-env/Scripts/python.exe "$WHEEL_FILE" + else + echo "No wheel file found in ./main-dist/" + exit 1 + fi + shell: bash + + - name: Install base package from wheel (Unix) + if: inputs.install-method == 'wheel' && matrix.os != 'windows' + run: | + ls -la ./base-dist/ + find ./base-dist -name "*.whl" -type f + WHEEL_FILE=$(find ./base-dist -name "*.whl" -type f | head -1) + if [ -n "$WHEEL_FILE" ]; then + uv pip install --python ./test-env/bin/python "$WHEEL_FILE" + else + echo "No wheel file found in ./base-dist/" + exit 1 + fi + shell: bash + + - name: Install main package from wheel (Unix) + if: inputs.install-method == 'wheel' && matrix.os != 'windows' + run: | + ls -la ./main-dist/ + find ./main-dist -name "*.whl" -type f + WHEEL_FILE=$(find ./main-dist -name "*.whl" -type f | head -1) + if [ -n "$WHEEL_FILE" ]; then + uv pip install --python ./test-env/bin/python "$WHEEL_FILE" + else + echo "No wheel file found in ./main-dist/" + exit 1 + fi + shell: bash + + # PyPI installation steps + - name: Install langflow from PyPI (Windows) + if: inputs.install-method == 'pypi' && matrix.os == 'windows' + run: | + if [ -n "${{ inputs.langflow-version }}" ]; then + uv pip install --python ./test-env/Scripts/python.exe langflow==${{ inputs.langflow-version }} + else + uv pip install --python ./test-env/Scripts/python.exe langflow + fi + shell: bash + + - name: Install langflow from PyPI (Unix) + if: inputs.install-method == 'pypi' && matrix.os != 'windows' + run: | + if [ -n "${{ inputs.langflow-version }}" ]; then + uv pip install --python ./test-env/bin/python langflow==${{ inputs.langflow-version }} + else + uv pip install --python ./test-env/bin/python langflow + fi + shell: bash + + # Install additional dependencies + - name: Install additional dependencies (Windows) + if: matrix.os == 'windows' + run: | + uv pip install --python ./test-env/Scripts/python.exe openai + shell: bash + + - name: Install additional dependencies (Unix) + if: matrix.os != 'windows' + run: | + uv pip install --python ./test-env/bin/python openai + shell: bash + + # Test steps + - name: Test CLI help command (Windows) + if: matrix.os == 'windows' + run: | + test-env\Scripts\python.exe -m langflow --help + shell: cmd + + - name: Test CLI help command (Unix) + if: matrix.os != 'windows' + run: | + ./test-env/bin/python -m langflow --help + shell: bash + + - name: Test server startup (Windows) + if: matrix.os == 'windows' + timeout-minutes: ${{ inputs.test-timeout }} + run: | + # Start server in background + $serverProcess = Start-Process -FilePath ".\test-env\Scripts\python.exe" -ArgumentList "-m", "langflow", "run", "--host", "localhost", "--port", "7860", "--backend-only" -PassThru -WindowStyle Hidden + + # Wait for server to be ready + $timeoutSeconds = ${{ inputs.test-timeout }} * 60 + $elapsed = 0 + do { + try { + $response = Invoke-WebRequest -Uri "http://localhost:7860/health_check" -UseBasicParsing -TimeoutSec 5 + if ($response.StatusCode -eq 200) { + Write-Host "✅ Server is ready on ${{ matrix.os }}-${{ matrix.arch }}" + break + } + } catch { + Start-Sleep -Seconds 5 + $elapsed += 5 + } + } while ($elapsed -lt $timeoutSeconds) + + if ($elapsed -ge $timeoutSeconds) { + Write-Host "❌ Server failed to start within timeout on ${{ matrix.os }}-${{ matrix.arch }}" + exit 1 + } + + # Stop the server process + Stop-Process -Id $serverProcess.Id -Force -ErrorAction SilentlyContinue + shell: powershell + + - name: Test server startup (Unix) + if: matrix.os != 'windows' + timeout-minutes: ${{ inputs.test-timeout }} + run: | + # Start server in background + ./test-env/bin/python -m langflow run --host localhost --port 7860 --backend-only & + SERVER_PID=$! + + # Wait for server to be ready (using bash loop instead of timeout command) + TIMEOUT_SECONDS=$((${{ inputs.test-timeout }} * 60)) + ELAPSED=0 + while [ $ELAPSED -lt $TIMEOUT_SECONDS ]; do + if curl -f http://localhost:7860/health_check >/dev/null 2>&1; then + echo "✅ Server is ready on ${{ matrix.os }}-${{ matrix.arch }}" + break + fi + sleep 5 + ELAPSED=$((ELAPSED + 5)) + done + + if [ $ELAPSED -ge $TIMEOUT_SECONDS ]; then + echo "❌ Server failed to start within timeout on ${{ matrix.os }}-${{ matrix.arch }}" + kill $SERVER_PID 2>/dev/null || true + exit 1 + fi + + # Clean shutdown + kill $SERVER_PID 2>/dev/null || true + sleep 5 + shell: bash + + - name: Test import in Python (Windows) + if: matrix.os == 'windows' + run: | + test-env\Scripts\python.exe -c " + try: + import langflow + print('✅ langflow import successful on ${{ matrix.os }}-${{ matrix.arch }}') + except Exception as e: + print(f'❌ langflow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}') + exit(1) + " + shell: cmd + + - name: Test import in Python (Unix) + if: matrix.os != 'windows' + run: | + ./test-env/bin/python -c " + try: + import langflow + print('✅ langflow import successful on ${{ matrix.os }}-${{ matrix.arch }}') + except Exception as e: + print(f'❌ langflow import failed on ${{ matrix.os }}-${{ matrix.arch }}: {e}') + exit(1) + " + shell: bash + + test-summary: + name: Cross-Platform Test Summary + needs: test-installation + runs-on: ubuntu-latest + if: always() + steps: + - name: Check test results + run: | + if [ "${{ needs.test-installation.result }}" != "success" ]; then + echo "❌ Cross-platform tests failed" + exit 1 + else + echo "✅ All cross-platform tests passed" + fi \ No newline at end of file diff --git a/.github/workflows/cross-platform-test.md b/.github/workflows/cross-platform-test.md new file mode 100644 index 000000000..008b3eada --- /dev/null +++ b/.github/workflows/cross-platform-test.md @@ -0,0 +1,105 @@ +# Ad-Hoc Cross-Platform Install Tests + +Quick guide for running cross-platform installation tests manually. + +## Available Tests + +### 1. Test from PyPI +Tests published langflow packages from PyPI across all platforms. + +**Via GitHub UI:** +1. Go to **Actions** → **Manual Cross-Platform Test** +2. Check **"Test from PyPI"** +3. Optionally specify a version (leave empty for latest) +4. Click **"Run workflow"** + +**Via CLI:** +```bash +# Test latest version +gh workflow run manual-cross-platform-test.yml -f test-from-pypi=true + +# Test specific version +gh workflow run manual-cross-platform-test.yml \ + -f test-from-pypi=true \ + -f langflow-version="1.0.18" +``` + +### 2. Test from Source +Builds and tests langflow from current branch source code. + +**Via GitHub UI:** +1. Go to **Actions** → **Manual Cross-Platform Test** +2. Leave **"Test from PyPI"** unchecked +3. Click **"Run workflow"** + +**Via CLI:** +```bash +# Test current branch +gh workflow run manual-cross-platform-test.yml -f test-from-pypi=false +``` + +## Platforms Tested + +- **Linux**: AMD64 +- **macOS**: Intel (AMD64), Apple Silicon (ARM64) +- **Windows**: AMD64 +- **Python versions**: + - **Linux & macOS**: 3.10 and 3.13 + - **Windows**: 3.10 and 3.12 (3.12 used instead of 3.13 for better stability) + +## What Gets Tested + +1. **Package Installation**: `uv pip install langflow` (PyPI) or local wheel installation +2. **Dependencies**: Additional packages like `openai` for full functionality +3. **CLI Help**: `langflow --help` +4. **Server Startup**: `langflow run --backend-only` with `/health_check` endpoint validation +5. **Python Import**: `import langflow` + +## Common Options + +```bash +# Extended timeout (10 minutes instead of default 5) +gh workflow run manual-cross-platform-test.yml \ + -f test-timeout=10 + +# Test specific PyPI version +gh workflow run manual-cross-platform-test.yml \ + -f test-from-pypi=true \ + -f langflow-version="1.0.18" +``` + +## Use Cases + +- **Before releases**: Verify current branch works on all platforms +- **After PyPI publish**: Confirm published packages install correctly +- **Debugging issues**: Test specific versions when users report problems +- **Development**: Quick cross-platform validation during feature work + +## Technical Details + +### Installation Methods +- **PyPI testing**: Uses `uv pip install` with official PyPI packages +- **Source testing**: Builds wheels from source, then installs locally +- **Dependencies**: Automatically installs additional packages (`openai`) for full functionality + +### Health Checking +- **Endpoint**: Uses `/health_check` for reliable server readiness validation +- **Validation**: Checks database connectivity and chat service functionality +- **Timeout**: Configurable timeout with proper cross-platform handling + +### Platform-Specific Optimizations +- **Windows**: Uses Python 3.12 for better package ecosystem stability +- **Unix**: Uses Python 3.13 for latest language features where stable +- **Virtual Environments**: Uses `uv venv --seed` for consistent pip availability + +### Workflow Architecture +- **Shared Logic**: Common test steps defined in `shared-cross-platform-test.yml` +- **DRY principle**: No code duplication between manual and automated workflows +- **Flexible**: Supports both wheel and PyPI installation methods through single workflow + +## Results + +- ✅ **Success**: All platforms pass installation and basic functionality +- ❌ **Failure**: One or more platforms fail (check logs for details) +- Each platform/Python combination runs independently +- **Parallel execution**: All platforms tested simultaneously for faster feedback \ No newline at end of file diff --git a/.github/workflows/cross-platform-test.yml b/.github/workflows/cross-platform-test.yml new file mode 100644 index 000000000..7b4f20fd8 --- /dev/null +++ b/.github/workflows/cross-platform-test.yml @@ -0,0 +1,109 @@ +name: Cross-Platform Installation Test + +on: + workflow_dispatch: + inputs: + base-artifact-name: + description: "Name of the base package artifact (leave empty to use latest from main branch)" + required: false + type: string + default: "" + main-artifact-name: + description: "Name of the main package artifact (leave empty to use latest from main branch)" + required: false + type: string + default: "" + test-timeout: + description: "Timeout for langflow server startup test (minutes)" + required: false + type: number + default: 5 + run-id: + description: "GitHub run ID to download artifacts from (leave empty for latest successful run)" + required: false + type: string + default: "" + workflow_call: + inputs: + base-artifact-name: + description: "Name of the base package artifact" + required: true + type: string + main-artifact-name: + description: "Name of the main package artifact" + required: true + type: string + test-timeout: + description: "Timeout for langflow server startup test (minutes)" + required: false + type: number + default: 5 + +jobs: + build-if-needed: + name: Build Packages (if no artifacts provided) + runs-on: ubuntu-latest + if: inputs.base-artifact-name == '' || inputs.main-artifact-name == '' + outputs: + base-artifact-name: ${{ steps.set-names.outputs.base-artifact-name }} + main-artifact-name: ${{ steps.set-names.outputs.main-artifact-name }} + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Setup Environment + uses: astral-sh/setup-uv@v6 + with: + enable-cache: true + cache-dependency-glob: "uv.lock" + python-version: "3.13" + - name: Install the project + run: uv sync + - name: Install frontend dependencies + run: make install_frontendci + - name: Build frontend + run: make build_frontend + - name: Build base package + run: make build_langflow_base args="--wheel" + - name: Build main package + run: make build_langflow args="--wheel" + - name: Upload base artifact + uses: actions/upload-artifact@v4 + with: + name: adhoc-dist-base + path: /home/runner/work/langflow/langflow/dist + - name: Upload main artifact + uses: actions/upload-artifact@v4 + with: + name: adhoc-dist-main + path: dist + - name: Set artifact names + id: set-names + run: | + echo "base-artifact-name=adhoc-dist-base" >> $GITHUB_OUTPUT + echo "main-artifact-name=adhoc-dist-main" >> $GITHUB_OUTPUT + + test-wheel-installation: + name: Test Wheel Installation + needs: [build-if-needed] + if: always() && (needs.build-if-needed.result == 'success' || needs.build-if-needed.result == 'skipped') + uses: ./.github/workflows/cross-platform-test-shared.yml + with: + install-method: "wheel" + test-timeout: ${{ inputs.test-timeout }} + base-artifact-name: ${{ inputs.base-artifact-name || needs.build-if-needed.outputs.base-artifact-name }} + main-artifact-name: ${{ inputs.main-artifact-name || needs.build-if-needed.outputs.main-artifact-name }} + + test-summary: + name: Cross-Platform Test Summary + needs: test-wheel-installation + runs-on: ubuntu-latest + if: always() + steps: + - name: Check test results + run: | + if [ "${{ needs.test-wheel-installation.result }}" != "success" ]; then + echo "❌ Cross-platform tests failed - PyPI upload blocked" + exit 1 + else + echo "✅ All cross-platform tests passed - PyPI upload can proceed" + fi \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab71fca72..b5e460eec 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -54,8 +54,8 @@ jobs: secrets: inherit - release-base: - name: Release Langflow Base + build-base: + name: Build Langflow Base needs: [ci] if: inputs.release_package_base == true runs-on: ubuntu-latest @@ -113,12 +113,9 @@ jobs: else echo "Server terminated successfully" fi - - name: Publish to PyPI - if: steps.check-version.outputs.skipped == 'false' - env: - UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: | - make publish base=true + + # PyPI publishing moved to after cross-platform testing + - name: Upload Artifact if: steps.check-version.outputs.skipped == 'false' uses: actions/upload-artifact@v4 @@ -126,10 +123,10 @@ jobs: name: dist-base path: src/backend/base/dist - release-main: - name: Release Langflow Main + build-main: + name: Build Langflow Main if: inputs.release_package_main == true - needs: [release-base] + needs: [build-base] runs-on: ubuntu-latest outputs: version: ${{ steps.check-version.outputs.version }} @@ -172,7 +169,7 @@ jobs: echo version=$version >> $GITHUB_OUTPUT fi - name: Wait for PyPI Propagation - if: needs.release-base.outputs.skipped == 'false' + if: needs.build-base.outputs.skipped == 'false' run: sleep 300 # wait for 5 minutes to ensure PyPI propagation - name: Build project for distribution @@ -194,25 +191,78 @@ jobs: else echo "Server terminated successfully" fi - - name: Publish to PyPI - env: - UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: | - make publish main=true + + # PyPI publishing moved to after cross-platform testing + - name: Upload Artifact uses: actions/upload-artifact@v4 with: name: dist-main path: dist + test-cross-platform: + name: Test Cross-Platform Installation + if: inputs.release_package_base == true || inputs.release_package_main == true + needs: [build-base, build-main] + uses: ./.github/workflows/cross-platform-test.yml + with: + base-artifact-name: "dist-base" + main-artifact-name: "dist-main" + test-timeout: 120 + + publish-base: + name: Publish Langflow Base to PyPI + if: inputs.release_package_base == true + needs: [build-base, test-cross-platform] + runs-on: ubuntu-latest + steps: + - name: Download base artifact + uses: actions/download-artifact@v4 + 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: needs.build-base.outputs.skipped == 'false' + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + run: | + cd src/backend/base && uv publish dist/*.whl + + publish-main: + name: Publish Langflow Main to PyPI + if: inputs.release_package_main == true + needs: [build-main, test-cross-platform, publish-base] + runs-on: ubuntu-latest + steps: + - name: Download main artifact + uses: actions/download-artifact@v4 + 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 + env: + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + run: | + uv publish dist/*.whl + call_docker_build_base: name: Call Docker Build Workflow for Langflow Base if: inputs.build_docker_base == true - needs: [release-base, release-main] + needs: [publish-base, publish-main] uses: ./.github/workflows/docker-build.yml with: - base_version: ${{ needs.release-base.outputs.version }} - main_version: ${{ needs.release-main.outputs.version }} + base_version: ${{ needs.publish-base.needs.build-base.outputs.version }} + main_version: ${{ needs.publish-main.needs.build-main.outputs.version }} release_type: base pre_release: ${{ inputs.pre_release }} secrets: inherit @@ -220,10 +270,10 @@ jobs: call_docker_build_main_ep: name: Call Docker Build Workflow for Langflow with Entrypoint if: inputs.build_docker_ep == true - needs: [release-main, call_docker_build_base] + needs: [publish-main, call_docker_build_base] uses: ./.github/workflows/docker-build.yml with: - main_version: ${{ needs.release-main.outputs.version }} + main_version: ${{ needs.publish-main.needs.build-main.outputs.version }} release_type: main-ep pre_release: False secrets: inherit @@ -231,10 +281,10 @@ jobs: call_docker_build_main: name: Call Docker Build Workflow for Langflow if: inputs.build_docker_main == true - needs: [release-main, call_docker_build_main_ep] + needs: [publish-main, call_docker_build_main_ep] uses: ./.github/workflows/docker-build.yml with: - main_version: ${{ needs.release-main.outputs.version }} + main_version: ${{ needs.publish-main.needs.build-main.outputs.version }} release_type: main pre_release: ${{ inputs.pre_release }} secrets: inherit @@ -242,10 +292,10 @@ jobs: call_docker_build_main_all: name: Call Docker Build Workflow for langflow-all if: inputs.build_docker_main == true - needs: [release-main] + needs: [publish-main] uses: ./.github/workflows/docker-build.yml with: - main_version: ${{ needs.release-main.outputs.version }} + main_version: ${{ needs.publish-main.needs.build-main.outputs.version }} release_type: main-all pre_release: ${{ inputs.pre_release }} secrets: inherit @@ -254,7 +304,7 @@ jobs: create_release: name: Create Release runs-on: ubuntu-latest - needs: release-main + needs: publish-main steps: - uses: actions/download-artifact@v4 with: @@ -268,5 +318,5 @@ jobs: draft: false generateReleaseNotes: true prerelease: ${{ inputs.pre_release }} - tag: ${{ needs.release-main.outputs.version }} + tag: ${{ needs.publish-main.needs.build-main.outputs.version }} commit: ${{ github.ref }} diff --git a/.github/workflows/release_nightly.yml b/.github/workflows/release_nightly.yml index a27905de1..09a38c64e 100644 --- a/.github/workflows/release_nightly.yml +++ b/.github/workflows/release_nightly.yml @@ -58,14 +58,15 @@ env: PYTHON_VERSION: "3.13" jobs: - release-nightly-base: - name: Release Langflow Nightly Base + build-nightly-base: + name: Build Langflow Nightly Base runs-on: ubuntu-latest defaults: run: shell: bash outputs: version: ${{ steps.verify.outputs.version }} + skipped: ${{ steps.verify.outputs.skipped }} steps: - name: Check out the code at a specific ref uses: actions/checkout@v4 @@ -126,22 +127,17 @@ jobs: echo "Server terminated successfully" fi - - name: Publish to PyPI - env: - POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }} - UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} - run: | - make publish base=true + # PyPI publishing moved to after cross-platform testing - name: Upload Artifact uses: actions/upload-artifact@v4 with: - name: dist-base + name: dist-nightly-base path: src/backend/base/dist - release-nightly-main: - name: Release Langflow Nightly Main - needs: [release-nightly-base] + build-nightly-main: + name: Build Langflow Nightly Main + needs: [build-nightly-base] runs-on: ubuntu-latest outputs: version: ${{ steps.verify.outputs.version }} @@ -181,6 +177,7 @@ jobs: version=$(echo $version | sed 's/^v//') echo "version=$version" >> $GITHUB_OUTPUT - name: Wait for PyPI Propagation + if: needs.build-nightly-base.outputs.skipped == 'false' run: sleep 300 # wait for 5 minutes to ensure PyPI propagation of base - name: Build project for distribution @@ -202,22 +199,73 @@ jobs: else echo "Server terminated successfully" fi + + # PyPI publishing moved to after cross-platform testing + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: dist-nightly-main + path: dist + + test-cross-platform: + name: Test Cross-Platform Installation + needs: [build-nightly-base, build-nightly-main] + uses: ./.github/workflows/cross-platform-test.yml + with: + base-artifact-name: "dist-nightly-base" + main-artifact-name: "dist-nightly-main" + test-timeout: 120 + + publish-nightly-base: + name: Publish Langflow Base Nightly to PyPI + needs: [build-nightly-base, test-cross-platform] + runs-on: ubuntu-latest + steps: + - name: Download base artifact + uses: actions/download-artifact@v4 + with: + name: dist-nightly-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: needs.build-nightly-base.outputs.skipped == 'false' + env: + POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }} + UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + run: | + make publish base=true + + publish-nightly-main: + name: Publish Langflow Main Nightly to PyPI + needs: [build-nightly-main, test-cross-platform, publish-nightly-base] + runs-on: ubuntu-latest + steps: + - name: Download main artifact + uses: actions/download-artifact@v4 + with: + name: dist-nightly-main + path: dist + - name: Setup Environment + uses: astral-sh/setup-uv@v6 + with: + enable-cache: false + python-version: "3.13" - name: Publish to PyPI env: POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }} UV_PUBLISH_TOKEN: ${{ secrets.PYPI_API_TOKEN }} run: | make publish main=true - - name: Upload Artifact - uses: actions/upload-artifact@v4 - with: - name: dist-main - path: dist call_docker_build_base: name: Call Docker Build Workflow for Langflow Base if: always() && ${{ inputs.build_docker_base == 'true' }} - needs: [release-nightly-base, release-nightly-main] + needs: [build-nightly-base, build-nightly-main] uses: ./.github/workflows/docker-build.yml with: release_type: nightly-base @@ -228,7 +276,7 @@ jobs: call_docker_build_main: name: Call Docker Build Workflow for Langflow if: always() && ${{ inputs.build_docker_main == 'true' }} - needs: [release-nightly-main, call_docker_build_base] + needs: [build-nightly-main, call_docker_build_base] uses: ./.github/workflows/docker-build.yml with: release_type: nightly-main @@ -239,7 +287,7 @@ jobs: # call_docker_build_main_all: # name: Call Docker Build Workflow for langflow-all # if: always() && ${{ inputs.build_docker_main == 'true' }} - # needs: [release-nightly-main] + # needs: [build-nightly-main] # uses: ./.github/workflows/docker-build.yml # with: # release_type: nightly-main-all @@ -249,7 +297,7 @@ jobs: call_docker_build_main_ep: name: Call Docker Build Workflow for Langflow with Entrypoint if: always() && ${{ inputs.build_docker_ep == 'true' }} - needs: [release-nightly-main, call_docker_build_main] + needs: [build-nightly-main, call_docker_build_main] uses: ./.github/workflows/docker-build.yml with: release_type: main-ep