From ac6e2d2eabeee28085f2739d79f7ce4205ca082c Mon Sep 17 00:00:00 2001 From: Gabriel Luiz Freitas Almeida Date: Mon, 20 Oct 2025 18:14:08 -0300 Subject: [PATCH] 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 --- .github/changes-filter.yaml | 4 + .github/workflows/py_autofix.yml | 26 ++ .github/workflows/update-component-index.yml | 314 ------------------- 3 files changed, 30 insertions(+), 314 deletions(-) delete mode 100644 .github/workflows/update-component-index.yml diff --git a/.github/changes-filter.yaml b/.github/changes-filter.yaml index 490e4cbc50..261e9ae0ff 100644 --- a/.github/changes-filter.yaml +++ b/.github/changes-filter.yaml @@ -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/**" diff --git a/.github/workflows/py_autofix.yml b/.github/workflows/py_autofix.yml index 6bd042271a..4ce507f689 100644 --- a/.github/workflows/py_autofix.yml +++ b/.github/workflows/py_autofix.yml @@ -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 + + diff --git a/.github/workflows/update-component-index.yml b/.github/workflows/update-component-index.yml deleted file mode 100644 index ed498ed9e4..0000000000 --- a/.github/workflows/update-component-index.yml +++ /dev/null @@ -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 = ''; - 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 = ''; - 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 - })