Skip to content

Add pre-commit hooks for flow validation - #4

Merged
vvemulapalli11 merged 28 commits into
mainfrom
feat/add-precommit-support
Sep 16, 2026
Merged

vvemulapalli11 merged 28 commits into
mainfrom
feat/add-precommit-support

Conversation

@vvemulapalli11

@vvemulapalli11 vvemulapalli11 commented Sep 14, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

  • Adds a shared Husky pre-commit entry point that routes Python checks and runs the existing Playwright pipeline for added, copied, modified, or renamed files under e2e/tests/ and e2e/test-setup/; deletion-only e2e changes skip the staged-file pipeline, and commits touching both project areas run both applicable check sets.
  • Adds Ruff linting and formatting with automatic fixes for staged Python files.
  • Adds flows/scripts/check_flows.py to discover QA flows, enforce repository conventions, and run Metaflow's native definition and DAG validation without authenticating or starting workloads.
  • Adds focused unit tests for the custom flow checker and pinned tool-version consistency. These tests run when checker code, tests, dependencies, or tool configuration changes rather than for every ordinary flow support-file change.
  • Runs staged-index FlowSpec filename validation for Python changes anywhere in the repository, while keeping Ruff and native Metaflow checks scoped to flows/.
  • Validates every tracked Python file directly from the Git index, rejecting any file that defines a FlowSpec without the required *_flow.py suffix, including heavily rewritten moves that Git represents as delete/add pairs.
  • Resolves direct and module import aliases for metaflow.FlowSpec, so aliased flow classes are discovered and remain subject to staged filename validation.
  • Handles configuration changes, deletions, and renames explicitly: moving a flow must retain the *_flow.py suffix, and deleting the final tracked flow fails based on the staged index rather than working-tree files.
  • Rejects conflict markers and whitespace errors in staged changes and documents setup and validation commands.

Test plan

  • pre-commit run --all-files - Ruff, Metaflow validation, and flow utility tests pass

  • pytest -q flows/tests - 23 tests pass

  • npm --prefix e2e run lint

  • npm --prefix e2e run validate

  • cd e2e && npx prettier --check package.json

  • sh -n .husky/pre-commit

  • pre-commit validate-config .pre-commit-config.yaml

  • Verified ordinary flow utility files run Ruff while skipping checker unit tests

  • Verified no unresolved conflict markers or whitespace errors remain

  • Verified the Playwright utility resolves e2e as its QA consumer root

  • Verified an untracked *_flow.py cannot satisfy final tracked-flow deletion validation

  • Verified heavily rewritten flow moves fail both inside and outside flows/

  • Verified FlowSpec aliases are recognized for discovery and misnamed-file rejection

  • Verified root-level Python paths activate the FlowSpec filename hook while non-Python paths do not

vvemulapalli11 and others added 11 commits September 11, 2026 14:54
- husky pre-commit no longer exits before running the e2e check when
  the pre-commit binary is missing, so a commit touching both flows/
  and e2e/ still runs both checks.
- narrow the check-flows hook's files pattern to *_flow.py so
  check_flows.py no longer needs to guess whether staged paths are an
  explicit selection, and drop the now-redundant --require-selection
  flag and the untested flows-relative path fallback.
Not part of this change; leaving it as an untracked working-tree file
as it was before.
README claimed check-flows validates all discovered flows, but
pre-commit only passes staged filenames. Also fixed
test_rejects_invalid_selected_paths, which resolved relative paths
against tmp_path.parent and accidentally tripped the outside-root
check instead of the missing-file/wrong-suffix checks it meant to test.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two moderate pre-commit integration issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds flow validation tooling and integrates Ruff, Metaflow checks, pytest, and Husky pre-commit routing.

Changes:

  • Adds AST-based flow discovery, convention checks, native Metaflow validation, and tests.
  • Configures Ruff, pytest, dependency pins, documentation, and tool-version checks.
  • Consolidates Husky routing and removes the nested E2E hook.
  • Reformats flow model code without logic changes.
