Skip to content

Commit 365d279

Browse files
committed
Patch gitignore-parser locally to support Windows paths
Refs: mherrmann/gitignore_parser#60 mherrmann/gitignore_parser#61
1 parent e6998f3 commit 365d279

2 files changed

Lines changed: 61 additions & 12 deletions

File tree

changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
> [!IMPORTANT]
66
> This version is not released yet and is under active development.
77
8+
- Patch `gitignore-parser` locally to support Windows paths.
9+
810
## [4.18.0 (2025-08-17)](https://github.com/kdeldycke/workflows/compare/v4.17.9...v4.18.0)
911

1012
- Adds `--format json` option.

gha_utils/metadata.py

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,22 @@
156156
import logging
157157
import os
158158
import re
159+
import sys
159160
import tomllib
160161
from collections.abc import Iterable
161162
from enum import StrEnum
162163
from functools import cached_property
163164
from operator import itemgetter
164-
from pathlib import Path, PureWindowsPath
165+
from pathlib import Path
165166
from random import randint
166167
from re import escape
167168
from typing import Any, Final, cast
168169

170+
import gitignore_parser
169171
from bumpversion.config import get_configuration # type: ignore[import-untyped]
170172
from bumpversion.config.files import find_config_file # type: ignore[import-untyped]
171173
from bumpversion.show import resolve_name # type: ignore[import-untyped]
172174
from extra_platforms import is_github_ci
173-
from gitignore_parser import parse_gitignore
174175
from packaging.specifiers import SpecifierSet
175176
from packaging.version import Version
176177
from pydriller import Commit, Git, Repository # type: ignore[import-untyped]
@@ -349,6 +350,58 @@ class TargetVersion(StrEnum):
349350
"""
350351

351352

353+
# XXX Patch gitignore-parser to support Windows paths.
354+
# Refs: https://github.com/mherrmann/gitignore_parser/pull/61
355+
356+
_OriginalIgnoreRule = gitignore_parser.IgnoreRule
357+
358+
359+
class PatchedIgnoreRule(_OriginalIgnoreRule):
360+
"""Patch version of ``IgnoreRule`` to support Windows paths.
361+
362+
Taken from: https://github.com/mherrmann/gitignore_parser/pull/61/files
363+
"""
364+
365+
@staticmethod
366+
def _count_trailing_symbol(symbol: str, text: str) -> int:
367+
"""Count the number of trailing characters in a string."""
368+
count = 0
369+
for char in reversed(str(text)):
370+
if char == symbol:
371+
count += 1
372+
else:
373+
break
374+
return count
375+
376+
def match(self, abs_path: str | Path) -> bool:
377+
matched = False
378+
if self.base_path:
379+
rel_path = (
380+
gitignore_parser._normalize_path(abs_path)
381+
.relative_to(self.base_path)
382+
.as_posix()
383+
)
384+
else:
385+
rel_path = gitignore_parser._normalize_path(abs_path).as_posix()
386+
# Path() strips the trailing following symbols on windows, so we need to
387+
# preserve it: ' ', '.'
388+
if sys.platform.startswith("win"):
389+
rel_path += " " * self._count_trailing_symbol(" ", abs_path)
390+
rel_path += "." * self._count_trailing_symbol(".", abs_path)
391+
# Path() strips the trailing slash, so we need to preserve it
392+
# in case of directory-only negation
393+
if self.negation and type(abs_path) is str and abs_path[-1] == "/":
394+
rel_path += "/"
395+
if rel_path.startswith("./"):
396+
rel_path = rel_path[2:]
397+
if re.search(self.regex, rel_path):
398+
matched = True
399+
return matched
400+
401+
402+
gitignore_parser.IgnoreRule = PatchedIgnoreRule
403+
404+
352405
class JSONMetadata(json.JSONEncoder):
353406
"""Custom JSON encoder for metadata serialization."""
354407

@@ -737,7 +790,7 @@ def glob_files(self, *patterns: str) -> list[Path]:
737790
gitignore = None
738791
if self.gitignore_exists:
739792
logging.debug(f"Load {GITIGNORE_PATH} to filter out ignored files.")
740-
gitignore = parse_gitignore(GITIGNORE_PATH)
793+
gitignore = gitignore_parser.parse_gitignore(GITIGNORE_PATH)
741794

742795
for file_path in iglob(
743796
patterns,
@@ -768,15 +821,9 @@ def glob_files(self, *patterns: str) -> list[Path]:
768821
continue
769822

770823
# Skip files that are ignored by .gitignore.
771-
if gitignore:
772-
if gitignore(
773-
# gitignore does not support WindowsPath.
774-
file_path.as_posix()
775-
if isinstance(file_path, PureWindowsPath)
776-
else file_path
777-
):
778-
logging.debug(f"Skip file matching {GITIGNORE_PATH}: {file_path}")
779-
continue
824+
if gitignore and gitignore(file_path):
825+
logging.debug(f"Skip file matching {GITIGNORE_PATH}: {file_path}")
826+
continue
780827

781828
seen.add(normalized_path)
782829
return sorted(seen)

0 commit comments

Comments
 (0)