saltext.github 1.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.
Files changed (73) hide show
  1. saltext/github/__init__.py +31 -0
  2. saltext/github/modules/__init__.py +0 -0
  3. saltext/github/modules/github.py +1873 -0
  4. saltext/github/modules/github_org.py +667 -0
  5. saltext/github/modules/github_repo.py +1658 -0
  6. saltext/github/modules/github_user.py +75 -0
  7. saltext/github/resources/__init__.py +0 -0
  8. saltext/github/resources/github/__init__.py +251 -0
  9. saltext/github/resources/github/modules/__init__.py +0 -0
  10. saltext/github/resources/github/modules/actions.py +175 -0
  11. saltext/github/resources/github/modules/config.py +69 -0
  12. saltext/github/resources/github/modules/deploy_key.py +122 -0
  13. saltext/github/resources/github/modules/environment.py +241 -0
  14. saltext/github/resources/github/modules/grains.py +18 -0
  15. saltext/github/resources/github/modules/issue.py +157 -0
  16. saltext/github/resources/github/modules/label.py +161 -0
  17. saltext/github/resources/github/modules/milestone.py +103 -0
  18. saltext/github/resources/github/modules/pages.py +149 -0
  19. saltext/github/resources/github/modules/pull.py +90 -0
  20. saltext/github/resources/github/modules/repo.py +155 -0
  21. saltext/github/resources/github/modules/ruleset.py +144 -0
  22. saltext/github/resources/github/modules/saltutil.py +24 -0
  23. saltext/github/resources/github/modules/state.py +116 -0
  24. saltext/github/resources/github/modules/test.py +29 -0
  25. saltext/github/resources/github/states/__init__.py +0 -0
  26. saltext/github/resources/github/states/actions.py +117 -0
  27. saltext/github/resources/github/states/deploy_key.py +130 -0
  28. saltext/github/resources/github/states/environment.py +99 -0
  29. saltext/github/resources/github/states/label.py +71 -0
  30. saltext/github/resources/github/states/pages.py +92 -0
  31. saltext/github/resources/github/states/repo.py +108 -0
  32. saltext/github/resources/github/states/ruleset.py +81 -0
  33. saltext/github/states/__init__.py +0 -0
  34. saltext/github/states/github.py +966 -0
  35. saltext/github/states/github_org.py +369 -0
  36. saltext/github/states/github_repo.py +722 -0
  37. saltext/github/utils/__init__.py +72 -0
  38. saltext/github/utils/gh/__init__.py +14 -0
  39. saltext/github/utils/gh/actions.py +195 -0
  40. saltext/github/utils/gh/cache.py +126 -0
  41. saltext/github/utils/gh/client.py +534 -0
  42. saltext/github/utils/gh/deploy_keys.py +121 -0
  43. saltext/github/utils/gh/environments.py +271 -0
  44. saltext/github/utils/gh/exceptions.py +28 -0
  45. saltext/github/utils/gh/grains_files.py +366 -0
  46. saltext/github/utils/gh/issues.py +193 -0
  47. saltext/github/utils/gh/labels.py +142 -0
  48. saltext/github/utils/gh/members.py +157 -0
  49. saltext/github/utils/gh/milestones.py +122 -0
  50. saltext/github/utils/gh/pages.py +128 -0
  51. saltext/github/utils/gh/profile.py +458 -0
  52. saltext/github/utils/gh/pulls.py +99 -0
  53. saltext/github/utils/gh/repos.py +465 -0
  54. saltext/github/utils/gh/resource.py +35 -0
  55. saltext/github/utils/gh/rulesets.py +191 -0
  56. saltext/github/utils/gh/statecores/__init__.py +70 -0
  57. saltext/github/utils/gh/statecores/actions.py +180 -0
  58. saltext/github/utils/gh/statecores/deploy_keys.py +241 -0
  59. saltext/github/utils/gh/statecores/environments.py +212 -0
  60. saltext/github/utils/gh/statecores/labels.py +116 -0
  61. saltext/github/utils/gh/statecores/pages.py +177 -0
  62. saltext/github/utils/gh/statecores/repo.py +249 -0
  63. saltext/github/utils/gh/statecores/rulesets.py +115 -0
  64. saltext/github/utils/gh/teams.py +375 -0
  65. saltext/github/utils/gh/users.py +87 -0
  66. saltext/github/version.py +1 -0
  67. saltext_github-1.1.0.dist-info/METADATA +151 -0
  68. saltext_github-1.1.0.dist-info/RECORD +73 -0
  69. saltext_github-1.1.0.dist-info/WHEEL +5 -0
  70. saltext_github-1.1.0.dist-info/entry_points.txt +2 -0
  71. saltext_github-1.1.0.dist-info/licenses/LICENSE +201 -0
  72. saltext_github-1.1.0.dist-info/licenses/NOTICE +10 -0
  73. saltext_github-1.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,193 @@
