mkdocstrings-github 0.1.0__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.
@@ -0,0 +1,64 @@
1
+ Metadata-Version: 2.4
2
+ Name: mkdocstrings-github
3
+ Version: 0.1.0
4
+ Summary: A GitHub Action handler for mkdocstrings
5
+ Author-email: Mark Hu <watermarkhu@gmail.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.10
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Classifier: Topic :: Documentation
18
+ Classifier: Topic :: Software Development
19
+ Classifier: Topic :: Software Development :: Documentation
20
+ Classifier: Topic :: Utilities
21
+ Classifier: Typing :: Typed
22
+ Requires-Python: <3.14,>=3.10
23
+ Requires-Dist: gitpython~=3.1.45
24
+ Requires-Dist: mkdocstrings~=0.29
25
+ Requires-Dist: pygithub~=2.8.1
26
+ Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
27
+ Description-Content-Type: text/markdown
28
+
29
+ <!-- --8<-- [start:header] -->
30
+
31
+ <h1 align="center">mkdocstrings-github</h1>
32
+
33
+ <p align="center">A GitHub Actions handler for <a href="https://github.com/mkdocstrings/mkdocstrings"><i>mkdocstrings</i></a>.</p>
34
+
35
+ <p align="center"><img width=300px src="logo.png"></p>
36
+
37
+ [![Qualify](https://github.com/watermarkhu/mkdocstrings-github/actions/workflows/qualify.yaml/badge.svg?branch=main)](https://github.com/watermarkhu/mkdocstrings-github/actions/workflows/qualify.yaml)
38
+ [![documentation](https://img.shields.io/badge/docs-mkdocs-708FCC.svg?style=flat)](https://watermarkhu.nl/mkdocstrings-github)
39
+ [![pypi version](https://img.shields.io/pypi/v/mkdocstrings-github.svg)](https://pypi.org/project/mkdocstrings-github/)
40
+
41
+ <!-- --8<-- [end:header] -->
42
+ <!-- --8<-- [start:install] -->
43
+ You can install the GitHub handler by specifying it as a dependency:
44
+
45
+ ```toml title="pyproject.toml"
46
+ # PEP 621 dependencies declaration
47
+ # adapt to your dependencies manager
48
+ [project]
49
+ dependencies = [
50
+ "mkdocstrings-github>=0.X.Y",
51
+ ]
52
+ ```
53
+ <!-- --8<-- [end:install] -->
54
+
55
+ <!-- --8<-- [start:footer] -->
56
+
57
+ ## Features
58
+
59
+ - 📝 **Automatic Example Signature**: Displays an example call signature alongside the description. The version shown can be the latest release, latest major, current reference, or any custom string.
60
+ - ✨ **Enhanced Markdown Descriptions**: All description elements are parsed using a markdown parser, enabling comprehensive formatting and rich documentation capabilities.
61
+ - 🧩 **Individual Parameter Hyperlinks**: Each action or workflow parameter—including inputs, outputs, and secrets—receives a unique HTML id, facilitating direct linking to specific parameter documentation.
62
+ - đź”’ **Automated Permission Aggregation**: For reusable workflows, if permissions are specified at the job level rather than the workflow level, the required final permissions are automatically determined and displayed in the signature.
63
+
64
+ <!-- --8<-- [end:footer] -->
@@ -0,0 +1,17 @@
1
+ mkdocstrings_handlers/github/__init__.py,sha256=0WdFUIq4Xu2ZFtlZNIYCQSoqcx3Ot9Wv41_X_dwbFww,248
2
+ mkdocstrings_handlers/github/config.py,sha256=Lma2xz46TfG5Tgj-Bkh6Lqa1hBuJH3uCtmfOFab7kI4,5459
3
+ mkdocstrings_handlers/github/handler.py,sha256=dN3maFhASZc4JzJKjpgMTDeXuz9VBwjR2YygnvTIEdk,8017
4
+ mkdocstrings_handlers/github/objects.py,sha256=deZlW1nuyaFd4FivOA5dJb2uzY7gHTheTdUzMkOIS9E,6796
5
+ mkdocstrings_handlers/github/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ mkdocstrings_handlers/github/rendering.py,sha256=XxejVRXR8n5pkKHAPyYWx4n0NyH8kHNUy2uHRlhQA3w,2184
7
+ mkdocstrings_handlers/github/templates/material/action.html.jinja,sha256=87NCgz-zY16rU7tEmJETJ0gLwdzxoBrqLtp9vsVCsiw,2435
8
+ mkdocstrings_handlers/github/templates/material/heading.html.jinja,sha256=wnvZpNED8Dhb935qnddeDExXN-MIUz8frRRfgq-A9VA,1396
9
+ mkdocstrings_handlers/github/templates/material/inputs.html.jinja,sha256=zP7z_9CO248LhSwvQZ-eG54y73DB67M2TFwNI5iFfM4,3352
10
+ mkdocstrings_handlers/github/templates/material/outputs.html.jinja,sha256=zDmKj9QjD9kd3VVN3xZqQSncVdNjXnTs1m98_Hj2hTM,2780
11
+ mkdocstrings_handlers/github/templates/material/secrets.html.jinja,sha256=uaKsGH_08JSdy5WbjDiDNaYaOXkCJ1K6Ac-6wYkLo2c,2990
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.1.0.dist-info/METADATA,sha256=4zfACSDnMmVa33t2ZLF8OFa7Cx4r-MRZvsYb9wTICUc,3008
15
+ mkdocstrings_github-0.1.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
16
+ mkdocstrings_github-0.1.0.dist-info/licenses/LICENSE,sha256=5enZtJ4zSp0Ps3jTqFQ4kadcx62BhgTaDNPrXWb3g3E,1069
17
+ mkdocstrings_github-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Mark Shui Hu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,9 @@
1
+ from mkdocstrings_handlers.github.config import GitHubConfig, GitHubOptions
2
+ from mkdocstrings_handlers.github.handler import GitHubHandler, get_handler
3
+
4
+ __all__ = [
5
+ "GitHubHandler",
6
+ "GitHubConfig",
7
+ "GitHubOptions",
8
+ "get_handler",
9
+ ]
@@ -0,0 +1,189 @@
1
+ """Configuration and options dataclasses."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import re
6
+ import sys
7
+ from typing import Literal
8
+
9
+ from mkdocstrings import get_logger
10
+ from pydantic import BaseModel, Field
11
+
12
+ # YORE: EOL 3.10: Replace block with line 2.
13
+ if sys.version_info >= (3, 11):
14
+ pass
15
+ else:
16
+ pass
17
+
18
+
19
+ logger = get_logger(__name__)
20
+
21
+
22
+ SIGNATURE_VERSION = Literal["ref", "major", "semver", "string"]
23
+ PARAMETERS_ORDER = Literal["alphabetical", "source"]
24
+ PARAMETERS_SECTION_STYLE = Literal["table", "list"]
25
+
26
+
27
+ class GitHubOptions(BaseModel):
28
+ """Input options for the GitHub handler."""
29
+
30
+ # General options
31
+ show_description: bool = Field(
32
+ default=True,
33
+ description="Whether to show the description in the documentation.",
34
+ )
35
+
36
+ description: str = Field(
37
+ default="",
38
+ description="A custom string to override the autogenerated description of the object.",
39
+ )
40
+
41
+ show_source: bool = Field(
42
+ default=True,
43
+ description="Whether to show the source link in the documentation.",
44
+ )
45
+
46
+ # Heading options
47
+ show_heading: bool = Field(
48
+ default=True,
49
+ description="Whether to show the heading in the documentation.",
50
+ )
51
+
52
+ heading: str = Field(
53
+ default="",
54
+ description="A custom string to override the autogenerated heading of the object.",
55
+ )
56
+
57
+ heading_level: int = Field(
58
+ default=2,
59
+ description="The initial heading level to use.",
60
+ )
61
+
62
+ show_branding: bool = Field(
63
+ default=True,
64
+ description="Whether to show the action branding (logo and color) in the documentation.",
65
+ )
66
+
67
+ branding_icon: str = Field(
68
+ default="",
69
+ description="Custom icon from https://feathericons.com/ to use for the branding.",
70
+ )
71
+
72
+ branding_icon_color: str = Field(
73
+ default="",
74
+ description="Custom icon color for the feather icon.",
75
+ )
76
+
77
+ show_toc_entry: bool = Field(
78
+ default=True,
79
+ description="If the heading is not shown, at least add a ToC entry for it.",
80
+ )
81
+
82
+ toc_label: str = Field(
83
+ default="",
84
+ description="A custom string to override the autogenerated toc label of the root object.",
85
+ )
86
+
87
+ # Signature options
88
+ show_signature: bool = Field(
89
+ default=True,
90
+ description="Whether to show the signature in the documentation.",
91
+ )
92
+
93
+ signature_show_secrets: bool = Field(
94
+ default=False,
95
+ description="Whether to show secrets in the signature.",
96
+ )
97
+
98
+ signature_show_permissions: bool = Field(
99
+ default=True,
100
+ description="Whether to show permissions in the workflow signature.",
101
+ )
102
+
103
+ signature_version: SIGNATURE_VERSION = Field(
104
+ default="ref",
105
+ description="The versioning scheme to use for the signature.",
106
+ )
107
+
108
+ signature_version_string: str = Field(
109
+ default="latest",
110
+ description="The version string to use if `signature_version` is set to `string`.",
111
+ )
112
+
113
+ # Parameter options
114
+ show_inputs: bool = Field(
115
+ default=True,
116
+ description="Whether to show inputs in the documentation.",
117
+ )
118
+
119
+ show_inputs_only_required: bool = Field(
120
+ default=False,
121
+ description="Whether to show only required inputs in the documentation.",
122
+ )
123
+
124
+ show_outputs: bool = Field(
125
+ default=False,
126
+ description="Whether to show outputs in the documentation.",
127
+ )
128
+
129
+ show_secrets: bool = Field(
130
+ default=True,
131
+ description="Whether to show secrets in the documentation.",
132
+ )
133
+
134
+ show_secrets_only_required: bool = Field(
135
+ default=False,
136
+ description="Whether to show only required secrets in the documentation.",
137
+ )
138
+
139
+ parameters_order: PARAMETERS_ORDER = Field(
140
+ default="source",
141
+ description="""The parameters ordering to use.
142
+
143
+ - `alphabetical`: order by the parameters names,
144
+ - `source`: order parameters as they appear in the source file.
145
+ """,
146
+ )
147
+
148
+ parameters_section_style: PARAMETERS_SECTION_STYLE = Field(
149
+ default="table",
150
+ description="""The style used to render docstring sections.
151
+
152
+ - `table`: render parameters in a table,
153
+ - `list`: render parameters in a list.
154
+ """,
155
+ )
156
+
157
+ parameters_anchors: bool = Field(
158
+ default=True,
159
+ description="Whether to add anchors to parameters in the documentation.",
160
+ )
161
+
162
+
163
+ class GitHubConfig(BaseModel):
164
+ """Configuration options for the GitHub handler."""
165
+
166
+ repo: str = Field(
167
+ default="",
168
+ description="""The GitHub repository in the format *owner/repo*.
169
+
170
+ By default, the repository is inferred from the current git repository using the default origin remote.
171
+ If it cannot be inferred, it must be set manually.
172
+ """,
173
+ pattern=re.compile(r"^[\w.-]+/[\w.-]+$"),
174
+ )
175
+
176
+ feather_icons_source: str = Field(
177
+ default="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js",
178
+ description="""The source URL for Feather icons.
179
+
180
+ In certain enterprise environments, external CDN access may be restricted.
181
+ In such cases, you can host the `feather.min.js` file locally and set this option to the local path or URL.
182
+ See more information at https://github.com/feathericons/feather.
183
+ """,
184
+ )
185
+
186
+ options: GitHubOptions = Field(
187
+ default_factory=GitHubOptions,
188
+ description="Options for the GitHub handler.",
189
+ )
@@ -0,0 +1,214 @@
1
+ """The mkdocstrings handler for processing MATLAB code documentation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import re
7
+ import sys
8
+ from pathlib import Path
9
+ from typing import TYPE_CHECKING, Any, ClassVar, Mapping
10
+
11
+ import git
12
+ from mkdocs.exceptions import PluginError
13
+ from mkdocstrings import (
14
+ BaseHandler,
15
+ CollectionError,
16
+ HandlerOptions,
17
+ get_logger,
18
+ )
19
+
20
+ from github import Github
21
+ from mkdocstrings_handlers.github import rendering
22
+ from mkdocstrings_handlers.github.config import GitHubConfig, GitHubOptions
23
+ from mkdocstrings_handlers.github.objects import Action, Workflow
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import MutableMapping
27
+
28
+ from mkdocs.config.defaults import MkDocsConfig
29
+
30
+
31
+ SEMVER_PATTERN = re.compile(r"^v(\d+\.\d+\.\d+)$")
32
+ MAJOR_PATTERN = re.compile(r"^v(\d+)$")
33
+
34
+
35
+ _logger = get_logger(__name__)
36
+
37
+
38
+ class GitHubHandler(BaseHandler):
39
+ """The `GitHubHandler` class is a handler for processing GitHub code documentation."""
40
+
41
+ name: ClassVar[str] = "github"
42
+ """The GitHub handler class."""
43
+
44
+ domain: ClassVar[str] = "gh" # to match Sphinx's default domain
45
+ """The cross-documentation domain/language for this handler."""
46
+
47
+ enable_inventory: ClassVar[bool] = True
48
+ """Whether this handler is interested in enabling the creation of the `objects.inv` Sphinx inventory file."""
49
+
50
+ fallback_theme: ClassVar[str] = "material"
51
+ """The fallback theme."""
52
+
53
+ def __init__(
54
+ self,
55
+ config: GitHubConfig,
56
+ repo: git.Repo,
57
+ **kwargs: Any,
58
+ ) -> None:
59
+ """
60
+ Initialize the handler with the given configuration.
61
+
62
+ Args:
63
+ config: The handler configuration.
64
+ base_dir: The base directory of the project.
65
+ **kwargs: Arguments passed to the parent constructor.
66
+ """
67
+ super().__init__(**kwargs)
68
+ self.config = config
69
+ self.repo = repo
70
+ self.global_options = config.options.__dict__
71
+ self.workflows: dict[Path, Workflow] = {}
72
+ self.actions: dict[Path, Action] = {}
73
+ self.major: str = ""
74
+ self.semver: str = ""
75
+
76
+ # Only run GitHub releases code if not running under pytest
77
+ if (
78
+ rendering.ENV_MAJOR_TAG not in os.environ or rendering.ENV_SEMVER_TAG not in os.environ
79
+ ) and "pytest" not in sys.modules:
80
+ # Use PyGitHub to find last GitHub releases with tags matching vX.X.X and vX
81
+ gh = Github()
82
+ owner, repo_name = self.config.repo.split("/", 1)
83
+ gh_repo = gh.get_repo(f"{owner}/{repo_name}")
84
+ releases = list(gh_repo.get_releases())
85
+ for release in releases:
86
+ tag = release.tag_name
87
+ if not self.semver and SEMVER_PATTERN.match(tag):
88
+ self.semver = tag
89
+ if not self.major and MAJOR_PATTERN.match(tag):
90
+ self.major = tag
91
+ if self.semver and self.major:
92
+ break
93
+ else:
94
+ _logger.warning(
95
+ "Could not find suitable GitHub releases for repo '%s'. "
96
+ "Make sure there are releases with tags matching 'vX.X.X' and 'vX', "
97
+ "if you wish to use the 'semver' and 'major' signature versions.",
98
+ self.config.repo,
99
+ )
100
+
101
+ if self.config.repo == ".":
102
+ url = next(repo.remote("origin").urls)
103
+ match = re.search(r"github.com[:/](?P<owner>[^/]+)/(?P<repo>[^/.]+)", url)
104
+ if match:
105
+ self.config.repo = f"{match.group('owner')}/{match.group('repo')}"
106
+ else:
107
+ _logger.warning(
108
+ "Could not determine GitHub repository automatically from git remote URL '%s'. "
109
+ "Make sure the remote URL is a GitHub URL, "
110
+ "or set the 'repo' option in the configuration.",
111
+ url,
112
+ )
113
+
114
+ # Glob all workflow YAML files using pathlib
115
+ working_tree_dir = Path(repo.working_tree_dir)
116
+ workflows_dir = working_tree_dir / ".github" / "workflows"
117
+ for workflow_file in list(workflows_dir.glob("*.yml")) + list(workflows_dir.glob("*.yaml")):
118
+ id = str(workflow_file.relative_to(working_tree_dir))
119
+ workflow = Workflow.from_file(workflow_file, id)
120
+ if workflow is not None:
121
+ self.workflows[workflow_file] = workflow
122
+
123
+ # Glob all action.yaml and action.yml files, skipping .git folder entirely using pathlib
124
+ def find_action_files(base: Path):
125
+ for entry in base.iterdir():
126
+ if entry.is_dir():
127
+ if entry.name == ".git":
128
+ continue
129
+ yield from find_action_files(entry)
130
+ elif entry.is_file() and entry.name in ("action.yaml", "action.yml"):
131
+ yield entry
132
+
133
+ for action_file in find_action_files(working_tree_dir):
134
+ id = str(action_file.relative_to(working_tree_dir).parent)
135
+ action = Action.from_file(action_file, id)
136
+ if action is not None:
137
+ self.actions[action_file] = action
138
+
139
+ def get_options(self, local_options: Mapping[str, Any]) -> HandlerOptions:
140
+ """Get combined default, global and local options.
141
+
142
+ Arguments:
143
+ local_options: The local options.
144
+
145
+ Returns:
146
+ The combined options.
147
+ """
148
+
149
+ options = {**self.global_options, **local_options}
150
+ try:
151
+ return GitHubOptions(**options)
152
+ except Exception as error:
153
+ raise PluginError(f"Invalid options: {error}") from error
154
+
155
+ def update_env(self, config: Any) -> None:
156
+ self.env.trim_blocks = True
157
+ self.env.lstrip_blocks = True
158
+ self.env.keep_trailing_newline = False
159
+ self.env.filters["format_action_signature"] = rendering.format_action_signature
160
+ self.env.filters["order_parameters"] = rendering.order_parameters
161
+ self.env.filters["filter_parameters"] = rendering.filter_parameters
162
+ self.env.globals["semver_tag"] = self.semver
163
+ self.env.globals["major_tag"] = self.major
164
+ self.env.globals["git_repo"] = self.repo
165
+
166
+ def collect(self, identifier: str, options: GitHubOptions) -> Workflow | Action:
167
+ path = Path(self.repo.working_tree_dir) / identifier
168
+ if path in self.workflows:
169
+ return self.workflows[path]
170
+ elif (action_path := path / "action.yml") in self.actions:
171
+ return self.actions[action_path]
172
+ elif (action_path := path / "action.yaml") in self.actions:
173
+ return self.actions[action_path]
174
+ else:
175
+ raise CollectionError(f"Identifier '{identifier}' not found as a workflow or action.")
176
+
177
+ def render(self, data: Workflow | Action, options: GitHubOptions) -> str:
178
+ """Render a template using provided data and configuration options.
179
+
180
+ Arguments:
181
+ data: The collected data to render.
182
+ options: The handler's configuration options.
183
+
184
+ Returns:
185
+ The rendered template as HTML.
186
+ """
187
+ template = self.env.get_template(data.template)
188
+ html = template.render(options=options, data=data, config=self.config)
189
+ return html
190
+
191
+
192
+ def get_handler(
193
+ handler_config: MutableMapping[str, Any],
194
+ tool_config: MkDocsConfig,
195
+ **kwargs: Any,
196
+ ) -> GitHubHandler:
197
+ """
198
+ Create and return a GitHubHandler object with the specified configuration.
199
+
200
+ Parameters:
201
+ handler_config: The handler configuration.
202
+ tool_config: The tool (SSG) configuration.
203
+
204
+ Returns:
205
+ GitHubHandler: An instance of GitHubHandler configured with the provided parameters.
206
+ """
207
+ config_file = Path(tool_config.config_file_path)
208
+ repo = git.Repo(path=config_file.parent, search_parent_directories=True)
209
+
210
+ return GitHubHandler(
211
+ config=GitHubConfig(**handler_config),
212
+ repo=repo,
213
+ **kwargs,
214
+ )
@@ -0,0 +1,216 @@
1
+ from collections import OrderedDict
2
+ from dataclasses import dataclass, field
3
+ from enum import Enum
4
+ from os import PathLike
5
+ from typing import Any, Literal, Optional
6
+
7
+ import yaml
8
+
9
+
10
+ @dataclass
11
+ class Input:
12
+ name: str
13
+ description: str = ""
14
+ required: bool = False
15
+ type: Literal["boolean", "number", "string"] = "string"
16
+ default: bool | float | int | str | None = None
17
+ deprecationMessage: Optional[str] = None
18
+
19
+ @staticmethod
20
+ def from_data(
21
+ name: str,
22
+ description: str = "",
23
+ required: bool = False,
24
+ type: Literal["boolean", "number", "string"] = "string",
25
+ default: bool | float | int | str | None = None,
26
+ deprecationMessage: Optional[str] = None,
27
+ **kwargs,
28
+ ) -> "Input":
29
+ return Input(name, description, required, type, default, deprecationMessage)
30
+
31
+
32
+ @dataclass
33
+ class Output:
34
+ name: str
35
+ description: str = ""
36
+
37
+ @staticmethod
38
+ def from_data(name: str, description: str = "", **kwargs) -> "Output":
39
+ return Output(name, description)
40
+
41
+
42
+ @dataclass
43
+ class Secret:
44
+ name: str
45
+ description: str = ""
46
+ required: bool = False
47
+
48
+ @staticmethod
49
+ def from_data(name: str, description: str = "", required: bool = False, **kwargs) -> "Secret":
50
+ return Secret(name, description, required)
51
+
52
+
53
+ def _get_member(d: dict, key: str, error_message: str = "", default: Any = None) -> Any:
54
+ if key not in d:
55
+ if default is not None:
56
+ return default
57
+ raise KeyError(error_message)
58
+ return d[key]
59
+
60
+
61
+ class _OrderedLoader(yaml.Loader):
62
+ pass
63
+
64
+
65
+ # Remove boolean resolver for "on", "off", "yes", "no" (and case variants)
66
+ for ch in "yYnNoO":
67
+ if ch in _OrderedLoader.yaml_implicit_resolvers:
68
+ _OrderedLoader.yaml_implicit_resolvers[ch] = [
69
+ res
70
+ for res in _OrderedLoader.yaml_implicit_resolvers[ch]
71
+ if res[0] != "tag:yaml.org,2002:bool"
72
+ ]
73
+
74
+
75
+ def _construct_mapping(loader, node):
76
+ loader.flatten_mapping(node)
77
+ return OrderedDict(loader.construct_pairs(node))
78
+
79
+
80
+ _OrderedLoader.add_constructor(
81
+ yaml.SafeLoader.DEFAULT_MAPPING_TAG,
82
+ _construct_mapping,
83
+ )
84
+
85
+
86
+ def _read_file(file: PathLike) -> tuple[str, dict]:
87
+ with open(file, "r", encoding="utf-8") as f:
88
+ source = f.read()
89
+ f.seek(0)
90
+ data = yaml.load(f, Loader=_OrderedLoader)
91
+ return source, data
92
+
93
+
94
+ @dataclass
95
+ class Action:
96
+ # https://docs.github.com/en/actions/reference/workflows-and-actions/metadata-syntax
97
+ file: PathLike
98
+ source: str
99
+ id: str
100
+ name: str
101
+ description: str
102
+ using: str
103
+ author: str = ""
104
+ inputs: list[Input] = field(default_factory=list)
105
+ outputs: list[Output] = field(default_factory=list)
106
+ branding: dict = field(default_factory=dict)
107
+ template: Literal["action.html.jinja"] = "action.html.jinja"
108
+
109
+ @staticmethod
110
+ def from_file(file: PathLike, id: str) -> "Action":
111
+ source, data = _read_file(file)
112
+
113
+ action = Action(
114
+ file=file,
115
+ source=source,
116
+ id=id,
117
+ name=_get_member(data, "name", "Action must have a name"),
118
+ description=_get_member(data, "description", "Action must have a description"),
119
+ using=_get_member(data, "runs", "Action must have a 'runs' section").get("using", ""),
120
+ author=_get_member(data, "author", default=""),
121
+ branding=_get_member(data, "branding", default={}),
122
+ )
123
+ for key, value in data.get("inputs", {}).items():
124
+ action.inputs.append(Input.from_data(key, **value))
125
+ for key, value in data.get("outputs", {}).items():
126
+ action.outputs.append(Output.from_data(key, **value))
127
+ return action
128
+
129
+
130
+ class PermissionLevel(Enum):
131
+ none = ("none", 0)
132
+ read = ("read", 1)
133
+ write = ("write", 2)
134
+
135
+ @property
136
+ def label(self) -> str:
137
+ return self.value[0]
138
+
139
+ @property
140
+ def number(self) -> int:
141
+ return self.value[1]
142
+
143
+ @staticmethod
144
+ def from_label(label: str) -> "PermissionLevel":
145
+ for perm in PermissionLevel:
146
+ if perm.label == label:
147
+ return perm
148
+ raise ValueError(f"No Permission with label '{label}'")
149
+
150
+ def __le__(self, other):
151
+ if isinstance(other, PermissionLevel):
152
+ return self.number <= other.number
153
+ return NotImplemented
154
+
155
+ def __lt__(self, other):
156
+ if isinstance(other, PermissionLevel):
157
+ return self.number < other.number
158
+ return NotImplemented
159
+
160
+ def __ge__(self, other):
161
+ if isinstance(other, PermissionLevel):
162
+ return self.number >= other.number
163
+ return NotImplemented
164
+
165
+ def __gt__(self, other):
166
+ if isinstance(other, PermissionLevel):
167
+ return self.number > other.number
168
+ return NotImplemented
169
+
170
+
171
+ @dataclass
172
+ class Workflow:
173
+ # https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax
174
+ file: PathLike
175
+ source: str
176
+ id: str
177
+ name: str
178
+ description: str
179
+ permissions: dict[str, PermissionLevel] = field(default_factory=dict)
180
+ inputs: list[Input] = field(default_factory=list)
181
+ secrets: list[Secret] = field(default_factory=list)
182
+ outputs: list[Output] = field(default_factory=list)
183
+ template: Literal["workflow.html.jinja"] = "workflow.html.jinja"
184
+
185
+ @staticmethod
186
+ def from_file(file: PathLike, id: str) -> "Workflow | None":
187
+ source, data = _read_file(file)
188
+
189
+ if "on" not in data or "workflow_call" not in data["on"]:
190
+ return None
191
+ call = data["on"]["workflow_call"]
192
+
193
+ workflow = Workflow(
194
+ file=file,
195
+ source=source,
196
+ id=id,
197
+ name=_get_member(data, "name", "Workflow must have a name"),
198
+ description=_get_member(data, "description", default=""),
199
+ )
200
+ for key, value in call.get("inputs", {}).items():
201
+ workflow.inputs.append(Input.from_data(key, **value))
202
+ for key, value in call.get("outputs", {}).items():
203
+ workflow.outputs.append(Output.from_data(key, **value))
204
+ for key, value in call.get("secrets", {}).items():
205
+ workflow.secrets.append(Secret.from_data(key, **value))
206
+
207
+ for key, label in data.get("permissions", {}).items():
208
+ workflow.permissions[key] = PermissionLevel.from_label(label)
209
+ for job in data.get("jobs", {}).values():
210
+ for key, label in job.get("permissions", {}).items():
211
+ if key in workflow.permissions:
212
+ if permission := PermissionLevel.from_label(label) > workflow.permissions[key]:
213
+ workflow.permissions[key] = permission
214
+ else:
215
+ workflow.permissions[key] = PermissionLevel.from_label(label)
216
+ return workflow
File without changes
@@ -0,0 +1,69 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from typing import TYPE_CHECKING, Sequence
5
+
6
+ from jinja2 import pass_context
7
+
8
+ from mkdocstrings_handlers.github.config import PARAMETERS_ORDER, GitHubOptions
9
+ from mkdocstrings_handlers.github.objects import Input, Output, Secret
10
+
11
+ if TYPE_CHECKING:
12
+ from git import Repo
13
+ from jinja2.runtime import Context
14
+
15
+
16
+ ENV_MAJOR_TAG = "MKDOCSTRINGS_GITHUB_MAJOR_TAG"
17
+ ENV_SEMVER_TAG = "MKDOCSTRINGS_GITHUB_SEMVER_TAG"
18
+
19
+
20
+ @pass_context
21
+ def format_action_signature(context: Context, id: str, repo: str, options: GitHubOptions) -> str:
22
+ name = repo if id == "." else f"{repo}/{id}"
23
+ match options.signature_version:
24
+ case "ref":
25
+ try:
26
+ repo: Repo = context.environment.globals["git_repo"]
27
+ version = repo.head.ref.name
28
+ except Exception:
29
+ version = "unknown"
30
+ case "major":
31
+ version = os.environ.get(ENV_MAJOR_TAG, context.environment.globals["major_tag"])
32
+ case "semver":
33
+ version = os.environ.get(ENV_SEMVER_TAG, context.environment.globals["semver_tag"])
34
+ case "string":
35
+ version = options.signature_version_string
36
+
37
+ return f"{name}@{version}"
38
+
39
+
40
+ def order_parameters(
41
+ parameters: Sequence[Input | Output | Secret], parameters_order: PARAMETERS_ORDER
42
+ ):
43
+ if parameters_order == "alphabetical":
44
+ return sorted(parameters, key=lambda x: x.name)
45
+ else:
46
+ return parameters
47
+
48
+
49
+ def filter_parameters(
50
+ parameters: Sequence[Input | Output | Secret],
51
+ required: bool = False,
52
+ optional: bool = False,
53
+ description: bool = False,
54
+ default: bool = False,
55
+ ):
56
+ filtered = []
57
+ for parameter in parameters:
58
+ filter = False
59
+ if required and not getattr(parameter, "required", False):
60
+ filter = True
61
+ if optional and getattr(parameter, "required", False):
62
+ filter = True
63
+ if description and not getattr(parameter, "description", ""):
64
+ filter = True
65
+ if default and not getattr(parameter, "default", None):
66
+ filter = True
67
+ if not filter:
68
+ filtered.append(parameter)
69
+ return filtered
@@ -0,0 +1,73 @@
1
+ {#- Template for GitHub Action.
2
+
3
+ This template renders a GitHub Action.
4
+
5
+ Context:
6
+ data (mkdocstrings_handlers.github.objects.Action): The action to render.
7
+ config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
8
+ options (dict): The local options
9
+ -#}
10
+
11
+ {% block logs scoped %}
12
+ {#- Logging block.
13
+
14
+ This block can be used to log debug messages, deprecation messages, warnings, etc.
15
+ -#}
16
+ {{ log.debug("Rendering " + data.id) }}
17
+ {% endblock logs %}
18
+
19
+ {% if options.show_branding %}
20
+ <script src="{{ config.feather_icons_source }}"></script>
21
+ {% endif %}
22
+ <div class="doc doc-object doc-action">
23
+
24
+ {% include "heading.html.jinja" with context %}
25
+
26
+ {% set signature = data.id | format_action_signature(config.repo, options) %}
27
+
28
+ {% block signature scoped %}
29
+ {% if options.show_signature %}
30
+ {% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
31
+ {% filter highlight(language="yaml", inline=False, linenums=False) %}
32
+ - uses: {{ signature }}
33
+ with:
34
+ {%+ for input in inputs %}{{ input.name }}: ''{% endfor +%}
35
+ {% endfilter %}
36
+ {% endwith %}
37
+ {% endif %}
38
+ {% endblock signature %}
39
+
40
+ {% block description scoped %}
41
+ {% if options.show_description %}
42
+ {{ options.description if options.description else data.description | convert_markdown(options.heading_level, data.id) }}
43
+ {% endif %}
44
+ {% endblock description %}
45
+
46
+ {% block inputs scoped %}
47
+ {% if options.show_inputs %}
48
+ {% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=options.show_inputs_only_required) %}
49
+ {% include "inputs.html.jinja" with context %}
50
+ {% endwith %}
51
+ {% endif %}
52
+ {% endblock inputs %}
53
+
54
+ {% block outputs scoped %}
55
+ {% if options.show_outputs %}
56
+ {% with outputs = data.outputs | order_parameters(options.parameters_order) %}
57
+ {% include "outputs.html.jinja" with context %}
58
+ {% endwith %}
59
+ {% endif %}
60
+ {% endblock outputs %}
61
+
62
+ {% block source scoped %}
63
+ {% if options.show_source %}
64
+ <details class="quote">
65
+ <summary>Source of <code>{{ signature }}</code></summary>
66
+ {{ data.source|highlight(language="yaml", linenums=True) }}
67
+ </details>
68
+ {% endif %}
69
+ {% endblock %}
70
+ </div>
71
+ {% if options.show_branding %}
72
+ <script>feather.replace()</script>
73
+ {% endif %}
@@ -0,0 +1,39 @@
1
+ {#- Template for heading
2
+
3
+ Context:
4
+ data (mkdocstrings_handlers.github.objects.Action | Workfow): The object to render.
5
+ config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
6
+ options (dict): The local options
7
+ -#}
8
+
9
+ {% if options.show_heading %}
10
+ {% filter heading(
11
+ options.heading_level,
12
+ role="gh",
13
+ id=data.id,
14
+ class="doc doc-heading",
15
+ toc_label=options.toc_label if options.toc_label else data.name,
16
+ )%}
17
+ {% block heading scoped %}
18
+ {% if options.show_branding and (options.branding_icon or data.branding) and (options.branding_icon_color or data.branding.icon) %}
19
+ <span style="display: inline-flex; align-items: center;">
20
+ <span class="gh-action-badge-img gh-action-badge--{{ options.branding_icon_color or data.branding.color }}" style="margin-right: 0.5em;">
21
+ <i data-feather="{{ options.branding_icon or data.branding.icon }}"></i>
22
+ </span>
23
+ {{ options.heading if options.heading else data.name }}
24
+ </span>
25
+ {% else %}
26
+ {{ options.heading if options.heading else data.name }}
27
+ {% endif %}
28
+ {% endblock heading %}
29
+ {% endfilter %}
30
+ {% elif options.show_toc_entry %}
31
+ {% filter heading(
32
+ options.heading_level,
33
+ role="gh",
34
+ id=data.id,
35
+ class="doc doc-heading",
36
+ toc_label=options.toc_label if options.toc_label else data.name,
37
+ )%}
38
+ {% endfilter %}
39
+ {% endif %}
@@ -0,0 +1,94 @@
1
+ {#- Template for inputs.
2
+
3
+ Context:
4
+ inputs (list of mkdocstrings_handlers.github.objects.Input): The inputs to render.
5
+ data (mkdocstrings_handlers.github.objects.Action | Workflow): The object to render.
6
+ config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
7
+ options (dict): The local options
8
+ -#}
9
+
10
+ {% block logs scoped %}
11
+ {{ log.debug("Rendering inputs of " + data.id) }}
12
+ {% endblock logs %}
13
+
14
+ {% set header_id -%}
15
+ inputs-{{ data.id | replace('/', '-') | replace('.', '') | lower }}
16
+ {%- endset %}
17
+
18
+ {% if options.parameters_section_style == "table" %}
19
+ {% block table_style scoped %}
20
+ <p>
21
+ <span class="doc-section-title">Inputs:</span>
22
+ <a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
23
+ </p>
24
+ <table>
25
+ <thead>
26
+ <tr>
27
+ <th>Name</th>
28
+ <th>Description</th>
29
+ <th>Default</th>
30
+ </tr>
31
+ </thead>
32
+ <tbody>
33
+ {% for input in inputs %}
34
+ {% if options.parameters_anchors %}
35
+ {% set anchor_id -%}
36
+ input-{{ data.id | replace('/', '-') | replace('.', '') | lower }}-{{ input.name | replace(' ', '-') | lower }}
37
+ {%- endset %}
38
+ {% else %}
39
+ {% set anchor_id = None %}
40
+ {% endif %}
41
+ <tr class="doc-section-item">
42
+ <td id="{{ anchor_id }}">
43
+ {% if input.required %}
44
+ <strong><code>{{ input.name }}</code></strong>
45
+ {% else %}
46
+ <code>{{ input.name }}</code>
47
+ {% endif %}
48
+ {% if options.parameters_anchors %}
49
+ <a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ input.name }}">¤</a>
50
+ {% endif %}
51
+ </td>
52
+ <td>
53
+ {{ input.description | convert_markdown(options.heading_level, data.id) }}
54
+ </td>
55
+ <td>
56
+ {% if input.default %}
57
+ <code>{{ input.default }}</code>
58
+ {% endif %}
59
+ </td>
60
+ </tr>
61
+ {% endfor %}
62
+ </tbody>
63
+ </table>
64
+ {% endblock table_style %}
65
+ {% elif options.parameters_section_style == "list" %}
66
+ {% block list_style scoped %}
67
+ <p>
68
+ <span class="doc-section-title">Inputs:</span>
69
+ <a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
70
+ </p>
71
+ <ul>
72
+ {% for input in inputs %}
73
+ {% set anchor_id -%}
74
+ input-{{ data.id | replace('/', '-') | replace('.', '') | lower }}-{{ input.name | replace(' ', '-') | lower }}
75
+ {%- endset %}
76
+ <li class="doc-section-item field-body">
77
+ <b><code>{{ input.name }}</code></b>
78
+ {%- if input.required %} - <em>required</em>{% endif %}
79
+ {% if options.parameters_anchors %}
80
+ <a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ input.name }}">¤</a>
81
+ {% endif %}
82
+ <div class="doc-md-description">
83
+ {{ input.description|convert_markdown(options.heading_level, data.id) }}
84
+ </div>
85
+ {% if input.default is not none %}
86
+ <div class="doc-md-description">
87
+ Default: <code>{{ input.default }}</code>
88
+ </div>
89
+ {% endif %}
90
+ </li>
91
+ {% endfor %}
92
+ </ul>
93
+ {% endblock list_style %}
94
+ {% endif %}
@@ -0,0 +1,78 @@
1
+ {#- Template for outputs.
2
+
3
+ Context:
4
+ outputs (list of mkdocstrings_handlers.github.objects.Output): The outputs to render.
5
+ data (mkdocstrings_handlers.github.objects.Action | Workflow): The object to render.
6
+ config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
7
+ options (dict): The local options
8
+ -#}
9
+
10
+ {% block logs scoped %}
11
+ {{ log.debug("Rendering outputs of " + data.id) }}
12
+ {% endblock logs %}
13
+
14
+ {% set header_id -%}
15
+ outputs-{{ data.id | replace('/', '-') | replace('.', '') | lower }}
16
+ {%- endset %}
17
+
18
+ {% if options.parameters_section_style == "table" %}
19
+ {% block table_style scoped %}
20
+ <p>
21
+ <span class="doc-section-title">Outputs:</span>
22
+ <a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
23
+ </p>
24
+ <table>
25
+ <thead>
26
+ <tr>
27
+ <th>Name</th>
28
+ <th>Description</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ {% for output in outputs %}
33
+ {% if options.parameters_anchors %}
34
+ {% set anchor_id -%}
35
+ output-{{ data.id | replace('/', '-') | replace('.', '') | lower }}-{{ output.name | replace(' ', '-') | lower }}
36
+ {%- endset %}
37
+ {% else %}
38
+ {% set anchor_id = None %}
39
+ {% endif %}
40
+ <tr class="doc-section-item">
41
+ <td id="{{ anchor_id }}">
42
+ <code>{{ output.name }}</code>
43
+ {% if options.parameters_anchors %}
44
+ <a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ output.name }}">¤</a>
45
+ {% endif %}
46
+ </td>
47
+ <td>
48
+ {{ output.description | convert_markdown(options.heading_level, data.id) }}
49
+ </td>
50
+ {% endfor %}
51
+ </tbody>
52
+ </table>
53
+ {% endblock table_style %}
54
+ {% elif options.parameters_section_style == "list" %}
55
+ {% block list_style scoped %}
56
+ <p>
57
+ <span class="doc-section-title">Outputs:</span>
58
+ <a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
59
+ </p>
60
+ <ul>
61
+ {% for output in outputs %}
62
+ {% set anchor_id -%}
63
+ output-{{ data.id | replace('/', '-') | replace('.', '') | lower }}-{{ output.name | replace(' ', '-') | lower }}
64
+ {%- endset %}
65
+ <li class="doc-section-item field-body">
66
+ <b><code>{{ output.name }}</code></b>
67
+ {% if options.parameters_anchors %}
68
+ <a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ output.name }}">¤</a>
69
+ {% endif %}
70
+ <div class="doc-md-description">
71
+ {{ output.description|convert_markdown(options.heading_level, data.id) }}
72
+ </div>
73
+ </li>
74
+ {% endfor %}
75
+ </ul>
76
+ {% endblock list_style %}
77
+ {% endif %}
78
+
@@ -0,0 +1,82 @@
1
+ {#- Template for secrets.
2
+
3
+ Context:
4
+ secrets (list of mkdocstrings_handlers.github.objects.Secret): The secrets to render.
5
+ data (mkdocstrings_handlers.github.objects.Workflow): The object to render.
6
+ config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
7
+ options (dict): The local options
8
+ -#}
9
+
10
+ {% block logs scoped %}
11
+ {{ log.debug("Rendering secrets of " + data.id) }}
12
+ {% endblock logs %}
13
+
14
+ {% set header_id -%}
15
+ secrets-{{ data.id | replace('/', '-') | replace('.', '') | lower }}
16
+ {%- endset %}
17
+
18
+ {% if options.parameters_section_style == "table" %}
19
+ {% block table_style scoped %}
20
+ <p>
21
+ <span class="doc-section-title">Secrets:</span>
22
+ <a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
23
+ </p>
24
+ <table>
25
+ <thead>
26
+ <tr>
27
+ <th>Name</th>
28
+ <th>Description</th>
29
+ </tr>
30
+ </thead>
31
+ <tbody>
32
+ {% for secret in secrets %}
33
+ {% if options.parameters_anchors %}
34
+ {% set anchor_id -%}
35
+ secret-{{ data.id | replace('/', '-') | replace('.', '') | lower }}-{{ secret.name | replace(' ', '-') | lower }}
36
+ {%- endset %}
37
+ {% else %}
38
+ {% set anchor_id = None %}
39
+ {% endif %}
40
+ <tr class="doc-section-item">
41
+ <td id="{{ anchor_id }}">
42
+ {% if secret.required %}
43
+ <strong><code>{{ secret.name }}</code></strong>
44
+ {% else %}
45
+ <code>{{ secret.name }}</code>
46
+ {% endif %}
47
+ {% if options.parameters_anchors %}
48
+ <a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ secret.name }}">¤</a>
49
+ {% endif %}
50
+ </td>
51
+ <td>
52
+ {{ secret.description | convert_markdown(options.heading_level, data.id) }}
53
+ </td>
54
+ {% endfor %}
55
+ </tbody>
56
+ </table>
57
+ {% endblock table_style %}
58
+ {% elif options.parameters_section_style == "list" %}
59
+ {% block list_style scoped %}
60
+ <p>
61
+ <span class="doc-section-title">Secrets:</span>
62
+ <a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
63
+ </p>
64
+ <ul>
65
+ {% for secret in secrets %}
66
+ {% set anchor_id -%}
67
+ secret-{{ data.id | replace('/', '-') | replace('.', '') | lower }}-{{ secret.name | replace(' ', '-') | lower }}
68
+ {%- endset %}
69
+ <li class="doc-section-item field-body">
70
+ <b><code>{{ secret.name }}</code></b>
71
+ {%- if secret.required %} - <em>required</em>{% endif %}
72
+ {% if options.parameters_anchors %}
73
+ <a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ secret.name }}">¤</a>
74
+ {% endif %}
75
+ <div class="doc-md-description">
76
+ {{ secret.description|convert_markdown(options.heading_level, data.id) }}
77
+ </div>
78
+ </li>
79
+ {% endfor %}
80
+ </ul>
81
+ {% endblock list_style %}
82
+ {% endif %}
@@ -0,0 +1,59 @@
1
+ /* .gh-action-badge {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ width: 140px;
6
+ margin: 15px 5px;
7
+ cursor: copy;
8
+ } */
9
+
10
+ .gh-action-badge-img {
11
+ width: 44px;
12
+ height: 44px;
13
+ border-radius: 50%;
14
+ box-shadow: 0 1px 5px rgba(27,31,35,.15);
15
+ display: flex;
16
+ justify-content: center;
17
+ align-items: center;
18
+ margin: 3px;
19
+ }
20
+
21
+ .gh-action-badge--white {
22
+ background-color: #ffffff;
23
+ color: #23292e;
24
+ }
25
+
26
+ .gh-action-badge--yellow {
27
+ background-color: #ffd33d;
28
+ color: #23292e;
29
+ }
30
+
31
+ .gh-action-badge--blue {
32
+ background-color: #0366d6;
33
+ color: #ffffff;
34
+ }
35
+
36
+ .gh-action-badge--green {
37
+ background-color: #28a745;
38
+ color: #ffffff;
39
+ }
40
+
41
+ .gh-action-badge--orange {
42
+ background-color: #f66a0a;
43
+ color: #ffffff;
44
+ }
45
+
46
+ .gh-action-badge--red {
47
+ background-color: #d73a49;
48
+ color: #ffffff;
49
+ }
50
+
51
+ .gh-action-badge--purple {
52
+ background-color: #6f42c1;
53
+ color: #ffffff;
54
+ }
55
+
56
+ .gh-action-badge--gray-dark {
57
+ background-color: #24292e;
58
+ color: #ffffff;
59
+ }
@@ -0,0 +1,90 @@
1
+ {#- Template for GitHub Action reusable workflow.
2
+
3
+ Context:
4
+ data (mkdocstrings_handlers.github.objects.Workflow): The workflow to render.
5
+ config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
6
+ options (dict): The local options
7
+ -#}
8
+
9
+ {% block logs scoped %}
10
+ {#- Logging block.
11
+
12
+ This block can be used to log debug messages, deprecation messages, warnings, etc.
13
+ -#}
14
+ {{ log.debug("Rendering " + data.id) }}
15
+ {% endblock logs %}
16
+
17
+ {% if options.show_branding %}
18
+ <script src="{{ config.feather_icons_source }}"></script>
19
+ {% endif %}
20
+ <div class="doc doc-object doc-workflow">
21
+ {% include "heading.html.jinja" with context %}
22
+
23
+ {% set signature = data.id | format_action_signature(config.repo, options) %}
24
+
25
+ {% block signature scoped %}
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 %}
46
+ {% endif %}
47
+ {% endblock signature %}
48
+
49
+ {% block description scoped %}
50
+ {% if options.show_description %}
51
+ {{ options.description if options.description else data.description | convert_markdown(options.heading_level, data.id) }}
52
+ {% endif %}
53
+ {% endblock description %}
54
+
55
+ {% block inputs scoped %}
56
+ {% if options.show_inputs %}
57
+ {% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=options.show_inputs_only_required) %}
58
+ {% include "inputs.html.jinja" with context %}
59
+ {% endwith %}
60
+ {% endif %}
61
+ {% endblock inputs %}
62
+
63
+ {% block secrets scoped %}
64
+ {% if options.show_secrets %}
65
+ {% with secrets = data.secrets | order_parameters(options.parameters_order) | filter_parameters(required=options.show_secrets_only_required) %}
66
+ {% include "secrets.html.jinja" with context %}
67
+ {% endwith %}
68
+ {% endif %}
69
+ {% endblock secrets %}
70
+
71
+ {% block outputs scoped %}
72
+ {% if options.show_outputs %}
73
+ {% with outputs = data.outputs | order_parameters(options.parameters_order) %}
74
+ {% include "outputs.html.jinja" with context %}
75
+ {% endwith %}
76
+ {% endif %}
77
+ {% endblock outputs %}
78
+
79
+ {% block source scoped %}
80
+ {% if options.show_source %}
81
+ <details class="quote">
82
+ <summary>Source of <code>{{ signature }}</code></summary>
83
+ {{ data.source|highlight(language="yaml", linenums=True) }}
84
+ </details>
85
+ {% endif %}
86
+ {% endblock %}
87
+ </div>
88
+ {% if options.show_branding %}
89
+ <script>feather.replace()</script>
90
+ {% endif %}