File summaries
File Summary Review notes
README.md Documents development checks. Nit (2 votes): Narrow the routing claim to staged *_flow.py files.
pyproject.toml Configures Ruff and pytest. —
flows/tests/test_tool_versions.py Tests tool-version consistency. —
flows/tests/test_check_flows.py Tests flow checker behavior. —
flows/scripts/check_flows.py Implements flow discovery and validation. —
flows/requirements.txt Pins Outerbounds dependencies. —
flows/requirements-dev.txt Adds development dependencies. —
flows/README.md Documents flow tooling and validation. Nits (2, 1, and 2 votes): Clarify hook selector scope, all-files exceptions, and the distinction between staged native checks and repository-wide discovery checks.
flows/models/utils/model_validators.py Applies Ruff formatting. —
flows/models/local_cache_model_flow.py Applies formatting and documentation updates. —
flows/models/download_safetensors_model_flow.py Applies formatting and documentation updates. —
flows/models/download_gguf_model_flow.py Applies formatting and documentation updates. —
flows/models/browse_models_flow.py Applies formatting and documentation updates. —
e2e/.husky/pre-commit Removes the nested E2E hook. —
.pre-commit-config.yaml Defines flow validation hooks. —
.husky/pre-commit Routes flow and E2E checks. Moderate (2 votes): Make Husky setup durable across later e2e installs. Moderate (1 vote): Run the E2E package hook for every staged path under e2e/.
.gitignore Preserves root pre-commit configuration. —
Review details

Suppressed comments (2)

.husky/pre-commit:53

  • playwright-utils-precommit is gated here only for e2e/tests and e2e/test-setup, so staged e2e/playwright.config.ts, package.json, JSON, or Markdown changes bypass the E2E hook even though the package's lint-staged and quality configuration covers them. Invoke the package hook for every staged path under e2e/; its own QA-scoped gate can skip non-QA commits, and run it from e2e so it resolves the correct consumer root.
if git diff --cached --name-only --diff-filter=ACMR | grep -Eq '^e2e/(tests|test-setup)/'; then
  npm --prefix e2e run precommit || status=1

flows/README.md:83

  • This is not true for all normal commits: the root hook explicitly switches to pre-commit run --all-files when hook/configuration files change or anything under flows/ is deleted. Please document these exceptions so the staged-only behavior is not relied on for those commits.
tool-version consistency checks. `check-flows` validates only the staged
flow files, and `test-flow-tools` runs the complete local test suite. Neither hook
  • Files reviewed: 16/17 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread .husky/pre-commit Outdated
Comment thread README.md Outdated
Comment thread flows/README.md Outdated
Comment thread flows/README.md Outdated
vvemulapalli11 and others added 3 commits September 14, 2026 12:51
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two moderate pre-commit routing gaps can bypass validation or focused tests; documentation nits also remain.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (5)

.pre-commit-config.yaml:32

  • When only pyproject.toml is staged, the root Husky hook forces pre-commit run --all-files, but this files pattern still excludes pyproject.toml, so test-flow-tools is skipped even though that file controls pytest/Ruff behavior. Include it in the hook's trigger pattern so configuration changes cannot bypass the focused suite.
        files: ^(flows/.*\.py|flows/requirements(-dev)?\.txt|\.pre-commit-config\.yaml)$

.pre-commit-config.yaml:19

  • The files filter prevents this hook from running when the final *_flow.py is deleted. In that case the root hook's pre-commit run --all-files invocation has no matching path, so discover_flows() is never called and its empty-matrix guard is bypassed. Add a deletion/empty-inventory path that invokes this checker even when no flow filename remains, while preserving staged-path selection for normal runs.
        files: ^flows/.*_flow\.py$

README.md:23

  • This routing description is broader than the hook: .husky/pre-commit invokes the Playwright command only for e2e/tests/ and e2e/test-setup/, so staged changes such as e2e/package.json do not run it. Please document the actual scoped paths or broaden the shell condition.
is the entry point and runs each area only when that area has staged changes. A
commit touching both directories runs both.

flows/README.md:81

  • The subject here is the plural list of requirements/configuration files, but the sentence uses singular is. Use the plural verb so the setup instructions are grammatically correct.
tool-version consistency checks. The native Metaflow check runs only for staged

flows/README.md:79

  • This also overstates the Playwright scope: the Husky hook matches only e2e/tests/ and e2e/test-setup/, so changes to e2e/package.json, configuration, or other files under e2e/ are intentionally skipped. Document the scoped paths here.
`flows/requirements.txt`, `flows/requirements-dev.txt`, or
  • Files reviewed: 17/18 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread README.md Outdated
Comment thread flows/README.md Outdated
vvemulapalli11 and others added 4 commits September 14, 2026 13:04
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved Ruff failure and three moderate pre-commit validation issues block approval.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