1
+ """
2
+ Operations on GitHub repository issues.
3
+ """
4
+
5
+ import logging
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+
10
+ def get(conn, repo_name, number, *, owner=None):
11
+ """
12
+ Return the raw data of a single issue.
13
+
14
+ conn
15
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
16
+
17
+ repo_name
18
+ Repository the issue belongs to.
19
+
20
+ number
21
+ Issue number to retrieve.
22
+
23
+ owner
24
+ Owner of the repository. Defaults to the connection's owner.
25
+ """
26
+ return conn.repo_query(owner, repo_name, "issues", str(number))
27
+
28
+
29
+ def get_comments(conn, repo_name, number, since=None, *, owner=None):
30
+ """
31
+ Return the raw comment data for a single issue.
32
+
33
+ conn
34
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
35
+
36
+ repo_name
37
+ Repository the issue belongs to.
38
+
39
+ number
40
+ Issue number whose comments to retrieve.
41
+
42
+ since
43
+ Only comments updated at or after this time are returned. This is a
44
+ timestamp in ISO 8601 format: ``YYYY-MM-DDTHH:MM:SSZ``.
45
+
46
+ owner
47
+ Owner of the repository. Defaults to the connection's owner.
48
+ """
49
+ params = {}
50
+ if since:
51
+ params["since"] = since
52
+ return conn.repo_query(
53
+ owner,
54
+ *(repo_name, "issues", str(number), "comments"),
55
+ params=params,
56
+ )
57
+
58
+
59
+ def list_all(
60
+ conn,
61
+ repo_name,
62
+ *,
63
+ milestone=None,
64
+ state="open",
65
+ assignee=None,
66
+ creator=None,
67
+ mentioned=None,
68
+ labels=None,
69
+ sort="created",
70
+ direction="desc",
71
+ since=None,
72
+ per_page=None,
73
+ owner=None,
74
+ ):
75
+ """
76
+ Return the raw data of all issues in a repository matching the search
77
+ options. Pull requests are excluded.
78
+
79
+ conn
80
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
81
+
82
+ repo_name
83
+ Repository whose issues to list.
84
+
85
+ milestone
86
+ Number of a GitHub milestone, or a string of either ``*`` or ``none``.
87
+
88
+ state
89
+ Filter returned issues by their state. Can be either ``open``,
90
+ ``closed``, or ``all``. Default is ``open``.
91
+
92
+ assignee
93
+ Filter returned issues by assigned user handle. Pass ``none``
94
+ (as a string) for issues with no assigned user or ``*`` for
95
+ issues assigned to any user.
96
+
97
+ creator
98
+ Filter by the username that created the issue.
99
+
100
+ mentioned
101
+ Filter issues for a user that's mentioned in the issue.
102
+
103
+ labels
104
+ Filter issues by associated labels. String of comma separated
105
+ label names. For example, ``bug,ui,@high``.
106
+
107
+ sort
108
+ Field to sort results by. Either ``created``, ``updated``, or
109
+ ``comments``. Default is ``created``.
110
+
111
+ direction
112
+ Sort direction. Either ``asc`` or ``desc``. Default is ``desc``.
113
+
114
+ since
115
+ Only list issues updated at or after this time. This is a
116
+ timestamp in ISO 8601 format: ``YYYY-MM-DDTHH:MM:SSZ``.
117
+
118
+ per_page
119
+ Pagination size, maximum 100.
120
+
121
+ owner
122
+ Owner of the repository. Defaults to the connection's owner.
123
+ """
124
+ params = {}
125
+
126
+ # Build API arguments, as necessary.
127
+ if milestone:
128
+ params["milestone"] = milestone
129
+ if assignee:
130
+ params["assignee"] = assignee
131
+ if creator:
132
+ params["creator"] = creator
133
+ if mentioned:
134
+ params["mentioned"] = mentioned
135
+ if labels:
136
+ params["labels"] = labels
137
+ if since:
138
+ params["since"] = since
139
+ if per_page:
140
+ params["per_page"] = per_page
141
+
142
+ # Only pass the following API args if they're not the defaults listed.
143
+ if state and state != "open":
144
+ params["state"] = state
145
+ if sort and sort != "created":
146
+ params["sort"] = sort
147
+ if direction and direction != "desc":
148
+ params["direction"] = direction
149
+
150
+ issues = conn.repo_query(owner, repo_name, "issues", params=params)
151
+
152
+ # Pull requests are included in the issue list from GitHub.
153
+ # Let's not include those in the return.
154
+ return [issue for issue in issues if not issue.get("pull_request")]
155
+
156
+
157
+ def format_issue(issue):
158
+ """
159
+ Format API return information into a more manageable
160
+ and useful dictionary for issue information.
161
+
162
+ Legacy function, only used by deprecated callers.
163
+
164
+ issue
165
+ Issue to format.
166
+ """
167
+ ret = {
168
+ "id": issue.get("id"),
169
+ "issue_number": issue.get("number"),
170
+ "state": issue.get("state"),
171
+ "title": issue.get("title"),
172
+ "user": issue.get("user").get("login"),
173
+ "html_url": issue.get("html_url"),
174
+ }
175
+
176
+ assignee = issue.get("assignee")
177
+ if assignee:
178
+ assignee = assignee.get("login")
179
+
180
+ labels = issue.get("labels")
181
+ label_names = []
182
+ for label in labels:
183
+ label_names.append(label.get("name"))
184
+
185
+ milestone = issue.get("milestone")
186
+ if milestone:
187
+ milestone = milestone.get("title")
188
+
189
+ ret["assignee"] = assignee
190
+ ret["labels"] = label_names
191
+ ret["milestone"] = milestone
192
+
193
+ return ret
@@ -0,0 +1,142 @@
1
+ """
2
+ Operations on GitHub repository (issue) labels.
3
+ """
4
+
5
+ import logging
6
+ from urllib.parse import quote
7
+
8
+ from saltext.github.utils import filter_unset
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ def _path(*suffix):
14
+ # Label names can contain characters that are invalid in URL paths
15
+ return ["labels"] + [quote(str(segment), safe="") for segment in suffix]
16
+
17
+
18
+ def normalize_color(color):
19
+ """
20
+ Normalize a label color for comparisons: lowercase, no leading ``#``.
21
+
22
+ color
23
+ Hexadecimal color code to normalize.
24
+ """
25
+ if color is None:
26
+ return None
27
+ return color.lstrip("#").lower()
28
+
29
+
30
+ def list_all(conn, repo_name, *, owner=None):
31
+ """
32
+ Return all labels of a repository.
33
+
34
+ conn
35
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
36
+
37
+ repo_name
38
+ Repository name.
39
+
40
+ owner
41
+ Owner of the repository. Defaults to the connection's owner.
42
+ """
43
+ return conn.repo_query(owner, repo_name, "labels")
44
+
45
+
46
+ def get(conn, repo_name, name, *, owner=None):
47
+ """
48
+ Return the data of a single label.
49
+
50
+ conn
51
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
52
+
53
+ repo_name
54
+ Repository name.
55
+
56
+ name
57
+ Label name.
58
+
59
+ owner
60
+ Owner of the repository. Defaults to the connection's owner.
61
+
62
+ Raises :class:`~saltext.github.utils.gh.exceptions.GitHubNotFoundError`
63
+ if the label does not exist.
64
+ """
65
+ return conn.repo_query(owner, repo_name, *_path(name))
66
+
67
+
68
+ def create(conn, repo_name, name, *, color=None, description=None, owner=None):
69
+ """
70
+ Create a label in a repository. Returns the data of the created label.
71
+
72
+ conn
73
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
74
+
75
+ repo_name
76
+ Repository name.
77
+
78
+ name
79
+ Label name.
80
+
81
+ color
82
+ Hexadecimal color code for the label, without the leading ``#``.
83
+ If unset, GitHub assigns a random one.
84
+
85
+ description
86
+ Short description of the label.
87
+
88
+ owner
89
+ Owner of the repository. Defaults to the connection's owner.
90
+ """
91
+ data = filter_unset({"name": name, "color": normalize_color(color), "description": description})
92
+ return conn.repo_query(owner, repo_name, "labels", method="POST", data=data)
93
+
94
+
95
+ def update(conn, repo_name, name, *, new_name=None, color=None, description=None, owner=None):
96
+ """
97
+ Update an existing label. Returns the data of the updated label.
98
+
99
+ conn
100
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
101
+
102
+ repo_name
103
+ Repository name.
104
+
105
+ name
106
+ Current label name.
107
+
108
+ new_name
109
+ New name for the label.
110
+
111
+ color
112
+ Hexadecimal color code for the label, without the leading ``#``.
113
+
114
+ description
115
+ Short description of the label.
116
+
117
+ owner
118
+ Owner of the repository. Defaults to the connection's owner.
119
+ """
120
+ data = filter_unset(
121
+ {"new_name": new_name, "color": normalize_color(color), "description": description}
122
+ )
123
+ return conn.repo_query(owner, repo_name, *_path(name), method="PATCH", data=data)
124
+
125
+
126
+ def delete(conn, repo_name, name, *, owner=None):
127
+ """
128
+ Delete a label from a repository.
129
+
130
+ conn
131
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
132
+
133
+ repo_name
134
+ Repository name.
135
+
136
+ name
137
+ Label name.
138
+
139
+ owner
140
+ Owner of the repository. Defaults to the connection's owner.
141
+ """
142
+ conn.repo_query(owner, repo_name, *_path(name), method="DELETE")
@@ -0,0 +1,157 @@
1
+ """
2
+ Operations on GitHub organization members.
3
+ """
4
+
5
+ import logging
6
+
7
+ from github.GithubException import UnknownObjectException
8
+
9
+ from saltext.github.utils.gh.client import api_request
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+
14
+ @api_request
15
+ def list_all(conn, *, owner=None, ignore_cache=False):
16
+ """
17
+ Return the logins of all members of an organization (cached).
18
+
19
+ conn
20
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
21
+
22
+ owner
23
+ Organization to target. Defaults to the connection's owner.
24
+
25
+ ignore_cache
26
+ Bypass the cached member list.
27
+ """
28
+ owner = owner or conn.owner
29
+ key = ("members", owner.lower())
30
+ if key not in conn.cache or ignore_cache:
31
+ conn.cache[key] = [member.login for member in conn.get_org(owner).get_members()]
32
+ return conn.cache[key]
33
+
34
+
35
+ @api_request
36
+ def get_info(conn, login, *, owner=None):
37
+ """
38
+ Return information about a user, including their organization
39
+ membership state.
40
+
41
+ conn
42
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
43
+
44
+ login
45
+ User handle to look up.
46
+
47
+ owner
48
+ Organization to target. Defaults to the connection's owner.
49
+
50
+ Raises :class:`~saltext.github.utils.gh.exceptions.GitHubNotFoundError`
51
+ if the user does not exist.
52
+ """
53
+ user = conn.client.get_user(login)
54
+
55
+ ret = {
56
+ "company": user.company,
57
+ "created_at": user.created_at,
58
+ "email": user.email,
59
+ "html_url": user.html_url,
60
+ "id": user.id,
61
+ "login": user.login,
62
+ "name": user.name,
63
+ "type": user.type,
64
+ "url": user.url,
65
+ }
66
+
67
+ org = conn.get_org(owner)
68
+ try:
69
+ membership = user.get_organization_membership(org)
70
+ except UnknownObjectException:
71
+ ret["membership_state"] = "nonexistent"
72
+ ret["in_org"] = False
73
+ return ret
74
+
75
+ ret["in_org"] = org.has_in_members(user)
76
+ ret["membership_state"] = membership.state
77
+
78
+ return ret
79
+
80
+
81
+ @api_request
82
+ def invite(conn, login, *, owner=None):
83
+ """
84
+ Invite a user into the organization. Returns whether the resulting
85
+ membership state is ``pending``.
86
+
87
+ conn
88
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
89
+
90
+ login
91
+ User handle to invite.
92
+
93
+ owner
94
+ Organization to target. Defaults to the connection's owner.
95
+
96
+ Raises :class:`~saltext.github.utils.gh.exceptions.GitHubNotFoundError`
97
+ if the user does not exist.
98
+ """
99
+ user = conn.client.get_user(login)
100
+
101
+ # There is no public method that also returns the resulting membership state
102
+ _, data = conn.client.requester.requestJsonAndCheck(
103
+ "PUT", conn.get_org(owner).url + "/memberships/" + user.login
104
+ )
105
+
106
+ return data.get("state") == "pending"
107
+
108
+
109
+ @api_request
110
+ def remove(conn, login, *, owner=None):
111
+ """
112
+ Remove a user from the organization (if they are a member).
113
+
114
+ conn
115
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
116
+
117
+ login
118
+ User handle to remove.
119
+
120
+ owner
121
+ Organization to target. Defaults to the connection's owner.
122
+
123
+ Raises :class:`~saltext.github.utils.gh.exceptions.GitHubNotFoundError`
124
+ if the user does not exist.
125
+ """
126
+ user = conn.client.get_user(login)
127
+
128
+ org = conn.get_org(owner)
129
+ if org.has_in_members(user):
130
+ org.remove_from_members(user)
131
+
132
+ return True
133
+
134
+
135
+ @api_request
136
+ def list_without_mfa(conn, *, owner=None, ignore_cache=False):
137
+ """
138
+ Return the logins (lowercase) of all organization members without
139
+ MFA turned on (cached).
140
+
141
+ conn
142
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
143
+
144
+ owner
145
+ Organization to target. Defaults to the connection's owner.
146
+
147
+ ignore_cache
148
+ Bypass the cached member list.
149
+ """
150
+ owner = owner or conn.owner
151
+ key = ("members_without_mfa", owner.lower())
152
+ if key not in conn.cache or ignore_cache:
153
+ conn.cache[key] = [
154
+ member.login.lower()
155
+ for member in conn.get_org(owner).get_members(filter_="2fa_disabled")
156
+ ]
157
+ return conn.cache[key]
@@ -0,0 +1,122 @@
1
+ """
2
+ Operations on GitHub repository milestones.
3
+ """
4
+
5
+ import logging
6
+
7
+ from saltext.github.utils.gh.exceptions import GitHubNotFoundError
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ def get(conn, repo_name, number, *, owner=None):
13
+ """
14
+ Return the raw data of a single milestone.
15
+
16
+ conn
17
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
18
+
19
+ repo_name
20
+ Repository the milestone belongs to.
21
+
22
+ number
23
+ Milestone number to retrieve.
24
+
25
+ owner
26
+ Owner of the repository. Defaults to the connection's owner.
27
+ """
28
+ return conn.repo_query(owner, repo_name, "milestones", str(number))
29
+
30
+
31
+ def list_all(
32
+ conn,
33
+ repo_name,
34
+ *,
35
+ state="open",
36
+ sort="due_on",
37
+ direction="asc",
38
+ per_page=None,
39
+ owner=None,
40
+ ):
41
+ """
42
+ Return the raw data of all milestones in a repository matching the
43
+ search options.
44
+
45
+ conn
46
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
47
+
48
+ repo_name
49
+ Repository whose milestones to list.
50
+
51
+ state
52
+ Filter milestones by their state. Either ``open``, ``closed``,
53
+ or ``all``. Default is ``open``.
54
+
55
+ sort
56
+ Field to sort results by. Either ``due_on`` or ``completeness``.
57
+ Default is ``due_on``.
58
+
59
+ direction
60
+ Sort direction. Either ``asc`` or ``desc``. Default is ``asc``.
61
+
62
+ per_page
63
+ Pagination size, maximum 100.
64
+
65
+ owner
66
+ Owner of the repository. Defaults to the connection's owner.
67
+ """
68
+ params = {}
69
+
70
+ if per_page:
71
+ params["per_page"] = per_page
72
+
73
+ # Only pass the following API args if they're not the defaults listed.
74
+ if state and state != "open":
75
+ params["state"] = state
76
+ if sort and sort != "due_on":
77
+ params["sort"] = sort
78
+ if direction and direction != "asc":
79
+ params["direction"] = direction
80
+
81
+ return conn.repo_query(owner, repo_name, "milestones", params=params)
82
+
83
+
84
+ def find_by_title(conn, repo_name, title, *, owner=None):
85
+ """
86
+ Return a milestone by its title. Since the GitHub API only addresses
87
+ milestones by number, this searches the complete list.
88
+
89
+ conn
90
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
91
+
92
+ repo_name
93
+ Name of the repository the milestone is part of.
94
+
95
+ title
96
+ Title of the milestone.
97
+
98
+ owner
99
+ Owner of the repository. Defaults to the connection's owner.
100
+
101
+ Raises :class:`~saltext.github.utils.gh.exceptions.GitHubNotFoundError`
102
+ if no milestone carries the title.
103
+ """
104
+ milestones = list_all(conn, repo_name, state="all", owner=owner)
105
+ for milestone in milestones or []:
106
+ if milestone.get("title") == title:
107
+ return milestone
108
+ raise GitHubNotFoundError(f"Milestone {title} was not found in repository {repo_name}.")
109
+
110
+
111
+ def format_milestone(milestone):
112
+ """
113
+ Trim milestone data to the fields that are useful in (CLI) output.
114
+
115
+ milestone
116
+ Milestone to format.
117
+ """
118
+ return {
119
+ key: value
120
+ for key, value in milestone.items()
121
+ if key not in ("creator", "html_url", "labels_url")
122
+ }