mkdocstrings-github 0.4.2__py3-none-any.whl → 0.6.1__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.
- {mkdocstrings_github-0.4.2.dist-info → mkdocstrings_github-0.6.1.dist-info}/METADATA +28 -7
- mkdocstrings_github-0.6.1.dist-info/RECORD +18 -0
- mkdocstrings_handlers/github/config.py +35 -11
- mkdocstrings_handlers/github/handler.py +50 -66
- mkdocstrings_handlers/github/objects.py +92 -82
- mkdocstrings_handlers/github/rendering.py +22 -2
- mkdocstrings_handlers/github/templates/material/_macros.html.jinja +38 -0
- mkdocstrings_handlers/github/templates/material/action.html.jinja +13 -4
- mkdocstrings_handlers/github/templates/material/inputs.html.jinja +13 -20
- mkdocstrings_handlers/github/templates/material/outputs.html.jinja +14 -14
- mkdocstrings_handlers/github/templates/material/secrets.html.jinja +14 -15
- mkdocstrings_handlers/github/templates/material/style.css +19 -0
- mkdocstrings_handlers/github/templates/material/workflow.html.jinja +29 -7
- mkdocstrings_github-0.4.2.dist-info/RECORD +0 -17
- {mkdocstrings_github-0.4.2.dist-info → mkdocstrings_github-0.6.1.dist-info}/WHEEL +0 -0
- {mkdocstrings_github-0.4.2.dist-info → mkdocstrings_github-0.6.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mkdocstrings-github
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.6.1
|
|
4
4
|
Summary: A GitHub Action handler for mkdocstrings
|
|
5
5
|
Author-email: Mark Hu <watermarkhu@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -21,9 +21,9 @@ Classifier: Topic :: Software Development :: Documentation
|
|
|
21
21
|
Classifier: Topic :: Utilities
|
|
22
22
|
Classifier: Typing :: Typed
|
|
23
23
|
Requires-Python: <3.15,>=3.10
|
|
24
|
-
Requires-Dist: gitpython
|
|
25
|
-
Requires-Dist: mkdocstrings
|
|
26
|
-
Requires-Dist:
|
|
24
|
+
Requires-Dist: gitpython<4,>=3.1.45
|
|
25
|
+
Requires-Dist: mkdocstrings<1,>=0.29
|
|
26
|
+
Requires-Dist: ruamel-yaml<1,>=0.18.16
|
|
27
27
|
Requires-Dist: typing-extensions>=4.0; python_version < '3.11'
|
|
28
28
|
Description-Content-Type: text/markdown
|
|
29
29
|
|
|
@@ -33,14 +33,26 @@ Description-Content-Type: text/markdown
|
|
|
33
33
|
|
|
34
34
|
<p align="center">A GitHub Actions handler for <a href="https://github.com/mkdocstrings/mkdocstrings"><i>mkdocstrings</i></a>.</p>
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
<!-- --8<-- [end:header] -->
|
|
37
|
+
|
|
38
|
+
<p align="center"><img width=300px src="docs/img/logo.png"></p>
|
|
37
39
|
|
|
38
40
|
[](https://github.com/watermarkhu/mkdocstrings-github/actions/workflows/qualify.yaml)
|
|
39
41
|
[](https://watermarkhu.nl/mkdocstrings-github)
|
|
40
42
|
[](https://pypi.org/project/mkdocstrings-github/)
|
|
41
43
|
[](https://codecov.io/github/watermarkhu/mkdocstrings-github)
|
|
42
44
|
|
|
43
|
-
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
For example, the following page is generated from [actions/checkout](https://github.com/actions/checkout):
|
|
48
|
+
|
|
49
|
+
<picture>
|
|
50
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/img/example_dark.png">
|
|
51
|
+
<source media="(prefers-color-scheme: light)" srcset="docs/img/example_light.png">
|
|
52
|
+
<img alt="Fallback image description" src="docs/img/example_light.png">
|
|
53
|
+
</picture>
|
|
54
|
+
|
|
55
|
+
|
|
44
56
|
<!-- --8<-- [start:install] -->
|
|
45
57
|
You can install the GitHub handler by specifying it as a dependency:
|
|
46
58
|
|
|
@@ -49,9 +61,17 @@ You can install the GitHub handler by specifying it as a dependency:
|
|
|
49
61
|
# adapt to your dependencies manager
|
|
50
62
|
[project]
|
|
51
63
|
dependencies = [
|
|
52
|
-
"mkdocstrings-github
|
|
64
|
+
"mkdocstrings-github",
|
|
53
65
|
]
|
|
54
66
|
```
|
|
67
|
+
|
|
68
|
+
after which the generated documentation can be inserted in the markdown page with:
|
|
69
|
+
|
|
70
|
+
```md
|
|
71
|
+
::: <path-to-action-or-workflow>
|
|
72
|
+
handler: github
|
|
73
|
+
```
|
|
74
|
+
|
|
55
75
|
<!-- --8<-- [end:install] -->
|
|
56
76
|
|
|
57
77
|
<!-- --8<-- [start:footer] -->
|
|
@@ -63,5 +83,6 @@ dependencies = [
|
|
|
63
83
|
- 🧩 **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.
|
|
64
84
|
- 🔒 **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.
|
|
65
85
|
- 🔗 **Parameter cross-linking**: Link to other parameters of the action or workflow via a simple Markdown syntax.
|
|
86
|
+
- 🧑🤝🧑 **Parameter grouping**: Organize related inputs, outputs, and secrets into visual groups using inline YAML comments for clearer documentation structure.
|
|
66
87
|
|
|
67
88
|
<!-- --8<-- [end:footer] -->
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
mkdocstrings_handlers/github/__init__.py,sha256=0WdFUIq4Xu2ZFtlZNIYCQSoqcx3Ot9Wv41_X_dwbFww,248
|
|
2
|
+
mkdocstrings_handlers/github/config.py,sha256=r7efiI-vKbVEeD6utrc55h4RP6VIlabqDebhiIIx_ZA,7120
|
|
3
|
+
mkdocstrings_handlers/github/handler.py,sha256=SQcd08VA3g4f3Fof2mam85ahPLiK99TteAJJpUg-iB4,8489
|
|
4
|
+
mkdocstrings_handlers/github/objects.py,sha256=v1GchB9fzqasnXbVEOXoDzOR2iVTwcfPQ9mFT4sdjgs,7625
|
|
5
|
+
mkdocstrings_handlers/github/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
mkdocstrings_handlers/github/rendering.py,sha256=pFk621Fqp_R6ZS2dJ0zwEEez0Urqpekial6kqKYDag8,3371
|
|
7
|
+
mkdocstrings_handlers/github/templates/material/_macros.html.jinja,sha256=1TNUgoOIxm-a1S7eiESrW1fYuzXOjrwFqXQSyA4tkkU,1576
|
|
8
|
+
mkdocstrings_handlers/github/templates/material/action.html.jinja,sha256=C7S8I9bjnrEUahyDB7CkFxtakFrr53KE3t3uyczBPzc,2864
|
|
9
|
+
mkdocstrings_handlers/github/templates/material/heading.html.jinja,sha256=wnvZpNED8Dhb935qnddeDExXN-MIUz8frRRfgq-A9VA,1396
|
|
10
|
+
mkdocstrings_handlers/github/templates/material/inputs.html.jinja,sha256=UE8RmfMlF6np7CP-920CwgkbXIcKNgl9KgK1BJ588GM,3271
|
|
11
|
+
mkdocstrings_handlers/github/templates/material/outputs.html.jinja,sha256=Z9QD1KSALLDS9VEyugWG1BHpLCHTKYEx4TEQkKIoC3M,2693
|
|
12
|
+
mkdocstrings_handlers/github/templates/material/secrets.html.jinja,sha256=jQ_HaG2ivbZTH74pyV4BAFGQu5Vn03kA_vaEbTSABds,2839
|
|
13
|
+
mkdocstrings_handlers/github/templates/material/style.css,sha256=Nfmds-xHtPJ_IzOv5svA7ih5talHDTiQryN_n0DGdZs,1553
|
|
14
|
+
mkdocstrings_handlers/github/templates/material/workflow.html.jinja,sha256=5dLdHRSQyulyFAVCVZAR_pkw-WXxCtM20cj6RS7IH1Q,4206
|
|
15
|
+
mkdocstrings_github-0.6.1.dist-info/METADATA,sha256=fdZ69Xer6TQ4ZpkPnzyv1P2H2eE5KLi27DltQAJWNqA,4055
|
|
16
|
+
mkdocstrings_github-0.6.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
17
|
+
mkdocstrings_github-0.6.1.dist-info/licenses/LICENSE,sha256=5enZtJ4zSp0Ps3jTqFQ4kadcx62BhgTaDNPrXWb3g3E,1069
|
|
18
|
+
mkdocstrings_github-0.6.1.dist-info/RECORD,,
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
import re
|
|
6
5
|
import sys
|
|
7
6
|
from typing import Literal
|
|
8
7
|
|
|
@@ -92,6 +91,15 @@ class GitHubOptions(BaseModel):
|
|
|
92
91
|
description="Whether to show the signature in the documentation.",
|
|
93
92
|
)
|
|
94
93
|
|
|
94
|
+
signature_repository: str = Field(
|
|
95
|
+
default="",
|
|
96
|
+
description="""The GitHub repository in the format *owner/repo*.
|
|
97
|
+
|
|
98
|
+
By default, the repository is inferred from the current git repository using the default origin remote.
|
|
99
|
+
If it cannot be inferred, it must be set manually.
|
|
100
|
+
""",
|
|
101
|
+
)
|
|
102
|
+
|
|
95
103
|
signature_show_secrets: bool = Field(
|
|
96
104
|
default=False,
|
|
97
105
|
description="Whether to show secrets in the signature.",
|
|
@@ -162,6 +170,32 @@ class GitHubOptions(BaseModel):
|
|
|
162
170
|
""",
|
|
163
171
|
)
|
|
164
172
|
|
|
173
|
+
parameters_groups: bool = Field(
|
|
174
|
+
default=True,
|
|
175
|
+
description="""Whether to group parameters by their group in the documentation.
|
|
176
|
+
|
|
177
|
+
This is done by adding a comment `# group: <group name>` directly after the parameter definition in the action/workflow file.
|
|
178
|
+
This can be done for inputs, outputs and secrets. E.g.:
|
|
179
|
+
|
|
180
|
+
```yaml
|
|
181
|
+
inputs:
|
|
182
|
+
my_input: # group: Example Group
|
|
183
|
+
description: "An example input"
|
|
184
|
+
required: true
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
This has no effect if there are no groups defined for any parameter.
|
|
188
|
+
""",
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
parameters_group_title_row: bool = Field(
|
|
192
|
+
default=True,
|
|
193
|
+
description="""Whether to add a title row for each parameter group in the documentation.
|
|
194
|
+
This only has an effect if [`parameters_groups`][mkdocstrings_handlers.github.config.GitHubOptions.parameters_groups] is set to `true`,
|
|
195
|
+
and if the [`parameters_section_style`][mkdocstrings_handlers.github.config.GitHubOptions.parameters_section_style] is set to `table`.
|
|
196
|
+
""",
|
|
197
|
+
)
|
|
198
|
+
|
|
165
199
|
parameters_anchors: bool = Field(
|
|
166
200
|
default=True,
|
|
167
201
|
description="Whether to add anchors to parameters in the documentation.",
|
|
@@ -171,16 +205,6 @@ class GitHubOptions(BaseModel):
|
|
|
171
205
|
class GitHubConfig(BaseModel):
|
|
172
206
|
"""Configuration options for the GitHub handler."""
|
|
173
207
|
|
|
174
|
-
repo: str = Field(
|
|
175
|
-
default="",
|
|
176
|
-
description="""The GitHub repository in the format *owner/repo*.
|
|
177
|
-
|
|
178
|
-
By default, the repository is inferred from the current git repository using the default origin remote.
|
|
179
|
-
If it cannot be inferred, it must be set manually.
|
|
180
|
-
""",
|
|
181
|
-
pattern=re.compile(r"^[\w.-]+/[\w.-]+$"),
|
|
182
|
-
)
|
|
183
|
-
|
|
184
208
|
feather_icons_source: str = Field(
|
|
185
209
|
default="https://cdn.jsdelivr.net/npm/feather-icons/dist/feather.min.js",
|
|
186
210
|
description="""The source URL for Feather icons.
|
|
@@ -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
|
|
|
@@ -68,69 +67,14 @@ class GitHubHandler(BaseHandler):
|
|
|
68
67
|
self.config = config
|
|
69
68
|
self.repo = repo
|
|
70
69
|
self.global_options = config.options.__dict__
|
|
71
|
-
self.workflows: dict[Path, Workflow] = {}
|
|
72
|
-
self.actions: dict[Path, Action] = {}
|
|
73
70
|
self.major: str = ""
|
|
74
71
|
self.semver: str = ""
|
|
75
72
|
|
|
76
|
-
|
|
77
|
-
if not self.config.repo:
|
|
78
|
-
# Try each remote to find a valid GitHub owner/repo
|
|
79
|
-
owner = None
|
|
80
|
-
repo_name = None
|
|
81
|
-
for remote in self.repo.remotes:
|
|
82
|
-
for url in remote.urls:
|
|
83
|
-
match = re.search(
|
|
84
|
-
r"(?P<host>[\w\.-]+)[/:](?P<owner>[^/]+)/(?P<repo>[^/.]+?)(?:\.git)?$",
|
|
85
|
-
url,
|
|
86
|
-
)
|
|
87
|
-
if match:
|
|
88
|
-
owner = match.group("owner")
|
|
89
|
-
repo_name = match.group("repo")
|
|
90
|
-
break
|
|
91
|
-
if owner and repo_name:
|
|
92
|
-
break
|
|
93
|
-
if not (owner and repo_name):
|
|
94
|
-
raise PluginError(
|
|
95
|
-
f"Could not determine GitHub repository owner/name from config.repo='{self.config.repo}' or any git remote URL."
|
|
96
|
-
)
|
|
97
|
-
self.config.repo = f"{owner}/{repo_name}"
|
|
98
|
-
|
|
99
|
-
# Only run GitHub releases code if required and not in testing
|
|
100
|
-
not_testing = "pytest" not in sys.modules
|
|
101
|
-
no_custom_tags = (
|
|
102
|
-
rendering.ENV_MAJOR_TAG not in os.environ or rendering.ENV_SEMVER_TAG not in os.environ
|
|
103
|
-
)
|
|
104
|
-
if not_testing and no_custom_tags:
|
|
73
|
+
if rendering.ENV_MAJOR_TAG not in os.environ or rendering.ENV_SEMVER_TAG not in os.environ:
|
|
105
74
|
self.get_releases()
|
|
106
75
|
|
|
107
|
-
# Glob all workflow YAML files using pathlib
|
|
108
|
-
working_tree_dir = Path(repo.working_tree_dir)
|
|
109
|
-
workflows_dir = working_tree_dir / ".github" / "workflows"
|
|
110
|
-
for workflow_file in list(workflows_dir.glob("*.yml")) + list(workflows_dir.glob("*.yaml")):
|
|
111
|
-
id = str(workflow_file.relative_to(working_tree_dir))
|
|
112
|
-
workflow = Workflow.from_file(workflow_file, id)
|
|
113
|
-
if workflow is not None:
|
|
114
|
-
self.workflows[workflow_file] = workflow
|
|
115
|
-
|
|
116
|
-
# Glob all action.yaml and action.yml files, skipping .git folder entirely using pathlib
|
|
117
|
-
def find_action_files(base: Path):
|
|
118
|
-
for entry in base.iterdir():
|
|
119
|
-
if entry.is_dir():
|
|
120
|
-
if entry.name == ".git":
|
|
121
|
-
continue
|
|
122
|
-
yield from find_action_files(entry)
|
|
123
|
-
elif entry.is_file() and entry.name in ("action.yaml", "action.yml"):
|
|
124
|
-
yield entry
|
|
125
|
-
|
|
126
|
-
for action_file in find_action_files(working_tree_dir):
|
|
127
|
-
id = str(action_file.relative_to(working_tree_dir).parent)
|
|
128
|
-
action = Action.from_file(action_file, id)
|
|
129
|
-
if action is not None:
|
|
130
|
-
self.actions[action_file] = action
|
|
131
|
-
|
|
132
76
|
def get_releases(self) -> None:
|
|
133
|
-
# Get all tags from the local git repository
|
|
77
|
+
# Get all tags from the local git repository.
|
|
134
78
|
try:
|
|
135
79
|
tags = [tag.name for tag in self.repo.tags]
|
|
136
80
|
except Exception as e:
|
|
@@ -191,6 +135,34 @@ class GitHubHandler(BaseHandler):
|
|
|
191
135
|
except Exception as error:
|
|
192
136
|
raise PluginError(f"Invalid options: {error}") from error
|
|
193
137
|
|
|
138
|
+
def get_repository_name(self) -> str:
|
|
139
|
+
# Get repo from environment variable or git remotes.
|
|
140
|
+
if os.environ.get("GITHUB_ACTIONS") == "true" and (
|
|
141
|
+
repo := os.environ.get("GITHUB_REPOSITORY")
|
|
142
|
+
):
|
|
143
|
+
return repo
|
|
144
|
+
else:
|
|
145
|
+
# Try each remote to find a valid GitHub owner/repo
|
|
146
|
+
owner = None
|
|
147
|
+
repo_name = None
|
|
148
|
+
for remote in self.repo.remotes:
|
|
149
|
+
for url in remote.urls:
|
|
150
|
+
match = re.search(
|
|
151
|
+
r"(?P<host>[\w\.-]+)[/:](?P<owner>[^/]+)/(?P<repo>[^/.]+?)(?:\.git)?$",
|
|
152
|
+
url,
|
|
153
|
+
)
|
|
154
|
+
if match:
|
|
155
|
+
owner = match.group("owner")
|
|
156
|
+
repo_name = match.group("repo")
|
|
157
|
+
break
|
|
158
|
+
if owner and repo_name:
|
|
159
|
+
break
|
|
160
|
+
if not (owner and repo_name):
|
|
161
|
+
raise PluginError(
|
|
162
|
+
"Could not determine GitHub repository owner/name from any git remote URL."
|
|
163
|
+
)
|
|
164
|
+
return f"{owner}/{repo_name}"
|
|
165
|
+
|
|
194
166
|
def update_env(self, config: Any) -> None:
|
|
195
167
|
self.env.trim_blocks = True
|
|
196
168
|
self.env.lstrip_blocks = True
|
|
@@ -198,22 +170,34 @@ class GitHubHandler(BaseHandler):
|
|
|
198
170
|
self.env.filters["format_action_signature"] = rendering.format_action_signature
|
|
199
171
|
self.env.filters["order_parameters"] = rendering.order_parameters
|
|
200
172
|
self.env.filters["filter_parameters"] = rendering.filter_parameters
|
|
173
|
+
self.env.filters["group_parameters"] = rendering.group_parameters
|
|
201
174
|
self.env.filters["anchor_id"] = rendering.anchor_id
|
|
202
175
|
self.env.filters["as_string"] = rendering.as_string
|
|
203
176
|
self.env.globals["semver_tag"] = self.semver
|
|
204
177
|
self.env.globals["major_tag"] = self.major
|
|
205
178
|
self.env.globals["git_repo"] = self.repo
|
|
179
|
+
self.env.globals["repository_name"] = self.get_repository_name()
|
|
206
180
|
|
|
207
|
-
def collect(self, identifier: str, options: GitHubOptions) -> Workflow | Action:
|
|
181
|
+
def collect(self, identifier: str, options: GitHubOptions) -> Workflow | Action | None:
|
|
208
182
|
path = Path(self.repo.working_tree_dir) / identifier
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
183
|
+
|
|
184
|
+
if path.suffix in (".yml", ".yaml"):
|
|
185
|
+
if not path.is_file():
|
|
186
|
+
raise CollectionError(f"Identifier '{identifier}' is not a valid workflow file.")
|
|
187
|
+
data = Workflow.from_file(path, id=identifier)
|
|
188
|
+
elif not path.is_dir():
|
|
189
|
+
raise CollectionError(
|
|
190
|
+
f"Identifier '{identifier}' is not a valid workflow file or action directory."
|
|
191
|
+
)
|
|
192
|
+
elif (action_path := path / "action.yml").is_file():
|
|
193
|
+
data = Action.from_file(action_path, id=identifier)
|
|
194
|
+
elif (action_path := path / "action.yaml").is_file():
|
|
195
|
+
data = Action.from_file(action_path, id=identifier)
|
|
215
196
|
else:
|
|
216
|
-
raise CollectionError(
|
|
197
|
+
raise CollectionError(
|
|
198
|
+
f"Identifier '{identifier}' is not a valid workflow file or action directory."
|
|
199
|
+
)
|
|
200
|
+
return data
|
|
217
201
|
|
|
218
202
|
def render(self, data: Workflow | Action, options: GitHubOptions) -> str:
|
|
219
203
|
"""Render a template using provided data and configuration options.
|
|
@@ -1,10 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
import re
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
3
|
from enum import Enum
|
|
4
4
|
from os import PathLike
|
|
5
5
|
from typing import Any, Literal, Optional
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
from ruamel.yaml import YAML
|
|
8
|
+
from ruamel.yaml.comments import CommentedMap
|
|
9
|
+
|
|
10
|
+
yaml = YAML()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
GROUP_PATTERN = r"#\s*group:\s*(.+)$"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def group_from_map(map: CommentedMap) -> str:
|
|
17
|
+
"""Extract group string from a comment line if it matches the group pattern."""
|
|
18
|
+
if map.ca.comment:
|
|
19
|
+
for comment in map.ca.comment:
|
|
20
|
+
if comment is not None:
|
|
21
|
+
group_matches = re.finditer(GROUP_PATTERN, comment.value)
|
|
22
|
+
group_string = next((m.group(1).strip() for m in group_matches), "")
|
|
23
|
+
if group_string:
|
|
24
|
+
return group_string
|
|
25
|
+
return ""
|
|
8
26
|
|
|
9
27
|
|
|
10
28
|
@dataclass
|
|
@@ -15,28 +33,15 @@ class Input:
|
|
|
15
33
|
type: Literal["boolean", "number", "string"] = "string"
|
|
16
34
|
default: bool | float | int | str | None = None
|
|
17
35
|
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)
|
|
36
|
+
group: str = ""
|
|
30
37
|
|
|
31
38
|
|
|
32
39
|
@dataclass
|
|
33
40
|
class Output:
|
|
34
41
|
name: str
|
|
35
42
|
description: str = ""
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def from_data(name: str, description: str = "", **kwargs) -> "Output":
|
|
39
|
-
return Output(name, description)
|
|
43
|
+
value: str = ""
|
|
44
|
+
group: str = ""
|
|
40
45
|
|
|
41
46
|
|
|
42
47
|
@dataclass
|
|
@@ -44,10 +49,7 @@ class Secret:
|
|
|
44
49
|
name: str
|
|
45
50
|
description: str = ""
|
|
46
51
|
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)
|
|
52
|
+
group: str = ""
|
|
51
53
|
|
|
52
54
|
|
|
53
55
|
def _get_member(d: dict, key: str, error_message: str = "", default: Any = None) -> Any:
|
|
@@ -58,36 +60,11 @@ def _get_member(d: dict, key: str, error_message: str = "", default: Any = None)
|
|
|
58
60
|
return d[key]
|
|
59
61
|
|
|
60
62
|
|
|
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
63
|
def _read_file(file: PathLike) -> tuple[str, dict]:
|
|
87
64
|
with open(file, "r", encoding="utf-8") as f:
|
|
88
65
|
source = f.read()
|
|
89
66
|
f.seek(0)
|
|
90
|
-
data = yaml.load(f
|
|
67
|
+
data = yaml.load(f)
|
|
91
68
|
return source, data
|
|
92
69
|
|
|
93
70
|
|
|
@@ -106,10 +83,6 @@ class Action:
|
|
|
106
83
|
branding: dict = field(default_factory=dict)
|
|
107
84
|
template: Literal["action.html.jinja"] = "action.html.jinja"
|
|
108
85
|
|
|
109
|
-
@property
|
|
110
|
-
def members(self) -> list[Input | Output]:
|
|
111
|
-
return self.inputs + self.outputs
|
|
112
|
-
|
|
113
86
|
@staticmethod
|
|
114
87
|
def from_file(file: PathLike, id: str) -> "Action":
|
|
115
88
|
source, data = _read_file(file)
|
|
@@ -125,12 +98,31 @@ class Action:
|
|
|
125
98
|
branding=_get_member(data, "branding", default={}),
|
|
126
99
|
)
|
|
127
100
|
for key, value in data.get("inputs", {}).items():
|
|
128
|
-
action.inputs.append(Input
|
|
101
|
+
action.inputs.append(Input(name=key, **value, group=group_from_map(value)))
|
|
129
102
|
for key, value in data.get("outputs", {}).items():
|
|
130
|
-
action.outputs.append(Output
|
|
103
|
+
action.outputs.append(Output(name=key, **value, group=group_from_map(value)))
|
|
131
104
|
return action
|
|
132
105
|
|
|
133
106
|
|
|
107
|
+
# https://docs.github.com/en/actions/reference/workflows-and-actions/workflow-syntax#jobsjob_idpermissions
|
|
108
|
+
PERMISSION_SCOPES: list[str] = [
|
|
109
|
+
"actions",
|
|
110
|
+
"attestations",
|
|
111
|
+
"checks",
|
|
112
|
+
"contents",
|
|
113
|
+
"deployments",
|
|
114
|
+
"discussions",
|
|
115
|
+
"id-token",
|
|
116
|
+
"issues",
|
|
117
|
+
"models",
|
|
118
|
+
"packages",
|
|
119
|
+
"pages",
|
|
120
|
+
"pull-requests",
|
|
121
|
+
"security-events",
|
|
122
|
+
"statuses",
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
|
|
134
126
|
class PermissionLevel(Enum):
|
|
135
127
|
none = ("none", 0)
|
|
136
128
|
read = ("read", 1)
|
|
@@ -151,21 +143,6 @@ class PermissionLevel(Enum):
|
|
|
151
143
|
return perm
|
|
152
144
|
raise ValueError(f"No Permission with label '{label}'")
|
|
153
145
|
|
|
154
|
-
def __le__(self, other):
|
|
155
|
-
if isinstance(other, PermissionLevel):
|
|
156
|
-
return self.number <= other.number
|
|
157
|
-
return NotImplemented
|
|
158
|
-
|
|
159
|
-
def __lt__(self, other):
|
|
160
|
-
if isinstance(other, PermissionLevel):
|
|
161
|
-
return self.number < other.number
|
|
162
|
-
return NotImplemented
|
|
163
|
-
|
|
164
|
-
def __ge__(self, other):
|
|
165
|
-
if isinstance(other, PermissionLevel):
|
|
166
|
-
return self.number >= other.number
|
|
167
|
-
return NotImplemented
|
|
168
|
-
|
|
169
146
|
def __gt__(self, other):
|
|
170
147
|
if isinstance(other, PermissionLevel):
|
|
171
148
|
return self.number > other.number
|
|
@@ -187,8 +164,18 @@ class Workflow:
|
|
|
187
164
|
template: Literal["workflow.html.jinja"] = "workflow.html.jinja"
|
|
188
165
|
|
|
189
166
|
@property
|
|
190
|
-
def
|
|
191
|
-
return
|
|
167
|
+
def permission_read_all(self) -> bool:
|
|
168
|
+
return all(
|
|
169
|
+
scope in self.permissions and self.permissions[scope] == PermissionLevel.read
|
|
170
|
+
for scope in PERMISSION_SCOPES
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
@property
|
|
174
|
+
def permission_write_all(self) -> bool:
|
|
175
|
+
return all(
|
|
176
|
+
scope in self.permissions and self.permissions[scope] == PermissionLevel.write
|
|
177
|
+
for scope in PERMISSION_SCOPES
|
|
178
|
+
)
|
|
192
179
|
|
|
193
180
|
@staticmethod
|
|
194
181
|
def from_file(file: PathLike, id: str) -> "Workflow | None":
|
|
@@ -208,18 +195,41 @@ class Workflow:
|
|
|
208
195
|
call = data["on"]["workflow_call"]
|
|
209
196
|
if call:
|
|
210
197
|
for key, value in call.get("inputs", {}).items():
|
|
211
|
-
workflow.inputs.append(Input
|
|
198
|
+
workflow.inputs.append(Input(name=key, **value, group=group_from_map(value)))
|
|
212
199
|
for key, value in call.get("outputs", {}).items():
|
|
213
|
-
workflow.outputs.append(Output
|
|
200
|
+
workflow.outputs.append(Output(name=key, **value, group=group_from_map(value)))
|
|
214
201
|
for key, value in call.get("secrets", {}).items():
|
|
215
|
-
workflow.secrets.append(Secret
|
|
216
|
-
|
|
217
|
-
|
|
202
|
+
workflow.secrets.append(Secret(name=key, **value, group=group_from_map(value)))
|
|
203
|
+
|
|
204
|
+
def set_all_permissions(level: str):
|
|
205
|
+
if level == "read-all":
|
|
206
|
+
for key in PERMISSION_SCOPES:
|
|
207
|
+
workflow.permissions[key] = PermissionLevel.read
|
|
208
|
+
elif level == "write-all":
|
|
209
|
+
for key in PERMISSION_SCOPES:
|
|
210
|
+
workflow.permissions[key] = PermissionLevel.write
|
|
211
|
+
else:
|
|
212
|
+
raise ValueError(f"Unknown permission level '{level}'")
|
|
213
|
+
|
|
214
|
+
if isinstance(permissions := data.get("permissions", {}), str):
|
|
215
|
+
set_all_permissions(permissions)
|
|
216
|
+
elif isinstance(permissions, dict):
|
|
217
|
+
for key, label in permissions.items():
|
|
218
|
+
workflow.permissions[key] = PermissionLevel.from_label(label)
|
|
219
|
+
else:
|
|
220
|
+
raise ValueError("permissions must be a string or a dictionary")
|
|
218
221
|
for job in data.get("jobs", {}).values():
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
222
|
+
if isinstance(permissions := job.get("permissions", {}), str):
|
|
223
|
+
set_all_permissions(permissions)
|
|
224
|
+
elif isinstance(permissions, dict):
|
|
225
|
+
for key, label in job.get("permissions", {}).items():
|
|
226
|
+
if key in workflow.permissions:
|
|
227
|
+
permission = PermissionLevel.from_label(label)
|
|
228
|
+
if permission > workflow.permissions[key]:
|
|
229
|
+
workflow.permissions[key] = permission
|
|
230
|
+
else:
|
|
231
|
+
workflow.permissions[key] = PermissionLevel.from_label(label)
|
|
232
|
+
else:
|
|
233
|
+
raise ValueError("permissions must be a string or a dictionary")
|
|
234
|
+
|
|
225
235
|
return workflow
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
from collections import OrderedDict
|
|
4
5
|
from typing import TYPE_CHECKING, Sequence
|
|
5
6
|
|
|
6
7
|
from jinja2 import pass_context
|
|
@@ -23,8 +24,11 @@ def format_action_signature(context: Context, id: str, repo: str, options: GitHu
|
|
|
23
24
|
match options.signature_version:
|
|
24
25
|
case "ref":
|
|
25
26
|
try:
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
git_repo = context.environment.globals["git_repo"]
|
|
28
|
+
if isinstance(git_repo, Repo):
|
|
29
|
+
version = git_repo.head.ref.name
|
|
30
|
+
else:
|
|
31
|
+
version = "unknown"
|
|
28
32
|
except Exception:
|
|
29
33
|
version = "unknown"
|
|
30
34
|
case "major":
|
|
@@ -37,6 +41,22 @@ def format_action_signature(context: Context, id: str, repo: str, options: GitHu
|
|
|
37
41
|
return f"{name}@{version}"
|
|
38
42
|
|
|
39
43
|
|
|
44
|
+
def group_parameters(
|
|
45
|
+
parameters: Sequence[Input | Output | Secret],
|
|
46
|
+
do_group: bool,
|
|
47
|
+
) -> OrderedDict[str, list[Input | Output | Secret]]:
|
|
48
|
+
grouped: OrderedDict[str, list[Input | Output | Secret]] = OrderedDict()
|
|
49
|
+
if not do_group:
|
|
50
|
+
grouped[""] = list(parameters)
|
|
51
|
+
return grouped
|
|
52
|
+
for parameter in parameters:
|
|
53
|
+
group = getattr(parameter, "group", "")
|
|
54
|
+
if group not in grouped:
|
|
55
|
+
grouped[group] = []
|
|
56
|
+
grouped[group].append(parameter)
|
|
57
|
+
return grouped
|
|
58
|
+
|
|
59
|
+
|
|
40
60
|
def order_parameters(
|
|
41
61
|
parameters: Sequence[Input | Output | Secret], parameters_order: PARAMETERS_ORDER
|
|
42
62
|
):
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{#- Shared macros for rendering parameters in different styles -#}
|
|
2
|
+
|
|
3
|
+
{#- Macro to render a single parameter item in list style -#}
|
|
4
|
+
{% macro render_parameter_item(item, item_type, options, data) %}
|
|
5
|
+
{% set anchor_id = item.name | anchor_id(item_type, data.id) %}
|
|
6
|
+
<li class="doc-section-item field-body">
|
|
7
|
+
<b><code>{{ item.name }}</code></b>
|
|
8
|
+
{%- if item.required is defined and item.required %} - <em>required</em>{% endif %}
|
|
9
|
+
{% if options.parameters_anchors %}
|
|
10
|
+
<a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ item.name }}">¤</a>
|
|
11
|
+
{% endif %}
|
|
12
|
+
<div class="doc-md-description">
|
|
13
|
+
{{ item.description | convert_markdown(options.heading_level, data.id) }}
|
|
14
|
+
</div>
|
|
15
|
+
{% if item.default is defined and item.default is not none %}
|
|
16
|
+
<div class="doc-md-description">
|
|
17
|
+
<code>{{ item.default | as_string }}</code>
|
|
18
|
+
</div>
|
|
19
|
+
{% endif %}
|
|
20
|
+
</li>
|
|
21
|
+
{% endmacro %}
|
|
22
|
+
|
|
23
|
+
{#- Macro to render grouped parameters in list style -#}
|
|
24
|
+
{% macro render_grouped_list(items, item_type, options, data) %}
|
|
25
|
+
{% set grouped_items = items | group_parameters(options.parameters_groups) %}
|
|
26
|
+
{% for group, group_items in grouped_items.items() %}
|
|
27
|
+
{% if group %}
|
|
28
|
+
<li class="gh-group-item">
|
|
29
|
+
<em>{{ group }}:</em>
|
|
30
|
+
<ul>
|
|
31
|
+
{% for item in group_items %}{{ render_parameter_item(item, item_type, options, data) }}{% endfor %}
|
|
32
|
+
</ul>
|
|
33
|
+
</li>
|
|
34
|
+
{% else %}
|
|
35
|
+
{% for item in group_items %}{{ render_parameter_item(item, item_type, options, data) }}{% endfor %}
|
|
36
|
+
{% endif %}
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endmacro %}
|
|
@@ -7,7 +7,6 @@ Context:
|
|
|
7
7
|
config (mkdocstrings_handlers.github.config.GitHubConfig): The global configuration
|
|
8
8
|
options (dict): The local options
|
|
9
9
|
-#}
|
|
10
|
-
|
|
11
10
|
{% block logs scoped %}
|
|
12
11
|
{#- Logging block.
|
|
13
12
|
|
|
@@ -23,20 +22,30 @@ Context:
|
|
|
23
22
|
|
|
24
23
|
{% include "heading.html.jinja" with context %}
|
|
25
24
|
|
|
26
|
-
{% set signature = data.id | format_action_signature(
|
|
25
|
+
{% set signature = data.id | format_action_signature(options.signature_repository if options.signature_repository else repository_name, options) %}
|
|
27
26
|
|
|
28
27
|
{% block signature scoped %}
|
|
29
28
|
{% if options.show_signature %}
|
|
30
29
|
{% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
|
|
30
|
+
<div class="annotate">
|
|
31
31
|
{% filter highlight(language="yaml", inline=False, linenums=False) %}
|
|
32
32
|
- uses: {{ signature }}
|
|
33
|
+
{% if inputs|length > 0 %}
|
|
33
34
|
with:
|
|
34
|
-
{
|
|
35
|
+
{% for input in inputs %}
|
|
36
|
+
{{ input.name }}: ({{ loop.index }})
|
|
37
|
+
{% endfor %}
|
|
38
|
+
{% endif %}
|
|
35
39
|
{% endfilter %}
|
|
40
|
+
</div>
|
|
41
|
+
<ol>
|
|
42
|
+
{% for input in inputs %}
|
|
43
|
+
<li>{{ input.description | convert_markdown(options.heading_level) if input.description else "(no description)" }}</li>
|
|
44
|
+
{% endfor %}
|
|
45
|
+
</ol>
|
|
36
46
|
{% endwith %}
|
|
37
47
|
{% endif %}
|
|
38
48
|
{% endblock signature %}
|
|
39
|
-
|
|
40
49
|
{% block description scoped %}
|
|
41
50
|
{% if options.show_description %}
|
|
42
51
|
{{ options.description if options.description else data.description | convert_markdown(options.heading_level, data.id) }}
|
|
@@ -7,6 +7,8 @@ Context:
|
|
|
7
7
|
options (dict): The local options
|
|
8
8
|
-#}
|
|
9
9
|
|
|
10
|
+
{% from "_macros.html.jinja" import render_grouped_list %}
|
|
11
|
+
|
|
10
12
|
{% block logs scoped %}
|
|
11
13
|
{{ log.debug("Rendering inputs of " + data.id) }}
|
|
12
14
|
{% endblock logs %}
|
|
@@ -27,7 +29,7 @@ Context:
|
|
|
27
29
|
<span class="doc-section-title">Inputs:</span>
|
|
28
30
|
<a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
|
|
29
31
|
</p>
|
|
30
|
-
<table>
|
|
32
|
+
<table data-gh-parameters>
|
|
31
33
|
<thead>
|
|
32
34
|
<tr>
|
|
33
35
|
<th>Name</th>
|
|
@@ -35,8 +37,15 @@ Context:
|
|
|
35
37
|
{% if default_column %}<th>Default</th>{% endif %}
|
|
36
38
|
</tr>
|
|
37
39
|
</thead>
|
|
40
|
+
{% set grouped_inputs = inputs | group_parameters(options.parameters_groups) %}
|
|
41
|
+
{% for group, group_inputs in grouped_inputs.items() %}
|
|
38
42
|
<tbody>
|
|
39
|
-
{%
|
|
43
|
+
{% if options.parameters_group_title_row and grouped_inputs | length > 1 and group != "" %}
|
|
44
|
+
<tr class="doc-section-item">
|
|
45
|
+
<td class="gh-group-title" colspan="{% if default_column %}3{% else %}2{% endif %}">{{ group }}</td>
|
|
46
|
+
</tr>
|
|
47
|
+
{% endif %}
|
|
48
|
+
{% for input in group_inputs %}
|
|
40
49
|
{% if options.parameters_anchors %}
|
|
41
50
|
{% set anchor_id = input.name | anchor_id("inputs", data.id) %}
|
|
42
51
|
{% else %}
|
|
@@ -66,6 +75,7 @@ Context:
|
|
|
66
75
|
</tr>
|
|
67
76
|
{% endfor %}
|
|
68
77
|
</tbody>
|
|
78
|
+
{% endfor %}
|
|
69
79
|
</table>
|
|
70
80
|
{% endblock table_style %}
|
|
71
81
|
{% elif options.parameters_section_style == "list" %}
|
|
@@ -75,24 +85,7 @@ Context:
|
|
|
75
85
|
<a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
|
|
76
86
|
</p>
|
|
77
87
|
<ul>
|
|
78
|
-
{
|
|
79
|
-
{% set anchor_id = input.name | anchor_id("inputs", data.id) %}
|
|
80
|
-
<li class="doc-section-item field-body">
|
|
81
|
-
<b><code>{{ input.name }}</code></b>
|
|
82
|
-
{%- if input.required %} - <em>required</em>{% endif %}
|
|
83
|
-
{% if options.parameters_anchors %}
|
|
84
|
-
<a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ input.name }}">¤</a>
|
|
85
|
-
{% endif %}
|
|
86
|
-
<div class="doc-md-description">
|
|
87
|
-
{{ input.description | convert_markdown(options.heading_level, data.id) }}
|
|
88
|
-
</div>
|
|
89
|
-
{% if input.default is not none %}
|
|
90
|
-
<div class="doc-md-description">
|
|
91
|
-
Default: <code>{{ input.default | as_string }}</code>
|
|
92
|
-
</div>
|
|
93
|
-
{% endif %}
|
|
94
|
-
</li>
|
|
95
|
-
{% endfor %}
|
|
88
|
+
{{ render_grouped_list(inputs, "inputs", options, data) }}
|
|
96
89
|
</ul>
|
|
97
90
|
{% endblock list_style %}
|
|
98
91
|
{% endif %}
|
|
@@ -7,6 +7,8 @@ Context:
|
|
|
7
7
|
options (dict): The local options
|
|
8
8
|
-#}
|
|
9
9
|
|
|
10
|
+
{% from "_macros.html.jinja" import render_grouped_list %}
|
|
11
|
+
|
|
10
12
|
{% block logs scoped %}
|
|
11
13
|
{{ log.debug("Rendering outputs of " + data.id) }}
|
|
12
14
|
{% endblock logs %}
|
|
@@ -24,15 +26,22 @@ Context:
|
|
|
24
26
|
<span class="doc-section-title">Outputs:</span>
|
|
25
27
|
<a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
|
|
26
28
|
</p>
|
|
27
|
-
<table>
|
|
29
|
+
<table data-gh-parameters>
|
|
28
30
|
<thead>
|
|
29
31
|
<tr>
|
|
30
32
|
<th>Name</th>
|
|
31
33
|
<th>Description</th>
|
|
32
34
|
</tr>
|
|
33
35
|
</thead>
|
|
36
|
+
{% set grouped_outputs = outputs | group_parameters(options.parameters_groups) %}
|
|
37
|
+
{% for group, group_outputs in grouped_outputs.items() %}
|
|
34
38
|
<tbody>
|
|
35
|
-
{%
|
|
39
|
+
{% if options.parameters_group_title_row and grouped_outputs | length > 1 and group != "" %}
|
|
40
|
+
<tr class="doc-section-item">
|
|
41
|
+
<td class="gh-group-title" colspan="2">{{ group }}</td>
|
|
42
|
+
</tr>
|
|
43
|
+
{% endif %}
|
|
44
|
+
{% for output in group_outputs %}
|
|
36
45
|
{% if options.parameters_anchors %}
|
|
37
46
|
{% set anchor_id = output.name | anchor_id("outputs", data.id) %}
|
|
38
47
|
{% else %}
|
|
@@ -48,8 +57,10 @@ Context:
|
|
|
48
57
|
<td>
|
|
49
58
|
{{ output.description | convert_markdown(options.heading_level, data.id) }}
|
|
50
59
|
</td>
|
|
60
|
+
</tr>
|
|
51
61
|
{% endfor %}
|
|
52
62
|
</tbody>
|
|
63
|
+
{% endfor %}
|
|
53
64
|
</table>
|
|
54
65
|
{% endblock table_style %}
|
|
55
66
|
{% elif options.parameters_section_style == "list" %}
|
|
@@ -59,18 +70,7 @@ Context:
|
|
|
59
70
|
<a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
|
|
60
71
|
</p>
|
|
61
72
|
<ul>
|
|
62
|
-
{
|
|
63
|
-
{% set anchor_id = output.name | anchor_id("outputs", data.id) %}
|
|
64
|
-
<li class="doc-section-item field-body">
|
|
65
|
-
<b><code>{{ output.name }}</code></b>
|
|
66
|
-
{% if options.parameters_anchors %}
|
|
67
|
-
<a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ output.name }}">¤</a>
|
|
68
|
-
{% endif %}
|
|
69
|
-
<div class="doc-md-description">
|
|
70
|
-
{{ output.description | convert_markdown(options.heading_level, data.id) }}
|
|
71
|
-
</div>
|
|
72
|
-
</li>
|
|
73
|
-
{% endfor %}
|
|
73
|
+
{{ render_grouped_list(outputs, "outputs", options, data) }}
|
|
74
74
|
</ul>
|
|
75
75
|
{% endblock list_style %}
|
|
76
76
|
{% endif %}
|
|
@@ -7,6 +7,8 @@ Context:
|
|
|
7
7
|
options (dict): The local options
|
|
8
8
|
-#}
|
|
9
9
|
|
|
10
|
+
{% from "_macros.html.jinja" import render_grouped_list %}
|
|
11
|
+
|
|
10
12
|
{% block logs scoped %}
|
|
11
13
|
{{ log.debug("Rendering secrets of " + data.id) }}
|
|
12
14
|
{% endblock logs %}
|
|
@@ -24,15 +26,22 @@ Context:
|
|
|
24
26
|
<span class="doc-section-title">Secrets:</span>
|
|
25
27
|
<a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
|
|
26
28
|
</p>
|
|
27
|
-
<table>
|
|
29
|
+
<table data-gh-parameters>
|
|
28
30
|
<thead>
|
|
29
31
|
<tr>
|
|
30
32
|
<th>Name</th>
|
|
31
33
|
<th>Description</th>
|
|
32
34
|
</tr>
|
|
33
35
|
</thead>
|
|
36
|
+
{% set grouped_secrets = secrets | group_parameters(options.parameters_groups) %}
|
|
37
|
+
{% for group, group_secrets in grouped_secrets.items() %}
|
|
34
38
|
<tbody>
|
|
35
|
-
{%
|
|
39
|
+
{% if options.parameters_group_title_row and grouped_secrets | length > 1 and group != "" %}
|
|
40
|
+
<tr class="doc-section-item">
|
|
41
|
+
<td class="gh-group-title" colspan="2">{{ group }}</td>
|
|
42
|
+
</tr>
|
|
43
|
+
{% endif %}
|
|
44
|
+
{% for secret in group_secrets %}
|
|
36
45
|
{% if options.parameters_anchors %}
|
|
37
46
|
{% set anchor_id = secret.name | anchor_id("secrets", data.id) %}
|
|
38
47
|
{% else %}
|
|
@@ -52,8 +61,10 @@ Context:
|
|
|
52
61
|
<td>
|
|
53
62
|
{{ secret.description | convert_markdown(options.heading_level, data.id) }}
|
|
54
63
|
</td>
|
|
64
|
+
</tr>
|
|
55
65
|
{% endfor %}
|
|
56
66
|
</tbody>
|
|
67
|
+
{% endfor %}
|
|
57
68
|
</table>
|
|
58
69
|
{% endblock table_style %}
|
|
59
70
|
{% elif options.parameters_section_style == "list" %}
|
|
@@ -63,19 +74,7 @@ Context:
|
|
|
63
74
|
<a class="headerlink" href="#{{ header_id }}" title="Link to {{ data.name }} outputs">¤</a>
|
|
64
75
|
</p>
|
|
65
76
|
<ul>
|
|
66
|
-
{
|
|
67
|
-
{% set anchor_id = secret.name | anchor_id("secrets", data.id) %}
|
|
68
|
-
<li class="doc-section-item field-body">
|
|
69
|
-
<b><code>{{ secret.name }}</code></b>
|
|
70
|
-
{%- if secret.required %} - <em>required</em>{% endif %}
|
|
71
|
-
{% if options.parameters_anchors %}
|
|
72
|
-
<a class="headerlink" href="#{{ anchor_id }}" title="Link to {{ secret.name }}">¤</a>
|
|
73
|
-
{% endif %}
|
|
74
|
-
<div class="doc-md-description">
|
|
75
|
-
{{ secret.description | convert_markdown(options.heading_level, data.id) }}
|
|
76
|
-
</div>
|
|
77
|
-
</li>
|
|
78
|
-
{% endfor %}
|
|
77
|
+
{{ render_grouped_list(secrets, "secrets", options, data) }}
|
|
79
78
|
</ul>
|
|
80
79
|
{% endblock list_style %}
|
|
81
80
|
{% endif %}
|
|
@@ -57,3 +57,22 @@
|
|
|
57
57
|
background-color: #24292e;
|
|
58
58
|
color: #ffffff;
|
|
59
59
|
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
/* Add thicker divider between thead and tbody, and between tbody groups */
|
|
63
|
+
table[data-gh-parameters] thead + tbody tr:first-child td,
|
|
64
|
+
table[data-gh-parameters] tbody:not(:first-of-type) tr:first-child td {
|
|
65
|
+
border-top: 2px solid var(--md-default-fg-color--lighter) !important;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Disable word-wrap in first column (except group titles) */
|
|
69
|
+
table[data-gh-parameters] td:first-child:not(.gh-group-title) {
|
|
70
|
+
white-space: nowrap;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Style group title rows */
|
|
74
|
+
table[data-gh-parameters] td.gh-group-title {
|
|
75
|
+
text-align: center !important;
|
|
76
|
+
font-style: italic;
|
|
77
|
+
white-space: normal;
|
|
78
|
+
}
|
|
@@ -20,28 +20,50 @@ Context:
|
|
|
20
20
|
<div class="doc doc-object doc-workflow">
|
|
21
21
|
{% include "heading.html.jinja" with context %}
|
|
22
22
|
|
|
23
|
-
{% set signature = data.id | format_action_signature(
|
|
23
|
+
{% set signature = data.id | format_action_signature(options.signature_repository if options.signature_repository else repository_name, options) %}
|
|
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) %}
|
|
27
|
+
{% with inputs = data.inputs | order_parameters(options.parameters_order) | filter_parameters(required=True), secrets = data.secrets | order_parameters(options.parameters_order) | filter_parameters(required=True) %}
|
|
28
|
+
<div class="annotate">
|
|
28
29
|
{% filter highlight(language="yaml", inline=False, linenums=False) %}
|
|
29
30
|
uses: {{ signature }}
|
|
30
|
-
{% if options.signature_show_permissions and data.permissions %}
|
|
31
|
+
{% if options.signature_show_permissions and data.permissions|length > 0 %}
|
|
32
|
+
{% if data.permission_read_all %}
|
|
33
|
+
permissions: read-all
|
|
34
|
+
{% elif data.permission_write_all %}
|
|
35
|
+
permissions: write-all
|
|
36
|
+
{% else %}
|
|
31
37
|
permissions:
|
|
32
38
|
{% for scope, level in data.permissions | items %}
|
|
33
39
|
{{ scope }}: {{ level.label }}
|
|
34
40
|
{% endfor %}
|
|
35
41
|
{% endif %}
|
|
42
|
+
{% endif %}
|
|
43
|
+
{% if inputs|length > 0 %}
|
|
36
44
|
with:
|
|
37
|
-
{
|
|
45
|
+
{% for input in inputs %}
|
|
46
|
+
{{ input.name }}: ({{ loop.index }})
|
|
47
|
+
{% endfor %}
|
|
48
|
+
{% endif %}
|
|
38
49
|
{% if options.signature_show_secrets %}
|
|
39
|
-
|
|
50
|
+
{% if secrets|length > 0 %}
|
|
40
51
|
secrets:
|
|
41
|
-
{
|
|
42
|
-
{
|
|
52
|
+
{% for secret in secrets %}
|
|
53
|
+
{{ secret.name }}: ({{ inputs|length + loop.index }})
|
|
54
|
+
{% endfor %}
|
|
55
|
+
{% endif %}
|
|
43
56
|
{% endif %}
|
|
44
57
|
{% endfilter %}
|
|
58
|
+
</div>
|
|
59
|
+
<ol>
|
|
60
|
+
{% for input in inputs %}
|
|
61
|
+
<li>{{ input.description | convert_markdown(options.heading_level) if input.description else "(no description)" }}</li>
|
|
62
|
+
{% endfor %}
|
|
63
|
+
{% for secret in secrets %}
|
|
64
|
+
<li>{{ secret.description | convert_markdown(options.heading_level) if secret.description else "(no description)" }}</li>
|
|
65
|
+
{% endfor %}
|
|
66
|
+
</ol>
|
|
45
67
|
{% endwith %}
|
|
46
68
|
{% endif %}
|
|
47
69
|
{% endblock signature %}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
mkdocstrings_handlers/github/__init__.py,sha256=0WdFUIq4Xu2ZFtlZNIYCQSoqcx3Ot9Wv41_X_dwbFww,248
|
|
2
|
-
mkdocstrings_handlers/github/config.py,sha256=pSjA6gU-kC_mXQqNIIGOYEOhtX5VzZDT0H1hRFlGaj8,6089
|
|
3
|
-
mkdocstrings_handlers/github/handler.py,sha256=d3bpciheO6BSH1EPAc8ijZ_xmcEzzhXTbfTrbcMmFIg,9310
|
|
4
|
-
mkdocstrings_handlers/github/objects.py,sha256=JDkY7mg_LGlIEwZHP2wSd8ZkB6RVtRsu_JEpwV-PikQ,7069
|
|
5
|
-
mkdocstrings_handlers/github/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
-
mkdocstrings_handlers/github/rendering.py,sha256=tJeAsSaijqSC2IkxYsIXq7d0lR2A3aB5PRUcFFTFpVU,2705
|
|
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=CIcw3OBQdCP4e5A4srLu1v3xoOjsedIw1Zh3qxtG0-A,3482
|
|
10
|
-
mkdocstrings_handlers/github/templates/material/outputs.html.jinja,sha256=jlzVF93q5AyJfOiSl3_1VBVL3c6rjmEcS81s3sri5Gg,2670
|
|
11
|
-
mkdocstrings_handlers/github/templates/material/secrets.html.jinja,sha256=1lMJoxjjeiqetVu0mdLKmZ1faYRReeyjiYvYTZESots,2881
|
|
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.2.dist-info/METADATA,sha256=humw71gGT_wkykxy7fRgxh_t1ri6JOm3keuIkoiGIyU,3340
|
|
15
|
-
mkdocstrings_github-0.4.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
16
|
-
mkdocstrings_github-0.4.2.dist-info/licenses/LICENSE,sha256=5enZtJ4zSp0Ps3jTqFQ4kadcx62BhgTaDNPrXWb3g3E,1069
|
|
17
|
-
mkdocstrings_github-0.4.2.dist-info/RECORD,,
|
|
File without changes
|
{mkdocstrings_github-0.4.2.dist-info → mkdocstrings_github-0.6.1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|