mkdocstrings-github 0.4.1__py3-none-any.whl → 0.4.3__py3-none-any.whl

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mkdocstrings-github
3
- Version: 0.4.1
3
+ Version: 0.4.3
4
4
  Summary: A GitHub Action handler for mkdocstrings
5
5
  Author-email: Mark Hu <watermarkhu@gmail.com>
6
6
  License: MIT
@@ -23,6 +23,7 @@ Classifier: Typing :: Typed
23
23
  Requires-Python: <3.15,>=3.10
24
24
  Requires-Dist: gitpython~=3.1.45
25
25
  Requires-Dist: mkdocstrings~=0.29
26
+ Requires-Dist: packaging~=25.0
26
27
  Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
27
28
  Description-Content-Type: text/markdown
28
29
 
@@ -1,17 +1,17 @@
1
1
  mkdocstrings_handlers/github/__init__.py,sha256=0WdFUIq4Xu2ZFtlZNIYCQSoqcx3Ot9Wv41_X_dwbFww,248
2
2
  mkdocstrings_handlers/github/config.py,sha256=pSjA6gU-kC_mXQqNIIGOYEOhtX5VzZDT0H1hRFlGaj8,6089
3
- mkdocstrings_handlers/github/handler.py,sha256=5-vc49Te_BIW7oX8KfuNrbQOWpM0xBMLugP1z1Hm4E8,7953
3
+ mkdocstrings_handlers/github/handler.py,sha256=QJbZjRbllUuGs5rY6SLwaII6hsPQnioa_OmauWGL-lU,8495
4
4
  mkdocstrings_handlers/github/objects.py,sha256=JDkY7mg_LGlIEwZHP2wSd8ZkB6RVtRsu_JEpwV-PikQ,7069
5
5
  mkdocstrings_handlers/github/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- mkdocstrings_handlers/github/rendering.py,sha256=tJeAsSaijqSC2IkxYsIXq7d0lR2A3aB5PRUcFFTFpVU,2705
6
+ mkdocstrings_handlers/github/rendering.py,sha256=6xcE2WwyTRW_38g7Ek55hlm53EsFFqueazFw12__DyA,2820
7
7
  mkdocstrings_handlers/github/templates/material/action.html.jinja,sha256=87NCgz-zY16rU7tEmJETJ0gLwdzxoBrqLtp9vsVCsiw,2435
8
8
  mkdocstrings_handlers/github/templates/material/heading.html.jinja,sha256=wnvZpNED8Dhb935qnddeDExXN-MIUz8frRRfgq-A9VA,1396
9
9
  mkdocstrings_handlers/github/templates/material/inputs.html.jinja,sha256=CIcw3OBQdCP4e5A4srLu1v3xoOjsedIw1Zh3qxtG0-A,3482
10
10
  mkdocstrings_handlers/github/templates/material/outputs.html.jinja,sha256=jlzVF93q5AyJfOiSl3_1VBVL3c6rjmEcS81s3sri5Gg,2670
11
11
  mkdocstrings_handlers/github/templates/material/secrets.html.jinja,sha256=1lMJoxjjeiqetVu0mdLKmZ1faYRReeyjiYvYTZESots,2881
12
12
  mkdocstrings_handlers/github/templates/material/style.css,sha256=R2hh1RfHwJ6XNT4YQl_txNkNXcPBZJMCBZn5kQEMQ6M,962
