Skip to content

Commit 850ccfa

Browse files
committed
Merge branch 'main' into docs-workflow-api
2 parents cedd5cc + 4b056b4 commit 850ccfa

14 files changed

Lines changed: 635 additions & 120 deletions

File tree

.github/workflows/docker-build-v2.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ jobs:
8383
id: version
8484
run: |
8585
echo "Extracting base version from pyproject.toml"
86-
version=$(uv tree 2>/dev/null | grep '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
86+
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
8787
echo "Using version: $version"
8888
echo version=$version >> $GITHUB_OUTPUT
8989
@@ -599,7 +599,7 @@ jobs:
599599
id: version
600600
run: |
601601
if [[ "${{ inputs.release_type }}" == "base" ]]; then
602-
version=$(uv tree 2>/dev/null | grep '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
602+
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
603603
else
604604
version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
605605
fi

.github/workflows/docker-nightly-build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ jobs:
7272
id: version
7373
run: |
7474
echo "Extracting base version from pyproject.toml"
75-
version=$(uv tree 2>/dev/null | grep '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
75+
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
7676
7777
7878
# Verify nightly tag format
@@ -345,7 +345,7 @@ jobs:
345345
id: version
346346
run: |
347347
if [[ "${{ inputs.release_type }}" == "nightly-base" ]]; then
348-
version=$(uv tree 2>/dev/null | grep '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
348+
version=$(uv tree 2>/dev/null | grep 'langflow-base' | awk '{print $3}' | sed 's/^v//' | head -n 1)
349349
else
350350
version=$(uv tree 2>/dev/null | grep '^langflow' | grep -v '^langflow-base' | cut -d' ' -f2 | sed 's/^v//')
351351
fi

.github/workflows/nightly_build.yml

Lines changed: 204 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ on:
2323
type: boolean
2424
default: false
2525
skip_slack:
26-
description: "Skip slack message on failure. Only do this for testing purposes."
26+
description: "Skip slack message. Only do this for testing purposes."
2727
required: false
2828
type: boolean
2929
default: false
@@ -32,6 +32,11 @@ on:
3232
required: false
3333
type: boolean
3434
default: true
35+
auto_merge_hash_history:
36+
description: "Create PR to merge hash history back to main. Set to false when not running from main."
37+
required: false
38+
type: boolean
39+
default: true
3540
schedule:
3641
# Run job at 00:00 UTC (4:00 PM PST / 5:00 PM PDT)
3742
- cron: "0 0 * * *"
@@ -128,6 +133,7 @@ jobs:
128133
129134
uv lock
130135
cd src/backend/base && uv lock && cd ../../..
136+
cd src/lfx && uv lock && cd ../..
131137
132138
git add pyproject.toml src/backend/base/pyproject.toml src/lfx/pyproject.toml uv.lock src/backend/base/uv.lock
133139
git commit -m "Update version and project name"
@@ -175,6 +181,77 @@ jobs:
175181
exit 1
176182
fi
177183
184+
build-hash-history:
185+
if: github.repository == 'langflow-ai/langflow'
186+
name: Build Nightly Hash History
187+
needs: create-nightly-tag
188+
runs-on: ubuntu-latest
189+
defaults:
190+
run:
191+
shell: bash -ex -o pipefail {0}
192+
permissions:
193+
contents: write
194+
steps:
195+
- name: Checkout nightly tag
196+
uses: actions/checkout@v6
197+
with:
198+
ref: ${{ needs.create-nightly-tag.outputs.main_tag }}
199+
persist-credentials: true
200+
201+
- name: "Setup Environment"
202+
uses: astral-sh/setup-uv@v6
203+
with:
204+
enable-cache: true
205+
cache-dependency-glob: "uv.lock"
206+
python-version: ${{ env.PYTHON_VERSION }}
207+
prune-cache: false
208+
209+
- name: Install the project
210+
run: uv sync
211+
212+
- name: Force reinstall LFX to pick up version change
213+
run: |
214+
echo "Force reinstalling lfx-nightly to ensure version metadata is updated..."
215+
uv pip install --reinstall --no-deps src/lfx
216+
217+
- name: Verify LFX version
218+
run: |
219+
echo "Checking installed LFX version..."
220+
uv run python -c "from importlib.metadata import version; print(f'lfx-nightly version: {version(\"lfx-nightly\")}')" || \
221+
uv run python -c "from importlib.metadata import version; print(f'lfx version: {version(\"lfx\")}')"
222+
223+
- name: Build and validate nightly hash history
224+
run: |
225+
# The script includes append-only validation
226+
uv run python scripts/build_hash_history.py --nightly
227+
228+
- name: Commit and push hash history changes
229+
run: |
230+
echo "=== Configuring git ==="
231+
git config --global user.email "bot-nightly-builds@langflow.org"
232+
git config --global user.name "Langflow Bot"
233+
234+
echo "=== Checking for hash history changes ==="
235+
# Check if there are changes to commit (handles if it's a new file for first run)
236+
git add src/lfx/src/lfx/_assets/nightly_hash_history.json
237+
if git diff --cached --quiet src/lfx/src/lfx/_assets/nightly_hash_history.json; then
238+
echo "No changes to nightly hash history"
239+
else
240+
echo "Hash history changes detected, committing..."
241+
# Commit to the nightly tag itself so builds include the hash history
242+
git commit -m "Update nightly hash history for ${{ needs.create-nightly-tag.outputs.main_tag }}"
243+
244+
echo "=== Updating nightly tag ${{ needs.create-nightly-tag.outputs.main_tag }} ==="
245+
# Update the tag to include the hash history
246+
git tag -f ${{ needs.create-nightly-tag.outputs.main_tag }}
247+
git push -f origin ${{ needs.create-nightly-tag.outputs.main_tag }}
248+
249+
echo "=== Pushing to nightly-hash-history-updates branch ==="
250+
# Also push to the branch for PR creation
251+
git push origin HEAD:refs/heads/nightly-hash-history-updates --force
252+
echo "Updated nightly tag and branch with hash history changes"
253+
fi
254+
178255
frontend-tests:
179256
if: github.repository == 'langflow-ai/langflow' && !inputs.skip_frontend_tests
180257
name: Run Frontend Tests
@@ -214,9 +291,9 @@ jobs:
214291
# ref: ${{ needs.create-nightly-tag.outputs.tag }}
215292

216293
release-nightly-build:
217-
if: github.repository == 'langflow-ai/langflow' && always() && needs.frontend-tests.result != 'failure' && needs.backend-unit-tests.result != 'failure'
294+
if: github.repository == 'langflow-ai/langflow' && always() && needs.frontend-tests.result != 'failure' && needs.backend-unit-tests.result != 'failure' && needs.build-hash-history.result != 'failure'
218295
name: Run Nightly Langflow Build
219-
needs: [create-nightly-tag, frontend-tests, backend-unit-tests]
296+
needs: [create-nightly-tag, frontend-tests, backend-unit-tests, build-hash-history]
220297
uses: ./.github/workflows/release_nightly.yml
221298
with:
222299
build_docker_base: true
@@ -275,8 +352,131 @@ jobs:
275352
]
276353
}' ${{ secrets.LANGFLOW_ENG_SLACK_WEBHOOK_URL }}
277354
355+
merge-hash-history-to-main:
356+
name: Create PR to Merge Hash History to Main
357+
needs: [create-nightly-tag, build-hash-history, release-nightly-build]
358+
# Run if auto_merge_hash_history is true (default) or not set (scheduled runs)
359+
# When triggered by schedule, inputs.auto_merge_hash_history is not set, so default to true
360+
# Only run when the base branch is 'main' to prevent PRs from feature branches
361+
if: github.repository == 'langflow-ai/langflow' && github.ref == 'refs/heads/main' && always() && needs.build-hash-history.result == 'success' && needs.release-nightly-build.result == 'success' && (github.event_name == 'schedule' || inputs.auto_merge_hash_history != false)
362+
runs-on: ubuntu-latest
363+
permissions:
364+
contents: write
365+
pull-requests: write
366+
steps:
367+
- name: Checkout main branch
368+
uses: actions/checkout@v6
369+
with:
370+
ref: main
371+
fetch-depth: 0
372+
persist-credentials: true
373+
374+
- name: Configure Git
375+
run: |
376+
git config --global user.email "bot-nightly-builds@langflow.org"
377+
git config --global user.name "Langflow Bot"
378+
379+
- name: "Setup Environment"
380+
uses: astral-sh/setup-uv@v6
381+
with:
382+
enable-cache: true
383+
cache-dependency-glob: "uv.lock"
384+
python-version: ${{ env.PYTHON_VERSION }}
385+
prune-cache: false
386+
387+
- name: Fetch nightly hash history branch
388+
run: |
389+
echo "=== Fetching nightly-hash-history-updates branch ==="
390+
git fetch origin nightly-hash-history-updates || echo "Branch does not exist yet, will be created"
391+
echo "Fetch completed"
392+
393+
- name: Check if branch exists and has changes
394+
id: check_branch
395+
run: |
396+
echo "=== Checking branch status ==="
397+
if git rev-parse --verify origin/nightly-hash-history-updates >/dev/null 2>&1; then
398+
echo "branch_exists=true" >> $GITHUB_OUTPUT
399+
echo "Branch exists"
400+
401+
# Check if there are differences between main and the nightly branch
402+
echo "=== Comparing with main branch ==="
403+
if git diff --quiet main origin/nightly-hash-history-updates -- src/lfx/src/lfx/_assets/nightly_hash_history.json; then
404+
echo "has_changes=false" >> $GITHUB_OUTPUT
405+
echo "No changes to merge"
406+
else
407+
echo "has_changes=true" >> $GITHUB_OUTPUT
408+
echo "Changes detected - PR will be created/updated"
409+
fi
410+
else
411+
echo "branch_exists=false" >> $GITHUB_OUTPUT
412+
echo "has_changes=false" >> $GITHUB_OUTPUT
413+
echo "Branch does not exist yet - will be created by build-hash-history job"
414+
fi
415+
416+
- name: Validate and prepare PR
417+
if: steps.check_branch.outputs.branch_exists == 'true' && steps.check_branch.outputs.has_changes == 'true'
418+
run: |
419+
echo "=== Checking out hash history file from nightly branch ==="
420+
# Checkout the nightly hash history file to verify it
421+
git checkout origin/nightly-hash-history-updates -- src/lfx/src/lfx/_assets/nightly_hash_history.json
422+
423+
echo "=== Verifying only hash history file was modified ==="
424+
# Verify that ONLY the nightly_hash_history.json file was modified
425+
CHANGED_FILES=$(git diff --name-only main)
426+
if [ "$CHANGED_FILES" != "src/lfx/src/lfx/_assets/nightly_hash_history.json" ]; then
427+
echo "ERROR: Unexpected files were modified: $CHANGED_FILES"
428+
echo "Only nightly_hash_history.json should be changed"
429+
exit 1
430+
fi
431+
echo "Only hash history file modified"
432+
433+
echo "=== Validating hash history file ==="
434+
# Basic validation - ensure file exists and is valid JSON
435+
436+
if [ ! -f "src/lfx/src/lfx/_assets/nightly_hash_history.json" ]; then
437+
echo "ERROR: nightly_hash_history.json file was deleted!"
438+
exit 1
439+
fi
440+
441+
if ! uv run python -c "import json; json.load(open('src/lfx/src/lfx/_assets/nightly_hash_history.json'))"; then
442+
echo "ERROR: nightly_hash_history.json is not valid JSON!"
443+
exit 1
444+
fi
445+
446+
echo "Hash history file validation passed"
447+
echo "Note: Append-only validation was performed during the build step"
448+
449+
- name: Create Pull Request
450+
if: steps.check_branch.outputs.branch_exists == 'true' && steps.check_branch.outputs.has_changes == 'true'
451+
env:
452+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
453+
run: |
454+
# Create or update PR from the nightly-hash-history-updates branch
455+
PR_URL=$(gh pr create \
456+
--title "chore: update nightly hash history" \
457+
--body "This PR updates the nightly hash history file with the latest component hashes from the nightly build.
458+
459+
**Automated PR** - Generated by nightly build workflow
460+
461+
- Updates: \`src/lfx/src/lfx/_assets/nightly_hash_history.json\`
462+
- Source: Nightly build tag ${{ needs.create-nightly-tag.outputs.main_tag }}
463+
464+
This PR is automatically updated each night with the latest hash history.
465+
Auto-merge is enabled - PR will merge automatically when checks pass." \
466+
--base main \
467+
--head nightly-hash-history-updates \
468+
--label "automated" \
469+
--label "nightly" 2>&1 || echo "")
470+
471+
# Enable auto-merge if PR was created or get existing PR
472+
if [ -n "$PR_URL" ]; then
473+
echo "PR created or found: $PR_URL"
474+
# Enable auto-merge on the PR
475+
gh pr merge nightly-hash-history-updates --auto --squash || echo "Auto-merge may already be enabled or PR doesn't exist yet"
476+
fi
477+
278478
- name: Send success notification to Slack
279-
if: ${{ needs.release-nightly-build.result == 'success' }}
479+
if: ${{ !inputs.skip_slack && needs.release-nightly-build.result == 'success' }}
280480
run: |
281481
curl -X POST -H 'Content-type: application/json' \
282482
--data '{

.github/workflows/release_nightly.yml

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,34 @@ jobs:
135135
cache-dependency-glob: "uv.lock"
136136
python-version: ${{ env.PYTHON_VERSION }}
137137
prune-cache: false
138+
139+
- name: Download LFX artifact
140+
if: inputs.build_lfx
141+
uses: actions/download-artifact@v7
142+
with:
143+
name: dist-nightly-lfx
144+
path: lfx-dist
145+
138146
- name: Install the project
139147
run: uv sync
140-
141-
- name: Wait for PyPI Propagation
148+
149+
- name: Force reinstall LFX from built wheel
142150
if: inputs.build_lfx
143-
run: sleep 300 # wait for 5 minutes to ensure PyPI propagation of LFX
151+
run: |
152+
echo "Installing LFX from built wheel to test the actual distribution package..."
153+
# While workspace resolution installs from source, we want to test the exact
154+
# wheel that will be published to PyPI to catch any packaging issues
155+
uv pip install --force-reinstall --no-deps lfx-dist/*.whl
144156
145157
- name: Verify Nightly Name and Version
146158
id: verify
147159
run: |
148160
name=$(uv tree | grep 'langflow-base' | awk '{print $2}' | head -n 1)
149161
version=$(uv tree | grep 'langflow-base' | awk '{print $3}' | head -n 1)
150-
if [ "$name" != "langflow-base-nightly" ]; then
151-
echo "Name $name does not match langflow-base-nightly. Exiting the workflow."
162+
# Strip extras from package name (e.g., "langflow-base-nightly[complete]" -> "langflow-base-nightly")
163+
name_without_extras=$(echo $name | sed 's/\[.*\]//')
164+
if [ "$name_without_extras" != "langflow-base-nightly" ]; then
165+
echo "Name $name_without_extras does not match langflow-base-nightly. Exiting the workflow."
152166
exit 1
153167
fi
154168
if [ "$version" != "${{ inputs.nightly_tag_base }}" ]; then
@@ -170,7 +184,9 @@ jobs:
170184
# TODO: Unsure why the whl is not built in src/backend/base/dist
171185
mkdir src/backend/base/dist
172186
mv dist/*.whl src/backend/base/dist/
173-
uv pip install src/backend/base/dist/*.whl
187+
# Install with [complete] extra to test all optional dependencies
188+
WHEEL_FILE=$(ls src/backend/base/dist/*.whl)
189+
uv pip install "${WHEEL_FILE}[complete]"
174190
uv run python -m langflow run --host localhost --port 7860 --backend-only &
175191
SERVER_PID=$!
176192
# Wait for the server to start
@@ -216,8 +232,33 @@ jobs:
216232
cache-dependency-glob: "uv.lock"
217233
python-version: ${{ env.PYTHON_VERSION }}
218234
prune-cache: false
235+
236+
- name: Download LFX artifact
237+
if: inputs.build_lfx
238+
uses: actions/download-artifact@v7
239+
with:
240+
name: dist-nightly-lfx
241+
path: lfx-dist
242+
243+
- name: Download base artifact
244+
uses: actions/download-artifact@v7
245+
with:
246+
name: dist-nightly-base
247+
path: base-dist
248+
219249
- name: Install the project
220250
run: uv sync
251+
252+
- name: Force reinstall packages from built wheels
253+
run: |
254+
# While workspace resolution installs from source, we want to test the exact
255+
# wheels that will be published to PyPI to catch any packaging issues
256+
if [ "${{ inputs.build_lfx }}" == "true" ]; then
257+
echo "Installing LFX from built wheel..."
258+
uv pip install --force-reinstall --no-deps lfx-dist/*.whl
259+
fi
260+
echo "Installing langflow-base from built wheel..."
261+
uv pip install --force-reinstall --no-deps base-dist/*.whl
221262
222263
- name: Verify Nightly Name and Version
223264
id: verify

0 commit comments

Comments
 (0)