Skip to content

Langflow Migration Test: Latest → Nightly #29

Langflow Migration Test: Latest → Nightly

Langflow Migration Test: Latest → Nightly #29

name: "Langflow Migration Test: Latest → Nightly"
on:
schedule:
- cron: "0 7 * * *" # 04:00 BRT (UTC-3)
workflow_dispatch:
env:
LANGFLOW_PORT: 7860
LANGFLOW_URL: http://localhost:7860
PG_USER: langflow
PG_PASSWORD: langflow_test_pw
PG_DB: langflow
STATE_FILE: /tmp/migration-test-state.json
REPORT_FILE: /tmp/migration-report.md
# Fixed key shared by both containers so credentials encrypted by latest
# can be decrypted by nightly after DB migration.
LANGFLOW_SECRET_KEY: "migration-test-fixed-secret-32chars!!"
permissions:
contents: read
issues: write
jobs:
migration-test:
runs-on: ubuntu-latest
timeout-minutes: 30
services:
postgres:
image: postgres:16
env:
POSTGRES_USER: langflow
POSTGRES_PASSWORD: langflow_test_pw
POSTGRES_DB: langflow
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
- name: Install dependencies
run: |
pip install requests playwright pytest pytest-playwright
playwright install chromium --with-deps
- name: Generate ephemeral Fernet key for this run
run: |
python - <<'PY'
import base64
import os
key = base64.urlsafe_b64encode(os.urandom(32)).decode()
with open(os.environ["GITHUB_ENV"], "a", encoding="utf-8") as github_env:
github_env.write(f"LANGFLOW_SECRET_KEY={key}\n")
PY
# ── Phase 1: Langflow Latest ──────────────────────────────
- name: Pull Langflow latest
run: |
docker pull langflowai/langflow:latest
docker inspect langflowai/langflow:latest --format='{{index .RepoDigests 0}}' > /tmp/latest-digest.txt
echo "Latest digest: $(cat /tmp/latest-digest.txt)"
- name: Start Langflow latest
run: |
docker run -d --name langflow \
--network host \
-e LANGFLOW_DATABASE_URL="postgresql://$PG_USER:$PG_PASSWORD@localhost:5432/$PG_DB" \
-e LANGFLOW_AUTO_LOGIN=true \
-e LANGFLOW_SKIP_AUTH_AUTO_LOGIN=true \
-e LANGFLOW_SUPERUSER=langflow \
-e LANGFLOW_SUPERUSER_PASSWORD=langflow123 \
-e LANGFLOW_STORE=false \
-e LANGFLOW_SECRET_KEY="$LANGFLOW_SECRET_KEY" \
langflowai/langflow:latest
- name: Wait for Langflow latest
run: python tests/github-workflows/migration/wait_for_langflow.py
- name: Create flow, configure and execute on latest
run: python tests/github-workflows/migration/setup_latest.py
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Save latest container logs
if: always()
run: docker logs langflow > /tmp/langflow-latest.log 2>&1 || true
# ── Phase 2: Upgrade to Nightly ───────────────────────────
- name: Stop Langflow latest
run: docker stop langflow && docker rm langflow
- name: Pull Langflow nightly
run: |
docker pull langflowai/langflow-nightly:latest
docker inspect langflowai/langflow-nightly:latest --format='{{index .RepoDigests 0}}' > /tmp/nightly-digest.txt
echo "Nightly digest: $(cat /tmp/nightly-digest.txt)"
- name: Start Langflow nightly (same database)
run: |
docker run -d --name langflow \
--network host \
-e LANGFLOW_DATABASE_URL="postgresql://$PG_USER:$PG_PASSWORD@localhost:5432/$PG_DB" \
-e LANGFLOW_AUTO_LOGIN=true \
-e LANGFLOW_SKIP_AUTH_AUTO_LOGIN=true \
-e LANGFLOW_SUPERUSER=langflow \
-e LANGFLOW_SUPERUSER_PASSWORD=langflow123 \
-e LANGFLOW_STORE=false \
-e LANGFLOW_SECRET_KEY="$LANGFLOW_SECRET_KEY" \
langflowai/langflow-nightly:latest
- name: Wait for Langflow nightly (includes migration)
id: nightly_start
run: python tests/github-workflows/migration/wait_for_langflow.py --timeout 180
- name: Save nightly container logs
if: always()
run: docker logs langflow > /tmp/langflow-nightly.log 2>&1 || true
# ── Phase 3: Verify Migration ─────────────────────────────
- name: Verify migration via API
run: python tests/github-workflows/migration/verify_migration_api.py
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
- name: Verify migration via UI (Playwright)
run: pytest tests/github-workflows/migration/test_ui_migration.py -v --tracing=retain-on-failure --output=test-results
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
# ── Phase 4: Report ───────────────────────────────────────
- name: Generate report
if: always()
run: python tests/github-workflows/migration/generate_report.py
- name: Print report
if: always()
run: cat /tmp/migration-report.md
- name: Upload test artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: migration-test-${{ github.run_number }}
path: |
test-results/
/tmp/migration-report.md
/tmp/langflow-latest.log
/tmp/langflow-nightly.log
/tmp/migration-test-state.json
/tmp/latest-digest.txt
/tmp/nightly-digest.txt
- name: Cleanup containers
if: always()
run: docker stop langflow 2>/dev/null; docker rm langflow 2>/dev/null; true
- name: Close issue on success
if: success()
uses: actions/github-script@v7
with:
script: |
const { data: existing } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'migration-test',
state: 'open',
});
if (existing.length > 0) {
const issue = existing[0];
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: [
`## ✅ Run #${context.runNumber} — ${new Date().toISOString().split('T')[0]}`,
'',
'Migration test passed. Closing this issue.',
'',
`[Workflow Run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`,
].join('\n'),
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
});
}
- name: Create or update issue on failure
if: failure()
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let report = 'Migration test failed. See workflow artifacts for details.';
try {
report = fs.readFileSync('/tmp/migration-report.md', 'utf8');
} catch (e) {
console.log('Report not available:', e.message);
}
const { data: existing } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'migration-test',
state: 'open',
});
const body = [
`## Run #${context.runNumber} — ${new Date().toISOString().split('T')[0]}`,
'',
report,
'',
`[Workflow Run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId})`,
'',
'/cc @lice-reis',
].join('\n');
if (existing.length > 0) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existing[0].number,
body,
});
} else {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Langflow Migration Test Failed (latest → nightly)`,
body,
labels: ['migration-test', 'automated'],
});
}