mirror of
https://github.com/langflow-ai/langflow.git
synced 2026-07-26 03:10:37 +08:00
chore: move update component index job to autofix workflow (#10342)
* chore: Update changes-filter.yaml to include component_index.json in various sections * chore: remove update-component-index workflow file * chore: add update component index job to autofix workflow
This commit is contained in:
committed by
GitHub
parent
aa3d8e621e
commit
ac6e2d2eab
4
.github/changes-filter.yaml
vendored
4
.github/changes-filter.yaml
vendored
@ -8,8 +8,10 @@ python:
|
||||
- "src/backend/base/uv.lock"
|
||||
- "**/python_test.yml"
|
||||
- ".github/workflows/ci.yml"
|
||||
- "src/lfx/src/lfx/_assets/component_index.json"
|
||||
components-changes:
|
||||
- "src/backend/base/langflow/components/**"
|
||||
- "src/lfx/src/lfx/_assets/component_index.json"
|
||||
starter-projects-changes:
|
||||
- "src/backend/base/langflow/initial_setup/**"
|
||||
frontend-tests:
|
||||
@ -19,6 +21,7 @@ frontend:
|
||||
- "**/typescript_test.yml"
|
||||
- "**/jest_test.yml"
|
||||
- ".github/workflows/ci.yml"
|
||||
- "src/lfx/src/lfx/_assets/component_index.json"
|
||||
docs:
|
||||
- "docs/**"
|
||||
docker:
|
||||
@ -66,6 +69,7 @@ components:
|
||||
- "src/backend/base/langflow/components/**"
|
||||
- "src/backend/base/langflow/initial_setup/**"
|
||||
- "src/backend/base/langflow/serialization/**"
|
||||
- "src/lfx/src/lfx/_assets/component_index.json"
|
||||
|
||||
workspace:
|
||||
- "src/backend/base/langflow/inputs/**"
|
||||
|
||||
26
.github/workflows/py_autofix.yml
vendored
26
.github/workflows/py_autofix.yml
vendored
@ -3,6 +3,8 @@ on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "**/*.py"
|
||||
- "src/lfx/src/lfx/components/**"
|
||||
- "scripts/build_component_index.py"
|
||||
env:
|
||||
PYTHON_VERSION: "3.13"
|
||||
|
||||
@ -49,4 +51,28 @@ jobs:
|
||||
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
|
||||
|
||||
|
||||
update-component-index:
|
||||
name: Update Component Index
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- 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 dependencies"
|
||||
run: uv sync --dev --project .
|
||||
|
||||
- name: Build component index
|
||||
env:
|
||||
LFX_DEV: "1"
|
||||
run: make build_component_index
|
||||
|
||||
- uses: autofix-ci/action@635ffb0c9798bd160680f18fd73371e355b85f27
|
||||
|
||||
|
||||
|
||||
|
||||
314
.github/workflows/update-component-index.yml
vendored
314
.github/workflows/update-component-index.yml
vendored
@ -1,314 +0,0 @@
|
||||
# SECURITY WARNING: This workflow uses pull_request_target to enable commenting on fork PRs.
|
||||
# DO NOT checkout or execute code from fork PRs - this could allow malicious code execution with write permissions.
|
||||
# Fork PRs are detected and handled safely by skipping checkout/build steps.
|
||||
|
||||
name: Update Component Index
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
paths:
|
||||
- "src/lfx/src/lfx/components/**"
|
||||
- "scripts/build_component_index.py"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
update-index:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository (PR from same repo only)
|
||||
if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
ref: ${{ github.event.pull_request.head.ref }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Checkout repository (workflow_dispatch)
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Install uv
|
||||
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository)
|
||||
uses: astral-sh/setup-uv@v6
|
||||
with:
|
||||
version: "latest"
|
||||
|
||||
- name: Install dependencies
|
||||
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository)
|
||||
run: uv sync --dev --project .
|
||||
|
||||
- name: Check if script exists
|
||||
if: github.event_name == 'workflow_dispatch' || (github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository)
|
||||
id: check_script
|
||||
run: |
|
||||
echo "Current directory: $(pwd)"
|
||||
echo "Checking for script at: scripts/build_component_index.py"
|
||||
ls -la scripts/ || echo "scripts/ directory not found"
|
||||
if [ ! -f scripts/build_component_index.py ]; then
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
echo "⚠️ Script not found - PR needs to be rebased with main"
|
||||
echo "Repository contents:"
|
||||
ls -la
|
||||
echo "Checking git history for the script:"
|
||||
git log --oneline --all -- scripts/build_component_index.py | head -5 || echo "No history found"
|
||||
else
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
echo "✅ Script found"
|
||||
fi
|
||||
|
||||
- name: Build component index
|
||||
if: steps.check_script.outputs.exists == 'true'
|
||||
env:
|
||||
LFX_DEV: "1"
|
||||
run: make build_component_index
|
||||
|
||||
- name: Check if index changed
|
||||
if: steps.check_script.outputs.exists == 'true'
|
||||
id: check_changes
|
||||
run: |
|
||||
INDEX_FILE="src/lfx/src/lfx/_assets/component_index.json"
|
||||
git add -N "$INDEX_FILE"
|
||||
|
||||
if git diff --quiet --exit-code -- "$INDEX_FILE"; then
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
echo "✅ No changes to component index"
|
||||
else
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
echo "📝 Component index was updated"
|
||||
echo ""
|
||||
|
||||
# Show diff statistics
|
||||
echo "Diff statistics:"
|
||||
git diff --stat -- "$INDEX_FILE"
|
||||
echo ""
|
||||
|
||||
# Compare SHA256 hashes
|
||||
if command -v jq >/dev/null 2>&1; then
|
||||
OLD_SHA=$(git show HEAD:"$INDEX_FILE" 2>/dev/null | jq -r '.sha256 // "N/A"')
|
||||
NEW_SHA=$(jq -r '.sha256 // "N/A"' "$INDEX_FILE")
|
||||
echo "SHA256 hash:"
|
||||
echo " Old: $OLD_SHA"
|
||||
echo " New: $NEW_SHA"
|
||||
echo ""
|
||||
|
||||
# Count components (not just categories)
|
||||
OLD_COMPONENTS=$(git show HEAD:"$INDEX_FILE" 2>/dev/null | jq '[.entries[] | .[1] | keys | length] | add' 2>/dev/null || echo "N/A")
|
||||
NEW_COMPONENTS=$(jq '[.entries[] | .[1] | keys | length] | add' "$INDEX_FILE" 2>/dev/null || echo "N/A")
|
||||
OLD_CATEGORIES=$(git show HEAD:"$INDEX_FILE" 2>/dev/null | jq '.entries | length' 2>/dev/null || echo "N/A")
|
||||
NEW_CATEGORIES=$(jq '.entries | length' "$INDEX_FILE" 2>/dev/null || echo "N/A")
|
||||
echo "Components: $OLD_COMPONENTS → $NEW_COMPONENTS"
|
||||
echo "Categories: $OLD_CATEGORIES → $NEW_CATEGORIES"
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Commit and push if changed
|
||||
if: steps.check_changes.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
run: |
|
||||
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git config --local user.name "github-actions[bot]"
|
||||
git add src/lfx/src/lfx/_assets/component_index.json
|
||||
git commit -m "chore: update component index"
|
||||
|
||||
# Retry push with rebase if needed (handles concurrent PR updates)
|
||||
for i in {1..3}; do
|
||||
if git push; then
|
||||
echo "Successfully pushed changes"
|
||||
exit 0
|
||||
fi
|
||||
echo "Push failed, attempt $i/3. Rebasing and retrying..."
|
||||
git pull --rebase
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "Failed to push after 3 attempts"
|
||||
exit 1
|
||||
|
||||
- name: Comment on PR (community fork - cannot auto-update)
|
||||
if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const marker = '<!-- component-index-update-needed -->';
|
||||
const commentBody = `${marker}\n⚠️ **Component index needs to be updated**\n\nPlease run the following command locally and commit the changes:\n\n\`\`\`bash\nmake build_component_index\n\`\`\`\n\nOr alternatively:\n\n\`\`\`bash\nLFX_DEV=1 uv run python scripts/build_component_index.py\n\`\`\`\n\nThen commit and push the updated \`src/lfx/src/lfx/_assets/component_index.json\` file.`;
|
||||
|
||||
// Find existing comments from github-actions bot with the marker
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
const botComments = comments.filter(
|
||||
comment => comment.user.login === 'github-actions[bot]' && comment.body.includes(marker)
|
||||
);
|
||||
|
||||
// Delete old comments to avoid duplicates
|
||||
for (const comment of botComments) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: comment.id,
|
||||
});
|
||||
}
|
||||
|
||||
// Post new comment
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: commentBody
|
||||
})
|
||||
|
||||
- name: Comment on PR (same repo - auto-updated)
|
||||
if: steps.check_changes.outputs.changed == 'true' && github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const indexPath = 'src/lfx/src/lfx/_assets/component_index.json';
|
||||
let changeDetails = '';
|
||||
|
||||
try {
|
||||
// Get the old and new JSON data
|
||||
const newData = JSON.parse(fs.readFileSync(indexPath, 'utf8'));
|
||||
let oldData = null;
|
||||
|
||||
try {
|
||||
const oldContent = execSync(`git show HEAD:${indexPath}`, { encoding: 'utf8' });
|
||||
oldData = JSON.parse(oldContent);
|
||||
} catch (e) {
|
||||
console.log('Could not get old version:', e.message);
|
||||
}
|
||||
|
||||
if (oldData) {
|
||||
// Compare versions
|
||||
const oldVersion = oldData.version || 'unknown';
|
||||
const newVersion = newData.version || 'unknown';
|
||||
|
||||
// Compare component counts
|
||||
const oldComponents = oldData.metadata?.num_components || 0;
|
||||
const newComponents = newData.metadata?.num_components || 0;
|
||||
const componentDiff = newComponents - oldComponents;
|
||||
|
||||
// Compare category counts
|
||||
const oldCategories = oldData.metadata?.num_modules || 0;
|
||||
const newCategories = newData.metadata?.num_modules || 0;
|
||||
const categoryDiff = newCategories - oldCategories;
|
||||
|
||||
// Find added/removed categories
|
||||
const oldCategoryNames = new Set(oldData.entries?.map(entry => entry[0]) || []);
|
||||
const newCategoryNames = new Set(newData.entries?.map(entry => entry[0]) || []);
|
||||
|
||||
const addedCategories = [...newCategoryNames].filter(name => !oldCategoryNames.has(name));
|
||||
const removedCategories = [...oldCategoryNames].filter(name => !newCategoryNames.has(name));
|
||||
|
||||
// Find added/removed components
|
||||
const oldComponentsFlat = new Set();
|
||||
const newComponentsFlat = new Set();
|
||||
|
||||
oldData.entries?.forEach(([category, components]) => {
|
||||
Object.keys(components || {}).forEach(comp => oldComponentsFlat.add(`${category}.${comp}`));
|
||||
});
|
||||
|
||||
newData.entries?.forEach(([category, components]) => {
|
||||
Object.keys(components || {}).forEach(comp => newComponentsFlat.add(`${category}.${comp}`));
|
||||
});
|
||||
|
||||
const addedComponents = [...newComponentsFlat].filter(comp => !oldComponentsFlat.has(comp));
|
||||
const removedComponents = [...oldComponentsFlat].filter(comp => !newComponentsFlat.has(comp));
|
||||
|
||||
// Build change summary
|
||||
let changes = [];
|
||||
|
||||
if (oldVersion !== newVersion) {
|
||||
changes.push(`📦 **Version:** ${oldVersion} → ${newVersion}`);
|
||||
}
|
||||
|
||||
if (componentDiff !== 0) {
|
||||
const sign = componentDiff > 0 ? '+' : '';
|
||||
changes.push(`🧩 **Components:** ${oldComponents} → ${newComponents} (${sign}${componentDiff})`);
|
||||
}
|
||||
|
||||
if (categoryDiff !== 0) {
|
||||
const sign = categoryDiff > 0 ? '+' : '';
|
||||
changes.push(`📁 **Categories:** ${oldCategories} → ${newCategories} (${sign}${categoryDiff})`);
|
||||
}
|
||||
|
||||
if (addedCategories.length > 0) {
|
||||
changes.push(`➕ **Added Categories:** ${addedCategories.join(', ')}`);
|
||||
}
|
||||
|
||||
if (removedCategories.length > 0) {
|
||||
changes.push(`➖ **Removed Categories:** ${removedCategories.join(', ')}`);
|
||||
}
|
||||
|
||||
if (addedComponents.length > 0) {
|
||||
const displayComponents = addedComponents.slice(0, 10);
|
||||
const moreCount = addedComponents.length - displayComponents.length;
|
||||
changes.push(`➕ **Added Components:** ${displayComponents.join(', ')}${moreCount > 0 ? ` (+${moreCount} more)` : ''}`);
|
||||
}
|
||||
|
||||
if (removedComponents.length > 0) {
|
||||
const displayComponents = removedComponents.slice(0, 10);
|
||||
const moreCount = removedComponents.length - displayComponents.length;
|
||||
changes.push(`➖ **Removed Components:** ${displayComponents.join(', ')}${moreCount > 0 ? ` (+${moreCount} more)` : ''}`);
|
||||
}
|
||||
|
||||
if (changes.length > 0) {
|
||||
changeDetails = '\n\n**Changes:**\n' + changes.join('\n');
|
||||
} else {
|
||||
changeDetails = '\n\n**Changes:** Internal structure or metadata updates';
|
||||
}
|
||||
|
||||
// Add SHA256 info
|
||||
const oldSha = oldData.sha256 || 'unknown';
|
||||
const newSha = newData.sha256 || 'unknown';
|
||||
changeDetails += `\n\n🔐 **SHA256:** \`${oldSha.substring(0, 12)}...\` → \`${newSha.substring(0, 12)}...\``;
|
||||
|
||||
} else {
|
||||
changeDetails = `\n\n**New Index:**\n🧩 **Components:** ${newData.metadata?.num_components || 0}\n📁 **Categories:** ${newData.metadata?.num_modules || 0}`;
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log('Error analyzing changes:', error.message);
|
||||
changeDetails = '\n\n*Could not analyze specific changes.*';
|
||||
}
|
||||
|
||||
const marker = '<!-- component-index-auto-updated -->';
|
||||
const commentBody = `${marker}\n✅ **Component index has been automatically updated** due to changes in \`src/lfx/src/lfx/components/\`${changeDetails}`;
|
||||
|
||||
// Find existing comments from github-actions bot with the marker
|
||||
const { data: comments } = await github.rest.issues.listComments({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
const botComments = comments.filter(
|
||||
comment => comment.user.login === 'github-actions[bot]' && comment.body.includes(marker)
|
||||
);
|
||||
|
||||
// Delete old comments to avoid duplicates
|
||||
for (const comment of botComments) {
|
||||
await github.rest.issues.deleteComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
comment_id: comment.id,
|
||||
});
|
||||
}
|
||||
|
||||
// Post new comment
|
||||
await github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: commentBody
|
||||
})
|
||||
Reference in New Issue
Block a user