gha-utils 4.18.0__tar.gz → 4.18.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of gha-utils might be problematic. Click here for more details.

Files changed (23) hide show
  1. {gha_utils-4.18.0 → gha_utils-4.18.1}/PKG-INFO +1 -1
  2. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/__init__.py +1 -1
  3. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/cli.py +1 -1
  4. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/matrix.py +3 -3
  5. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/metadata.py +67 -10
  6. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils.egg-info/PKG-INFO +1 -1
  7. {gha_utils-4.18.0 → gha_utils-4.18.1}/pyproject.toml +3 -3
  8. {gha_utils-4.18.0 → gha_utils-4.18.1}/tests/test_metadata.py +12 -8
  9. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/__main__.py +0 -0
  10. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/changelog.py +0 -0
  11. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/mailmap.py +0 -0
  12. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/py.typed +0 -0
  13. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils/test_plan.py +0 -0
  14. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils.egg-info/SOURCES.txt +0 -0
  15. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils.egg-info/dependency_links.txt +0 -0
  16. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils.egg-info/entry_points.txt +0 -0
  17. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils.egg-info/requires.txt +0 -0
  18. {gha_utils-4.18.0 → gha_utils-4.18.1}/gha_utils.egg-info/top_level.txt +0 -0
  19. {gha_utils-4.18.0 → gha_utils-4.18.1}/readme.md +0 -0
  20. {gha_utils-4.18.0 → gha_utils-4.18.1}/setup.cfg +0 -0
  21. {gha_utils-4.18.0 → gha_utils-4.18.1}/tests/test_changelog.py +0 -0
  22. {gha_utils-4.18.0 → gha_utils-4.18.1}/tests/test_mailmap.py +0 -0
  23. {gha_utils-4.18.0 → gha_utils-4.18.1}/tests/test_matrix.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gha-utils
3
- Version: 4.18.0
3
+ Version: 4.18.1
4
4
  Summary: ⚙️ CLI helpers for GitHub Actions + reuseable workflows
5
5
  Author-email: Kevin Deldycke <kevin@deldycke.com>
6
6
  Project-URL: Homepage, https://github.com/kdeldycke/workflows
@@ -17,4 +17,4 @@
17
17
 
18
18
  from __future__ import annotations
19
19
 
20
- __version__ = "4.18.0"
20
+ __version__ = "4.18.1"
@@ -116,7 +116,7 @@ def gha_utils():
116
116
  )
117
117
  @option(
118
118
  "--format",
119
- type=Choice(Dialects, case_sensitive=False),
119
+ type=Choice(Dialects, case_sensitive=False), # type: ignore[arg-type]
120
120
  default=Dialects.github,
121
121
  help="Rendering format of the metadata.",
122
122
  )
@@ -48,7 +48,7 @@ class Matrix:
48
48
  """
49
49
 
50
50
  def __init__(self, *args, **kwargs):
51
- self.variations: dict = {}
51
+ self.variations: dict[str, tuple[str, ...]] = {}
52
52
 
53
53
  # Tuples are used to keep track of the insertion order and force immutability.
54
54
  self.include: tuple[dict[str, str], ...] = tuple()
@@ -66,9 +66,9 @@ class Matrix:
66
66
  """
67
67
  dict_copy = self.variations.copy()
68
68
  if not ignore_includes and self.include:
69
- dict_copy["include"] = self.include
69
+ dict_copy["include"] = self.include # type: ignore[assignment]
70
70
  if not ignore_excludes and self.exclude:
71
- dict_copy["exclude"] = self.exclude
71
+ dict_copy["exclude"] = self.exclude # type: ignore[assignment]
72
72
  return FrozenDict(dict_copy)
73
73
 
74
74
  def __repr__(self) -> str:
@@ -156,6 +156,7 @@ import json
156
156
  import logging
157
157
  import os
158
158
  import re
159
+ import sys
159
160
  import tomllib
160
161
  from collections.abc import Iterable
161
162
  from enum import StrEnum
@@ -166,11 +167,11 @@ from random import randint
166
167
  from re import escape
167
168
  from typing import Any, Final, cast
168
169
 
170
+ import gitignore_parser
169
171
  from bumpversion.config import get_configuration # type: ignore[import-untyped]
170
172
  from bumpversion.config.files import find_config_file # type: ignore[import-untyped]
171
173
  from bumpversion.show import resolve_name # type: ignore[import-untyped]
172
174
  from extra_platforms import is_github_ci
173
- from gitignore_parser import parse_gitignore
174
175
  from packaging.specifiers import SpecifierSet
175
176
  from packaging.version import Version
176
177
  from pydriller import Commit, Git, Repository # type: ignore[import-untyped]