13
- mkdocstrings_handlers/github/templates/material/workflow.html.jinja,sha256=E1VUi2w7_NDkpS9VNrWRV52hhyhQvnKUrjPbV_j0Qcg,3312
14
- mkdocstrings_github-0.4.1.dist-info/METADATA,sha256=G-g63IhkT-QCiHSrVFuXZRYr_juCVpy9MIfVAOoJCQc,3309
15
- mkdocstrings_github-0.4.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
- mkdocstrings_github-0.4.1.dist-info/licenses/LICENSE,sha256=5enZtJ4zSp0Ps3jTqFQ4kadcx62BhgTaDNPrXWb3g3E,1069
17
- mkdocstrings_github-0.4.1.dist-info/RECORD,,
13
+ mkdocstrings_handlers/github/templates/material/workflow.html.jinja,sha256=89hEu1dagyqEV_40iTeCR4UKvdI4HlIJaUAebqugxNM,3400
14
+ mkdocstrings_github-0.4.3.dist-info/METADATA,sha256=0G1SP3Qs5hbC6rPz32iZ1uJT-jnaFq6X7pWNUfeHLnc,3340
15
+ mkdocstrings_github-0.4.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ mkdocstrings_github-0.4.3.dist-info/licenses/LICENSE,sha256=5enZtJ4zSp0Ps3jTqFQ4kadcx62BhgTaDNPrXWb3g3E,1069
17
+ mkdocstrings_github-0.4.3.dist-info/RECORD,,
@@ -4,7 +4,6 @@ from __future__ import annotations
4
4
 
5
5
  import os
6
6
  import re
7
- import sys
8
7
  from pathlib import Path
9
8
  from typing import TYPE_CHECKING, Any, ClassVar, Mapping
10
9
 
@@ -16,6 +15,7 @@ from mkdocstrings import (
16
15
  HandlerOptions,
17
16
  get_logger,
18
17
  )
18
+ from packaging.version import InvalidVersion, Version
19
19
 
20
20
  from mkdocstrings_handlers.github import rendering
21
21
  from mkdocstrings_handlers.github.config import GitHubConfig, GitHubOptions
@@ -67,75 +67,89 @@ class GitHubHandler(BaseHandler):
67
67
  self.config = config
68
68
  self.repo = repo
69
69
  self.global_options = config.options.__dict__
70
- self.workflows: dict[Path, Workflow] = {}
71
- self.actions: dict[Path, Action] = {}
72
70
  self.major: str = ""
73
71
  self.semver: str = ""
74
72
 
75
- # Only run GitHub releases code if required and not in testing
76
- not_testing = "pytest" not in sys.modules
77
- no_custom_tags = (
78
- rendering.ENV_MAJOR_TAG not in os.environ or rendering.ENV_SEMVER_TAG not in os.environ
79
- )
80
- if not_testing and no_custom_tags:
73
+ # Determine owner and repo name
74
+ if not self.config.repo:
75
+ self.get_repo()
76
+
77
+ if rendering.ENV_MAJOR_TAG not in os.environ or rendering.ENV_SEMVER_TAG not in os.environ:
81
78
  self.get_releases()
82
79
 
83
- # Glob all workflow YAML files using pathlib
84
- working_tree_dir = Path(repo.working_tree_dir)
85
- workflows_dir = working_tree_dir / ".github" / "workflows"
86
- for workflow_file in list(workflows_dir.glob("*.yml")) + list(workflows_dir.glob("*.yaml")):
87
- id = str(workflow_file.relative_to(working_tree_dir))
88
- workflow = Workflow.from_file(workflow_file, id)
89
- if workflow is not None:
90
- self.workflows[workflow_file] = workflow
91
-
92
- # Glob all action.yaml and action.yml files, skipping .git folder entirely using pathlib
93
- def find_action_files(base: Path):
94
- for entry in base.iterdir():
95
- if entry.is_dir():
96
- if entry.name == ".git":
97
- continue
98
- yield from find_action_files(entry)
99
- elif entry.is_file() and entry.name in ("action.yaml", "action.yml"):
100
- yield entry
101
-
102
- for action_file in find_action_files(working_tree_dir):
103
- id = str(action_file.relative_to(working_tree_dir).parent)
104
- action = Action.from_file(action_file, id)
105
- if action is not None:
106
- self.actions[action_file] = action
80
+ def get_repo(self) -> None:
81
+ # Get repo from environment variable or git remotes.
82
+ if os.environ.get("GITHUB_ACTIONS") == "true" and (
83
+ repo := os.environ.get("GITHUB_REPOSITORY")
84
+ ):
85
+ self.config.repo = repo
86
+ else:
87
+ # Try each remote to find a valid GitHub owner/repo
88
+ owner = None
89
+ repo_name = None
90
+ for remote in self.repo.remotes:
91
+ for url in remote.urls:
92
+ match = re.search(
93
+ r"(?P<host>[\w\.-]+)[/:](?P<owner>[^/]+)/(?P<repo>[^/.]+?)(?:\.git)?$",
94
+ url,
95
+ )
96
+ if match:
97
+ owner = match.group("owner")
98
+ repo_name = match.group("repo")
99
+ break
100
+ if owner and repo_name:
101
+ break
102
+ if not (owner and repo_name):
103
+ raise PluginError(
104
+ f"Could not determine GitHub repository owner/name from config.repo='{self.config.repo}' or any git remote URL."
105
+ )
106
+ self.config.repo = f"{owner}/{repo_name}"
107
107
 
