Skip to content

feat(scripts): add lint:py:fix to apply ruff autofixes across Python skills#1450

Merged
katriendg merged 6 commits intomainfrom
feat/886-python-lint-fix
Apr 29, 2026
Merged

feat(scripts): add lint:py:fix to apply ruff autofixes across Python skills#1450
katriendg merged 6 commits intomainfrom
feat/886-python-lint-fix

Conversation

@WilliamBerryiii
Copy link
Copy Markdown
Member

@WilliamBerryiii WilliamBerryiii commented Apr 26, 2026

Description

Adds an npm run lint:py:fix script that wraps a new scripts/linting/Invoke-PythonLintFix.ps1 runner. The script discovers every Python skill (any directory containing pyproject.toml, excluding node_modules) and runs both ruff check . --fix and ruff format . against each one, falling back from the local .venv ruff to a global ruff when needed. Both ruff exit codes are captured and the combined output is written to logs/python-lint-fix-results.json.

The new script is intentionally not wired into npm run lint:all, since it mutates source files. It is opt-in for contributors who want to apply ruff autofixes across all Python skills in one command.

Related Issue(s)

Closes #886

Type of Change

Code & Documentation:

  • New feature (non-breaking change adding functionality)
  • Refactor (shared module extraction, no behavior change for lint:py)

Infrastructure & Configuration:

  • Linting configuration (markdown, PowerShell, etc.)

Other:

  • Script/automation (.ps1, .sh, .py)

Testing

Validation performed locally on feat/886-python-lint-fix:

  • Pester unit tests: npm run test:ps -- -TestPath "scripts/tests/linting/" — all green, including new PythonLintHelpers.Tests.ps1 (11 tests covering Get-PythonSkill, Resolve-RuffCommand, and Write-PythonLintResults).
  • PowerShell static analysis: npm run lint:ps — clean for the new module and runners.
  • Smoke test: npm run lint:py:fix — exit 0, valid JSON written to logs/python-lint-fix-results.json with both fixExitCode and formatExitCode per skill.

Test coverage includes parameter validation, ruff tool availability and .venv fallback behavior, skill discovery (pyproject.toml inclusion + node_modules exclusion), ruff format chaining and exit-code propagation, parent-directory creation before writing results, and output JSON persistence.

Review Comment Resolution

This revision addresses all five review threads on the PR:

  1. [OutputType([hashtable])] on runners — added to both Invoke-PythonLint.ps1 and Invoke-PythonLintFix.ps1 along with # Purpose: / # Author: headers.
  2. Chain ruff format after ruff check --fixInvoke-PythonLintFix.ps1 now invokes both subcommands per skill and surfaces fixExitCode and formatExitCode in the result hashtable.
  3. Inline header comment — added Purpose/Author block matching repo conventions.
  4. Duplication between runners — extracted Get-PythonSkill, Resolve-RuffCommand, and Write-PythonLintResults into scripts/linting/Modules/PythonLintHelpers.psm1, consumed by both runners.
  5. Parent-dir guard before Out-FileWrite-PythonLintResults creates the output's parent directory when missing.

Checklist

Required Checks

  • Documentation is updated (if applicable) — N/A; no doc surface changes.
  • Files follow existing naming conventions (Invoke-*.ps1 runners; shared module under scripts/linting/Modules/; mirrored *.Tests.ps1 under scripts/tests/linting/).
  • Changes are backwards compatible (purely additive script + internal refactor; lint:py behavior unchanged).
  • Tests added for new functionality.

Required Automated Checks

  • PowerShell analysis: npm run lint:ps
  • Markdown linting: npm run lint:md
  • Spell checking: npm run spell-check
  • Frontmatter validation: npm run lint:frontmatter
  • Skill structure validation: npm run validate:skills
  • Link validation: npm run lint:md-links
  • Plugin freshness: npm run plugin:generate
  • Docusaurus tests: npm run docs:test

Security Considerations

  • This PR does not contain any sensitive or NDA information
  • Any new dependencies have been reviewed for security issues — no new package dependencies; relies on ruff already required by Python skills.
  • Security-related scripts follow the principle of least privilege — script reads pyproject.toml, invokes ruff with --fix and format, and writes a single JSON log file under logs/.

Additional Notes

  • lint:py:fix is intentionally excluded from lint:all because it modifies source files. It is meant to be invoked explicitly by contributors.
  • The runner prefers each skill's local .venv ruff and falls back to a globally available ruff only when no .venv is present, matching the resolution logic used by lint:py.

…skills

Closes #886

- add Invoke-PythonLintFix.ps1 to discover Python skills via pyproject.toml and run ruff check --fix per skill

- add npm run lint:py:fix script wrapping the runner

- add Pester unit tests covering parameter validation, tool availability, skill discovery, lint execution, and output persistence

🐍 - Generated by Copilot
@WilliamBerryiii WilliamBerryiii requested a review from a team as a code owner April 26, 2026 17:00
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 26, 2026

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@codecov-commenter
Copy link
Copy Markdown

codecov-commenter commented Apr 26, 2026

Codecov Report

❌ Patch coverage is 75.58140% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 86.83%. Comparing base (ec2aa53) to head (98debf8).

Files with missing lines Patch % Lines
scripts/linting/Invoke-PythonLint.ps1 67.18% 21 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #1450      +/-   ##
==========================================
- Coverage   87.70%   86.83%   -0.87%     
==========================================
  Files          65       63       -2     
  Lines       10198     9550     -648     
==========================================
- Hits         8944     8293     -651     
- Misses       1254     1257       +3     
Flag Coverage Δ
pester 85.05% <75.58%> (-0.09%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
scripts/linting/Modules/PythonLintHelpers.psm1 100.00% <100.00%> (ø)
scripts/linting/Invoke-PythonLint.ps1 75.82% <67.18%> (-8.69%) ⬇️

... and 4 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions Bot mentioned this pull request Apr 26, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Advisory review, this PR is from a maintainer. Findings are informational only.

Overview

This PR adds npm run lint:py:fix backed by a new Invoke-PythonLintFix.ps1 script and a comprehensive Pester test suite (23 tests covering parameter validation, tool availability, skill discovery, lint execution paths, and output persistence). The implementation is clean, well-structured, and consistent with the existing Invoke-PythonLint.ps1 pattern.


✅ Issue Alignment

Issue #886 requires four items; all are confirmed satisfied:

Acceptance Criterion Status
npm run lint:py ✅ Pre-existing in package.json
npm run lint:py:fix ✅ Added by this PR
npm run test:py ✅ Pre-existing in package.json
lint:all includes lint:py ✅ Confirmed in package.json

The intentional exclusion of lint:py:fix from lint:all (due to file mutation) is well-documented in the PR description. This is a reasonable design decision.


✅ PR Template Compliance

  • Description: clear and complete
  • Related issue: Closes #886
  • Type of Change checkboxes: correctly checked (New feature, Linting configuration, Script/automation) ✅
  • Testing: thorough — Pester unit tests, lint:ps static analysis, and smoke test documented ✅
  • Security considerations: all checked and appropriate ✅

Minor note: Several Required Automated Checks are unchecked (markdown linting, spell checking, frontmatter, etc.). For a pure PowerShell + package.json change these are arguably N/A, but marking them explicitly as N/A (or checking them if they were run and passed) in the checklist would help reviewers confirm their scope was considered.


🔍 Coding Standards

Two advisory findings are posted as inline comments:

  1. Missing [OutputType([hashtable])] on Invoke-PythonLintFix (line 26) — per PSUseOutputTypeCorrectly rule in the PowerShell instructions. The same omission exists in the existing Invoke-PythonLint.ps1, so both could be aligned in a follow-up.

  2. ruff check . --fix vs ruff format . (line 86) — the issue's example specified ruff format (formatting), while the implementation applies ruff check --fix (lint rule autofixes). These are distinct operations; clarifying the scope or combining both would strengthen the command.


✅ Code Quality

  • Skill discovery (pyproject.toml find + node_modules exclusion): correct ✅
  • Ruff resolution chain (venv → global fallback): matches Invoke-PythonLint.ps1
  • Push-Location/Pop-Location pairing with try/finally: correct ✅
  • $LASTEXITCODE capture for external process exit: correct (unaffected by $ErrorActionPreference = 'Stop') ✅
  • JSON output persistence: consistent with sibling scripts ✅
  • Test coverage: comprehensive, uses established Pester patterns for this repo ✅

No security concerns identified.

Generated by PR Review for issue #1450 · ● 1.1M

Comment thread scripts/linting/Invoke-PythonLintFix.ps1 Outdated
Comment thread scripts/linting/Invoke-PythonLintFix.ps1 Outdated
Copy link
Copy Markdown
Contributor

@katriendg katriendg left a comment

Choose a reason for hiding this comment

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

Approving, two small comments by AW reviewer worth checking.

Comment thread package.json Outdated
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Advisory review, this PR is from a maintainer. Findings are informational only.


Review Summary

Overall the PR is clean, well-tested, and consistent with the existing Invoke-PythonLint.ps1 sibling. The implementation is correct and the 23 Pester tests give good coverage of the meaningful behavioral paths. Two inline comments flag areas worth addressing; additional notes follow.


Issue Alignment

Issue #886 is legitimately closeable. Reviewing the base package.json:

  • lint:py already exists and is already wired into lint:all
  • test:py already exists
  • This PR supplies the missing lint:py:fix entry

All seven acceptance criteria from #886 are now met.

i️ Informational — ruff check --fix vs ruff format

Issue #886 used ruff format in its example snippet for lint:py:fix. The implementation instead uses ruff check . --fix, which auto-corrects lint-rule violations; ruff format applies code formatting (PEP 8 / Black-style). These are complementary but distinct operations. The current choice is reasonable for a lint-fix command and the PR description describes it accurately. It may be worth adding a one-liner to the Additional Notes in the description (or a # See also: ruff format comment in the script) to help contributors who expected formatter-style output.


PR Template Compliance

✅ Description, issue reference, and type-of-change checkboxes are all correctly filled.

The remaining unchecked automated checks (lint:md, lint:frontmatter, validate:skills, lint:md-links, plugin:generate, docs:test) are all legitimately N/A for a pure .ps1 / package.json change. It would be helpful to annotate each unchecked item with (N/A — no markdown/frontmatter/skill/plugin changes) per the template guidance, but this is minor.

spell-check is technically applicable to English text in PS comments and is not marked N/A — low risk but worth a quick run.


Coding Standards

✅ Copyright header, SPDX identifier, #Requires -Version 7.0, [CmdletBinding()], $ErrorActionPreference = 'Stop', #region/#endregion, and the $MyInvocation.InvocationName -ne '.' invocation guard are all present and correct.

The script intentionally mirrors the sibling's header style (inline # comments rather than a <# .SYNOPSIS #> block). PSScriptAnalyzer passes, confirming the rule configuration accepts this pattern.


Test Quality

✅ 23 tests across parameter validation, tool availability, skill discovery, ruff execution, and output persistence. Exception handling and the node_modules exclusion are explicitly covered.

i️ Test naming convention — Per pester.instructions.md, the repo standard is given_context_when_action_then_expected (e.g., given_ruff_missing_when_fixing_then_returns_failure). Current names use plain English like 'Returns failure when ruff not available'. This matches the sibling Invoke-PythonLint.Tests.ps1 exactly, so it is a pre-existing pattern. Worth standardizing in a future pass when both test files are touched.


Action Items (informational)

  1. Duplication — See inline comment at line 25 of Invoke-PythonLintFix.ps1. Extracting a PythonLintHelpers.psm1 module would prevent the two scripts from diverging silently over time.
  2. OutputPath parent-dir guard — See inline comment at line 126. The same gap exists in Invoke-PythonLint.ps1 and would be cleanly resolved alongside the shared-module extraction above.
  3. ruff format coverage — Consider whether a future lint:py:format / lint:py:format:check entry is desired to give contributors Black-style formatting via ruff format.

Generated by PR Review for issue #1450 · ● 1.1M

Comment thread scripts/linting/Invoke-PythonLintFix.ps1 Outdated
Comment thread scripts/linting/Invoke-PythonLintFix.ps1 Outdated
@WilliamBerryiii
Copy link
Copy Markdown
Member Author

Pushed a revision addressing all five review threads — ready for re-review:

  1. [OutputType([hashtable])] added to Invoke-PythonLint.ps1 and Invoke-PythonLintFix.ps1, along with the # Purpose: / # Author: header comment.
  2. ruff format chained after ruff check --fix in Invoke-PythonLintFix.ps1; both fixExitCode and formatExitCode are surfaced per skill in the JSON output.
  3. Inline header comment added to both runners.
  4. Duplication eliminated by extracting Get-PythonSkill, Resolve-RuffCommand, and Write-PythonLintResults into scripts/linting/Modules/PythonLintHelpers.psm1 (consumed by both runners).
  5. Parent-directory guard added in Write-PythonLintResults before Out-File.

Validation locally on feat/886-python-lint-fix:

  • npm run lint:ps — clean.
  • npm run test:ps -- -TestPath scripts/tests/linting/ — all green, including a new PythonLintHelpers.Tests.ps1 (11 tests covering all three helpers).
  • npm run lint:py:fix — exit 0; valid JSON with fixExitCode + formatExitCode for each of the 4 Python skills.

…ormat in lint:py:fix

- extract Get-PythonSkill / Resolve-RuffCommand / Write-PythonLintResults into scripts/linting/Modules/PythonLintHelpers.psm1
- add [OutputType([hashtable])] and Purpose/Author header to Invoke-PythonLint(Fix).ps1
- chain ruff check --fix then ruff format . in Invoke-PythonLintFix.ps1, capture both exit codes
- guard results-output parent directory before Out-File
- cover format chain, formatExitCode propagation, and PythonLintHelpers module in scripts/tests/linting/

🐍 - Generated by Copilot
@github-actions github-actions Bot mentioned this pull request Apr 28, 2026
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Advisory review — this PR is from a maintainer. Findings are informational only.


Review Summary

This is a well-structured PR. The shared module extraction into PythonLintHelpers.psm1 is the right call, the test coverage across PythonLintHelpers.Tests.ps1 and Invoke-PythonLintFix.Tests.ps1 is thorough, and the dual ruff check --fix + ruff format chain correctly satisfies the acceptance criterion from #886. With lint:all already including lint:py and test:py already present, this PR cleanly closes the issue. Two small convention items are noted inline.


Issue Alignment ✅

All acceptance criteria from #886 are now satisfied:

  • lint:py — already present and now delegates to the refactored shared module
  • lint:py:fix — added by this PR ✅
  • test:py — already present
  • lint:all includes lint:py — already in place (line 27, package.json)
  • Both fixExitCode and formatExitCode are surfaced per-skill ✅
  • Skill discovery is pyproject.toml-driven (no hardcoded paths) ✅

PR Template Compliance ⚠️

Two minor template items to be aware of:

  1. Custom "Refactor" checkbox — The template's "Type of Change" section does not include a "Refactor" option. The description text adequately covers the shared-module extraction, so this checkbox is informational noise. Consider using "Other (please describe)" for items not in the template, or simply relying on the description.

  2. "Linting configuration" checkbox — The PR adds linting runner scripts (.ps1), not linting configuration files (e.g., .markdownlint.json, PSScriptAnalyzer.psd1). The "Script/automation (.ps1, .sh, .py)" checkbox already accurately describes the changes; "Linting configuration" doesn't apply here.


Coding Standards ✅ (with notes)

Inline comments are raised for:

  • Missing try-catch in main execution guard (Invoke-PythonLintFix.ps1, line 137) — informational; same gap exists in the sibling Invoke-PythonLint.ps1.
  • Missing #Requires -Version 7.0 in module (PythonLintHelpers.psm1, line 9) — informational; consistent with the existing gap in LintingHelpers.psm1 and FrontmatterValidation.psm1.

Code Quality ✅

  • Resolve-RuffCommand correctly short-circuits: Linux .venv/bin/ruff → Windows .venv/Scripts/ruff.exe → global fallback → $null. No issues.
  • Write-PythonLintResults correctly guards the parent directory before writing and returns the resolved path. No issues.
  • The ruff format step is unconditional after ruff check --fix, which is correct — formatting should run regardless of whether --fix made changes.
  • $global:LASTEXITCODE set in the ruff mock is the right pattern for Pester testing of external-process exit codes.

No security concerns, logic errors, or breaking changes found.

Generated by PR Review for issue #1450 · ● 4.5M

Comment thread scripts/linting/Invoke-PythonLintFix.ps1 Outdated
Comment thread scripts/linting/Modules/PythonLintHelpers.psm1
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Advisory review — this PR is from a maintainer. Findings are informational only.


Overview

This PR cleanly delivers the missing lint:py:fix entry that completes issue #886. The shared-module extraction into PythonLintHelpers.psm1 is the right architectural move, the dual ruff check --fix + ruff format chain is correct, and the 23 Pester tests provide solid coverage of the meaningful behavioral paths. Two inline comments flag new items not raised in prior rounds; the two open threads from the previous review remain unresolved.


Issue Alignment ✅

All seven acceptance criteria from #886 are now satisfied:

Criterion Status
npm run lint:py ✅ Pre-existing
npm run lint:py:fix ✅ Added by this PR
npm run test:py ✅ Pre-existing
lint:all includes lint:py ✅ Confirmed
Both fixExitCode and formatExitCode surfaced per-skill
pyproject.toml-driven discovery (no hardcoded paths)
Adding a new skill is auto-discovered

PR Template Compliance ⚠️

Two minor inaccuracies in the Type of Change section:

  1. "Refactor" checkbox — this option does not exist in the template. The shared-module extraction is an implementation detail adequately described in the prose Description. Checking a non-existent option can confuse automation that parses checkbox state. "Other (please describe)" or the existing "Script/automation" checkbox would be more accurate.

  2. "Linting configuration" checkbox — the template intends this for configuration files (.markdownlint.json, PSScriptAnalyzer.psd1, etc.), not linting runner scripts. The "Script/automation (.ps1, .sh, .py)" checkbox already covers the new .ps1 files accurately.

Several Required Automated Checks are unchecked without an N/A annotation (lint:md, spell-check, lint:frontmatter, validate:skills, lint:md-links, plugin:generate, docs:test). For a pure .ps1 + package.json change these are legitimately out of scope, but annotating them as (N/A — no markdown/frontmatter/skill/plugin changes) per the template guidance makes reviewer intent explicit. Of the unchecked items, spell-check is technically in-scope for English text in PowerShell comments and is worth a quick pass.


Open Threads from Prior Review

Two inline threads from the previous automated review (run 25033819647) remain unresolved in the current head commit:

  • Missing #Requires -Version 7.0 in PythonLintHelpers.psm1 — per PowerShell module conventions, the #Requires statement belongs after the purpose/author comment block (line 9 area). Open thread: scripts/linting/Modules/PythonLintHelpers.psm1 #discussion_r3151589208.
  • Missing try-catch in main execution guard (Invoke-PythonLintFix.ps1, line 137) — if Invoke-PythonLintFix throws an unhandled terminating error the script exits with a raw exception trace rather than a clean exit 1. Open thread: #discussion_r3151589203.

Both are low-risk for this PR's intended use case; bindsi's approval reflects that judgment. They are worth tracking for a follow-up that aligns all linting runners.


New Findings (inline comments)

  1. PythonLintHelpers.psm1 line 9 — CIHelpers.psm1 imported but unused. None of the three exported functions call Write-CIAnnotation, Set-CIOutput, Write-CIStepSummary, or Set-CIEnv. The import adds a hard relative-path dependency with no current benefit. If CI annotation support is planned for a future pass, a forward-intent comment clarifies the decision; otherwise the import can be removed.

  2. Invoke-PythonLintFix.ps1 line 117 — errors array has mixed entry formats. The no-ruff path pushes a bare path string; the exception-catch path pushes a formatted string "$skillPath - error: $_". Callers iterating $result.errors expecting consistent bare paths will encounter a mixed-type array. Prefer a bare path in errors and surface the exception detail in the output field or a dedicated key. The corresponding test assertion (Should -Not -BeNullOrEmpty) does not catch this regression; tightening it to Should -Contain $script:SkillDir would.


Code Quality ✅

  • Resolve-RuffCommand short-circuit order (Linux .venv → Windows .venv → global → $null) is correct and consistent with Invoke-PythonLint.ps1.
  • Write-PythonLintResults correctly guards the parent directory and returns the resolved path.
  • ruff format is invoked unconditionally after ruff check --fix, which is correct — formatting should apply regardless of whether --fix made changes.
  • $global:LASTEXITCODE in the Pester ruff mock is the right pattern for testing external-process exit codes.
  • No security concerns, logic errors, or breaking changes identified.

Generated by PR Review for issue #1450 · ● 1.7M

Comment thread scripts/linting/Modules/PythonLintHelpers.psm1
Comment thread scripts/linting/Invoke-PythonLintFix.ps1 Outdated
…nLint

- add -Fix switch and remove Invoke-PythonLintFix.ps1 plus its tests
- extract shared logic into PythonLintHelpers.psm1 with #Requires 7.0
- wrap main execution in try-catch with Write-CIAnnotation
- update package.json lint:py:fix to call main script with -Fix

♻️ - Generated by Copilot
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Advisory review, this PR is from a maintainer. Findings are informational only.


Review Summary

This PR cleanly extends the existing Invoke-PythonLint.ps1 runner with a -Fix switch, extracts three shared helpers into a new PythonLintHelpers.psm1 module, and ships a dedicated test file for those helpers. The implementation is well-structured and the refactor reduces duplication without changing the behavior of the existing lint:py path.

Three advisory observations are posted as inline comments; none are blocking.


Issue Alignment

✅ Closes #886. The key acceptance criteria are met:

  • npm run lint:py:fix applies ruff check --fix + ruff format across all Python skills.
  • lint:all already includes lint:py (confirmed in the current package.json); lint:py:fix is intentionally excluded because it mutates source files — the PR description explains this clearly.
  • New Python skills with pyproject.toml are auto-discovered through Get-PythonSkill without any script changes required.

PR Template Compliance

✅ Description, related issue, type of change, testing, and security sections are all populated.

🔍 Minor description inaccuracy: The Description section and "Review Comment Resolution" item 1 both refer to Invoke-PythonLintFix.ps1 as a separate file, but the actual implementation adds a -Fix switch to the existing Invoke-PythonLint.ps1 — no separate Invoke-PythonLintFix.ps1 was created. The package.json script confirms this (pwsh -NoProfile -File ./scripts/linting/Invoke-PythonLint.ps1 -Fix ...). The description could be updated to accurately reflect the implementation choice.

The unchecked automated checks (lint:md, lint:frontmatter, spell-check, etc.) are reasonable N/A for a PowerShell-only change with no markdown or frontmatter files modified.


Coding Standards

✅ Copyright headers, #Requires -Version 7.0, [CmdletBinding()], [OutputType()], comment-based help, Export-ModuleMember, and the if ($MyInvocation.InvocationName -ne '.') guard are all present and correct.

Three minor observations posted as inline comments:

  1. Write-CIAnnotation implicit transitive dependency (Invoke-PythonLint.ps1:195) — CIHelpers should be imported directly in the script rather than relying on the nested import inside PythonLintHelpers.psm1.
  2. Out-File vs Set-Content (PythonLintHelpers.psm1:135) — Set-Content -Encoding UTF8 is the conventional pattern in this codebase.
  3. Lost debug output (PythonLintHelpers.psm1:78) — The original code printed Using venv ruff when selecting the .venv binary; that observability was dropped in the refactor.

Code Quality

✅ The dual-path if ($Fix) inside the foreach loop is verbose but readable. The alternative — a separate inner function per mode — would add indirection without significant benefit at this scale.

✅ The Excludes node_modules from discovery test in Invoke-PythonLint.Tests.ps1 is correctly updated to a pass-through mock (Mock Get-PythonSkill { @() }) with a comment explaining that the filter logic is now tested in PythonLintHelpers.Tests.ps1. This is the right approach after the extraction.

PythonLintHelpers.Tests.ps1 uses real filesystem fixtures (New-Item, Set-Content) rather than mocks for Get-PythonSkill tests — appropriate since the function's value is precisely its file-system scanning behavior.

No security vulnerabilities or logic errors identified.

Generated by PR Review for issue #1450 · ● 2.5M

Comment thread scripts/linting/Invoke-PythonLint.ps1
Comment thread scripts/linting/Modules/PythonLintHelpers.psm1
Comment thread scripts/linting/Modules/PythonLintHelpers.psm1
Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Advisory review, this PR is from a maintainer. Findings are informational only.

Overview

This PR cleanly adds npm run lint:py:fix by extending Invoke-PythonLint.ps1 with a -Fix switch and extracting shared discovery/resolution/output logic into a new PythonLintHelpers.psm1 module. The implementation is well-structured, the Pester tests are comprehensive (both the new PythonLintHelpers.Tests.ps1 and the updated runner tests), and the PR description is thorough. No security issues or logic bugs were found.


1. Issue Alignment ✅

Closes #886 is accurate. lint:py and test:py were already present; lint:all already includes lint:py; and lint:py:fix is correctly excluded from lint:all since it mutates source files — all aligning with the issue's acceptance criteria.


2. PR Template Compliance ⚠️

The Required Automated Checks section lists eight commands that "must pass before merging." Only npm run lint:ps is checked. The following remain unchecked:

  • npm run lint:md
  • npm run spell-check
  • npm run lint:frontmatter
  • npm run validate:skills
  • npm run lint:md-links
  • npm run plugin:generate
  • npm run docs:test

For a purely PowerShell/JSON change, most of these will be green without any findings, but the template requires them to be run and checked before merge. Please run the remaining commands and tick the boxes (or annotate with N/A for those that genuinely do not apply).


3. Coding Standards ✅

  • Copyright headers, #Requires -Version 7.0, shebang placement, [CmdletBinding()], [OutputType()], and Export-ModuleMember are all correct in the new module.
  • Function naming (Get-PythonSkill, Resolve-RuffCommand, Write-PythonLintResults) uses approved verbs and follows Verb-Noun PascalCase.
  • Comment-based help is present on all three exported functions.
  • The double-quote style in PythonLintHelpers.psm1's Import-Module matches the pre-existing LintingHelpers.psm1 sibling — consistent within the module tier.

One structural deviation was flagged inline (see comment on line 29): CIHelpers.psm1 is loaded transitively rather than explicitly, which diverges from the pattern every other linting runner follows.


4. Code Quality ✅

No bugs, logic errors, or security concerns. The -Fix mode correctly chains ruff check --fix followed by ruff format, captures both exit codes, and surfaces them in the result hashtable — matching the issue's acceptance criterion. The Invoke-PythonLint.Tests.ps1 now covers the fix-mode path with four dedicated It blocks. The separate PythonLintHelpers.Tests.ps1 exercises Get-PythonSkill (including the node_modules exclusion at the real implementation level), Resolve-RuffCommand for all four resolution paths, and Write-PythonLintResults for default and explicit output paths with parent-directory creation.


Action Items

  1. Required: Run and check the remaining automated check items in the PR checklist (or annotate N/A where genuinely inapplicable).
  2. Suggested: Add an explicit Import-Module for CIHelpers.psm1 alongside the PythonLintHelpers.psm1 import in Invoke-PythonLint.ps1 (see inline comment).

Generated by PR Review for issue #1450 · ● 3M

Comment thread scripts/linting/Invoke-PythonLint.ps1
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.

feat(scripts): Add npm run scripts for Python linting and testing

4 participants