@@ -349,10 +350,66 @@ MYPY_VERSION_MIN: Final = (3, 8)
349
350
  """
350
351
 
351
352
 
353
+ # XXX Patch gitignore-parser to support Windows paths. Refs:
354
+ # https://github.com/mherrmann/gitignore_parser/issues/60
355
+ # https://github.com/mherrmann/gitignore_parser/pull/61
356
+ # XXX In the future, replace this with wcmatch once it supports gitignore files:
357
+ # https://github.com/facelessuser/wcmatch/issues/226
358
+
359
+
360
+ _OriginalIgnoreRule = gitignore_parser.IgnoreRule
361
+
362
+
363
+ class PatchedIgnoreRule(_OriginalIgnoreRule): # type: ignore[misc,valid-type]
364
+ """Patch version of ``IgnoreRule`` to support Windows paths.
365
+
366
+ Taken from: https://github.com/mherrmann/gitignore_parser/pull/61/files
367
+ """
368
+
369
+ @staticmethod
370
+ def _count_trailing_symbol(symbol: str, text: str) -> int:
371
+ """Count the number of trailing characters in a string."""
372
+ count = 0
373
+ for char in reversed(str(text)):
374
+ if char == symbol:
375
+ count += 1
376
+ else:
377
+ break
378
+ return count
379
+
380
+ def match(self, abs_path: str | Path) -> bool:
381
+ matched = False
382
+ if self.base_path:
383
+ rel_path = (
384
+ gitignore_parser._normalize_path(abs_path)
385
+ .relative_to(self.base_path)
386
+ .as_posix()
387
+ )
388
+ else:
389
+ rel_path = gitignore_parser._normalize_path(abs_path).as_posix()
390
+ # Path() strips the trailing following symbols on windows, so we need to
391
+ # preserve it: ' ', '.'
392
+ if sys.platform.startswith("win"):
393
+ rel_path += " " * self._count_trailing_symbol(" ", abs_path)
394
+ rel_path += "." * self._count_trailing_symbol(".", abs_path)
395
+ # Path() strips the trailing slash, so we need to preserve it
396
+ # in case of directory-only negation
397
+ if self.negation and type(abs_path) is str and abs_path[-1] == "/":
398
+ rel_path += "/"
399
+ if rel_path.startswith("./"):
400
+ rel_path = rel_path[2:]
401
+ if re.search(self.regex, rel_path):
402
+ matched = True
403
+ return matched
404
+
405
+
406
+ gitignore_parser.IgnoreRule = PatchedIgnoreRule
407
+
408
+
352
409
  class JSONMetadata(json.JSONEncoder):
353
410
  """Custom JSON encoder for metadata serialization."""
354
411
 
355
- def default(self, o: Any) -> str:
412
+ def default(self, o: Any) -> Any:
356
413
  if isinstance(o, Matrix):
357
414
  return o.matrix()
358
415
 
@@ -592,11 +649,15 @@ class Metadata:
592
649
  events.
593
650
 
594
651
  .. seealso::
595
-
596
652
  - https://stackoverflow.com/a/67204539
597
653
  - https://stackoverflow.com/a/62953566
598
654
  - https://stackoverflow.com/a/61861763
599
655
 
656
+ .. seealso::
657
+ Pull request events on GitHub are a bit complex, see: `The Many SHAs of a
658
+ GitHub Pull Request
659
+ <https://www.kenmuse.com/blog/the-many-shas-of-a-github-pull-request/>`_.
660
+
600
661
  .. todo::
601
662
  Refactor so we can get rid of ``self.github_context``. Maybe there's enough
602
663
  metadata lying around in the environment variables that we can inspect the
@@ -657,11 +718,7 @@ class Metadata:
657
718
  @cached_property
658
719
  def new_commits_hash(self) -> tuple[str, ...] | None:
659
720
  """List all hashes of new commits."""
660
- return (
661
- cast(tuple[str, ...], self.new_commits_matrix["commit"])
662
- if self.new_commits_matrix
663
- else None
664
- )
721
+ return self.new_commits_matrix["commit"] if self.new_commits_matrix else None
665
722
 
666
723
  @cached_property
667
724
  def release_commits(self) -> tuple[Commit, ...] | None:
@@ -695,7 +752,7 @@ class Metadata:
695
752
  def release_commits_hash(self) -> tuple[str, ...] | None:
696
753
  """List all hashes of release commits."""
697
754
  return (
698
- cast(tuple[str, ...], self.release_commits_matrix["commit"])
755
+ self.release_commits_matrix["commit"]
699
756
  if self.release_commits_matrix
700
757
  else None
701
758
  )
@@ -737,7 +794,7 @@ class Metadata:
737
794
  gitignore = None
738
795
  if self.gitignore_exists:
739
796
  logging.debug(f"Load {GITIGNORE_PATH} to filter out ignored files.")
740
- gitignore = parse_gitignore(GITIGNORE_PATH)
797
+ gitignore = gitignore_parser.parse_gitignore(GITIGNORE_PATH)
741
798
 
742
799
  for file_path in iglob(
743
800
  patterns,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gha-utils
3
- Version: 4.18.0
3
+ Version: 4.18.1
4
4
  Summary: ⚙️ CLI helpers for GitHub Actions + reuseable workflows
5
5
  Author-email: Kevin Deldycke <kevin@deldycke.com>
6
6
  Project-URL: Homepage, https://github.com/kdeldycke/workflows
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  # Docs: https://packaging.python.org/en/latest/guides/writing-pyproject-toml/
3
3
  name = "gha-utils"
4
- version = "4.18.0"
4
+ version = "4.18.1"
5
5
  # Python versions and their status: https://devguide.python.org/versions/
6
6
  requires-python = ">= 3.11"
7
7
  description = "⚙️ CLI helpers for GitHub Actions + reuseable workflows"
@@ -120,7 +120,7 @@ pretty = true
120
120
 
121
121
  [[tool.mypy.overrides]]
122
122
  ignore_missing_imports = true
123
- module = ["boltons.*"]
123
+ module = ["boltons.*", "gitignore_parser.*"]
124
124
 
125
125
  [tool.pytest.ini_options]
126
126
  # https://docs.pytest.org/en/latest/customize.html#pyproject-toml
@@ -138,7 +138,7 @@ addopts = [
138
138
  xfail_strict = true
139
139
 
140
140
  [tool.bumpversion]
141
- current_version = "4.18.0"
141
+ current_version = "4.18.1"
142
142
  allow_dirty = true
143
143
  ignore_missing_files = true
144
144
 
@@ -58,27 +58,31 @@ def regex(pattern: str) -> re.Pattern:
58
58
  return re.compile(pattern, re.DOTALL)
59
59
 
60
60
 
61
- def iter_checks(metadata: Any, expected: Any) -> None:
61
+ def iter_checks(metadata: Any, expected: Any, context: Any) -> None:
62
62
  """Recursively iterate over expected content and check it matches in metadata."""
63
63
 
64
64
  if isinstance(expected, re.Pattern):
65
65
  assert isinstance(metadata, str)
66
- assert re.fullmatch(expected, metadata) is not None
66
+ assert re.fullmatch(expected, metadata) is not None, (
67
+ f"{metadata!r} does not match {expected.pattern!r} in {context!r}"
68
+ )
67
69
 
68
70
  elif isinstance(expected, dict):
69
71
  assert isinstance(metadata, dict)
70
72
  assert set(metadata) == set(expected)
71
73
  for key, value in expected.items():
72
- iter_checks(metadata[key], value)
74
+ iter_checks(metadata[key], value, metadata)
73
75
 
74
76
  elif isinstance(expected, list):
75
77
  assert isinstance(metadata, list)
76
78
  assert len(metadata) == len(expected)
77
79
  for item in expected:
78
- iter_checks(metadata[expected.index(item)], item)
80
+ iter_checks(metadata[expected.index(item)], item, metadata)
79
81
 
80
82
  else:
81
- assert metadata == expected
83
+ assert metadata == expected, (
84
+ f"{metadata!r} does not match {expected!r} in {context!r}"
85
+ )
82
86
  assert type(metadata) is type(expected)
83
87
 
84
88
 
@@ -203,7 +207,7 @@ expected = {
203
207
  "cli_id": "gha-utils",
204
208
  "module_id": "gha_utils.__main__",
205
209
  "callable_id": "main",
206
- "module_path": regex(r"gha_utils(/|\\\\)__main__\.py"),
210
+ "module_path": regex(r"gha_utils(/|\\)__main__\.py"),
207
211
  },
208
212
  {
209
213
  "commit": regex(r"[a-z0-9]+"),
@@ -256,7 +260,7 @@ def test_metadata_json_format():
256
260
  metadata = Metadata().dump(Dialects.json)
257
261
  assert isinstance(metadata, str)
258
262
 
259
- iter_checks(json.loads(metadata), expected)
263
+ iter_checks(json.loads(metadata), expected, metadata)
260
264
 
261
265
 
262
266
  def test_metadata_github_format():
@@ -326,4 +330,4 @@ def test_metadata_github_format():
326
330
  new_value = " ".join(f'"{i}"' for i in value)
327
331
  github_format_expected[key] = new_value
328
332
 
329
- iter_checks(metadata, github_format_expected)
333
+ iter_checks(metadata, github_format_expected, raw_metadata)
File without changes
File without changes