From cbe8d23fc98427a12aae55a995baaef5d7f8dc67 Mon Sep 17 00:00:00 2001 From: Eric Hare Date: Thu, 11 Jun 2026 12:32:44 -0700 Subject: [PATCH] ci(bundles): make freeze gate reachable on PRs; review follow-ups - Move the freeze-components job from lint-py.yml (workflow_call/ workflow_dispatch only -- never invoked, so the gate could not block a PR) into extension-migration-checks.yml, which already triggers on pull_request for src/lfx/src/lfx/components/**. Add the gate's script and baseline to the path filter. - Add timeout-minutes to the cross-bundle-test jobs so a hung install or test leg cannot occupy a runner for the 360-minute default. - _discover_shimmed_component_dirs: read only the first line of each __init__.py instead of the whole file -- the shim marker contract is line 1 (enforced by test_shim_source_contract), and this prevents a non-shim file with the marker after leading blank lines from being misclassified and silently skipped from the in-tree walk. --- .github/workflows/cross-bundle-test.yml | 2 ++ .../workflows/extension-migration-checks.yml | 17 +++++++++++++++++ .github/workflows/lint-py.yml | 14 -------------- src/lfx/src/lfx/interface/components.py | 7 ++++++- 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/.github/workflows/cross-bundle-test.yml b/.github/workflows/cross-bundle-test.yml index c4445536c2..b241736999 100644 --- a/.github/workflows/cross-bundle-test.yml +++ b/.github/workflows/cross-bundle-test.yml @@ -38,6 +38,7 @@ jobs: discover: name: Discover bundles runs-on: ubuntu-latest + timeout-minutes: 5 outputs: bundles: ${{ steps.find.outputs.bundles }} steps: @@ -66,6 +67,7 @@ jobs: needs: discover if: needs.discover.outputs.bundles != '[]' runs-on: ubuntu-latest + timeout-minutes: 30 strategy: fail-fast: false matrix: diff --git a/.github/workflows/extension-migration-checks.yml b/.github/workflows/extension-migration-checks.yml index c2c01deffd..e9a741a1ad 100644 --- a/.github/workflows/extension-migration-checks.yml +++ b/.github/workflows/extension-migration-checks.yml @@ -10,6 +10,8 @@ on: - "src/lfx/src/lfx/components/**" - "src/bundles/**" - "src/backend/base/langflow/api/**.py" + - "scripts/ci/check_components_frozen.py" + - "scripts/ci/frozen_component_dirs.txt" - ".github/workflows/extension-migration-checks.yml" jobs: @@ -84,3 +86,18 @@ jobs: - name: Run check_router_trust.py run: python scripts/migrate/check_router_trust.py + + freeze-components: + name: Freeze lfx/components + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - name: Checkout code + uses: actions/checkout@v6 + with: + persist-credentials: false + + # Stdlib-only gate; no uv sync needed. After the bundle metapackage + # split, new providers go to lfx-bundles, not src/lfx/src/lfx/components/. + - name: Forbid new top-level directories under lfx/components (post-freeze) + run: python3 scripts/ci/check_components_frozen.py diff --git a/.github/workflows/lint-py.yml b/.github/workflows/lint-py.yml index 0a6af9679a..b5f004595f 100644 --- a/.github/workflows/lint-py.yml +++ b/.github/workflows/lint-py.yml @@ -45,17 +45,3 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.github_token }} - freeze-components: - name: Freeze lfx/components - runs-on: ubuntu-latest - steps: - - name: Check out the code at a specific ref - uses: actions/checkout@v6 - with: - ref: ${{ inputs.branch || github.ref }} - persist-credentials: false - # Stdlib-only gate; no uv sync needed. After the bundle metapackage - # split, new providers go to lfx-bundles, not src/lfx/src/lfx/components/. - - name: Forbid new top-level directories under lfx/components (post-freeze) - run: python3 scripts/ci/check_components_frozen.py - diff --git a/src/lfx/src/lfx/interface/components.py b/src/lfx/src/lfx/interface/components.py index fab44e89b3..55862329c3 100644 --- a/src/lfx/src/lfx/interface/components.py +++ b/src/lfx/src/lfx/interface/components.py @@ -413,8 +413,13 @@ def _discover_shimmed_component_dirs(search_paths: list[str]) -> set[str]: init_py = child / "__init__.py" if not (child.is_dir() and init_py.is_file()): continue + # The shim contract puts the marker on line 1 (enforced by + # test_shim_source_contract), so only the first line is read -- + # a non-shim file that merely mentions the marker further down + # can never be misclassified and silently skipped. try: - head = init_py.read_text(encoding="utf-8").lstrip() + with init_py.open(encoding="utf-8") as f: + head = f.readline() except OSError: continue if head.startswith(_LFX_BUNDLES_SHIM_MARKER):