108
108
  def get_releases(self) -> None:
109
- # Get all tags from the local git repository
109
+ # Get all tags from the local git repository.
110
110
  try:
111
- tags = sorted([tag.name for tag in self.repo.tags], reverse=True)
111
+ tags = [tag.name for tag in self.repo.tags]
112
112
  except Exception as e:
113
113
  _logger.warning(f"Could not get git tags from repository: {e}")
114
114
  return
115
115
 
116
- # Find matching tags
116
+ # Separate semver, major, and other tags
117
+ semver_tags = []
118
+ major_tags = []
119
+ other_tags = []
117
120
  for tag in tags:
118
- if not self.semver and SEMVER_PATTERN.match(tag):
119
- _logger.info(f"Using git tag '{tag}' for semver.")
120
- self.semver = tag
121
- if not self.major and MAJOR_PATTERN.match(tag):
122
- _logger.info(f"Using git tag '{tag}' for major.")
123
- self.major = tag
124
- if self.semver and self.major:
125
- break
126
-
127
- if not self.semver or not self.major:
128
- if not self.semver and not self.major:
129
- messages = ("'vX.X.X' and 'vX'", "'semver and major'")
130
- elif not self.semver:
131
- messages = ("'vX.X.X'", "'semver'")
132
- else: # not self.major
133
- messages = ("'vX'", "'major'")
134
- _logger.warning(
135
- f"Could not find suitable git tags in repository. "
136
- f"Make sure there are tags matching {messages[0]}, "
137
- f"if you wish to use option signature_version {messages[1]}.",
138
- )
121
+ if SEMVER_PATTERN.match(tag):
122
+ semver_tags.append(tag)
123
+ elif MAJOR_PATTERN.match(tag):
124
+ major_tags.append(tag)
125
+ else:
126
+ other_tags.append(tag)
127
+
128
+ # Sort tags using packaging.version.Version
129
+ def version_key(tag):
130
+ try:
131
+ return Version(tag.lstrip("v"))
132
+ except InvalidVersion:
133
+ return Version("0.0.0")
134
+
135
+ semver_tags_sorted = sorted(semver_tags, key=version_key, reverse=True)
136
+ major_tags_sorted = sorted(major_tags, key=version_key, reverse=True)
137
+ other_tags_sorted = sorted(other_tags, reverse=True)
138
+
139
+ if semver_tags_sorted:
140
+ self.semver = semver_tags_sorted[0]
141
+ _logger.info(f"Using git tag '{self.semver}' for semver.")
142
+ else:
143
+ _logger.warning("No semver tags found in repository.")
144
+
145
+ if major_tags_sorted:
146
+ self.major = major_tags_sorted[0]
147
+ _logger.info(f"Using git tag '{self.major}' for major.")
148
+ else:
149
+ _logger.warning("No major tags found in repository.")
150
+
151
+ if other_tags_sorted:
152
+ _logger.debug(f"Other git tags found: {', '.join(other_tags_sorted)}")
139
153
 
140
154
  def get_options(self, local_options: Mapping[str, Any]) -> HandlerOptions:
141
155
  """Get combined default, global and local options.
@@ -166,16 +180,26 @@ class GitHubHandler(BaseHandler):
166
180
  self.env.globals["major_tag"] = self.major
167
181
  self.env.globals["git_repo"] = self.repo
168
182
 
169
- def collect(self, identifier: str, options: GitHubOptions) -> Workflow | Action:
183
+ def collect(self, identifier: str, options: GitHubOptions) -> Workflow | Action | None:
170
184
  path = Path(self.repo.working_tree_dir) / identifier
171
- if path in self.workflows:
172
- return self.workflows[path]
173
- elif (action_path := path / "action.yml") in self.actions:
174
- return self.actions[action_path]
175
- elif (action_path := path / "action.yaml") in self.actions:
176
- return self.actions[action_path]
185
+
186
+ if path.suffix in (".yml", ".yaml"):
187
+ if not path.is_file():
188
+ raise CollectionError(f"Identifier '{identifier}' is not a valid workflow file.")
189
+ data = Workflow.from_file(path, id=identifier)
190
+ elif not path.is_dir():
191
+ raise CollectionError(
192
+ f"Identifier '{identifier}' is not a valid workflow file or action directory."
193
+ )
194
+ elif (action_path := path / "action.yml").is_file():
195
+ data = Action.from_file(action_path, id=identifier)
196
+ elif (action_path := path / "action.yaml").is_file():
197
+ data = Action.from_file(action_path, id=identifier)
177
198
  else:
178
- raise CollectionError(f"Identifier '{identifier}' not found as a workflow or action.")
199
+ raise CollectionError(
200
+ f"Identifier '{identifier}' is not a valid workflow file or action directory."
201
+ )
202
+ return data
179
203
 
180
204
  def render(self, data: Workflow | Action, options: GitHubOptions) -> str:
181
205
  """Render a template using provided data and configuration options.
@@ -23,8 +23,11 @@ def format_action_signature(context: Context, id: str, repo: str, options: GitHu
23
23
  match options.signature_version:
24
24
  case "ref":
25
25
  try:
26
- repo: Repo = context.environment.globals["git_repo"]
27
- version = repo.head.ref.name
26
+ git_repo = context.environment.globals["git_repo"]
27
+ if isinstance(git_repo, Repo):
28
+ version = git_repo.head.ref.name
29
+ else:
30
+ version = "unknown"
28
31
  except Exception:
29
32
  version = "unknown"
30
33
  case "major":
@@ -24,25 +24,29 @@ Context:
24
24
 
25
25
  {% block signature scoped %}
26
26
  {% if options.show_signature %}
27
- {% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
28
- {% filter highlight(language="yaml", inline=False, linenums=False) %}
29
- uses: {{ signature }}
30
- {% if options.signature_show_permissions and data.permissions %}
31
- permissions:
32
- {% for scope, level in data.permissions | items %}
33
- {{ scope }}: {{ level.label }}
34
- {% endfor %}
35
- {% endif %}
36
- with:
37
- {%+ for input in inputs %}{{ input.name }}: ''{% endfor +%}
38
- {% if options.signature_show_secrets %}
39
- {% with secrets = data.secrets | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
40
- secrets:
41
- {%+ for secret in secrets %}{{ secret.name }}: ''{% endfor +%}
42
- {% endwith %}
43
- {% endif %}
44
- {% endfilter %}
45
- {% endwith %}
27
+ {% filter highlight(language="yaml", inline=False, linenums=False) %}
28
+ uses: {{ signature }}
29
+ {% if options.signature_show_permissions and data.permissions|length > 0 %}
30
+ permissions:
31
+ {% for scope, level in data.permissions | items %}
32
+ {{ scope }}: {{ level.label }}
33
+ {% endfor %}
34
+ {% endif %}
35
+ {% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
36
+ {% if inputs|length > 0 %}
37
+ with:
38
+ {%+ for input in inputs %}{{ input.name }}: ''{% endfor +%}
39
+ {% endif %}
40
+ {% endwith %}
41
+ {% if options.signature_show_secrets %}
42
+ {% with secrets = data.secrets | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
43
+ {% if secrets|length > 0 %}
44
+ secrets:
45
+ {%+ for secret in secrets %}{{ secret.name }}: ''{% endfor +%}
46
+ {% endif %}
47
+ {% endwith %}
48
+ {% endif %}
49
+ {% endfilter %}
46
50
  {% endif %}
47
51
  {% endblock signature %}
48
52