.husky/pre-commit:61

  • npm --prefix e2e run precommit is launched with the repository root as npm's INIT_CWD. The Playwright utility explicitly uses INIT_CWD to resolve CONSUMER_ROOT, so this can scope lint-staged and the staged quality report to the root instead of e2e (which has the relevant package.json and globs), causing the preserved E2E checks to skip or mis-scope their files. Run npm from the QA package directory so the utility receives e2e as its consumer root.
  npm --prefix e2e run precommit || status=1

.husky/pre-commit:51

  • The final-flow guard checks the index, but the manual inventory hook invokes discover_flows() without a selection and that function globs the working tree. An untracked flows/**/*_flow.py can therefore satisfy the inventory check, allowing the last tracked flow to be deleted even though the resulting commit contains no flow. Make the inventory validation enumerate the staged/tracked flow paths (or otherwise exclude untracked files) before allowing this deletion.
      if printf '%s\n' "$deleted" | grep -Eq '^flows/.*_flow\.py$' \
        && ! git ls-files --cached 'flows/*_flow.py' 'flows/**/*_flow.py' | grep -q .; then
        "$pre_commit" run check-flow-inventory --hook-stage manual || status=1
  • Files reviewed: 17/18 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread flows/tests/test_check_flows.py Outdated
Comment thread .husky/pre-commit Outdated
vvemulapalli11 and others added 3 commits September 14, 2026 13:45
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Three moderate findings remain involving rename detection, virtualenv selection, and misnamed flow discovery.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

.husky/pre-commit:46

  • When flows/.venv exists but is not activated, any globally installed pre-commit wins this branch, so the documented fallback and the pinned pre-commit==4.6.2 environment are bypassed. That can run a different pre-commit version and hook environment than the one whose dependencies this PR defines; prefer the repository virtualenv path before searching PATH.
  if command -v pre-commit >/dev/null 2>&1; then
    pre_commit=pre-commit
  elif [ -x flows/.venv/bin/pre-commit ]; then
    pre_commit=flows/.venv/bin/pre-commit

.pre-commit-config.yaml:19

  • A newly added or copied flow can bypass this hook by using a non-*_flow.py filename: the root hook still enters pre-commit for any flows/ change, but this files pattern excludes flows/foo.py, and discover_flows() only scans the same suffix. Such a file can contain a FlowSpec and still be committed despite the documented requirement that every executable flow use *_flow.py; inspect staged Python files for flow definitions (or otherwise reject misnamed FlowSpec files) rather than using the suffix as the sole discovery filter.
        files: ^flows/.*_flow\.py$
  • Files reviewed: 17/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread .husky/pre-commit Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two moderate validation gaps remain in hook coverage and aliased FlowSpec detection.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

.husky/pre-commit:30

  • This gate only enters the Python checks when a staged path starts with flows/ (or matches the config pattern), so a commit that adds or moves a FlowSpec in another tracked Python path, such as renamed.py covered by test_rejects_rewritten_flow_moved_to_filename_without_suffix, never invokes the validator. The check-flow-filenames hook is also scoped to ^flows/.*\.py$, despite validate_tracked_flow_filenames promising to inspect every tracked Python file. Trigger the filename check for all staged Python files and broaden its pre-commit file selector accordingly.
if printf '%s\n' "$staged" | grep -Eq "^flows/|$config_pattern"; then
  • Files reviewed: 17/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread flows/scripts/check_flows.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two unresolved moderate findings affect flow detection and deleted-file validation.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (1)

.husky/pre-commit:63

  • This filter omits pure deletions, so deleting a file under e2e/tests/ or e2e/test-setup/ never invokes npm run precommit, even though the README says staged paths in those directories activate the Playwright checks. Include D so the shared hook validates deletions as well.
if git diff --cached --name-only --diff-filter=ACMR | grep -Eq '^e2e/(tests|test-setup)/'; then
  • Files reviewed: 17/18 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread flows/scripts/check_flows.py Outdated
vvemulapalli11 and others added 2 commits September 14, 2026 14:53
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The broad hook, staged-index, and flow-validation changes warrant final human review.

Review details
  • Files reviewed: 17/18 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@RidaZubair RidaZubair left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@vvemulapalli11
vvemulapalli11 merged commit 443921e into main Sep 16, 2026
1 check passed
@vvemulapalli11
vvemulapalli11 deleted the feat/add-precommit-support branch September 16, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants