Skip to content

Comments

[ci] Test new ci/cd#4

Merged
barisgit merged 8 commits intomainfrom
feature/ci-cd
Sep 5, 2025
Merged

[ci] Test new ci/cd#4
barisgit merged 8 commits intomainfrom
feature/ci-cd

Conversation

@barisgit
Copy link
Owner

@barisgit barisgit commented Sep 5, 2025

Add auto release on new version

Summary by CodeRabbit

  • New Features

    • Rich templating: render filenames/content, find templates, create projects from templates, post-create hooks, dry-run and filename rendering.
  • Bug Fixes

    • Config validation now discards invalid library entries and auto-saves corrected config.
  • Chores

    • CI revamped: matrix across OSes, upgraded Python setup, switched to ruff, added type checks and coverage, and new release automation that builds, drafts releases, and publishes packages.
  • Documentation

    • README cleaned: simplified labels and updated links.
  • Tests

    • Tests updated for new typings and style/OS-aware checks.

@vercel
Copy link

vercel bot commented Sep 5, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
kilm Ready Ready Preview Comment Sep 5, 2025 8:54pm

@coderabbitai
Copy link

coderabbitai bot commented Sep 5, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Updates CI to a matrix workflow (ruff, pyrefly, coverage, Codecov) and adds a Release workflow that validates versions, builds, generates release notes, creates GitHub Releases, and publishes to PyPI. Introduces extensive templating APIs for rendering and project creation and a config normalization change that validates and persists cleaned libraries. Other edits are formatting and test adjustments.

Changes

Cohort / File(s) Summary
CI workflow updates
.github/workflows/python-package.yml
Renames workflow to "CI", expands triggers (push, pull_request, workflow_dispatch), switches job to matrix OS runners, upgrades actions/setup-python to v5, replaces flake8 with ruff, adds pyrefly type checks, collects coverage, and uploads to Codecov (gated to ubuntu + py3.11).
Release automation
.github/workflows/release.yml
New Release workflow: triggers on tag v* and manual dispatch, checks tag vs package version, runs lint/type/tests, builds package, runs twine check, assembles release notes (commits/PRs), creates draft GitHub Release with artifacts, and publishes to PyPI.
Documentation formatting
README.md
Removes emoji markers and updates documentation/installation links to a new domain; formatting adjustments to Quick Start and installation lines.
Template utilities (new & refactor)
kicad_lib_manager/utils/template.py
Adds templating/rendering APIs (render_template_string, render_filename[_custom], render_template_file), template discovery (find_all_templates), create_project_from_template with post-create hooks, enhanced filename rendering, KiCad file processing, improved path/gitignore handling, MAX_PATH guard, and related refactors.
Config normalization (behavioral)
kicad_lib_manager/config.py
Adds _validate_library_entry, centralizes validation, discards invalid library entries with a warning, persists cleaned libraries back to config (calls save()), and makes _make_library_dict construct typed LibraryDict.
Git utilities & hooks
kicad_lib_manager/utils/git_utils.py
Minor refactors and formatting, adds import os, guards preserving executable bit to non-Windows platforms, and tweaks string quoting and subprocess call formatting.
Other utils (signature/formatting)
kicad_lib_manager/utils/file_ops.py, kicad_lib_manager/utils/metadata.py
Reflowed function signatures across multiple lines; no logic changes.
Commands — formatting-only
kicad_lib_manager/commands/add_hook/command.py, .../config/command.py, .../setup/command.py, .../status/command.py, .../template/command.py, .../unpin/command.py, .../update/command.py
Formatting-only: reflowed/parenthesized conditionals and call formatting; semantics unchanged.
Tests: config commands
tests/test_config_commands.py
Test data now uses typed LibraryDict instances and adjusted typing/imports; minor fixture reflow.
Tests: git utils
tests/test_git_utils.py
Adds os import, standardizes patch quoting, guards executable-bit assertion by OS, and removes trailing whitespace.
Tests: unpin & update commands
tests/test_unpin_command.py, tests/test_update_command.py
Formatting-only changes (quote style, multi-line strings, reflowed monkeypatch calls); test behavior unchanged.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as Developer
  participant GH as GitHub Actions (Release)
  participant Py as Python Tooling
  participant GHRel as GitHub Release
  participant PyPI as PyPI

  Dev->>GH: Push tag vX.Y.Z / workflow_dispatch
  GH->>Py: Setup Python, install build tools
  GH->>Py: Read package __version__
  GH->>GH: Compare tag vs package version
  alt mismatch
    GH-->>Dev: Fail job (version mismatch)
  else match
    GH->>Py: Lint (ruff), type-check (pyrefly), run tests (pytest + coverage)
    GH->>Py: Build sdist/wheel
    GH->>Py: Twine check
    GH->>GH: Generate release notes (commits, PRs)
    GH->>GHRel: Create draft release with artifacts
    GH->>PyPI: Publish package
    PyPI-->>GH: Publish result
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant T as Template Dir
  participant U as Template Utils
  participant P as Project Dir
  participant H as Post-create Hook (optional)

  User->>U: create_project_from_template(T, P, vars, metadata, dry_run/skip_hooks)
  U->>U: find_all_templates / read metadata
  U->>U: Scan files, apply excludes, enforce MAX_PATH
  U->>U: Render filenames (render_filename)
  alt text file
    U->>U: render_template_file (variables) -> write
  else binary/KiCad special
    U->>U: process_kicad_* or copy as-is -> write
  end
  opt hook present and not skipped
    U->>H: run_post_create_hook(P, vars, metadata)
    H-->>U: Completion
  end
  U-->>User: Return success (honors dry-run)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

A rabbit taps the release drum, thump-thump!
CI hops across each OS and bump.
Templates sprout where filenames sing,
Configs pruned to tidy things.
Hop, build, release — a perfect jump! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d0050e0 and 34b9f8f.

📒 Files selected for processing (4)
  • .github/workflows/python-package.yml (2 hunks)
  • README.md (3 hunks)
  • kicad_lib_manager/utils/git_utils.py (6 hunks)
  • tests/test_git_utils.py (6 hunks)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/ci-cd

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
kicad_lib_manager/commands/update/command.py (2)

119-132: False positives: change detection triggers whenever any content exists.

check_for_library_changes returns labels based on presence of files under symbols/footprints/templates, not newly added ones. This will prompt users to run setup after every pull that fetched anything, even if no new libraries were added.

Proposed fix: derive “added” paths from Git and infer categories from those paths.

-                # Check if there are new library files that would require setup
-                if "Already up to date" not in output:
-                    changes_require_setup = check_for_library_changes(
-                        result.stdout, lib_path
-                    )
+                # Check if newly ADDED library files/directories require setup
+                if "Already up to date" not in output:
+                    changes_require_setup = check_for_library_changes(
+                        result.stdout, lib_path
+                    )

And update implementation below (see dedicated diff on check_for_library_changes).


178-238: Detect newly added libraries via git diff instead of filesystem presence.

Rework to parse added paths between previous and current HEAD and only flag categories when additions occur under symbols/.kicad_sym, footprints//.kicad_mod (within .pretty), or templates//metadata.yaml.

Apply:

 def check_for_library_changes(git_output, lib_path):
@@
-    changes = []
-
-    # Check git output for new files in key directories
-    pattern = r"[^\s]+\s+\|\s+\d+ [+]+(?:-+)?\s+(?:symbols|footprints|templates|3d)"
-    if re.search(pattern, git_output, re.IGNORECASE):
-        # This is a basic heuristic that indicates changes in library directories
-        # For more accuracy, we'll check the actual directories
-        pass
-
-    # Check for specific library file types
-    symbols_path = lib_path / "symbols"
-    footprints_path = lib_path / "footprints"
-    templates_path = lib_path / "templates"
-
-    # Look for symbol libraries (.kicad_sym files)
-    if (
-        symbols_path.exists()
-        and symbols_path.is_dir()
-        and any(
-            f.name.endswith(".kicad_sym") for f in symbols_path.glob("**/*.kicad_sym")
-        )
-    ):
-        changes.append("symbols")
-
-    # Look for footprint libraries (.pretty directories)
-    if (
-        footprints_path.exists()
-        and footprints_path.is_dir()
-        and any(
-            f.is_dir() and f.name.endswith(".pretty")
-            for f in footprints_path.glob("**/*.pretty")
-        )
-    ):
-        changes.append("footprints")
-
-    # Look for project templates (directories with metadata.yaml)
-    if (
-        templates_path.exists()
-        and templates_path.is_dir()
-        and any(
-            (f / "metadata.yaml").exists()
-            for f in templates_path.glob("*")
-            if f.is_dir()
-        )
-    ):
-        changes.append("templates")
-
-    return changes
+    changes: list[str] = []
+
+    # Try to compute added paths between previous and current HEAD
+    diff_specs = [
+        ["git", "-C", str(lib_path), "diff", "--name-status", "--diff-filter=A", "HEAD@{1}", "HEAD"],
+        ["git", "-C", str(lib_path), "diff", "--name-status", "--diff-filter=A", "ORIG_HEAD", "HEAD"],
+    ]
+    added_paths: set[str] = set()
+    for cmd in diff_specs:
+        try:
+            rp = subprocess.run(cmd, capture_output=True, text=True, check=True, timeout=30)
+            for line in rp.stdout.splitlines():
+                # Format: A<TAB>path/to/file
+                if not line:
+                    continue
+                status, _, path = line.partition("\t")
+                if status.strip().upper() == "A" and path:
+                    added_paths.add(path.strip())
+            if added_paths:
+                break  # we got a usable spec
+        except subprocess.CalledProcessError:
+            continue
+        except subprocess.TimeoutExpired:
+            continue
+
+    # Infer categories from added paths
+    for p in added_paths:
+        # symbols: new .kicad_sym files under symbols/
+        if p.startswith("symbols/") and p.endswith(".kicad_sym"):
+            changes.append("symbols")
+        # footprints: any added .kicad_mod within a *.pretty/ directory
+        elif p.startswith("footprints/") and ".pretty/" in p and p.endswith(".kicad_mod"):
+            changes.append("footprints")
+        # templates: a new metadata.yaml within templates/<name>/
+        elif p.startswith("templates/") and p.endswith("/metadata.yaml"):
+            changes.append("templates")
+
+    # Deduplicate while preserving order
+    seen = set()
+    deduped = [c for c in changes if not (c in seen or seen.add(c))]
+    return deduped
kicad_lib_manager/utils/template.py (2)

446-456: Fix Path vs. str comparisons blocking main KiCad file detection/processing.
main_*_file are stored as str while file_path is Path, so equality checks never match; special naming and processing paths are skipped.

Apply:

-                    main_project_file = str(Path(root) / file)
+                    main_project_file = Path(root) / file
@@
-                elif (
-                    file_lower.endswith(KICAD_SCHEMATIC_EXT) and not main_schematic_file
-                ):
-                    main_schematic_file = str(Path(root) / file)
+                elif (
+                    file_lower.endswith(KICAD_SCHEMATIC_EXT) and not main_schematic_file
+                ):
+                    main_schematic_file = Path(root) / file
@@
-                elif file_lower.endswith(KICAD_PCB_EXT) and not main_pcb_file:
-                    main_pcb_file = str(Path(root) / file)
+                elif file_lower.endswith(KICAD_PCB_EXT) and not main_pcb_file:
+                    main_pcb_file = Path(root) / file

Optional (if you prefer strings): convert file_path to str(...) at its declaration instead.

Also applies to: 541-556, 561-574


598-633: Generated post-create hook misses imports and will crash at runtime.
The script uses click and Path without importing them.

Apply:

 script_content = '''"""
 Post-creation hook for template.
 This script runs after the template has been used to create a new project.
 """
 
+import click
+from pathlib import Path
+
 def post_create(context):
🧹 Nitpick comments (21)
kicad_lib_manager/commands/unpin/command.py (1)

49-55: Avoid shadowing built-in name and set explicit file encoding.

  • The parameter named all shadows Python’s built-in all(). Consider renaming the Click destination (e.g., @click.option("--all", "unpin_all", is_flag=True, ...)) and updating references accordingly.
  • When reading/writing JSON config files, prefer open(encoding="utf-8") to avoid locale-dependent decoding issues.
kicad_lib_manager/commands/template/command.py (1)

820-825: Make boolean precedence explicit in exclusion check.

and binds tighter than or, so it currently works, but adding grouping removes any ambiguity for future readers.

-                if (
-                    gitignore_spec
-                    and gitignore_spec.match_file(git_path)
-                    or additional_spec
-                    and additional_spec.match_file(git_path)
-                ):
+                if (
+                    (gitignore_spec and gitignore_spec.match_file(git_path))
+                    or (additional_spec and additional_spec.match_file(git_path))
+                ):
kicad_lib_manager/utils/file_ops.py (1)

10-12: LGTM on signature wrap; consider guarding empty encodings.

Formatting-only change looks good. Minor: if a caller passes an empty list for encodings, this function returns "" silently. Consider raising ValueError when encodings == [] to avoid masking errors.

kicad_lib_manager/commands/update/command.py (4)

91-95: Don’t count dry-run executions as “updated.”

Incrementing updated_count in dry-run skews the summary. Either don’t change counters in dry-run or track a separate would_update_count.

Apply:

         if dry_run:
             click.echo(f"    Dry run: would execute 'git pull' in {lib_path}")
-            updated_count += 1
+            # No-op in dry-run: do not change counters
             continue

98-104: Add a timeout to git pull to avoid hanging processes.

A hung git process will block the command. Add a sane timeout (e.g., 120s) and handle TimeoutExpired.

             result = subprocess.run(
                 ["git", "pull"],
                 cwd=lib_path,
                 capture_output=True,
                 text=True,
-                check=False,
+                check=False,
+                timeout=120,
             )

Also add an except subprocess.TimeoutExpired to report and increment failed_count.


111-118: Avoid parsing “Already up to date” strings; compare commits instead.

Git messages vary by version/locale. More robust: capture old_head = git rev-parse HEAD before pull, then compare to new head after pull to decide updated vs up-to-date.


153-165: Programmatic click invocation: prefer main(..., standalone_mode=False).

setup_cmd.invoke with a bare Context can miss Click’s option handling and may swallow exceptions differently. Use setup_cmd.main(standalone_mode=False) or call the underlying callback directly if exported.

Example:

-                ctx = click.Context(setup_cmd)
-                setup_cmd.invoke(ctx)
+                setup_cmd.main(standalone_mode=False)

Verify tests still pass and options default as expected.

README.md (1)

48-55: Optional: add Release and CI badges to reflect new workflows.

Given this PR adds CI and Release automation, consider adding badges for build status and latest GitHub release to the header.

kicad_lib_manager/utils/metadata.py (1)

39-41: Use logging instead of print for error reporting.

Printing in libraries can be noisy and hard to trace. Prefer logging.getLogger(name).warning/error so callers can configure handlers.

Also applies to: 62-63, 89-90, 111-112

kicad_lib_manager/config.py (2)

66-69: Deep-copy DEFAULT_CONFIG to avoid shared mutable state.

DEFAULT_CONFIG contains a list (libraries). dict.copy() is shallow; deep-copy prevents accidental mutation of module-level defaults.

+import copy
@@
     def __init__(self):
         """Initialize configuration with default values"""
-        self._config = DEFAULT_CONFIG.copy()
+        self._config = copy.deepcopy(DEFAULT_CONFIG)
         self._load_config()

301-307: Persist cleanup after removing invalid entries.

You already save when needs_save is True; consider also saving when libraries_raw wasn’t a list and you reset to [] for consistency.

kicad_lib_manager/utils/git_utils.py (1)

33-38: Add timeouts to subprocess.run to harden against hung git processes.

Add timeout (e.g., 10s) to both rev-parse calls and handle TimeoutExpired with a clear RuntimeError.

         rp = subprocess.run(
             ["git", "-C", str(repo_path), "rev-parse", "--git-path", "hooks"],
             capture_output=True,
             text=True,
-            check=True,
+            check=True,
+            timeout=10,
         )

And similarly for the fallback rev-parse --git-common-dir.

kicad_lib_manager/commands/add_hook/command.py (1)

93-95: Write hook file with explicit UTF-8 and normalized newlines.
Prevents locale-dependent encoding and CRLF surprises on Windows.

Apply:

-        with post_merge_hook.open("w") as f:
+        with post_merge_hook.open("w", encoding="utf-8", newline="\n") as f:
             f.write(new_content)
kicad_lib_manager/utils/template.py (1)

67-69: Use explicit UTF-8 when reading/writing text files.
Avoids platform-default encoding pitfalls.

-        with Path(gitignore_file).open() as f:
+        with Path(gitignore_file).open(encoding="utf-8") as f:
             lines = f.readlines()
@@
-            with Path(metadata_file).open() as f:
+            with Path(metadata_file).open(encoding="utf-8") as f:
                 metadata = yaml.safe_load(f)
@@
-    with Path(metadata_file).open("w") as f:
+    with Path(metadata_file).open("w", encoding="utf-8") as f:
         yaml.dump(metadata, f, default_flow_style=False)

Also applies to: 123-125, 297-299

.github/workflows/python-package.yml (3)

21-21: Trim trailing spaces to satisfy yamllint.
These blanks have spaces; remove them to keep CI lint clean.

Also applies to: 26-26, 31-31, 36-36, 40-40, 44-44


22-26: Enable pip cache for faster runs.

-    - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v5
-      with:
-        python-version: ${{ matrix.python-version }}
+    - name: Set up Python ${{ matrix.python-version }}
+      uses: actions/setup-python@v5
+      with:
+        python-version: ${{ matrix.python-version }}
+        cache: pip

11-13: Bound job time to avoid stuck runners.

   test:
     runs-on: ${{ matrix.os }}
+    timeout-minutes: 20
.github/workflows/release.yml (1)

14-17: Strip trailing spaces and add final newline.
Yamllint flags these; easy cleanup to keep workflows tidy.

Also applies to: 21-21, 26-26, 31-31, 36-36, 45-45, 47-47, 52-52, 54-54, 62-62, 66-66, 71-71, 79-79, 87-87, 90-90, 94-94, 97-97, 99-99, 102-102, 105-105, 108-108, 110-110, 112-112, 117-117, 122-122, 131-131, 135-135, 140-140, 152-152, 157-157

tests/test_unpin_command.py (3)

53-60: Prefer patching Path.open + mock_open for robustness.

Path.open may call io.open; patching builtins.open can miss it on some Python versions. Patch pathlib.Path.open with mock_open to make the test resilient.

Apply within this block:

-                with patch("builtins.open") as mock_open:
-                    mock_open.return_value.__enter__.return_value.read.return_value = (
-                        '{"session": {"pinned_symbol_libs": [], "pinned_fp_libs": []}}'
-                    )
+                from unittest.mock import mock_open as u_mock_open
+                m = u_mock_open(
+                    read_data='{"session": {"pinned_symbol_libs": [], "pinned_fp_libs": []}}'
+                )
+                with patch("pathlib.Path.open", m):

If you prefer, add the import once at file top instead.


73-78: Repeat the Path.open mock pattern here.

Use pathlib.Path.open + mock_open as suggested above to avoid relying on builtins.open.

-                with patch("builtins.open") as mock_open:
-                    mock_open.return_value.__enter__.return_value.read.return_value = '{"session": {"pinned_symbol_libs": ["lib1"], "pinned_fp_libs": []}}'
+                from unittest.mock import mock_open as u_mock_open
+                m = u_mock_open(
+                    read_data='{"session": {"pinned_symbol_libs": ["lib1"], "pinned_fp_libs": []}}'
+                )
+                with patch("pathlib.Path.open", m):

91-96: Repeat the Path.open mock pattern for the footprints case.

-                with patch("builtins.open") as mock_open:
-                    mock_open.return_value.__enter__.return_value.read.return_value = '{"session": {"pinned_symbol_libs": [], "pinned_fp_libs": ["lib1"]}}'
+                from unittest.mock import mock_open as u_mock_open
+                m = u_mock_open(
+                    read_data='{"session": {"pinned_symbol_libs": [], "pinned_fp_libs": ["lib1"]}}'
+                )
+                with patch("pathlib.Path.open", m):
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 60685bf and 7a57b65.

📒 Files selected for processing (19)
  • .github/workflows/python-package.yml (1 hunks)
  • .github/workflows/release.yml (1 hunks)
  • README.md (2 hunks)
  • kicad_lib_manager/commands/add_hook/command.py (1 hunks)
  • kicad_lib_manager/commands/config/command.py (2 hunks)
  • kicad_lib_manager/commands/setup/command.py (0 hunks)
  • kicad_lib_manager/commands/status/command.py (4 hunks)
  • kicad_lib_manager/commands/template/command.py (1 hunks)
  • kicad_lib_manager/commands/unpin/command.py (1 hunks)
  • kicad_lib_manager/commands/update/command.py (2 hunks)
  • kicad_lib_manager/config.py (6 hunks)
  • kicad_lib_manager/utils/file_ops.py (1 hunks)
  • kicad_lib_manager/utils/git_utils.py (4 hunks)
  • kicad_lib_manager/utils/metadata.py (1 hunks)
  • kicad_lib_manager/utils/template.py (2 hunks)
  • tests/test_config_commands.py (1 hunks)
  • tests/test_git_utils.py (4 hunks)
  • tests/test_unpin_command.py (1 hunks)
  • tests/test_update_command.py (2 hunks)
💤 Files with no reviewable changes (1)
  • kicad_lib_manager/commands/setup/command.py
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-05T07:17:34.953Z
Learnt from: barisgit
PR: barisgit/KiLM#3
File: kicad_lib_manager/__init__.py:5-5
Timestamp: 2025-09-05T07:17:34.953Z
Learning: In the KiLM project, different version numbers are intentionally maintained separately: the main Python package version in kicad_lib_manager/__init__.py, the docs site version in docs/package.json, and example versions in documentation files are not meant to be synchronized.

Applied to files:

  • README.md
🧬 Code graph analysis (5)
tests/test_config_commands.py (1)
tests/test_update_command.py (1)
  • mock_config (21-29)
kicad_lib_manager/commands/status/command.py (1)
kicad_lib_manager/config.py (1)
  • get (66-70)
tests/test_unpin_command.py (1)
kicad_lib_manager/commands/unpin/command.py (1)
  • unpin (49-189)
kicad_lib_manager/commands/add_hook/command.py (1)
kicad_lib_manager/utils/git_utils.py (2)
  • merge_hook_content (86-120)
  • create_kilm_hook_content (123-141)
kicad_lib_manager/commands/update/command.py (2)
kicad_lib_manager/library_manager.py (1)
  • add_libraries (176-335)
kicad_lib_manager/commands/init/command.py (1)
  • init (58-252)
🪛 YAMLlint (1.37.1)
.github/workflows/python-package.yml

[error] 21-21: trailing spaces

(trailing-spaces)


[error] 26-26: trailing spaces

(trailing-spaces)


[error] 31-31: trailing spaces

(trailing-spaces)


[error] 36-36: trailing spaces

(trailing-spaces)


[error] 40-40: trailing spaces

(trailing-spaces)


[error] 44-44: trailing spaces

(trailing-spaces)

.github/workflows/release.yml

[error] 21-21: trailing spaces

(trailing-spaces)


[warning] 23-23: wrong indentation: expected 6 but found 4

(indentation)


[error] 26-26: trailing spaces

(trailing-spaces)


[error] 31-31: trailing spaces

(trailing-spaces)


[error] 36-36: trailing spaces

(trailing-spaces)


[error] 45-45: trailing spaces

(trailing-spaces)


[error] 47-47: trailing spaces

(trailing-spaces)


[error] 52-52: trailing spaces

(trailing-spaces)


[error] 54-54: trailing spaces

(trailing-spaces)


[error] 62-62: trailing spaces

(trailing-spaces)


[error] 66-66: trailing spaces

(trailing-spaces)


[error] 71-71: trailing spaces

(trailing-spaces)


[error] 79-79: trailing spaces

(trailing-spaces)


[error] 87-87: trailing spaces

(trailing-spaces)


[error] 90-90: trailing spaces

(trailing-spaces)


[error] 94-94: trailing spaces

(trailing-spaces)


[error] 97-97: trailing spaces

(trailing-spaces)


[error] 99-99: trailing spaces

(trailing-spaces)


[error] 102-102: trailing spaces

(trailing-spaces)


[error] 105-105: trailing spaces

(trailing-spaces)


[error] 108-108: trailing spaces

(trailing-spaces)


[error] 110-110: trailing spaces

(trailing-spaces)


[error] 112-112: trailing spaces

(trailing-spaces)


[error] 117-117: trailing spaces

(trailing-spaces)


[error] 122-122: trailing spaces

(trailing-spaces)


[error] 131-131: trailing spaces

(trailing-spaces)


[error] 135-135: trailing spaces

(trailing-spaces)


[error] 140-140: trailing spaces

(trailing-spaces)


[error] 152-152: trailing spaces

(trailing-spaces)


[error] 157-157: no new line character at the end of file

(new-line-at-end-of-file)

🪛 LanguageTool
README.md

[grammar] ~50-~50: There might be a mistake here.
Context: ...ristovnik.me)** | Guide | Description | |-------|-------------| | [Getting Start...

(QB_NEW_EN)


[grammar] ~51-~51: There might be a mistake here.
Context: ... | Description | |-------|-------------| | [Getting Started](https://kilm.aristov...

(QB_NEW_EN)


[grammar] ~52-~52: There might be a mistake here.
Context: ...onsumer workflows with Git integration | | [Configuration](https://kilm.aristovni...

(QB_NEW_EN)


[grammar] ~53-~53: There might be a mistake here.
Context: ...iLM and KiCad configuration management | | [CLI Reference](https://kilm.aristovni...

(QB_NEW_EN)


[grammar] ~54-~54: There might be a mistake here.
Context: ...te command documentation with examples | | [Development](https://kilm.aristovnik....

(QB_NEW_EN)

🔇 Additional comments (30)
kicad_lib_manager/commands/unpin/command.py (1)

53-55: LGTM on the multi-line UsageError.

Readability improved; behavior unchanged.

kicad_lib_manager/commands/config/command.py (2)

295-297: LGTM: clearer multi-line error echo.

Keeps the same stderr behavior and exit semantics.


355-357: LGTM: parenthesized condition reads better.

The logic is unchanged and less error-prone to future edits.

kicad_lib_manager/commands/status/command.py (1)

29-33: LGTM: multiline guards improve readability.

The checks for config presence, current library marker, and current library display are clearer with no semantic change.

Also applies to: 55-57, 75-77, 92-94

README.md (2)

11-11: Docs heading tweak looks good.

Emoji removal and bolded “Official Documentation” reads clean. No issues.


44-44: Nice: clearer callout for installation guide.

The blockquote improves scannability.

kicad_lib_manager/utils/metadata.py (1)

15-17: Formatting-only change: LGTM.

kicad_lib_manager/config.py (3)

21-21: Tiny style change: LGTM.


128-129: Minor: comprehension reflow is fine.

No semantic change; readability is acceptable.


267-271: Good guardrail for malformed configs.

Warning with type info helps users recover.

kicad_lib_manager/utils/git_utils.py (1)

100-118: merge_hook_content replacement is correct and idempotent.

Using exact marker bounds and re-inserting kilm_content (which includes markers) is sound. Split/join on "\n" is consistent.

kicad_lib_manager/commands/add_hook/command.py (1)

80-82: LGTM: multiline call improves readability.
No behavioral change.

kicad_lib_manager/utils/template.py (2)

701-701: LGTM: signature formatting only.

Also applies to: 738-738


416-459: Sanity-check: top-level file discovery assumes “root or one subdir”.
If main files live deeper, they won’t be detected. Confirm this constraint is intentional.

Would you like me to add a fallback that scans all depths but prefers shallow matches?

.github/workflows/python-package.yml (1)

45-51: Codecov v4 token requirements.
Public repos are fine; private need CODECOV_TOKEN. Make sure org/repo visibility matches intended behavior.

.github/workflows/release.yml (2)

111-131: Validate install instructions and wheel name match your distribution name.
The notes use kilm, but the package module is kicad_lib_manager. Avoid confusing users.

If the project publishes as kicad-lib-manager, update pip/pipx commands and wheel filename pattern accordingly. I can generate the edits once you confirm the canonical package name.


154-157: Ensure PyPI Trusted Publisher is configured for this repo.
OIDC publish requires PyPI project linkage; otherwise this step fails.

tests/test_git_utils.py (1)

78-78: LGTM: consistent patch decorators with double quotes.

Also applies to: 93-93, 110-110, 125-125

tests/test_update_command.py (2)

26-28: LGTM: reformatted monkeypatch for readability; behavior unchanged.


174-176: LGTM: consistent multiline monkeypatch; no semantic changes.

tests/test_config_commands.py (1)

44-46: LGTM: multiline monkeypatch improves readability; same target and effect.

tests/test_unpin_command.py (9)

22-26: LGTM: assertion still matches current Click error message; exit code 2 is correct.


30-34: LGTM: same mutual-exclusivity check, message preserved.


38-44: LGTM: multiline invocation formatting only; assertions unchanged.


48-51: LGTM: mocking find_kicad_config is appropriate for isolating filesystem.


62-62: LGTM: invocation remains the same; allowing exit_code in [0, 1] keeps test tolerant.


68-71: LGTM: consistent mocking of config path.


80-80: LGTM: symbols-only path remains covered; tolerant exit code assertion OK.


86-89: LGTM: same isolation pattern for footprints-only case.


98-98: LGTM: footprints-only invocation; tolerant exit code assertion OK.

Comment on lines 37 to 40
- name: Type check with pyrefly
run: |
pyrefly

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Confirm pyrefly is installed in dev extras or add explicit install.
Without it, the job will fail at type-check step.

Run:


🏁 Script executed:

#!/bin/bash
# Verify pyrefly presence in dev dependencies
rg -nP '^\s*dev\s*=\s*\[.*pyrefly' -n pyproject.toml || rg -n 'pyrefly' -n requirements* || python -c 'import pyrefly' 2>/dev/null || echo "pyrefly missing"

Length of output: 213


Add installation for pyrefly in CI workflow
The pyrefly command isn’t installed by default (confirmed missing from dev dependencies), so the type-check step will fail. In .github/workflows/python-package.yml (around lines 37–40), before running pyrefly, either:

  • Install it explicitly:

    • run: pip install pyrefly
  • Or ensure it’s listed in your project’s dev dependencies (e.g. pyproject.toml extras or requirements-dev.txt).

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 40-40: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
.github/workflows/python-package.yml around lines 37 to 40: the workflow runs
the pyrefly command but pyrefly is not guaranteed to be installed in the CI
environment; update the job to install pyrefly before running it (for example
add a step that runs pip install pyrefly) or ensure pyrefly is added to the
project's dev dependencies (pyproject.toml extras or requirements-dev.txt) and
install those dev deps in the workflow prior to executing pyrefly.

Comment on lines +46 to +54
PACKAGE_VERSION=$(python -c "import kicad_lib_manager; print(kicad_lib_manager.__version__)")

if [[ "$TAG_VERSION" != "$PACKAGE_VERSION" ]]; then
echo "Version mismatch: tag=$TAG_VERSION, package=$PACKAGE_VERSION"
exit 1
fi

echo "VERSION=$TAG_VERSION" >> $GITHUB_ENV

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Don’t import package to read version during CI.
Import may fail before deps are installed; parse the version file instead.

-        PACKAGE_VERSION=$(python -c "import kicad_lib_manager; print(kicad_lib_manager.__version__)")
+        PACKAGE_VERSION=$(python - <<'PY'
+from pathlib import Path
+import re
+m = re.search(r"__version__\s*=\s*['\"]([^'\"]+)['\"]",
+              Path("kicad_lib_manager/__init__.py").read_text(encoding="utf-8"))
+print(m.group(1) if m else "")
+PY
+)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
PACKAGE_VERSION=$(python -c "import kicad_lib_manager; print(kicad_lib_manager.__version__)")
if [[ "$TAG_VERSION" != "$PACKAGE_VERSION" ]]; then
echo "Version mismatch: tag=$TAG_VERSION, package=$PACKAGE_VERSION"
exit 1
fi
echo "VERSION=$TAG_VERSION" >> $GITHUB_ENV
PACKAGE_VERSION=$(python - <<'PY'
from pathlib import Path
import re
m = re.search(r"__version__\s*=\s*['\"]([^'\"]+)['\"]",
Path("kicad_lib_manager/__init__.py").read_text(encoding="utf-8"))
print(m.group(1) if m else "")
PY
)
if [[ "$TAG_VERSION" != "$PACKAGE_VERSION" ]]; then
echo "Version mismatch: tag=$TAG_VERSION, package=$PACKAGE_VERSION"
exit 1
fi
echo "VERSION=$TAG_VERSION" >> $GITHUB_ENV
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 47-47: trailing spaces

(trailing-spaces)


[error] 52-52: trailing spaces

(trailing-spaces)


[error] 54-54: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
In .github/workflows/release.yml around lines 46 to 54, the workflow imports the
package to get its version which can fail when dependencies are not yet
installed; instead read and parse the package's version source file (e.g., the
module's __init__.py or dedicated version file) directly to extract the
__version__ string without importing. Replace the python import step with a
shell-safe extraction that opens the version file, finds the line defining
__version__, parses the quoted version value, assigns it to PACKAGE_VERSION,
then perform the TAG_VERSION vs PACKAGE_VERSION check and write VERSION to
GITHUB_ENV as before.

Comment on lines +88 to +105
# Get PR information
PRS=$(gh pr list --state merged --search "merged:>${PREVIOUS_TAG:-1970-01-01}" --json number,title,url --jq '.[] | "- #\(.number): \(.title) (\(.url))"' 2>/dev/null || echo "")

# Generate release notes
cat > release_notes.md << EOF
## What's Changed in v${VERSION}

### Commits
$(echo "$COMMITS" | sed 's/^/- /')

EOF

if [ ! -z "$PRS" ]; then
cat >> release_notes.md << EOF

### Pull Requests
$(echo "$PRS")

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix PR query: using tag name in merged:> filter is invalid.
gh pr list --search merged:> expects a date, not a tag.

Apply:

-        # Get PR information
-        PRS=$(gh pr list --state merged --search "merged:>${PREVIOUS_TAG:-1970-01-01}" --json number,title,url --jq '.[] | "- #\(.number): \(.title) (\(.url))"' 2>/dev/null || echo "")
+        # Compute a date to query PRs merged since previous tag
+        if [ -n "$PREVIOUS_TAG" ]; then
+          SINCE=$(git show -s --format=%cI "$PREVIOUS_TAG")
+        else
+          SINCE="1970-01-01"
+        fi
+        # Get PR information since that date
+        PRS=$(gh pr list --state merged --search "merged:>$SINCE" --json number,title,url --jq '.[] | "- #\(.number): \(.title) (\(.url))"' 2>/dev/null || echo "")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Get PR information
PRS=$(gh pr list --state merged --search "merged:>${PREVIOUS_TAG:-1970-01-01}" --json number,title,url --jq '.[] | "- #\(.number): \(.title) (\(.url))"' 2>/dev/null || echo "")
# Generate release notes
cat > release_notes.md << EOF
## What's Changed in v${VERSION}
### Commits
$(echo "$COMMITS" | sed 's/^/- /')
EOF
if [ ! -z "$PRS" ]; then
cat >> release_notes.md << EOF
### Pull Requests
$(echo "$PRS")
# Compute a date to query PRs merged since previous tag
if [ -n "$PREVIOUS_TAG" ]; then
SINCE=$(git show -s --format=%cI "$PREVIOUS_TAG")
else
SINCE="1970-01-01"
fi
# Get PR information since that date
PRS=$(gh pr list --state merged --search "merged:>$SINCE" \
--json number,title,url \
--jq '.[] | "- #\(.number): \(.title) (\(.url))"' \
2>/dev/null || echo "")
# Generate release notes
cat > release_notes.md << EOF
## What's Changed in v${VERSION}
### Commits
$(echo "$COMMITS" | sed 's/^/- /')
EOF
if [ ! -z "$PRS" ]; then
cat >> release_notes.md << EOF
### Pull Requests
$(echo "$PRS")
🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 90-90: trailing spaces

(trailing-spaces)


[error] 94-94: trailing spaces

(trailing-spaces)


[error] 97-97: trailing spaces

(trailing-spaces)


[error] 99-99: trailing spaces

(trailing-spaces)


[error] 102-102: trailing spaces

(trailing-spaces)


[error] 105-105: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
.github/workflows/release.yml around lines 88 to 105: the GH CLI search filter
uses merged:>${PREVIOUS_TAG} but gh expects a date, not a tag name; change the
workflow to derive the commit/tag date for PREVIOUS_TAG (e.g. via a git command
that outputs the tag/commit date) and then pass that ISO date into the gh pr
list --search "merged:>DATE" call so the search uses a valid date string; ensure
the derived date variable is set before the gh pr list invocation and used in
place of the tag.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
kicad_lib_manager/config.py (1)

261-285: Persist normalization changes to disk (missing save()).
When _normalize_libraries_field() drops invalid entries, the in-memory config is updated but not persisted; a restart reintroduces bad data. Save when changes occur.

Apply:

 def _normalize_libraries_field(self) -> None:
@@
-        # Validate and clean up each library entry
-        normalized_libraries: List[LibraryDict] = []
+        # Validate and clean up each library entry
+        normalized_libraries: List[LibraryDict] = []
+        needs_save = False
         for lib in libraries:
             validated_lib = _validate_library_entry(lib)
             if validated_lib is not None:
                 normalized_libraries.append(validated_lib)
             else:
                 click.echo(f"Warning: Skipping invalid library entry: {lib}", err=True)
-
-        self._config["libraries"] = normalized_libraries
+                needs_save = True
+
+        if normalized_libraries != libraries:
+            self._config["libraries"] = normalized_libraries
+            if needs_save:
+                self.save()
kicad_lib_manager/utils/template.py (1)

600-635: Hook script uses click without import.
post_create.py calls click.echo but doesn’t import click; will raise NameError at runtime.

 script_content = '''"""
 Post-creation hook for template.
 This script runs after the template has been used to create a new project.
 """
 
+import click
+
 def post_create(context):
🧹 Nitpick comments (4)
kicad_lib_manager/config.py (1)

294-301: Also save when resetting non-list libraries.
If libraries is not a list, you reset it but don’t save. Persist this correction.

-        if not isinstance(libraries_raw, list):
+        if not isinstance(libraries_raw, list):
             click.echo(
                 f"Warning: libraries field was {type(libraries_raw).__name__}, resetting to empty list",
                 err=True,
             )
             self._config["libraries"] = []
-            return []
+            self.save()
+            return []
kicad_lib_manager/utils/template.py (3)

486-495: Safer exclude check: avoid substring matches.
Using “excl in rel_root” can exclude unintended paths (e.g., “invent” matching “env”). Compare path parts.

-        if any(excl in rel_root for excl in common_excludes):
+        if any(part in common_excludes for part in Path(rel_root).parts):
             continue

87-91: Exact-match when augmenting .gitignore patterns.
Substring matching can add duplicates; normalize and compare trimmed lines.

-        for pattern in common_patterns:
-            if not any(pattern in line for line in lines):
-                lines.append(pattern + "\n")
+        existing = {ln.strip() for ln in lines}
+        for pattern in common_patterns:
+            if pattern not in existing:
+                lines.append(pattern + "\n")
+                existing.add(pattern)

