saltext.github 1.0.0__py2.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.
- saltext/github/__init__.py +28 -0
- saltext/github/modules/__init__.py +0 -0
- saltext/github/modules/github.py +2195 -0
- saltext/github/states/__init__.py +0 -0
- saltext/github/states/github.py +930 -0
- saltext/github/utils/__init__.py +0 -0
- saltext/github/utils/github.py +64 -0
- saltext/github/version.py +1 -0
- saltext.github-1.0.0.dist-info/LICENSE +201 -0
- saltext.github-1.0.0.dist-info/METADATA +142 -0
- saltext.github-1.0.0.dist-info/NOTICE +10 -0
- saltext.github-1.0.0.dist-info/RECORD +15 -0
- saltext.github-1.0.0.dist-info/WHEEL +6 -0
- saltext.github-1.0.0.dist-info/entry_points.txt +2 -0
- saltext.github-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,2195 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Module for interacting with the GitHub v3 API.
|
|
3
|
+
|
|
4
|
+
.. versionadded:: 2016.3.0
|
|
5
|
+
|
|
6
|
+
:depends: PyGithub python module
|
|
7
|
+
|
|
8
|
+
Configuration
|
|
9
|
+
-------------
|
|
10
|
+
|
|
11
|
+
Configure this module by specifying the name of a configuration
|
|
12
|
+
profile in the minion config, minion pillar, or master config. The module
|
|
13
|
+
will use the 'github' key by default, if defined.
|
|
14
|
+
|
|
15
|
+
For example:
|
|
16
|
+
|
|
17
|
+
.. code-block:: yaml
|
|
18
|
+
|
|
19
|
+
github:
|
|
20
|
+
token: abc1234
|
|
21
|
+
org_name: my_organization
|
|
22
|
+
|
|
23
|
+
# optional: some functions require a repo_name, which
|
|
24
|
+
# can be set in the config file, or passed in at the CLI.
|
|
25
|
+
repo_name: my_repo
|
|
26
|
+
|
|
27
|
+
# optional: it can be dangerous to change the privacy of a repository
|
|
28
|
+
# in an automated way. set this to True to allow privacy modifications
|
|
29
|
+
allow_repo_privacy_changes: False
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import logging
|
|
33
|
+
|
|
34
|
+
import salt.utils.http
|
|
35
|
+
import salt.utils.json
|
|
36
|
+
from salt.exceptions import CommandExecutionError
|
|
37
|
+
|
|
38
|
+
HAS_LIBS = False
|
|
39
|
+
try:
|
|
40
|
+
# pylint: disable=no-name-in-module
|
|
41
|
+
import github
|
|
42
|
+
import github.NamedUser
|
|
43
|
+
import github.PaginatedList
|
|
44
|
+
from github.GithubException import UnknownObjectException
|
|
45
|
+
|
|
46
|
+
# pylint: enable=no-name-in-module
|
|
47
|
+
HAS_LIBS = True
|
|
48
|
+
except ImportError:
|
|
49
|
+
pass
|
|
50
|
+
|
|
51
|
+
log = logging.getLogger(__name__)
|
|
52
|
+
|
|
53
|
+
__virtualname__ = "github"
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def __virtual__():
|
|
57
|
+
"""
|
|
58
|
+
Only load this module if PyGithub is installed on this minion.
|
|
59
|
+
"""
|
|
60
|
+
if HAS_LIBS:
|
|
61
|
+
return __virtualname__
|
|
62
|
+
return (
|
|
63
|
+
False,
|
|
64
|
+
"The github execution module cannot be loaded: PyGithub library is not installed.",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _get_config_value(profile, config_name):
|
|
69
|
+
"""
|
|
70
|
+
Helper function that returns a profile's configuration value based on
|
|
71
|
+
the supplied configuration name.
|
|
72
|
+
|
|
73
|
+
profile
|
|
74
|
+
The profile name that contains configuration information.
|
|
75
|
+
|
|
76
|
+
config_name
|
|
77
|
+
The configuration item's name to use to return configuration values.
|
|
78
|
+
"""
|
|
79
|
+
config = __salt__["config.option"](profile)
|
|
80
|
+
if not config:
|
|
81
|
+
raise CommandExecutionError(
|
|
82
|
+
f"Authentication information could not be found for the '{profile}' profile."
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
config_value = config.get(config_name)
|
|
86
|
+
if config_value is None:
|
|
87
|
+
raise CommandExecutionError(
|
|
88
|
+
f"The '{config_name}' parameter was not found in the '{profile}' profile."
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
return config_value
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _get_client(profile):
|
|
95
|
+
"""
|
|
96
|
+
Return the GitHub client, cached into __context__ for performance
|
|
97
|
+
"""
|
|
98
|
+
token = _get_config_value(profile, "token")
|
|
99
|
+
key = "github.{}:{}".format( # pylint: disable=consider-using-f-string
|
|
100
|
+
token, _get_config_value(profile, "org_name")
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
if key not in __context__:
|
|
104
|
+
__context__[key] = github.Github(token, per_page=100)
|
|
105
|
+
return __context__[key]
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _get_members(organization, params=None):
|
|
109
|
+
return github.PaginatedList.PaginatedList(
|
|
110
|
+
github.NamedUser.NamedUser,
|
|
111
|
+
organization._requester,
|
|
112
|
+
organization.url + "/members",
|
|
113
|
+
params,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def _get_repos(profile, params=None, ignore_cache=False):
|
|
118
|
+
# Use cache when no params are given
|
|
119
|
+
org_name = _get_config_value(profile, "org_name")
|
|
120
|
+
key = f"github.{org_name}:repos"
|
|
121
|
+
|
|
122
|
+
if key not in __context__ or ignore_cache or params is not None:
|
|
123
|
+
org_name = _get_config_value(profile, "org_name")
|
|
124
|
+
client = _get_client(profile)
|
|
125
|
+
organization = client.get_organization(org_name)
|
|
126
|
+
|
|
127
|
+
result = github.PaginatedList.PaginatedList(
|
|
128
|
+
github.Repository.Repository,
|
|
129
|
+
organization._requester,
|
|
130
|
+
organization.url + "/repos",
|
|
131
|
+
params,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Only cache results if no params were given (full scan)
|
|
135
|
+
if params is not None:
|
|
136
|
+
return result
|
|
137
|
+
|
|
138
|
+
next_result = []
|
|
139
|
+
|
|
140
|
+
for repo in result:
|
|
141
|
+
next_result.append(repo)
|
|
142
|
+
|
|
143
|
+
# Cache a copy of each repo for single lookups
|
|
144
|
+
repo_key = f"github.{org_name}:{repo.name.lower()}:repo_info"
|
|
145
|
+
__context__[repo_key] = _repo_to_dict(repo)
|
|
146
|
+
|
|
147
|
+
__context__[key] = next_result
|
|
148
|
+
|
|
149
|
+
return __context__[key]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def list_users(profile="github", ignore_cache=False):
|
|
153
|
+
"""
|
|
154
|
+
List all users within the organization.
|
|
155
|
+
|
|
156
|
+
profile
|
|
157
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
158
|
+
|
|
159
|
+
ignore_cache
|
|
160
|
+
Bypasses the use of cached users.
|
|
161
|
+
|
|
162
|
+
.. versionadded:: 2016.11.0
|
|
163
|
+
|
|
164
|
+
CLI Example:
|
|
165
|
+
|
|
166
|
+
.. code-block:: bash
|
|
167
|
+
|
|
168
|
+
salt myminion github.list_users
|
|
169
|
+
salt myminion github.list_users profile='my-github-profile'
|
|
170
|
+
"""
|
|
171
|
+
org_name = _get_config_value(profile, "org_name")
|
|
172
|
+
key = f"github.{org_name}:users"
|
|
173
|
+
if key not in __context__ or ignore_cache:
|
|
174
|
+
client = _get_client(profile)
|
|
175
|
+
organization = client.get_organization(org_name)
|
|
176
|
+
__context__[key] = [member.login for member in _get_members(organization, None)]
|
|
177
|
+
return __context__[key]
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def get_user(name, profile="github", user_details=False):
|
|
181
|
+
"""
|
|
182
|
+
Get a GitHub user by name.
|
|
183
|
+
|
|
184
|
+
name
|
|
185
|
+
The user for which to obtain information.
|
|
186
|
+
|
|
187
|
+
profile
|
|
188
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
189
|
+
|
|
190
|
+
user_details
|
|
191
|
+
Prints user information details. Defaults to ``False``. If the user is
|
|
192
|
+
already in the organization and user_details is set to False, the
|
|
193
|
+
get_user function returns ``True``. If the user is not already present
|
|
194
|
+
in the organization, user details will be printed by default.
|
|
195
|
+
|
|
196
|
+
CLI Example:
|
|
197
|
+
|
|
198
|
+
.. code-block:: bash
|
|
199
|
+
|
|
200
|
+
salt myminion github.get_user github-handle
|
|
201
|
+
salt myminion github.get_user github-handle user_details=true
|
|
202
|
+
|
|
203
|
+
"""
|
|
204
|
+
|
|
205
|
+
if not user_details and name in list_users(profile):
|
|
206
|
+
# User is in the org, no need for additional Data
|
|
207
|
+
return True
|
|
208
|
+
|
|
209
|
+
response = {}
|
|
210
|
+
client = _get_client(profile)
|
|
211
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
user = client.get_user(name)
|
|
215
|
+
except UnknownObjectException:
|
|
216
|
+
log.exception("Resource not found")
|
|
217
|
+
return False
|
|
218
|
+
|
|
219
|
+
response["company"] = user.company
|
|
220
|
+
response["created_at"] = user.created_at
|
|
221
|
+
response["email"] = user.email
|
|
222
|
+
response["html_url"] = user.html_url
|
|
223
|
+
response["id"] = user.id
|
|
224
|
+
response["login"] = user.login
|
|
225
|
+
response["name"] = user.name
|
|
226
|
+
response["type"] = user.type
|
|
227
|
+
response["url"] = user.url
|
|
228
|
+
|
|
229
|
+
try:
|
|
230
|
+
headers, data = organization._requester.requestJsonAndCheck(
|
|
231
|
+
"GET", organization.url + "/memberships/" + user._identity
|
|
232
|
+
)
|
|
233
|
+
except UnknownObjectException:
|
|
234
|
+
response["membership_state"] = "nonexistent"
|
|
235
|
+
response["in_org"] = False
|
|
236
|
+
return response
|
|
237
|
+
|
|
238
|
+
response["in_org"] = organization.has_in_members(user)
|
|
239
|
+
response["membership_state"] = data.get("state")
|
|
240
|
+
|
|
241
|
+
return response
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def add_user(name, profile="github"):
|
|
245
|
+
"""
|
|
246
|
+
Add a GitHub user.
|
|
247
|
+
|
|
248
|
+
name
|
|
249
|
+
The user for which to obtain information.
|
|
250
|
+
|
|
251
|
+
profile
|
|
252
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
253
|
+
|
|
254
|
+
CLI Example:
|
|
255
|
+
|
|
256
|
+
.. code-block:: bash
|
|
257
|
+
|
|
258
|
+
salt myminion github.add_user github-handle
|
|
259
|
+
"""
|
|
260
|
+
|
|
261
|
+
client = _get_client(profile)
|
|
262
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
263
|
+
|
|
264
|
+
try:
|
|
265
|
+
github_named_user = client.get_user(name)
|
|
266
|
+
except UnknownObjectException:
|
|
267
|
+
log.exception("Resource not found")
|
|
268
|
+
return False
|
|
269
|
+
|
|
270
|
+
headers, data = organization._requester.requestJsonAndCheck(
|
|
271
|
+
"PUT", organization.url + "/memberships/" + github_named_user._identity
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
return data.get("state") == "pending"
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
def remove_user(name, profile="github"):
|
|
278
|
+
"""
|
|
279
|
+
Remove a Github user by name.
|
|
280
|
+
|
|
281
|
+
name
|
|
282
|
+
The user for which to obtain information.
|
|
283
|
+
|
|
284
|
+
profile
|
|
285
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
286
|
+
|
|
287
|
+
CLI Example:
|
|
288
|
+
|
|
289
|
+
.. code-block:: bash
|
|
290
|
+
|
|
291
|
+
salt myminion github.remove_user github-handle
|
|
292
|
+
"""
|
|
293
|
+
|
|
294
|
+
client = _get_client(profile)
|
|
295
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
296
|
+
|
|
297
|
+
try:
|
|
298
|
+
git_user = client.get_user(name)
|
|
299
|
+
except UnknownObjectException:
|
|
300
|
+
log.exception("Resource not found")
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
if organization.has_in_members(git_user):
|
|
304
|
+
organization.remove_from_members(git_user)
|
|
305
|
+
|
|
306
|
+
return not organization.has_in_members(git_user)
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def get_issue(issue_number, repo_name=None, profile="github", output="min"):
|
|
310
|
+
"""
|
|
311
|
+
Return information about a single issue in a named repository.
|
|
312
|
+
|
|
313
|
+
.. versionadded:: 2016.11.0
|
|
314
|
+
|
|
315
|
+
issue_number
|
|
316
|
+
The number of the issue to retrieve.
|
|
317
|
+
|
|
318
|
+
repo_name
|
|
319
|
+
The name of the repository from which to get the issue. This argument is
|
|
320
|
+
required, either passed via the CLI, or defined in the configured
|
|
321
|
+
profile. A ``repo_name`` passed as a CLI argument will override the
|
|
322
|
+
repo_name defined in the configured profile, if provided.
|
|
323
|
+
|
|
324
|
+
profile
|
|
325
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
326
|
+
|
|
327
|
+
output
|
|
328
|
+
The amount of data returned by each issue. Defaults to ``min``. Change
|
|
329
|
+
to ``full`` to see all issue output.
|
|
330
|
+
|
|
331
|
+
CLI Example:
|
|
332
|
+
|
|
333
|
+
.. code-block:: bash
|
|
334
|
+
|
|
335
|
+
salt myminion github.get_issue 514
|
|
336
|
+
salt myminion github.get_issue 514 repo_name=salt
|
|
337
|
+
"""
|
|
338
|
+
org_name = _get_config_value(profile, "org_name")
|
|
339
|
+
if repo_name is None:
|
|
340
|
+
repo_name = _get_config_value(profile, "repo_name")
|
|
341
|
+
|
|
342
|
+
action = "/".join(["repos", org_name, repo_name])
|
|
343
|
+
command = "issues/" + str(issue_number)
|
|
344
|
+
|
|
345
|
+
ret = {}
|
|
346
|
+
issue_data = _query(profile, action=action, command=command)
|
|
347
|
+
|
|
348
|
+
issue_id = issue_data.get("dict", {}).get("id")
|
|
349
|
+
|
|
350
|
+
if issue_id:
|
|
351
|
+
if output.lower() == "full":
|
|
352
|
+
ret[issue_id] = issue_data["dict"]
|
|
353
|
+
else:
|
|
354
|
+
ret[issue_id] = _format_issue(issue_data["dict"])
|
|
355
|
+
|
|
356
|
+
return ret
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def get_issue_comments(issue_number, repo_name=None, profile="github", since=None, output="min"):
|
|
360
|
+
"""
|
|
361
|
+
Return information about the comments for a given issue in a named repository.
|
|
362
|
+
|
|
363
|
+
.. versionadded:: 2016.11.0
|
|
364
|
+
|
|
365
|
+
issue_number
|
|
366
|
+
The number of the issue for which to retrieve comments.
|
|
367
|
+
|
|
368
|
+
repo_name
|
|
369
|
+
The name of the repository to which the issue belongs. This argument is
|
|
370
|
+
required, either passed via the CLI, or defined in the configured
|
|
371
|
+
profile. A ``repo_name`` passed as a CLI argument will override the
|
|
372
|
+
repo_name defined in the configured profile, if provided.
|
|
373
|
+
|
|
374
|
+
profile
|
|
375
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
376
|
+
|
|
377
|
+
since
|
|
378
|
+
Only comments updated at or after this time are returned. This is a
|
|
379
|
+
timestamp in ISO 8601 format: ``YYYY-MM-DDTHH:MM:SSZ``.
|
|
380
|
+
|
|
381
|
+
output
|
|
382
|
+
The amount of data returned by each issue. Defaults to ``min``. Change
|
|
383
|
+
to ``full`` to see all issue output.
|
|
384
|
+
|
|
385
|
+
CLI Example:
|
|
386
|
+
|
|
387
|
+
.. code-block:: bash
|
|
388
|
+
|
|
389
|
+
salt myminion github.get_issue_comments 514
|
|
390
|
+
salt myminion github.get_issue 514 repo_name=salt
|
|
391
|
+
"""
|
|
392
|
+
org_name = _get_config_value(profile, "org_name")
|
|
393
|
+
if repo_name is None:
|
|
394
|
+
repo_name = _get_config_value(profile, "repo_name")
|
|
395
|
+
|
|
396
|
+
action = "/".join(["repos", org_name, repo_name])
|
|
397
|
+
command = "/".join(["issues", str(issue_number), "comments"])
|
|
398
|
+
|
|
399
|
+
args = {}
|
|
400
|
+
if since:
|
|
401
|
+
args["since"] = since
|
|
402
|
+
|
|
403
|
+
comments = _query(profile, action=action, command=command, args=args)
|
|
404
|
+
|
|
405
|
+
ret = {}
|
|
406
|
+
for comment in comments.get("dict", {}):
|
|
407
|
+
comment_id = comment.get("id")
|
|
408
|
+
if output == "full":
|
|
409
|
+
ret[comment_id] = comment
|
|
410
|
+
else:
|
|
411
|
+
ret[comment_id] = {
|
|
412
|
+
"id": comment.get("id"),
|
|
413
|
+
"created_at": comment.get("created_at"),
|
|
414
|
+
"updated_at": comment.get("updated_at"),
|
|
415
|
+
"user_login": comment.get("user").get("login"),
|
|
416
|
+
}
|
|
417
|
+
return ret
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
def get_issues(
|
|
421
|
+
repo_name=None,
|
|
422
|
+
profile="github",
|
|
423
|
+
milestone=None,
|
|
424
|
+
state="open",
|
|
425
|
+
assignee=None,
|
|
426
|
+
creator=None,
|
|
427
|
+
mentioned=None,
|
|
428
|
+
labels=None,
|
|
429
|
+
sort="created",
|
|
430
|
+
direction="desc",
|
|
431
|
+
since=None,
|
|
432
|
+
output="min",
|
|
433
|
+
per_page=None,
|
|
434
|
+
):
|
|
435
|
+
"""
|
|
436
|
+
Returns information for all issues in a given repository, based on the search options.
|
|
437
|
+
|
|
438
|
+
.. versionadded:: 2016.11.0
|
|
439
|
+
|
|
440
|
+
repo_name
|
|
441
|
+
The name of the repository for which to list issues. This argument is
|
|
442
|
+
required, either passed via the CLI, or defined in the configured
|
|
443
|
+
profile. A ``repo_name`` passed as a CLI argument will override the
|
|
444
|
+
repo_name defined in the configured profile, if provided.
|
|
445
|
+
|
|
446
|
+
profile
|
|
447
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
448
|
+
|
|
449
|
+
milestone
|
|
450
|
+
The number of a GitHub milestone, or a string of either ``*`` or
|
|
451
|
+
``none``.
|
|
452
|
+
|
|
453
|
+
If a number is passed, it should refer to a milestone by its number
|
|
454
|
+
field. Use the ``github.get_milestone`` function to obtain a milestone's
|
|
455
|
+
number.
|
|
456
|
+
|
|
457
|
+
If the string ``*`` is passed, issues with any milestone are
|
|
458
|
+
accepted. If the string ``none`` is passed, issues without milestones
|
|
459
|
+
are returned.
|
|
460
|
+
|
|
461
|
+
state
|
|
462
|
+
Indicates the state of the issues to return. Can be either ``open``,
|
|
463
|
+
``closed``, or ``all``. Default is ``open``.
|
|
464
|
+
|
|
465
|
+
assignee
|
|
466
|
+
Can be the name of a user. Pass in ``none`` (as a string) for issues
|
|
467
|
+
with no assigned user or ``*`` for issues assigned to any user.
|
|
468
|
+
|
|
469
|
+
creator
|
|
470
|
+
The user that created the issue.
|
|
471
|
+
|
|
472
|
+
mentioned
|
|
473
|
+
A user that's mentioned in the issue.
|
|
474
|
+
|
|
475
|
+
labels
|
|
476
|
+
A string of comma separated label names. For example, ``bug,ui,@high``.
|
|
477
|
+
|
|
478
|
+
sort
|
|
479
|
+
What to sort results by. Can be either ``created``, ``updated``, or
|
|
480
|
+
``comments``. Default is ``created``.
|
|
481
|
+
|
|
482
|
+
direction
|
|
483
|
+
The direction of the sort. Can be either ``asc`` or ``desc``. Default
|
|
484
|
+
is ``desc``.
|
|
485
|
+
|
|
486
|
+
since
|
|
487
|
+
Only issues updated at or after this time are returned. This is a
|
|
488
|
+
timestamp in ISO 8601 format: ``YYYY-MM-DDTHH:MM:SSZ``.
|
|
489
|
+
|
|
490
|
+
output
|
|
491
|
+
The amount of data returned by each issue. Defaults to ``min``. Change
|
|
492
|
+
to ``full`` to see all issue output.
|
|
493
|
+
|
|
494
|
+
per_page
|
|
495
|
+
GitHub paginates data in their API calls. Use this value to increase or
|
|
496
|
+
decrease the number of issues gathered from GitHub, per page. If not set,
|
|
497
|
+
GitHub defaults are used. Maximum is 100.
|
|
498
|
+
|
|
499
|
+
CLI Example:
|
|
500
|
+
|
|
501
|
+
.. code-block:: bash
|
|
502
|
+
|
|
503
|
+
salt myminion github.get_issues my-github-repo
|
|
504
|
+
"""
|
|
505
|
+
org_name = _get_config_value(profile, "org_name")
|
|
506
|
+
if repo_name is None:
|
|
507
|
+
repo_name = _get_config_value(profile, "repo_name")
|
|
508
|
+
|
|
509
|
+
action = "/".join(["repos", org_name, repo_name])
|
|
510
|
+
args = {}
|
|
511
|
+
|
|
512
|
+
# Build API arguments, as necessary.
|
|
513
|
+
if milestone:
|
|
514
|
+
args["milestone"] = milestone
|
|
515
|
+
if assignee:
|
|
516
|
+
args["assignee"] = assignee
|
|
517
|
+
if creator:
|
|
518
|
+
args["creator"] = creator
|
|
519
|
+
if mentioned:
|
|
520
|
+
args["mentioned"] = mentioned
|
|
521
|
+
if labels:
|
|
522
|
+
args["labels"] = labels
|
|
523
|
+
if since:
|
|
524
|
+
args["since"] = since
|
|
525
|
+
if per_page:
|
|
526
|
+
args["per_page"] = per_page
|
|
527
|
+
|
|
528
|
+
# Only pass the following API args if they're not the defaults listed.
|
|
529
|
+
if state and state != "open":
|
|
530
|
+
args["state"] = state
|
|
531
|
+
if sort and sort != "created":
|
|
532
|
+
args["sort"] = sort
|
|
533
|
+
if direction and direction != "desc":
|
|
534
|
+
args["direction"] = direction
|
|
535
|
+
|
|
536
|
+
ret = {}
|
|
537
|
+
issues = _query(profile, action=action, command="issues", args=args)
|
|
538
|
+
|
|
539
|
+
for issue in issues.get("dict", {}):
|
|
540
|
+
# Pull requests are included in the issue list from GitHub
|
|
541
|
+
# Let's not include those in the return.
|
|
542
|
+
if issue.get("pull_request"):
|
|
543
|
+
continue
|
|
544
|
+
issue_id = issue.get("id")
|
|
545
|
+
if output == "full":
|
|
546
|
+
ret[issue_id] = issue
|
|
547
|
+
else:
|
|
548
|
+
ret[issue_id] = _format_issue(issue)
|
|
549
|
+
|
|
550
|
+
return ret
|
|
551
|
+
|
|
552
|
+
|
|
553
|
+
def get_milestones(
|
|
554
|
+
repo_name=None,
|
|
555
|
+
profile="github",
|
|
556
|
+
state="open",
|
|
557
|
+
sort="due_on",
|
|
558
|
+
direction="asc",
|
|
559
|
+
output="min",
|
|
560
|
+
per_page=None,
|
|
561
|
+
):
|
|
562
|
+
"""
|
|
563
|
+
Return information about milestones for a given repository.
|
|
564
|
+
|
|
565
|
+
.. versionadded:: 2016.11.0
|
|
566
|
+
|
|
567
|
+
repo_name
|
|
568
|
+
The name of the repository for which to list issues. This argument is
|
|
569
|
+
required, either passed via the CLI, or defined in the configured
|
|
570
|
+
profile. A ``repo_name`` passed as a CLI argument will override the
|
|
571
|
+
repo_name defined in the configured profile, if provided.
|
|
572
|
+
|
|
573
|
+
profile
|
|
574
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
575
|
+
|
|
576
|
+
state
|
|
577
|
+
The state of the milestone. Either ``open``, ``closed``, or ``all``.
|
|
578
|
+
Default is ``open``.
|
|
579
|
+
|
|
580
|
+
sort
|
|
581
|
+
What to sort results by. Either ``due_on`` or ``completeness``. Default
|
|
582
|
+
is ``due_on``.
|
|
583
|
+
|
|
584
|
+
direction
|
|
585
|
+
The direction of the sort. Either ``asc`` or ``desc``. Default is ``asc``.
|
|
586
|
+
|
|
587
|
+
output
|
|
588
|
+
The amount of data returned by each issue. Defaults to ``min``. Change
|
|
589
|
+
to ``full`` to see all issue output.
|
|
590
|
+
|
|
591
|
+
per_page
|
|
592
|
+
GitHub paginates data in their API calls. Use this value to increase or
|
|
593
|
+
decrease the number of issues gathered from GitHub, per page. If not set,
|
|
594
|
+
GitHub defaults are used.
|
|
595
|
+
|
|
596
|
+
CLI Example:
|
|
597
|
+
|
|
598
|
+
.. code-block:: bash
|
|
599
|
+
|
|
600
|
+
salt myminion github.get_milestones
|
|
601
|
+
|
|
602
|
+
"""
|
|
603
|
+
org_name = _get_config_value(profile, "org_name")
|
|
604
|
+
if repo_name is None:
|
|
605
|
+
repo_name = _get_config_value(profile, "repo_name")
|
|
606
|
+
|
|
607
|
+
action = "/".join(["repos", org_name, repo_name])
|
|
608
|
+
args = {}
|
|
609
|
+
|
|
610
|
+
if per_page:
|
|
611
|
+
args["per_page"] = per_page
|
|
612
|
+
|
|
613
|
+
# Only pass the following API args if they're not the defaults listed.
|
|
614
|
+
if state and state != "open":
|
|
615
|
+
args["state"] = state
|
|
616
|
+
if sort and sort != "due_on":
|
|
617
|
+
args["sort"] = sort
|
|
618
|
+
if direction and direction != "asc":
|
|
619
|
+
args["direction"] = direction
|
|
620
|
+
|
|
621
|
+
ret = {}
|
|
622
|
+
milestones = _query(profile, action=action, command="milestones", args=args)
|
|
623
|
+
|
|
624
|
+
for milestone in milestones.get("dict", {}):
|
|
625
|
+
milestone_id = milestone.get("id")
|
|
626
|
+
if output == "full":
|
|
627
|
+
ret[milestone_id] = milestone
|
|
628
|
+
else:
|
|
629
|
+
milestone.pop("creator")
|
|
630
|
+
milestone.pop("html_url")
|
|
631
|
+
milestone.pop("labels_url")
|
|
632
|
+
ret[milestone_id] = milestone
|
|
633
|
+
|
|
634
|
+
return ret
|
|
635
|
+
|
|
636
|
+
|
|
637
|
+
def get_milestone(number=None, name=None, repo_name=None, profile="github", output="min"):
|
|
638
|
+
"""
|
|
639
|
+
Return information about a single milestone in a named repository.
|
|
640
|
+
|
|
641
|
+
.. versionadded:: 2016.11.0
|
|
642
|
+
|
|
643
|
+
number
|
|
644
|
+
The number of the milestone to retrieve. If provided, this option
|
|
645
|
+
will be favored over ``name``.
|
|
646
|
+
|
|
647
|
+
name
|
|
648
|
+
The name of the milestone to retrieve.
|
|
649
|
+
|
|
650
|
+
repo_name
|
|
651
|
+
The name of the repository for which to list issues. This argument is
|
|
652
|
+
required, either passed via the CLI, or defined in the configured
|
|
653
|
+
profile. A ``repo_name`` passed as a CLI argument will override the
|
|
654
|
+
repo_name defined in the configured profile, if provided.
|
|
655
|
+
|
|
656
|
+
profile
|
|
657
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
658
|
+
|
|
659
|
+
output
|
|
660
|
+
The amount of data returned by each issue. Defaults to ``min``. Change
|
|
661
|
+
to ``full`` to see all issue output.
|
|
662
|
+
|
|
663
|
+
CLI Example:
|
|
664
|
+
|
|
665
|
+
.. code-block:: bash
|
|
666
|
+
|
|
667
|
+
salt myminion github.get_milestone 72
|
|
668
|
+
salt myminion github.get_milestone name=my_milestone
|
|
669
|
+
|
|
670
|
+
"""
|
|
671
|
+
ret = {}
|
|
672
|
+
|
|
673
|
+
if not any([number, name]):
|
|
674
|
+
raise CommandExecutionError("Either a milestone 'name' or 'number' must be provided.")
|
|
675
|
+
|
|
676
|
+
org_name = _get_config_value(profile, "org_name")
|
|
677
|
+
if repo_name is None:
|
|
678
|
+
repo_name = _get_config_value(profile, "repo_name")
|
|
679
|
+
|
|
680
|
+
action = "/".join(["repos", org_name, repo_name])
|
|
681
|
+
if number:
|
|
682
|
+
command = "milestones/" + str(number)
|
|
683
|
+
milestone_data = _query(profile, action=action, command=command)
|
|
684
|
+
milestone_data = milestone_data.get("dict", {})
|
|
685
|
+
milestone_id = milestone_data.get("id")
|
|
686
|
+
if milestone_id:
|
|
687
|
+
if output.lower() == "full":
|
|
688
|
+
ret[milestone_id] = milestone_data
|
|
689
|
+
else:
|
|
690
|
+
milestone_data.pop("creator")
|
|
691
|
+
milestone_data.pop("html_url")
|
|
692
|
+
milestone_data.pop("labels_url")
|
|
693
|
+
ret[milestone_id] = milestone_data
|
|
694
|
+
return ret
|
|
695
|
+
|
|
696
|
+
else:
|
|
697
|
+
milestones = get_milestones(repo_name=repo_name, profile=profile, output=output)
|
|
698
|
+
for key, val in milestones.items():
|
|
699
|
+
if val.get("title") == name:
|
|
700
|
+
ret[key] = val
|
|
701
|
+
return ret
|
|
702
|
+
|
|
703
|
+
return ret
|
|
704
|
+
|
|
705
|
+
|
|
706
|
+
def _repo_to_dict(repo):
|
|
707
|
+
ret = {}
|
|
708
|
+
ret["id"] = repo.id
|
|
709
|
+
ret["name"] = repo.name
|
|
710
|
+
ret["full_name"] = repo.full_name
|
|
711
|
+
ret["owner"] = repo.owner.login
|
|
712
|
+
ret["private"] = repo.private
|
|
713
|
+
ret["html_url"] = repo.html_url
|
|
714
|
+
ret["description"] = repo.description
|
|
715
|
+
ret["fork"] = repo.fork
|
|
716
|
+
ret["homepage"] = repo.homepage
|
|
717
|
+
ret["size"] = repo.size
|
|
718
|
+
ret["stargazers_count"] = repo.stargazers_count
|
|
719
|
+
ret["watchers_count"] = repo.watchers_count
|
|
720
|
+
ret["language"] = repo.language
|
|
721
|
+
ret["open_issues_count"] = repo.open_issues_count
|
|
722
|
+
ret["forks"] = repo.forks
|
|
723
|
+
ret["open_issues"] = repo.open_issues
|
|
724
|
+
ret["watchers"] = repo.watchers
|
|
725
|
+
ret["default_branch"] = repo.default_branch
|
|
726
|
+
ret["has_issues"] = repo.has_issues
|
|
727
|
+
ret["has_wiki"] = repo.has_wiki
|
|
728
|
+
ret["has_downloads"] = repo.has_downloads
|
|
729
|
+
return ret
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def get_repo_info(repo_name, profile="github", ignore_cache=False):
|
|
733
|
+
"""
|
|
734
|
+
Return information for a given repo.
|
|
735
|
+
|
|
736
|
+
.. versionadded:: 2016.11.0
|
|
737
|
+
|
|
738
|
+
repo_name
|
|
739
|
+
The name of the repository.
|
|
740
|
+
|
|
741
|
+
profile
|
|
742
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
743
|
+
|
|
744
|
+
CLI Example:
|
|
745
|
+
|
|
746
|
+
.. code-block:: bash
|
|
747
|
+
|
|
748
|
+
salt myminion github.get_repo_info salt
|
|
749
|
+
salt myminion github.get_repo_info salt profile='my-github-profile'
|
|
750
|
+
"""
|
|
751
|
+
|
|
752
|
+
org_name = _get_config_value(profile, "org_name")
|
|
753
|
+
key = "github.{}:{}:repo_info".format( # pylint: disable=consider-using-f-string
|
|
754
|
+
_get_config_value(profile, "org_name"), repo_name.lower()
|
|
755
|
+
)
|
|
756
|
+
|
|
757
|
+
if key not in __context__ or ignore_cache:
|
|
758
|
+
client = _get_client(profile)
|
|
759
|
+
try:
|
|
760
|
+
repo = client.get_repo("/".join([org_name, repo_name]))
|
|
761
|
+
if not repo:
|
|
762
|
+
return {}
|
|
763
|
+
|
|
764
|
+
# client.get_repo can return a github.Repository.Repository object,
|
|
765
|
+
# even if the repo is invalid. We need to catch the exception when
|
|
766
|
+
# we try to perform actions on the repo object, rather than above
|
|
767
|
+
# the if statement.
|
|
768
|
+
ret = _repo_to_dict(repo)
|
|
769
|
+
|
|
770
|
+
__context__[key] = ret
|
|
771
|
+
except github.UnknownObjectException as exc:
|
|
772
|
+
raise CommandExecutionError(
|
|
773
|
+
f"The '{repo_name}' repository under the '{org_name}' organization could not be found."
|
|
774
|
+
) from exc
|
|
775
|
+
return __context__[key]
|
|
776
|
+
|
|
777
|
+
|
|
778
|
+
def get_repo_teams(repo_name, profile="github"):
|
|
779
|
+
"""
|
|
780
|
+
Return teams belonging to a repository.
|
|
781
|
+
|
|
782
|
+
.. versionadded:: 2017.7.0
|
|
783
|
+
|
|
784
|
+
repo_name
|
|
785
|
+
The name of the repository from which to retrieve teams.
|
|
786
|
+
|
|
787
|
+
profile
|
|
788
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
789
|
+
|
|
790
|
+
CLI Example:
|
|
791
|
+
|
|
792
|
+
.. code-block:: bash
|
|
793
|
+
|
|
794
|
+
salt myminion github.get_repo_teams salt
|
|
795
|
+
salt myminion github.get_repo_teams salt profile='my-github-profile'
|
|
796
|
+
"""
|
|
797
|
+
ret = []
|
|
798
|
+
org_name = _get_config_value(profile, "org_name")
|
|
799
|
+
client = _get_client(profile)
|
|
800
|
+
|
|
801
|
+
try:
|
|
802
|
+
repo = client.get_repo("/".join([org_name, repo_name]))
|
|
803
|
+
except github.UnknownObjectException as exc:
|
|
804
|
+
raise CommandExecutionError(
|
|
805
|
+
f"The '{repo_name}' repository under the '{org_name}' organization could not be found."
|
|
806
|
+
) from exc
|
|
807
|
+
try:
|
|
808
|
+
teams = repo.get_teams()
|
|
809
|
+
for team in teams:
|
|
810
|
+
ret.append({"id": team.id, "name": team.name, "permission": team.permission})
|
|
811
|
+
except github.UnknownObjectException as exc:
|
|
812
|
+
raise CommandExecutionError(
|
|
813
|
+
f"Unable to retrieve teams for repository '{repo_name}' under the '{org_name}' organization."
|
|
814
|
+
) from exc
|
|
815
|
+
return ret
|
|
816
|
+
|
|
817
|
+
|
|
818
|
+
def list_repos(profile="github"):
|
|
819
|
+
"""
|
|
820
|
+
List all repositories within the organization. Includes public and private
|
|
821
|
+
repositories within the organization Dependent upon the access rights of
|
|
822
|
+
the profile token.
|
|
823
|
+
|
|
824
|
+
.. versionadded:: 2016.11.0
|
|
825
|
+
|
|
826
|
+
profile
|
|
827
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
828
|
+
|
|
829
|
+
CLI Example:
|
|
830
|
+
|
|
831
|
+
.. code-block:: bash
|
|
832
|
+
|
|
833
|
+
salt myminion github.list_repos
|
|
834
|
+
salt myminion github.list_repos profile='my-github-profile'
|
|
835
|
+
"""
|
|
836
|
+
return [repo.name for repo in _get_repos(profile)]
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
def list_private_repos(profile="github"):
|
|
840
|
+
"""
|
|
841
|
+
List private repositories within the organization. Dependent upon the access
|
|
842
|
+
rights of the profile token.
|
|
843
|
+
|
|
844
|
+
.. versionadded:: 2016.11.0
|
|
845
|
+
|
|
846
|
+
profile
|
|
847
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
848
|
+
|
|
849
|
+
CLI Example:
|
|
850
|
+
|
|
851
|
+
.. code-block:: bash
|
|
852
|
+
|
|
853
|
+
salt myminion github.list_private_repos
|
|
854
|
+
salt myminion github.list_private_repos profile='my-github-profile'
|
|
855
|
+
"""
|
|
856
|
+
repos = []
|
|
857
|
+
for repo in _get_repos(profile):
|
|
858
|
+
if repo.private is True:
|
|
859
|
+
repos.append(repo.name)
|
|
860
|
+
return repos
|
|
861
|
+
|
|
862
|
+
|
|
863
|
+
def list_public_repos(profile="github"):
|
|
864
|
+
"""
|
|
865
|
+
List public repositories within the organization.
|
|
866
|
+
|
|
867
|
+
.. versionadded:: 2016.11.0
|
|
868
|
+
|
|
869
|
+
profile
|
|
870
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
871
|
+
|
|
872
|
+
CLI Example:
|
|
873
|
+
|
|
874
|
+
.. code-block:: bash
|
|
875
|
+
|
|
876
|
+
salt myminion github.list_public_repos
|
|
877
|
+
salt myminion github.list_public_repos profile='my-github-profile'
|
|
878
|
+
"""
|
|
879
|
+
repos = []
|
|
880
|
+
for repo in _get_repos(profile):
|
|
881
|
+
if repo.private is False:
|
|
882
|
+
repos.append(repo.name)
|
|
883
|
+
return repos
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
def add_repo(
|
|
887
|
+
name,
|
|
888
|
+
description=None,
|
|
889
|
+
homepage=None,
|
|
890
|
+
private=None,
|
|
891
|
+
has_issues=None,
|
|
892
|
+
has_wiki=None,
|
|
893
|
+
has_downloads=None,
|
|
894
|
+
auto_init=None,
|
|
895
|
+
gitignore_template=None,
|
|
896
|
+
license_template=None,
|
|
897
|
+
profile="github",
|
|
898
|
+
):
|
|
899
|
+
"""
|
|
900
|
+
Create a new github repository.
|
|
901
|
+
|
|
902
|
+
name
|
|
903
|
+
The name of the team to be created.
|
|
904
|
+
|
|
905
|
+
description
|
|
906
|
+
The description of the repository.
|
|
907
|
+
|
|
908
|
+
homepage
|
|
909
|
+
The URL with more information about the repository.
|
|
910
|
+
|
|
911
|
+
private
|
|
912
|
+
The visiblity of the repository. Note that private repositories require
|
|
913
|
+
a paid GitHub account.
|
|
914
|
+
|
|
915
|
+
has_issues
|
|
916
|
+
Whether to enable issues for this repository.
|
|
917
|
+
|
|
918
|
+
has_wiki
|
|
919
|
+
Whether to enable the wiki for this repository.
|
|
920
|
+
|
|
921
|
+
has_downloads
|
|
922
|
+
Whether to enable downloads for this repository.
|
|
923
|
+
|
|
924
|
+
auto_init
|
|
925
|
+
Whether to create an initial commit with an empty README.
|
|
926
|
+
|
|
927
|
+
gitignore_template
|
|
928
|
+
The desired language or platform for a .gitignore, e.g "Haskell".
|
|
929
|
+
|
|
930
|
+
license_template
|
|
931
|
+
The desired LICENSE template to apply, e.g "mit" or "mozilla".
|
|
932
|
+
|
|
933
|
+
profile
|
|
934
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
935
|
+
|
|
936
|
+
CLI Example:
|
|
937
|
+
|
|
938
|
+
.. code-block:: bash
|
|
939
|
+
|
|
940
|
+
salt myminion github.add_repo 'repo_name'
|
|
941
|
+
|
|
942
|
+
.. versionadded:: 2016.11.0
|
|
943
|
+
"""
|
|
944
|
+
try:
|
|
945
|
+
client = _get_client(profile)
|
|
946
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
947
|
+
given_params = {
|
|
948
|
+
"description": description,
|
|
949
|
+
"homepage": homepage,
|
|
950
|
+
"private": private,
|
|
951
|
+
"has_issues": has_issues,
|
|
952
|
+
"has_wiki": has_wiki,
|
|
953
|
+
"has_downloads": has_downloads,
|
|
954
|
+
"auto_init": auto_init,
|
|
955
|
+
"gitignore_template": gitignore_template,
|
|
956
|
+
"license_template": license_template,
|
|
957
|
+
}
|
|
958
|
+
parameters = {"name": name}
|
|
959
|
+
for param_name, param_value in given_params.items():
|
|
960
|
+
if param_value is not None:
|
|
961
|
+
parameters[param_name] = param_value
|
|
962
|
+
|
|
963
|
+
organization._requester.requestJsonAndCheck(
|
|
964
|
+
"POST", organization.url + "/repos", input=parameters
|
|
965
|
+
)
|
|
966
|
+
return True
|
|
967
|
+
except github.GithubException:
|
|
968
|
+
log.exception("Error creating a repo")
|
|
969
|
+
return False
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
def edit_repo(
|
|
973
|
+
name,
|
|
974
|
+
description=None,
|
|
975
|
+
homepage=None,
|
|
976
|
+
private=None,
|
|
977
|
+
has_issues=None,
|
|
978
|
+
has_wiki=None,
|
|
979
|
+
has_downloads=None,
|
|
980
|
+
profile="github",
|
|
981
|
+
):
|
|
982
|
+
"""
|
|
983
|
+
Updates an existing Github repository.
|
|
984
|
+
|
|
985
|
+
name
|
|
986
|
+
The name of the team to be created.
|
|
987
|
+
|
|
988
|
+
description
|
|
989
|
+
The description of the repository.
|
|
990
|
+
|
|
991
|
+
homepage
|
|
992
|
+
The URL with more information about the repository.
|
|
993
|
+
|
|
994
|
+
private
|
|
995
|
+
The visiblity of the repository. Note that private repositories require
|
|
996
|
+
a paid GitHub account.
|
|
997
|
+
|
|
998
|
+
has_issues
|
|
999
|
+
Whether to enable issues for this repository.
|
|
1000
|
+
|
|
1001
|
+
has_wiki
|
|
1002
|
+
Whether to enable the wiki for this repository.
|
|
1003
|
+
|
|
1004
|
+
has_downloads
|
|
1005
|
+
Whether to enable downloads for this repository.
|
|
1006
|
+
|
|
1007
|
+
profile
|
|
1008
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1009
|
+
|
|
1010
|
+
CLI Example:
|
|
1011
|
+
|
|
1012
|
+
.. code-block:: bash
|
|
1013
|
+
|
|
1014
|
+
salt myminion github.add_repo 'repo_name'
|
|
1015
|
+
|
|
1016
|
+
.. versionadded:: 2016.11.0
|
|
1017
|
+
"""
|
|
1018
|
+
|
|
1019
|
+
try:
|
|
1020
|
+
allow_private_change = _get_config_value(profile, "allow_repo_privacy_changes")
|
|
1021
|
+
except CommandExecutionError:
|
|
1022
|
+
allow_private_change = False
|
|
1023
|
+
|
|
1024
|
+
if private is not None and not allow_private_change:
|
|
1025
|
+
raise CommandExecutionError(
|
|
1026
|
+
f"The private field is set to be changed for repo {name} but allow_repo_privacy_changes disallows this."
|
|
1027
|
+
)
|
|
1028
|
+
|
|
1029
|
+
try:
|
|
1030
|
+
client = _get_client(profile)
|
|
1031
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1032
|
+
repo = organization.get_repo(name)
|
|
1033
|
+
|
|
1034
|
+
given_params = {
|
|
1035
|
+
"description": description,
|
|
1036
|
+
"homepage": homepage,
|
|
1037
|
+
"private": private,
|
|
1038
|
+
"has_issues": has_issues,
|
|
1039
|
+
"has_wiki": has_wiki,
|
|
1040
|
+
"has_downloads": has_downloads,
|
|
1041
|
+
}
|
|
1042
|
+
parameters = {"name": name}
|
|
1043
|
+
for param_name, param_value in given_params.items():
|
|
1044
|
+
if param_value is not None:
|
|
1045
|
+
parameters[param_name] = param_value
|
|
1046
|
+
|
|
1047
|
+
organization._requester.requestJsonAndCheck("PATCH", repo.url, input=parameters)
|
|
1048
|
+
get_repo_info(name, profile=profile, ignore_cache=True) # Refresh cache
|
|
1049
|
+
return True
|
|
1050
|
+
except github.GithubException:
|
|
1051
|
+
log.exception("Error editing a repo")
|
|
1052
|
+
return False
|
|
1053
|
+
|
|
1054
|
+
|
|
1055
|
+
def remove_repo(name, profile="github"):
|
|
1056
|
+
"""
|
|
1057
|
+
Remove a Github repository.
|
|
1058
|
+
|
|
1059
|
+
name
|
|
1060
|
+
The name of the repository to be removed.
|
|
1061
|
+
|
|
1062
|
+
profile
|
|
1063
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1064
|
+
|
|
1065
|
+
CLI Example:
|
|
1066
|
+
|
|
1067
|
+
.. code-block:: bash
|
|
1068
|
+
|
|
1069
|
+
salt myminion github.remove_repo 'my-repo'
|
|
1070
|
+
|
|
1071
|
+
.. versionadded:: 2016.11.0
|
|
1072
|
+
"""
|
|
1073
|
+
repo_info = get_repo_info(name, profile=profile)
|
|
1074
|
+
if not repo_info:
|
|
1075
|
+
log.error("Repo %s to be removed does not exist.", name)
|
|
1076
|
+
return False
|
|
1077
|
+
try:
|
|
1078
|
+
client = _get_client(profile)
|
|
1079
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1080
|
+
repo = organization.get_repo(name)
|
|
1081
|
+
repo.delete()
|
|
1082
|
+
_get_repos(profile=profile, ignore_cache=True) # refresh cache
|
|
1083
|
+
return True
|
|
1084
|
+
except github.GithubException:
|
|
1085
|
+
log.exception("Error deleting a repo")
|
|
1086
|
+
return False
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
def get_team(name, profile="github"):
|
|
1090
|
+
"""
|
|
1091
|
+
Returns the team details if a team with the given name exists, or None
|
|
1092
|
+
otherwise.
|
|
1093
|
+
|
|
1094
|
+
name
|
|
1095
|
+
The team name for which to obtain information.
|
|
1096
|
+
|
|
1097
|
+
profile
|
|
1098
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1099
|
+
|
|
1100
|
+
CLI Example:
|
|
1101
|
+
|
|
1102
|
+
.. code-block:: bash
|
|
1103
|
+
|
|
1104
|
+
salt myminion github.get_team 'team_name'
|
|
1105
|
+
"""
|
|
1106
|
+
return list_teams(profile).get(name)
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
def add_team(
|
|
1110
|
+
name,
|
|
1111
|
+
description=None,
|
|
1112
|
+
repo_names=None,
|
|
1113
|
+
privacy=None,
|
|
1114
|
+
permission=None,
|
|
1115
|
+
profile="github",
|
|
1116
|
+
):
|
|
1117
|
+
"""
|
|
1118
|
+
Create a new Github team within an organization.
|
|
1119
|
+
|
|
1120
|
+
name
|
|
1121
|
+
The name of the team to be created.
|
|
1122
|
+
|
|
1123
|
+
description
|
|
1124
|
+
The description of the team.
|
|
1125
|
+
|
|
1126
|
+
repo_names
|
|
1127
|
+
The names of repositories to add the team to.
|
|
1128
|
+
|
|
1129
|
+
privacy
|
|
1130
|
+
The level of privacy for the team, can be 'secret' or 'closed'.
|
|
1131
|
+
|
|
1132
|
+
permission
|
|
1133
|
+
The default permission for new repositories added to the team, can be
|
|
1134
|
+
'pull', 'push' or 'admin'.
|
|
1135
|
+
|
|
1136
|
+
profile
|
|
1137
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1138
|
+
|
|
1139
|
+
CLI Example:
|
|
1140
|
+
|
|
1141
|
+
.. code-block:: bash
|
|
1142
|
+
|
|
1143
|
+
salt myminion github.add_team 'team_name'
|
|
1144
|
+
|
|
1145
|
+
.. versionadded:: 2016.11.0
|
|
1146
|
+
"""
|
|
1147
|
+
try:
|
|
1148
|
+
client = _get_client(profile)
|
|
1149
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1150
|
+
parameters = {}
|
|
1151
|
+
parameters["name"] = name
|
|
1152
|
+
|
|
1153
|
+
if description is not None:
|
|
1154
|
+
parameters["description"] = description
|
|
1155
|
+
if repo_names is not None:
|
|
1156
|
+
parameters["repo_names"] = repo_names
|
|
1157
|
+
if permission is not None:
|
|
1158
|
+
parameters["permission"] = permission
|
|
1159
|
+
if privacy is not None:
|
|
1160
|
+
parameters["privacy"] = privacy
|
|
1161
|
+
|
|
1162
|
+
organization._requester.requestJsonAndCheck(
|
|
1163
|
+
"POST", organization.url + "/teams", input=parameters
|
|
1164
|
+
)
|
|
1165
|
+
list_teams(ignore_cache=True) # Refresh cache
|
|
1166
|
+
return True
|
|
1167
|
+
except github.GithubException:
|
|
1168
|
+
log.exception("Error creating a team")
|
|
1169
|
+
return False
|
|
1170
|
+
|
|
1171
|
+
|
|
1172
|
+
def edit_team(name, description=None, privacy=None, permission=None, profile="github"):
|
|
1173
|
+
"""
|
|
1174
|
+
Updates an existing Github team.
|
|
1175
|
+
|
|
1176
|
+
name
|
|
1177
|
+
The name of the team to be edited.
|
|
1178
|
+
|
|
1179
|
+
description
|
|
1180
|
+
The description of the team.
|
|
1181
|
+
|
|
1182
|
+
privacy
|
|
1183
|
+
The level of privacy for the team, can be 'secret' or 'closed'.
|
|
1184
|
+
|
|
1185
|
+
permission
|
|
1186
|
+
The default permission for new repositories added to the team, can be
|
|
1187
|
+
'pull', 'push' or 'admin'.
|
|
1188
|
+
|
|
1189
|
+
profile
|
|
1190
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1191
|
+
|
|
1192
|
+
CLI Example:
|
|
1193
|
+
|
|
1194
|
+
.. code-block:: bash
|
|
1195
|
+
|
|
1196
|
+
salt myminion github.edit_team 'team_name' description='Team description'
|
|
1197
|
+
|
|
1198
|
+
.. versionadded:: 2016.11.0
|
|
1199
|
+
"""
|
|
1200
|
+
team = get_team(name, profile=profile)
|
|
1201
|
+
if not team:
|
|
1202
|
+
log.error("Team %s does not exist", name)
|
|
1203
|
+
return False
|
|
1204
|
+
try:
|
|
1205
|
+
client = _get_client(profile)
|
|
1206
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1207
|
+
team = organization.get_team(team["id"])
|
|
1208
|
+
|
|
1209
|
+
parameters = {}
|
|
1210
|
+
if name is not None:
|
|
1211
|
+
parameters["name"] = name
|
|
1212
|
+
if description is not None:
|
|
1213
|
+
parameters["description"] = description
|
|
1214
|
+
if privacy is not None:
|
|
1215
|
+
parameters["privacy"] = privacy
|
|
1216
|
+
if permission is not None:
|
|
1217
|
+
parameters["permission"] = permission
|
|
1218
|
+
|
|
1219
|
+
team._requester.requestJsonAndCheck("PATCH", team.url, input=parameters)
|
|
1220
|
+
return True
|
|
1221
|
+
except UnknownObjectException:
|
|
1222
|
+
log.exception("Resource not found")
|
|
1223
|
+
return False
|
|
1224
|
+
|
|
1225
|
+
|
|
1226
|
+
def remove_team(name, profile="github"):
|
|
1227
|
+
"""
|
|
1228
|
+
Remove a github team.
|
|
1229
|
+
|
|
1230
|
+
name
|
|
1231
|
+
The name of the team to be removed.
|
|
1232
|
+
|
|
1233
|
+
profile
|
|
1234
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1235
|
+
|
|
1236
|
+
CLI Example:
|
|
1237
|
+
|
|
1238
|
+
.. code-block:: bash
|
|
1239
|
+
|
|
1240
|
+
salt myminion github.remove_team 'team_name'
|
|
1241
|
+
|
|
1242
|
+
.. versionadded:: 2016.11.0
|
|
1243
|
+
"""
|
|
1244
|
+
team_info = get_team(name, profile=profile)
|
|
1245
|
+
if not team_info:
|
|
1246
|
+
log.error("Team %s to be removed does not exist.", name)
|
|
1247
|
+
return False
|
|
1248
|
+
try:
|
|
1249
|
+
client = _get_client(profile)
|
|
1250
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1251
|
+
team = organization.get_team(team_info["id"])
|
|
1252
|
+
team.delete()
|
|
1253
|
+
return list_teams(ignore_cache=True, profile=profile).get(name) is None
|
|
1254
|
+
except github.GithubException:
|
|
1255
|
+
log.exception("Error deleting a team")
|
|
1256
|
+
return False
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
def list_team_repos(team_name, profile="github", ignore_cache=False):
|
|
1260
|
+
"""
|
|
1261
|
+
Gets the repo details for a given team as a dict from repo_name to repo details.
|
|
1262
|
+
Note that repo names are always in lower case.
|
|
1263
|
+
|
|
1264
|
+
team_name
|
|
1265
|
+
The name of the team from which to list repos.
|
|
1266
|
+
|
|
1267
|
+
profile
|
|
1268
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1269
|
+
|
|
1270
|
+
ignore_cache
|
|
1271
|
+
Bypasses the use of cached team repos.
|
|
1272
|
+
|
|
1273
|
+
CLI Example:
|
|
1274
|
+
|
|
1275
|
+
.. code-block:: bash
|
|
1276
|
+
|
|
1277
|
+
salt myminion github.list_team_repos 'team_name'
|
|
1278
|
+
|
|
1279
|
+
.. versionadded:: 2016.11.0
|
|
1280
|
+
"""
|
|
1281
|
+
cached_team = get_team(team_name, profile=profile)
|
|
1282
|
+
if not cached_team:
|
|
1283
|
+
log.error("Team %s does not exist.", team_name)
|
|
1284
|
+
return False
|
|
1285
|
+
|
|
1286
|
+
# Return from cache if available
|
|
1287
|
+
if cached_team.get("repos") and not ignore_cache:
|
|
1288
|
+
return cached_team.get("repos")
|
|
1289
|
+
|
|
1290
|
+
try:
|
|
1291
|
+
client = _get_client(profile)
|
|
1292
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1293
|
+
team = organization.get_team(cached_team["id"])
|
|
1294
|
+
except UnknownObjectException:
|
|
1295
|
+
log.exception("Resource not found: %s", cached_team["id"])
|
|
1296
|
+
try:
|
|
1297
|
+
repos = {}
|
|
1298
|
+
for repo in team.get_repos():
|
|
1299
|
+
permission = "pull"
|
|
1300
|
+
if repo.permissions.admin:
|
|
1301
|
+
permission = "admin"
|
|
1302
|
+
elif repo.permissions.push:
|
|
1303
|
+
permission = "push"
|
|
1304
|
+
|
|
1305
|
+
repos[repo.name.lower()] = {"permission": permission}
|
|
1306
|
+
cached_team["repos"] = repos
|
|
1307
|
+
return repos
|
|
1308
|
+
except UnknownObjectException:
|
|
1309
|
+
log.exception("Resource not found: %s", cached_team["id"])
|
|
1310
|
+
return []
|
|
1311
|
+
|
|
1312
|
+
|
|
1313
|
+
def add_team_repo(repo_name, team_name, profile="github", permission=None):
|
|
1314
|
+
"""
|
|
1315
|
+
Adds a repository to a team with team_name.
|
|
1316
|
+
|
|
1317
|
+
repo_name
|
|
1318
|
+
The name of the repository to add.
|
|
1319
|
+
|
|
1320
|
+
team_name
|
|
1321
|
+
The name of the team of which to add the repository.
|
|
1322
|
+
|
|
1323
|
+
profile
|
|
1324
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1325
|
+
|
|
1326
|
+
permission
|
|
1327
|
+
The permission for team members within the repository, can be 'pull',
|
|
1328
|
+
'push' or 'admin'. If not specified, the default permission specified on
|
|
1329
|
+
the team will be used.
|
|
1330
|
+
|
|
1331
|
+
.. versionadded:: 2017.7.0
|
|
1332
|
+
|
|
1333
|
+
CLI Example:
|
|
1334
|
+
|
|
1335
|
+
.. code-block:: bash
|
|
1336
|
+
|
|
1337
|
+
salt myminion github.add_team_repo 'my_repo' 'team_name'
|
|
1338
|
+
|
|
1339
|
+
.. versionadded:: 2016.11.0
|
|
1340
|
+
"""
|
|
1341
|
+
team = get_team(team_name, profile=profile)
|
|
1342
|
+
if not team:
|
|
1343
|
+
log.error("Team %s does not exist", team_name)
|
|
1344
|
+
return False
|
|
1345
|
+
try:
|
|
1346
|
+
client = _get_client(profile)
|
|
1347
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1348
|
+
team = organization.get_team(team["id"])
|
|
1349
|
+
repo = organization.get_repo(repo_name)
|
|
1350
|
+
except UnknownObjectException:
|
|
1351
|
+
log.exception("Resource not found: %s", team["id"])
|
|
1352
|
+
return False
|
|
1353
|
+
params = None
|
|
1354
|
+
if permission is not None:
|
|
1355
|
+
params = {"permission": permission}
|
|
1356
|
+
|
|
1357
|
+
headers, data = team._requester.requestJsonAndCheck(
|
|
1358
|
+
"PUT", team.url + "/repos/" + repo._identity, input=params
|
|
1359
|
+
)
|
|
1360
|
+
# Try to refresh cache
|
|
1361
|
+
list_team_repos(team_name, profile=profile, ignore_cache=True)
|
|
1362
|
+
return True
|
|
1363
|
+
|
|
1364
|
+
|
|
1365
|
+
def remove_team_repo(repo_name, team_name, profile="github"):
|
|
1366
|
+
"""
|
|
1367
|
+
Removes a repository from a team with team_name.
|
|
1368
|
+
|
|
1369
|
+
repo_name
|
|
1370
|
+
The name of the repository to remove.
|
|
1371
|
+
|
|
1372
|
+
team_name
|
|
1373
|
+
The name of the team of which to remove the repository.
|
|
1374
|
+
|
|
1375
|
+
profile
|
|
1376
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1377
|
+
|
|
1378
|
+
CLI Example:
|
|
1379
|
+
|
|
1380
|
+
.. code-block:: bash
|
|
1381
|
+
|
|
1382
|
+
salt myminion github.remove_team_repo 'my_repo' 'team_name'
|
|
1383
|
+
|
|
1384
|
+
.. versionadded:: 2016.11.0
|
|
1385
|
+
"""
|
|
1386
|
+
team = get_team(team_name, profile=profile)
|
|
1387
|
+
if not team:
|
|
1388
|
+
log.error("Team %s does not exist", team_name)
|
|
1389
|
+
return False
|
|
1390
|
+
try:
|
|
1391
|
+
client = _get_client(profile)
|
|
1392
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1393
|
+
team = organization.get_team(team["id"])
|
|
1394
|
+
repo = organization.get_repo(repo_name)
|
|
1395
|
+
except UnknownObjectException:
|
|
1396
|
+
log.exception("Resource not found: %s", team["id"])
|
|
1397
|
+
return False
|
|
1398
|
+
team.remove_from_repos(repo)
|
|
1399
|
+
return repo_name not in list_team_repos(team_name, profile=profile, ignore_cache=True)
|
|
1400
|
+
|
|
1401
|
+
|
|
1402
|
+
def list_team_members(team_name, profile="github", ignore_cache=False):
|
|
1403
|
+
"""
|
|
1404
|
+
Gets the names of team members in lower case.
|
|
1405
|
+
|
|
1406
|
+
team_name
|
|
1407
|
+
The name of the team from which to list members.
|
|
1408
|
+
|
|
1409
|
+
profile
|
|
1410
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1411
|
+
|
|
1412
|
+
ignore_cache
|
|
1413
|
+
Bypasses the use of cached team members.
|
|
1414
|
+
|
|
1415
|
+
CLI Example:
|
|
1416
|
+
|
|
1417
|
+
.. code-block:: bash
|
|
1418
|
+
|
|
1419
|
+
salt myminion github.list_team_members 'team_name'
|
|
1420
|
+
|
|
1421
|
+
.. versionadded:: 2016.11.0
|
|
1422
|
+
"""
|
|
1423
|
+
cached_team = get_team(team_name, profile=profile)
|
|
1424
|
+
if not cached_team:
|
|
1425
|
+
log.error("Team %s does not exist.", team_name)
|
|
1426
|
+
return False
|
|
1427
|
+
# Return from cache if available
|
|
1428
|
+
if cached_team.get("members") and not ignore_cache:
|
|
1429
|
+
return cached_team.get("members")
|
|
1430
|
+
|
|
1431
|
+
try:
|
|
1432
|
+
client = _get_client(profile)
|
|
1433
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1434
|
+
team = organization.get_team(cached_team["id"])
|
|
1435
|
+
except UnknownObjectException:
|
|
1436
|
+
log.exception("Resource not found: %s", cached_team["id"])
|
|
1437
|
+
try:
|
|
1438
|
+
cached_team["members"] = [member.login.lower() for member in team.get_members()]
|
|
1439
|
+
return cached_team["members"]
|
|
1440
|
+
except UnknownObjectException:
|
|
1441
|
+
log.exception("Resource not found: %s", cached_team["id"])
|
|
1442
|
+
return []
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
def list_members_without_mfa(profile="github", ignore_cache=False):
|
|
1446
|
+
"""
|
|
1447
|
+
List all members (in lower case) without MFA turned on.
|
|
1448
|
+
|
|
1449
|
+
profile
|
|
1450
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1451
|
+
|
|
1452
|
+
ignore_cache
|
|
1453
|
+
Bypasses the use of cached team repos.
|
|
1454
|
+
|
|
1455
|
+
CLI Example:
|
|
1456
|
+
|
|
1457
|
+
.. code-block:: bash
|
|
1458
|
+
|
|
1459
|
+
salt myminion github.list_members_without_mfa
|
|
1460
|
+
|
|
1461
|
+
.. versionadded:: 2016.11.0
|
|
1462
|
+
"""
|
|
1463
|
+
key = "github.{}:non_mfa_users".format( # pylint: disable=consider-using-f-string
|
|
1464
|
+
_get_config_value(profile, "org_name")
|
|
1465
|
+
)
|
|
1466
|
+
|
|
1467
|
+
if key not in __context__ or ignore_cache:
|
|
1468
|
+
client = _get_client(profile)
|
|
1469
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1470
|
+
|
|
1471
|
+
filter_key = "filter"
|
|
1472
|
+
# Silly hack to see if we're past PyGithub 1.26.0, where the name of
|
|
1473
|
+
# the filter kwarg changed
|
|
1474
|
+
if hasattr(github.Team.Team, "membership"):
|
|
1475
|
+
filter_key = "filter_"
|
|
1476
|
+
|
|
1477
|
+
__context__[key] = [
|
|
1478
|
+
m.login.lower() for m in _get_members(organization, {filter_key: "2fa_disabled"})
|
|
1479
|
+
]
|
|
1480
|
+
return __context__[key]
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
def is_team_member(name, team_name, profile="github"):
|
|
1484
|
+
"""
|
|
1485
|
+
Returns True if the github user is in the team with team_name, or False
|
|
1486
|
+
otherwise.
|
|
1487
|
+
|
|
1488
|
+
name
|
|
1489
|
+
The name of the user whose membership to check.
|
|
1490
|
+
|
|
1491
|
+
team_name
|
|
1492
|
+
The name of the team to check membership in.
|
|
1493
|
+
|
|
1494
|
+
profile
|
|
1495
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1496
|
+
|
|
1497
|
+
CLI Example:
|
|
1498
|
+
|
|
1499
|
+
.. code-block:: bash
|
|
1500
|
+
|
|
1501
|
+
salt myminion github.is_team_member 'user_name' 'team_name'
|
|
1502
|
+
|
|
1503
|
+
.. versionadded:: 2016.11.0
|
|
1504
|
+
"""
|
|
1505
|
+
return name.lower() in list_team_members(team_name, profile=profile)
|
|
1506
|
+
|
|
1507
|
+
|
|
1508
|
+
def add_team_member(name, team_name, profile="github"):
|
|
1509
|
+
"""
|
|
1510
|
+
Adds a team member to a team with team_name.
|
|
1511
|
+
|
|
1512
|
+
name
|
|
1513
|
+
The name of the team member to add.
|
|
1514
|
+
|
|
1515
|
+
team_name
|
|
1516
|
+
The name of the team of which to add the user.
|
|
1517
|
+
|
|
1518
|
+
profile
|
|
1519
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1520
|
+
|
|
1521
|
+
CLI Example:
|
|
1522
|
+
|
|
1523
|
+
.. code-block:: bash
|
|
1524
|
+
|
|
1525
|
+
salt myminion github.add_team_member 'user_name' 'team_name'
|
|
1526
|
+
|
|
1527
|
+
.. versionadded:: 2016.11.0
|
|
1528
|
+
"""
|
|
1529
|
+
team = get_team(team_name, profile=profile)
|
|
1530
|
+
if not team:
|
|
1531
|
+
log.error("Team %s does not exist", team_name)
|
|
1532
|
+
return False
|
|
1533
|
+
try:
|
|
1534
|
+
client = _get_client(profile)
|
|
1535
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1536
|
+
team = organization.get_team(team["id"])
|
|
1537
|
+
member = client.get_user(name)
|
|
1538
|
+
except UnknownObjectException:
|
|
1539
|
+
log.exception("Resource not found: %s", team["id"])
|
|
1540
|
+
return False
|
|
1541
|
+
|
|
1542
|
+
try:
|
|
1543
|
+
# Can't use team.add_membership due to this bug that hasn't made it into
|
|
1544
|
+
# a PyGithub release yet https://github.com/PyGithub/PyGithub/issues/363
|
|
1545
|
+
headers, data = team._requester.requestJsonAndCheck(
|
|
1546
|
+
"PUT",
|
|
1547
|
+
team.url + "/memberships/" + member._identity,
|
|
1548
|
+
input={"role": "member"},
|
|
1549
|
+
parameters={"role": "member"},
|
|
1550
|
+
)
|
|
1551
|
+
except github.GithubException:
|
|
1552
|
+
log.exception("Error in adding a member to a team")
|
|
1553
|
+
return False
|
|
1554
|
+
return True
|
|
1555
|
+
|
|
1556
|
+
|
|
1557
|
+
def remove_team_member(name, team_name, profile="github"):
|
|
1558
|
+
"""
|
|
1559
|
+
Removes a team member from a team with team_name.
|
|
1560
|
+
|
|
1561
|
+
name
|
|
1562
|
+
The name of the team member to remove.
|
|
1563
|
+
|
|
1564
|
+
team_name
|
|
1565
|
+
The name of the team from which to remove the user.
|
|
1566
|
+
|
|
1567
|
+
profile
|
|
1568
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1569
|
+
|
|
1570
|
+
CLI Example:
|
|
1571
|
+
|
|
1572
|
+
.. code-block:: bash
|
|
1573
|
+
|
|
1574
|
+
salt myminion github.remove_team_member 'user_name' 'team_name'
|
|
1575
|
+
|
|
1576
|
+
.. versionadded:: 2016.11.0
|
|
1577
|
+
"""
|
|
1578
|
+
team = get_team(team_name, profile=profile)
|
|
1579
|
+
if not team:
|
|
1580
|
+
log.error("Team %s does not exist", team_name)
|
|
1581
|
+
return False
|
|
1582
|
+
try:
|
|
1583
|
+
client = _get_client(profile)
|
|
1584
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1585
|
+
team = organization.get_team(team["id"])
|
|
1586
|
+
member = client.get_user(name)
|
|
1587
|
+
|
|
1588
|
+
except UnknownObjectException:
|
|
1589
|
+
log.exception("Resource not found: %s", team["id"])
|
|
1590
|
+
return False
|
|
1591
|
+
|
|
1592
|
+
if not hasattr(team, "remove_from_members"):
|
|
1593
|
+
return (
|
|
1594
|
+
False,
|
|
1595
|
+
"PyGithub 1.26.0 or greater is required for team management, please upgrade.",
|
|
1596
|
+
)
|
|
1597
|
+
|
|
1598
|
+
team.remove_from_members(member)
|
|
1599
|
+
return not team.has_in_members(member)
|
|
1600
|
+
|
|
1601
|
+
|
|
1602
|
+
def list_teams(profile="github", ignore_cache=False):
|
|
1603
|
+
"""
|
|
1604
|
+
Lists all teams with the organization.
|
|
1605
|
+
|
|
1606
|
+
profile
|
|
1607
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1608
|
+
|
|
1609
|
+
ignore_cache
|
|
1610
|
+
Bypasses the use of cached teams.
|
|
1611
|
+
|
|
1612
|
+
CLI Example:
|
|
1613
|
+
|
|
1614
|
+
.. code-block:: bash
|
|
1615
|
+
|
|
1616
|
+
salt myminion github.list_teams
|
|
1617
|
+
|
|
1618
|
+
.. versionadded:: 2016.11.0
|
|
1619
|
+
"""
|
|
1620
|
+
key = "github.{}:teams".format( # pylint: disable=consider-using-f-string
|
|
1621
|
+
_get_config_value(profile, "org_name")
|
|
1622
|
+
)
|
|
1623
|
+
|
|
1624
|
+
if key not in __context__ or ignore_cache:
|
|
1625
|
+
client = _get_client(profile)
|
|
1626
|
+
organization = client.get_organization(_get_config_value(profile, "org_name"))
|
|
1627
|
+
teams_data = organization.get_teams()
|
|
1628
|
+
teams = {}
|
|
1629
|
+
for team in teams_data:
|
|
1630
|
+
# Note that _rawData is used to access some properties here as they
|
|
1631
|
+
# are not exposed in older versions of PyGithub. It's VERY important
|
|
1632
|
+
# to use team._rawData instead of team.raw_data, as the latter forces
|
|
1633
|
+
# an API call to retrieve team details again.
|
|
1634
|
+
teams[team.name] = {
|
|
1635
|
+
"id": team.id,
|
|
1636
|
+
"slug": team.slug,
|
|
1637
|
+
"description": team._rawData["description"],
|
|
1638
|
+
"permission": team.permission,
|
|
1639
|
+
"privacy": team._rawData["privacy"],
|
|
1640
|
+
}
|
|
1641
|
+
__context__[key] = teams
|
|
1642
|
+
|
|
1643
|
+
return __context__[key]
|
|
1644
|
+
|
|
1645
|
+
|
|
1646
|
+
def get_prs(
|
|
1647
|
+
repo_name=None,
|
|
1648
|
+
profile="github",
|
|
1649
|
+
state="open",
|
|
1650
|
+
head=None,
|
|
1651
|
+
base=None,
|
|
1652
|
+
sort="created",
|
|
1653
|
+
direction="desc",
|
|
1654
|
+
output="min",
|
|
1655
|
+
per_page=None,
|
|
1656
|
+
):
|
|
1657
|
+
"""
|
|
1658
|
+
Returns information for all pull requests in a given repository, based on
|
|
1659
|
+
the search options provided.
|
|
1660
|
+
|
|
1661
|
+
.. versionadded:: 2017.7.0
|
|
1662
|
+
|
|
1663
|
+
repo_name
|
|
1664
|
+
The name of the repository for which to list pull requests. This
|
|
1665
|
+
argument is required, either passed via the CLI, or defined in the
|
|
1666
|
+
configured profile. A ``repo_name`` passed as a CLI argument will
|
|
1667
|
+
override the ``repo_name`` defined in the configured profile, if
|
|
1668
|
+
provided.
|
|
1669
|
+
|
|
1670
|
+
profile
|
|
1671
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1672
|
+
|
|
1673
|
+
state
|
|
1674
|
+
Indicates the state of the pull requests to return. Can be either
|
|
1675
|
+
``open``, ``closed``, or ``all``. Default is ``open``.
|
|
1676
|
+
|
|
1677
|
+
head
|
|
1678
|
+
Filter pull requests by head user and branch name in the format of
|
|
1679
|
+
``user:ref-name``. Example: ``'github:new-script-format'``. Default
|
|
1680
|
+
is ``None``.
|
|
1681
|
+
|
|
1682
|
+
base
|
|
1683
|
+
Filter pulls by base branch name. Example: ``gh-pages``. Default is
|
|
1684
|
+
``None``.
|
|
1685
|
+
|
|
1686
|
+
sort
|
|
1687
|
+
What to sort results by. Can be either ``created``, ``updated``,
|
|
1688
|
+
``popularity`` (comment count), or ``long-running`` (age, filtering
|
|
1689
|
+
by pull requests updated within the last month). Default is ``created``.
|
|
1690
|
+
|
|
1691
|
+
direction
|
|
1692
|
+
The direction of the sort. Can be either ``asc`` or ``desc``. Default
|
|
1693
|
+
is ``desc``.
|
|
1694
|
+
|
|
1695
|
+
output
|
|
1696
|
+
The amount of data returned by each pull request. Defaults to ``min``.
|
|
1697
|
+
Change to ``full`` to see all pull request output.
|
|
1698
|
+
|
|
1699
|
+
per_page
|
|
1700
|
+
GitHub paginates data in their API calls. Use this value to increase or
|
|
1701
|
+
decrease the number of pull requests gathered from GitHub, per page. If
|
|
1702
|
+
not set, GitHub defaults are used. Maximum is 100.
|
|
1703
|
+
|
|
1704
|
+
CLI Example:
|
|
1705
|
+
|
|
1706
|
+
.. code-block:: bash
|
|
1707
|
+
|
|
1708
|
+
salt myminion github.get_prs
|
|
1709
|
+
salt myminion github.get_prs base=2016.11
|
|
1710
|
+
"""
|
|
1711
|
+
org_name = _get_config_value(profile, "org_name")
|
|
1712
|
+
if repo_name is None:
|
|
1713
|
+
repo_name = _get_config_value(profile, "repo_name")
|
|
1714
|
+
|
|
1715
|
+
action = "/".join(["repos", org_name, repo_name])
|
|
1716
|
+
args = {}
|
|
1717
|
+
|
|
1718
|
+
# Build API arguments, as necessary.
|
|
1719
|
+
if head:
|
|
1720
|
+
args["head"] = head
|
|
1721
|
+
if base:
|
|
1722
|
+
args["base"] = base
|
|
1723
|
+
if per_page:
|
|
1724
|
+
args["per_page"] = per_page
|
|
1725
|
+
|
|
1726
|
+
# Only pass the following API args if they're not the defaults listed.
|
|
1727
|
+
if state and state != "open":
|
|
1728
|
+
args["state"] = state
|
|
1729
|
+
if sort and sort != "created":
|
|
1730
|
+
args["sort"] = sort
|
|
1731
|
+
if direction and direction != "desc":
|
|
1732
|
+
args["direction"] = direction
|
|
1733
|
+
|
|
1734
|
+
ret = {}
|
|
1735
|
+
prs = _query(profile, action=action, command="pulls", args=args)
|
|
1736
|
+
|
|
1737
|
+
for pr_ in prs.get("dict", {}):
|
|
1738
|
+
pr_id = pr_.get("id")
|
|
1739
|
+
if output == "full":
|
|
1740
|
+
ret[pr_id] = pr_
|
|
1741
|
+
else:
|
|
1742
|
+
ret[pr_id] = _format_pr(pr_)
|
|
1743
|
+
|
|
1744
|
+
return ret
|
|
1745
|
+
|
|
1746
|
+
|
|
1747
|
+
def _format_pr(pr_):
|
|
1748
|
+
"""
|
|
1749
|
+
Helper function to format API return information into a more manageable
|
|
1750
|
+
and useful dictionary for pull request information.
|
|
1751
|
+
|
|
1752
|
+
pr_
|
|
1753
|
+
The pull request to format.
|
|
1754
|
+
"""
|
|
1755
|
+
ret = {
|
|
1756
|
+
"id": pr_.get("id"),
|
|
1757
|
+
"pr_number": pr_.get("number"),
|
|
1758
|
+
"state": pr_.get("state"),
|
|
1759
|
+
"title": pr_.get("title"),
|
|
1760
|
+
"user": pr_.get("user").get("login"),
|
|
1761
|
+
"html_url": pr_.get("html_url"),
|
|
1762
|
+
"base_branch": pr_.get("base").get("ref"),
|
|
1763
|
+
}
|
|
1764
|
+
|
|
1765
|
+
return ret
|
|
1766
|
+
|
|
1767
|
+
|
|
1768
|
+
def _format_issue(issue):
|
|
1769
|
+
"""
|
|
1770
|
+
Helper function to format API return information into a more manageable
|
|
1771
|
+
and useful dictionary for issue information.
|
|
1772
|
+
|
|
1773
|
+
issue
|
|
1774
|
+
The issue to format.
|
|
1775
|
+
"""
|
|
1776
|
+
ret = {
|
|
1777
|
+
"id": issue.get("id"),
|
|
1778
|
+
"issue_number": issue.get("number"),
|
|
1779
|
+
"state": issue.get("state"),
|
|
1780
|
+
"title": issue.get("title"),
|
|
1781
|
+
"user": issue.get("user").get("login"),
|
|
1782
|
+
"html_url": issue.get("html_url"),
|
|
1783
|
+
}
|
|
1784
|
+
|
|
1785
|
+
assignee = issue.get("assignee")
|
|
1786
|
+
if assignee:
|
|
1787
|
+
assignee = assignee.get("login")
|
|
1788
|
+
|
|
1789
|
+
labels = issue.get("labels")
|
|
1790
|
+
label_names = []
|
|
1791
|
+
for label in labels:
|
|
1792
|
+
label_names.append(label.get("name"))
|
|
1793
|
+
|
|
1794
|
+
milestone = issue.get("milestone")
|
|
1795
|
+
if milestone:
|
|
1796
|
+
milestone = milestone.get("title")
|
|
1797
|
+
|
|
1798
|
+
ret["assignee"] = assignee
|
|
1799
|
+
ret["labels"] = label_names
|
|
1800
|
+
ret["milestone"] = milestone
|
|
1801
|
+
|
|
1802
|
+
return ret
|
|
1803
|
+
|
|
1804
|
+
|
|
1805
|
+
def _query(
|
|
1806
|
+
profile,
|
|
1807
|
+
action=None,
|
|
1808
|
+
command=None,
|
|
1809
|
+
args=None,
|
|
1810
|
+
method="GET",
|
|
1811
|
+
header_dict=None,
|
|
1812
|
+
data=None,
|
|
1813
|
+
url="https://api.github.com/",
|
|
1814
|
+
per_page=None,
|
|
1815
|
+
):
|
|
1816
|
+
"""
|
|
1817
|
+
Make a web call to the GitHub API and deal with paginated results.
|
|
1818
|
+
"""
|
|
1819
|
+
if not isinstance(args, dict):
|
|
1820
|
+
args = {}
|
|
1821
|
+
|
|
1822
|
+
if action:
|
|
1823
|
+
url += action
|
|
1824
|
+
|
|
1825
|
+
if command:
|
|
1826
|
+
url += f"/{command}"
|
|
1827
|
+
|
|
1828
|
+
log.debug("GitHub URL: %s", url)
|
|
1829
|
+
|
|
1830
|
+
if header_dict is None:
|
|
1831
|
+
header_dict = {}
|
|
1832
|
+
|
|
1833
|
+
if not header_dict.get("Authorization"):
|
|
1834
|
+
header_dict["Authorization"] = f"Bearer {_get_config_value(profile, 'token')}"
|
|
1835
|
+
if per_page and "per_page" not in args.keys():
|
|
1836
|
+
args["per_page"] = per_page
|
|
1837
|
+
|
|
1838
|
+
header_dict["Accept"] = "application/vnd.github+json"
|
|
1839
|
+
|
|
1840
|
+
decode = True
|
|
1841
|
+
if method == "DELETE":
|
|
1842
|
+
decode = False
|
|
1843
|
+
|
|
1844
|
+
# GitHub paginates all queries when returning many items.
|
|
1845
|
+
# Gather all data using multiple queries and handle pagination.
|
|
1846
|
+
ret = {}
|
|
1847
|
+
complete_result = []
|
|
1848
|
+
next_page = True
|
|
1849
|
+
page_number = ""
|
|
1850
|
+
while next_page is True:
|
|
1851
|
+
if page_number:
|
|
1852
|
+
args["page"] = page_number
|
|
1853
|
+
result = salt.utils.http.query(
|
|
1854
|
+
url,
|
|
1855
|
+
method,
|
|
1856
|
+
params=args,
|
|
1857
|
+
data=data,
|
|
1858
|
+
header_dict=header_dict,
|
|
1859
|
+
decode=decode,
|
|
1860
|
+
decode_type="json",
|
|
1861
|
+
headers=True,
|
|
1862
|
+
status=True,
|
|
1863
|
+
text=True,
|
|
1864
|
+
hide_fields=None,
|
|
1865
|
+
opts=__opts__,
|
|
1866
|
+
)
|
|
1867
|
+
log.debug("GitHub Response Status Code: %s", result.get("status"))
|
|
1868
|
+
|
|
1869
|
+
if result.get("status") in [200, 201]:
|
|
1870
|
+
|
|
1871
|
+
if isinstance(result["dict"], dict):
|
|
1872
|
+
# If only querying for one item, such as a single issue
|
|
1873
|
+
# The GitHub API returns a single dictionary, instead of
|
|
1874
|
+
# A list of dictionaries. In that case, we can return.
|
|
1875
|
+
return result
|
|
1876
|
+
|
|
1877
|
+
ret = result
|
|
1878
|
+
complete_result = complete_result + result["dict"]
|
|
1879
|
+
ret["dict"] = complete_result
|
|
1880
|
+
|
|
1881
|
+
else:
|
|
1882
|
+
if result:
|
|
1883
|
+
return result
|
|
1884
|
+
raise CommandExecutionError
|
|
1885
|
+
|
|
1886
|
+
try:
|
|
1887
|
+
link_info = result.get("headers").get("Link").split(",")[0]
|
|
1888
|
+
except AttributeError:
|
|
1889
|
+
# Only one page of data was returned; exit the loop.
|
|
1890
|
+
next_page = False
|
|
1891
|
+
continue
|
|
1892
|
+
|
|
1893
|
+
if "next" in link_info:
|
|
1894
|
+
# Get the 'next' page number from the Link header.
|
|
1895
|
+
page_number = link_info.split(">")[0].split("&page=")[1]
|
|
1896
|
+
else:
|
|
1897
|
+
# Last page already processed; break the loop.
|
|
1898
|
+
next_page = False
|
|
1899
|
+
|
|
1900
|
+
return ret
|
|
1901
|
+
|
|
1902
|
+
|
|
1903
|
+
def _check_ruleset_params(profile, rule_id=False, rule_params=False, **kwargs):
|
|
1904
|
+
"""
|
|
1905
|
+
Helper function to check for param values on command line and in config file
|
|
1906
|
+
|
|
1907
|
+
profile
|
|
1908
|
+
The name of the profile configuration to use.
|
|
1909
|
+
|
|
1910
|
+
ruleset_id
|
|
1911
|
+
Defautls to false. If ruleset_id is required, set to True.
|
|
1912
|
+
|
|
1913
|
+
ruleset_params
|
|
1914
|
+
Defautls to false. If ruleset_params are required, set to True.
|
|
1915
|
+
|
|
1916
|
+
"""
|
|
1917
|
+
if not kwargs.get("ruleset_type"):
|
|
1918
|
+
kwargs["ruleset_type"] = _get_config_value(profile, "ruleset_type")
|
|
1919
|
+
if kwargs["ruleset_type"] not in ["repo", "org"]:
|
|
1920
|
+
raise CommandExecutionError
|
|
1921
|
+
|
|
1922
|
+
if kwargs["ruleset_type"] == "repo":
|
|
1923
|
+
if not kwargs.get("owner"):
|
|
1924
|
+
kwargs["owner"] = _get_config_value(profile, "owner")
|
|
1925
|
+
if not kwargs.get("repo_name"):
|
|
1926
|
+
kwargs["repo_name"] = _get_config_value(profile, "repo_name")
|
|
1927
|
+
|
|
1928
|
+
action = "/".join(["repos", kwargs["owner"], kwargs["repo_name"], "rulesets"])
|
|
1929
|
+
else:
|
|
1930
|
+
if not kwargs.get("org_name"):
|
|
1931
|
+
kwargs["org_name"] = _get_config_value(profile, "org_name")
|
|
1932
|
+
|
|
1933
|
+
action = "/".join(["orgs", kwargs["org_name"], "rulesets"])
|
|
1934
|
+
|
|
1935
|
+
# check for optional header_dict
|
|
1936
|
+
if not kwargs.get("header_dict"):
|
|
1937
|
+
try:
|
|
1938
|
+
kwargs["header_dict"] = _get_config_value(profile, "header_dict")
|
|
1939
|
+
except CommandExecutionError:
|
|
1940
|
+
kwargs["header_dict"] = {}
|
|
1941
|
+
|
|
1942
|
+
# verify header_dict is a dict
|
|
1943
|
+
if not isinstance(kwargs["header_dict"], dict):
|
|
1944
|
+
kwargs["header_dict"] = {}
|
|
1945
|
+
|
|
1946
|
+
# if ruleset is required, check for ruleset_id
|
|
1947
|
+
if rule_id:
|
|
1948
|
+
if not kwargs.get("ruleset_id"):
|
|
1949
|
+
kwargs["ruleset_id"] = _get_config_value(profile, "ruleset_id")
|
|
1950
|
+
|
|
1951
|
+
action = action + "/" + str(kwargs["ruleset_id"])
|
|
1952
|
+
|
|
1953
|
+
# if ruleset_params are required, check for ruleset_params
|
|
1954
|
+
if rule_params:
|
|
1955
|
+
if not kwargs.get("ruleset_params"):
|
|
1956
|
+
kwargs["ruleset_params"] = _get_config_value(profile, "ruleset_params")
|
|
1957
|
+
|
|
1958
|
+
return kwargs, action
|
|
1959
|
+
|
|
1960
|
+
|
|
1961
|
+
def get_ruleset(profile="github", **kwargs):
|
|
1962
|
+
"""
|
|
1963
|
+
Get information of specific ruleset.
|
|
1964
|
+
|
|
1965
|
+
profile
|
|
1966
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
1967
|
+
ruleset_type
|
|
1968
|
+
The type of ruleset. 'repo' or 'org'.
|
|
1969
|
+
ruleset_id
|
|
1970
|
+
Id of the ruleset.
|
|
1971
|
+
owner
|
|
1972
|
+
The account owner of the repository.
|
|
1973
|
+
repo_name
|
|
1974
|
+
The name of the repo.
|
|
1975
|
+
org_name
|
|
1976
|
+
The name of the organization.
|
|
1977
|
+
header_dict
|
|
1978
|
+
Headers to pass to Github API.
|
|
1979
|
+
|
|
1980
|
+
CLI Example:
|
|
1981
|
+
|
|
1982
|
+
.. code-block:: bash
|
|
1983
|
+
|
|
1984
|
+
salt myminion github.get_ruleset
|
|
1985
|
+
salt myminion github.get_ruleset ruleset_id=1
|
|
1986
|
+
"""
|
|
1987
|
+
params, action = _check_ruleset_params(profile, rule_id=True, **kwargs)
|
|
1988
|
+
|
|
1989
|
+
try:
|
|
1990
|
+
ret = _query(profile, action, header_dict=params["header_dict"])
|
|
1991
|
+
if not ret.get("error"):
|
|
1992
|
+
return ret["dict"]
|
|
1993
|
+
ret["comment"] = f"GitHub Response Status Code: {ret.get('error')}"
|
|
1994
|
+
ret["result"] = False
|
|
1995
|
+
except CommandExecutionError:
|
|
1996
|
+
ret = {}
|
|
1997
|
+
ret["result"] = False
|
|
1998
|
+
ret["comment"] = "Error getting ruleset"
|
|
1999
|
+
|
|
2000
|
+
return ret
|
|
2001
|
+
|
|
2002
|
+
|
|
2003
|
+
def delete_ruleset(profile="github", **kwargs):
|
|
2004
|
+
"""
|
|
2005
|
+
Delete ruleset
|
|
2006
|
+
|
|
2007
|
+
profile
|
|
2008
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
2009
|
+
ruleset_type
|
|
2010
|
+
The type of ruleset. 'repo' or 'org'.
|
|
2011
|
+
owner
|
|
2012
|
+
The account owner of the repository.
|
|
2013
|
+
repo_name
|
|
2014
|
+
The name of the repo.
|
|
2015
|
+
ruleset_id
|
|
2016
|
+
Id of the ruleset.
|
|
2017
|
+
org_name
|
|
2018
|
+
The name of the organization.
|
|
2019
|
+
header_dict
|
|
2020
|
+
Headers to pass to Github API.
|
|
2021
|
+
|
|
2022
|
+
CLI Example:
|
|
2023
|
+
|
|
2024
|
+
.. code-block:: bash
|
|
2025
|
+
|
|
2026
|
+
salt myminion github.delete_ruleset
|
|
2027
|
+
salt myminion github.delete_ruleset ruleset_id=1
|
|
2028
|
+
"""
|
|
2029
|
+
params, action = _check_ruleset_params(profile, rule_id=True, **kwargs)
|
|
2030
|
+
|
|
2031
|
+
try:
|
|
2032
|
+
ret = _query(profile, action, method="DELETE", header_dict=params["header_dict"])
|
|
2033
|
+
if ret.get("error"):
|
|
2034
|
+
ret["comment"] = f"GitHub Response Status Code: {ret.get('error')}"
|
|
2035
|
+
ret["result"] = False
|
|
2036
|
+
else:
|
|
2037
|
+
ret["comment"] = f"ruleset {params['ruleset_id']} successfully deleted"
|
|
2038
|
+
except CommandExecutionError:
|
|
2039
|
+
ret = {}
|
|
2040
|
+
ret["result"] = False
|
|
2041
|
+
ret["comment"] = "Error deleting ruleset"
|
|
2042
|
+
return ret
|
|
2043
|
+
|
|
2044
|
+
|
|
2045
|
+
def update_ruleset(profile="github", **kwargs):
|
|
2046
|
+
"""
|
|
2047
|
+
Update ruleset
|
|
2048
|
+
|
|
2049
|
+
profile
|
|
2050
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
2051
|
+
ruleset_type
|
|
2052
|
+
The type of ruleset. 'repo' or 'org'.
|
|
2053
|
+
ruleset_id
|
|
2054
|
+
Id of the ruleset.
|
|
2055
|
+
owner
|
|
2056
|
+
The account owner of the repository.
|
|
2057
|
+
repo_name
|
|
2058
|
+
The name of the repo.
|
|
2059
|
+
org_name
|
|
2060
|
+
The name of the organization.
|
|
2061
|
+
header_dict
|
|
2062
|
+
headers to pass to Github API.
|
|
2063
|
+
ruleset_params
|
|
2064
|
+
number of returned results (max 100).
|
|
2065
|
+
|
|
2066
|
+
CLI Example:
|
|
2067
|
+
|
|
2068
|
+
.. code-block:: bash
|
|
2069
|
+
|
|
2070
|
+
salt myminion github.update_ruleset
|
|
2071
|
+
salt myminion github.update_ruleset ruleset_id=1
|
|
2072
|
+
"""
|
|
2073
|
+
params, action = _check_ruleset_params(profile, rule_id=True, rule_params=True, **kwargs)
|
|
2074
|
+
|
|
2075
|
+
if not isinstance(params["ruleset_params"], dict):
|
|
2076
|
+
raise CommandExecutionError("params need to be a dict")
|
|
2077
|
+
|
|
2078
|
+
ruleset_params = salt.utils.json.dumps(params["ruleset_params"])
|
|
2079
|
+
try:
|
|
2080
|
+
ret = _query(
|
|
2081
|
+
profile, action, method="PUT", data=ruleset_params, header_dict=params["header_dict"]
|
|
2082
|
+
)
|
|
2083
|
+
if not ret.get("error"):
|
|
2084
|
+
return ret["dict"]
|
|
2085
|
+
else:
|
|
2086
|
+
ret["comment"] = f"GitHub Response Status Code: {ret.get('error')}"
|
|
2087
|
+
ret["result"] = False
|
|
2088
|
+
except CommandExecutionError:
|
|
2089
|
+
ret = {}
|
|
2090
|
+
ret["result"] = False
|
|
2091
|
+
ret["comment"] = "Error updating ruleset"
|
|
2092
|
+
|
|
2093
|
+
return ret
|
|
2094
|
+
|
|
2095
|
+
|
|
2096
|
+
def add_ruleset(profile="github", **kwargs):
|
|
2097
|
+
"""
|
|
2098
|
+
Add ruleset
|
|
2099
|
+
|
|
2100
|
+
profile
|
|
2101
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
2102
|
+
ruleset_type
|
|
2103
|
+
The type of ruleset. 'repo' or 'org'.
|
|
2104
|
+
owner
|
|
2105
|
+
The account owner of the repository.
|
|
2106
|
+
repo_name
|
|
2107
|
+
The name of the repo.
|
|
2108
|
+
org_name
|
|
2109
|
+
The name of the organization.
|
|
2110
|
+
header_dict
|
|
2111
|
+
headers to pass to Github API.
|
|
2112
|
+
ruleset_params
|
|
2113
|
+
number of returned results (max 100).
|
|
2114
|
+
|
|
2115
|
+
CLI Example:
|
|
2116
|
+
|
|
2117
|
+
.. code-block:: bash
|
|
2118
|
+
|
|
2119
|
+
salt myminion github.add_ruleset
|
|
2120
|
+
"""
|
|
2121
|
+
params, action = _check_ruleset_params(profile, rule_params=True, **kwargs)
|
|
2122
|
+
|
|
2123
|
+
if not isinstance(params["ruleset_params"], dict):
|
|
2124
|
+
raise CommandExecutionError("params need to be a dict")
|
|
2125
|
+
if "name" not in params["ruleset_params"]:
|
|
2126
|
+
raise CommandExecutionError("name is required")
|
|
2127
|
+
if "enforcement" not in params["ruleset_params"]:
|
|
2128
|
+
raise CommandExecutionError("enforcement is required")
|
|
2129
|
+
|
|
2130
|
+
ruleset_params = salt.utils.json.dumps(params["ruleset_params"])
|
|
2131
|
+
try:
|
|
2132
|
+
ret = _query(
|
|
2133
|
+
profile, action, method="POST", data=ruleset_params, header_dict=params["header_dict"]
|
|
2134
|
+
)
|
|
2135
|
+
if not ret.get("error"):
|
|
2136
|
+
return ret["dict"]
|
|
2137
|
+
else:
|
|
2138
|
+
ret["comment"] = f"GitHub Response Status Code: {ret.get('error')}"
|
|
2139
|
+
ret["result"] = False
|
|
2140
|
+
except CommandExecutionError:
|
|
2141
|
+
ret = {}
|
|
2142
|
+
ret["result"] = False
|
|
2143
|
+
ret["comment"] = "Error adding ruleset"
|
|
2144
|
+
return ret
|
|
2145
|
+
|
|
2146
|
+
|
|
2147
|
+
def list_rulesets(profile="github", **kwargs):
|
|
2148
|
+
"""
|
|
2149
|
+
List rulesets
|
|
2150
|
+
|
|
2151
|
+
profile
|
|
2152
|
+
The name of the profile configuration to use. Defaults to ``github``.
|
|
2153
|
+
ruleset_type
|
|
2154
|
+
The type of ruleset. 'repo' or 'org'.
|
|
2155
|
+
owner
|
|
2156
|
+
The account owner of the repository.
|
|
2157
|
+
repo_name
|
|
2158
|
+
The name of the repo.
|
|
2159
|
+
org_name
|
|
2160
|
+
The name of the organization.
|
|
2161
|
+
header_dict
|
|
2162
|
+
headers to pass to Github API.
|
|
2163
|
+
per_page
|
|
2164
|
+
number of returned results (max 100).
|
|
2165
|
+
|
|
2166
|
+
CLI Example:
|
|
2167
|
+
|
|
2168
|
+
.. code-block:: bash
|
|
2169
|
+
|
|
2170
|
+
salt myminion github.list_rulesets
|
|
2171
|
+
"""
|
|
2172
|
+
params, action = _check_ruleset_params(profile, **kwargs)
|
|
2173
|
+
|
|
2174
|
+
if not kwargs.get("per_page"):
|
|
2175
|
+
try:
|
|
2176
|
+
kwargs["per_page"] = _get_config_value(profile, "per_page")
|
|
2177
|
+
except CommandExecutionError:
|
|
2178
|
+
kwargs["per_page"] = None
|
|
2179
|
+
|
|
2180
|
+
try:
|
|
2181
|
+
ret = _query(
|
|
2182
|
+
profile, action, header_dict=params["header_dict"], per_page=kwargs["per_page"]
|
|
2183
|
+
)
|
|
2184
|
+
if not ret.get("error"):
|
|
2185
|
+
if ret["dict"]:
|
|
2186
|
+
return {"rulesets": ret["dict"]}
|
|
2187
|
+
return {"rulesets": None}
|
|
2188
|
+
else:
|
|
2189
|
+
ret["comment"] = f"GitHub Response Status Code: {ret.get('error')}"
|
|
2190
|
+
ret["result"] = False
|
|
2191
|
+
except CommandExecutionError:
|
|
2192
|
+
ret = {}
|
|
2193
|
+
ret["result"] = False
|
|
2194
|
+
ret["comment"] = "Error getting rulesets"
|
|
2195
|
+
return ret
|