803-808: Use StrictUndefined for template string rendering (consistency with filenames/files).
This surfaces missing variables early.

-    try:
-        template = jinja2.Template(template_str)
-        return template.render(**variables)
+    try:
+        env = jinja2.Environment(undefined=jinja2.StrictUndefined)
+        template = env.from_string(template_str)
+        return template.render(**variables)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7a57b65 and 7e88ff6.

📒 Files selected for processing (3)
  • kicad_lib_manager/config.py (7 hunks)
  • kicad_lib_manager/utils/template.py (7 hunks)
  • tests/test_config_commands.py (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/test_config_commands.py
🧰 Additional context used
🧬 Code graph analysis (1)
kicad_lib_manager/utils/template.py (1)
kicad_lib_manager/commands/template/command.py (3)
  • template (37-43)
  • make (560-933)
  • create (78-498)
🔇 Additional comments (3)
kicad_lib_manager/config.py (2)

66-69: LGTM: typed get() API looks good.


323-326: Typed constructor is clean.

kicad_lib_manager/utils/template.py (1)

752-767: Confirm KiCad regex robustness.
S-expression formats vary; ensure the PCB sheetfile and schematic project regexes won’t over-match. Recommend tests with KiCad 7/8 sample files.

I can add tests with sample .kicad_pro/.kicad_sch/.kicad_pcb to validate substitutions across versions. Want me to open a follow-up PR?

Comment on lines +332 to +338
if isinstance(lib, dict) and all(key in lib for key in ["name", "path", "type"]):
return _make_library_dict(
name=str(lib["name"]),
path=str(lib["path"]),
type_=str(lib["type"]),
)
return None
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enforce allowed library types and normalize path.
Guard against typos (e.g., “gihub”) and normalize paths once here.

-    if isinstance(lib, dict) and all(key in lib for key in ["name", "path", "type"]):
-        return _make_library_dict(
-            name=str(lib["name"]),
-            path=str(lib["path"]),
-            type_=str(lib["type"]),
-        )
+    if isinstance(lib, dict) and all(key in lib for key in ["name", "path", "type"]):
+        name = str(lib["name"])
+        # Normalize path separators; store as string
+        path = str(Path(str(lib["path"])))
+        type_val = str(lib["type"]).lower().strip()
+        if type_val not in {"github", "cloud"}:
+            click.echo(f"Warning: Invalid library type '{type_val}' for {name}", err=True)
+            return None
+        return _make_library_dict(name=name, path=path, type_=type_val)

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +413 to 416
main_project_file: Optional[str] = None
main_schematic_file: Optional[str] = None
main_pcb_file: Optional[str] = None

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Bug: Path vs str mismatch prevents main KiCad files from being templated.
main_project_file/main_schematic_file/main_pcb_file are stored as str but later compared to Path objects; comparisons always fail, so special handling never runs.

Apply:

-    main_project_file: Optional[str] = None
-    main_schematic_file: Optional[str] = None
-    main_pcb_file: Optional[str] = None
+    main_project_file: Optional[Path] = None
+    main_schematic_file: Optional[Path] = None
+    main_pcb_file: Optional[Path] = None
@@
-                if file_lower.endswith(KICAD_PROJECT_EXT) and not main_project_file:
-                    main_project_file = str(Path(root) / file_name)
+                if file_lower.endswith(KICAD_PROJECT_EXT) and not main_project_file:
+                    main_project_file = Path(root) / file_name
                     click.echo(f"Found main project file: {file_name}")
@@
-                elif (
-                    file_lower.endswith(KICAD_SCHEMATIC_EXT) and not main_schematic_file
-                ):
-                    main_schematic_file = str(Path(root) / file_name)
+                elif (
+                    file_lower.endswith(KICAD_SCHEMATIC_EXT) and not main_schematic_file
+                ):
+                    main_schematic_file = Path(root) / file_name
                     click.echo(f"Found main schematic file: {file_name}")
@@
-                elif file_lower.endswith(KICAD_PCB_EXT) and not main_pcb_file:
-                    main_pcb_file = str(Path(root) / file_name)
+                elif file_lower.endswith(KICAD_PCB_EXT) and not main_pcb_file:
+                    main_pcb_file = Path(root) / file_name
                     click.echo(f"Found main PCB file: {file_name}")
@@
-            if main_project_file and file_path == main_project_file:
+            if main_project_file and file_path == main_project_file:
                 target_file = (
                     template_content_dir / rel_root / "%{project_filename}.kicad_pro"
                 )
-            elif main_schematic_file and file_path == main_schematic_file:
+            elif main_schematic_file and file_path == main_schematic_file:
                 target_file = (
                     template_content_dir / rel_root / "%{project_filename}.kicad_sch"
                 )
-            elif main_pcb_file and file_path == main_pcb_file:
+            elif main_pcb_file and file_path == main_pcb_file:
                 target_file = (
                     template_content_dir / rel_root / "%{project_filename}.kicad_pcb"
                 )
@@
-            if main_project_file and file_path == main_project_file:
+            if main_project_file and file_path == main_project_file:
                 process_kicad_project_file(
                     source_file, target_file, metadata.get("variables", {})
                 )
-            elif main_schematic_file and file_path == main_schematic_file:
+            elif main_schematic_file and file_path == main_schematic_file:
                 process_kicad_schematic_file(source_file, target_file)
-            elif main_pcb_file and file_path == main_pcb_file:
+            elif main_pcb_file and file_path == main_pcb_file:
                 process_kicad_pcb_file(source_file, target_file)

Also applies to: 448-460, 543-554, 564-576

🤖 Prompt for AI Agents
In kicad_lib_manager/utils/template.py around lines 413-416 (and similarly at
448-460, 543-554, 564-576) the fields
main_project_file/main_schematic_file/main_pcb_file are annotated/stored as str
but later compared to Path objects causing comparisons to always fail; change
those fields to Optional[Path] (or Optional[Union[str, Path>] if needed for
backwards compatibility) and ensure any assignments convert incoming strings to
Path (Path(value)) or convert the Path to str only at I/O/serialization
boundaries so runtime comparisons use Path objects and the special-case handling
executes as intended.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
.github/workflows/python-package.yml (1)

37-40: Ensure pyrefly is installed before running type check

Previous review noted pyrefly isn’t in dev deps; step will fail unless you install it explicitly.

Apply:

     - name: Install dependencies
       run: |
         python -m pip install --upgrade pip
-        pip install -e .[dev]
+        pip install -e .[dev]
+        pip install pyrefly

Also applies to: 27-31

🧹 Nitpick comments (2)
.github/workflows/python-package.yml (2)

21-21: Remove trailing spaces flagged by yamllint

Lines 21, 26, 31, 36, 40, 44 have trailing spaces. Please strip them to satisfy YAML linters.

Also applies to: 26-26, 31-31, 36-36, 40-40, 44-44


23-26: Add pip cache for faster installs

Use built-in caching to speed repeated CI runs.

Apply:

       uses: actions/setup-python@v5
       with:
         python-version: ${{ matrix.python-version }}
+        cache: 'pip'
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7e88ff6 and d0050e0.

📒 Files selected for processing (3)
  • .github/workflows/python-package.yml (1 hunks)
  • kicad_lib_manager/utils/git_utils.py (6 hunks)
  • tests/test_git_utils.py (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_git_utils.py
  • kicad_lib_manager/utils/git_utils.py
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/python-package.yml

[error] 21-21: trailing spaces

(trailing-spaces)


[error] 26-26: trailing spaces

(trailing-spaces)


[error] 31-31: trailing spaces

(trailing-spaces)


[error] 36-36: trailing spaces

(trailing-spaces)


[error] 40-40: trailing spaces

(trailing-spaces)


[error] 44-44: trailing spaces

(trailing-spaces)

🔇 Additional comments (3)
.github/workflows/python-package.yml (3)

3-8: Triggers look good

Push to main/feature branches and PRs to main are covered.


41-44: Pytest with coverage: LGTM

Coverage XML generation fits the Codecov upload step.


32-36: No action needed: ruff is installed via dev extras
ruff >= 0.1.0 is declared in pyproject.toml, so the existing pip install -e .[dev] step already installs it.

Comment on lines +11 to 18
test:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Matrix includes Python 3.13; enable prereleases to avoid runner misses

3.13 may be RC/pre-release on some runners. Enable prereleases for setup-python.

Apply:

     - name: Set up Python ${{ matrix.python-version }}
       uses: actions/setup-python@v5
       with:
         python-version: ${{ matrix.python-version }}
+        allow-prereleases: true

Also applies to: 23-26

🤖 Prompt for AI Agents
.github/workflows/python-package.yml lines 11-18 (and likewise update lines
23-26): the workflow matrix includes Python 3.13 which may be a pre-release on
some runners; update the setup-python step to enable prerelease checking by
adding the setup-python input (check-latest: true) so the action can install
pre-release/RC versions. Modify the setup-python job step(s) to include
check-latest: true under with:, and apply the same change to the other repeated
setup-python step at lines 23-26.

Comment on lines +45 to +50
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Codecov v4 inputs/token — verify and adjust

v4 commonly requires a token for private repos and may use files: instead of file:. Please verify and update.

Apply (if needed):

-    - name: Upload coverage to Codecov
+    - name: Upload coverage to Codecov
       if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
       uses: codecov/codecov-action@v4
       with:
-        file: ./coverage.xml
+        files: ./coverage.xml
         fail_ci_if_error: false
+        token: ${{ secrets.CODECOV_TOKEN }}

Queries to confirm:


🌐 Web query:

Does codecov/codecov-action@v4 require a CODECOV_TOKEN for uploads from GitHub Actions, and is the input key `files` (plural) or `file` (singular)?

💡 Result:

Short answer:

  • Yes — codecov/codecov-action@v4 generally requires a CODECOV_TOKEN for uploads (unless you use OIDC or your repo/public-org is configured to allow tokenless uploads). [1][2]
  • The input is files (plural); file (singular) is deprecated in favor of files. [1]

Sources: [1] codecov/codecov-action README (v4) — inputs and token/OIDC notes. [2] Codecov docs on tokens / tokenless uploads.


Update Codecov v4 action inputs

  • Replace the deprecated file: key with files:
  • Add token: ${{ secrets.CODECOV_TOKEN }} (required for private repos; omit only if you’ve enabled tokenless OIDC uploads)
-    - name: Upload coverage to Codecov
+    - name: Upload coverage to Codecov
       if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
       uses: codecov/codecov-action@v4
       with:
-        file: ./coverage.xml
+        files: ./coverage.xml
+        token: ${{ secrets.CODECOV_TOKEN }}
        fail_ci_if_error: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
fail_ci_if_error: false
- name: Upload coverage to Codecov
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.11'
uses: codecov/codecov-action@v4
with:
files: ./coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
fail_ci_if_error: false
🤖 Prompt for AI Agents
.github/workflows/python-package.yml around lines 45-50: the Codecov v4 action
inputs are outdated—replace the deprecated file: key with files: (accepts a glob
or list like ./coverage.xml) and add the token input using token: ${{
secrets.CODECOV_TOKEN }} (omit only if tokenless OIDC uploads are enabled);
ensure the files value is correct and keep fail_ci_if_error: false as before.

@barisgit barisgit merged commit fdc1e4b into main Sep 5, 2025
1 of 3 checks passed
@barisgit barisgit deleted the feature/ci-cd branch September 5, 2025 20:54
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.

1 participant