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,128 @@
1
+ """
2
+ Operations on GitHub Pages sites of repositories.
3
+ """
4
+
5
+ import logging
6
+
7
+ from saltext.github.utils import filter_unset
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ def build_source(branch=None, path=None):
13
+ """
14
+ Build a Pages ``source`` payload from branch and path, or ``None``
15
+ when both are unset.
16
+
17
+ branch
18
+ Repository branch to publish from.
19
+
20
+ path
21
+ Repository directory to publish from, either ``/`` or ``/docs``.
22
+ """
23
+ source = filter_unset({"branch": branch, "path": path})
24
+ return source or None
25
+
26
+
27
+ def get(conn, repo_name, *, owner=None):
28
+ """
29
+ Return information about the GitHub Pages site of a repository.
30
+
31
+ conn
32
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
33
+
34
+ repo_name
35
+ Repository name.
36
+
37
+ owner
38
+ Owner of the repository. Defaults to the connection's owner.
39
+
40
+ Raises :class:`~saltext.github.utils.gh.exceptions.GitHubNotFoundError`
41
+ if the repository has no Pages site.
42
+ """
43
+ return conn.repo_query(owner, repo_name, "pages")
44
+
45
+
46
+ def create(conn, repo_name, *, build_type=None, source=None, owner=None):
47
+ """
48
+ Configure a GitHub Pages site for a repository.
49
+ Returns the data of the created site.
50
+
51
+ conn
52
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
53
+
54
+ repo_name
55
+ Repository name.
56
+
57
+ build_type
58
+ Process by which the site is built, either ``legacy``
59
+ (deploy from a branch) or ``workflow`` (GitHub Actions).
60
+
61
+ source
62
+ For ``legacy`` builds, the deployment source as a mapping with
63
+ ``branch`` and ``path``.
64
+
65
+ owner
66
+ Owner of the repository. Defaults to the connection's owner.
67
+ """
68
+ return conn.repo_query(
69
+ owner,
70
+ repo_name,
71
+ "pages",
72
+ method="POST",
73
+ data=filter_unset({"build_type": build_type, "source": source}),
74
+ )
75
+
76
+
77
+ def update(
78
+ conn, repo_name, *, build_type=None, source=None, cname=..., https_enforced=None, owner=None
79
+ ):
80
+ """
81
+ Update the GitHub Pages site configuration of a repository.
82
+
83
+ conn
84
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
85
+
86
+ repo_name
87
+ Repository name.
88
+
89
+ build_type
90
+ Process by which the site is built, either ``legacy``
91
+ (deploy from a branch) or ``workflow`` (GitHub Actions).
92
+
93
+ source
94
+ For ``legacy`` builds, the deployment source as a mapping with
95
+ ``branch`` and ``path``.
96
+
97
+ cname
98
+ Custom domain for the site. Pass ``None`` explicitly
99
+ to remove it.
100
+
101
+ https_enforced
102
+ Enforce HTTPS for the site.
103
+
104
+ owner
105
+ Owner of the repository. Defaults to the connection's owner.
106
+ """
107
+ data = filter_unset(
108
+ {"build_type": build_type, "source": source, "https_enforced": https_enforced}
109
+ )
110
+ if cname is not ...:
111
+ data["cname"] = cname
112
+ conn.repo_query(owner, repo_name, "pages", method="PUT", data=data)
113
+
114
+
115
+ def delete(conn, repo_name, *, owner=None):
116
+ """
117
+ Delete the GitHub Pages site of a repository.
118
+
119
+ conn
120
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
121
+
122
+ repo_name
123
+ Repository name.
124
+
125
+ owner
126
+ Owner of the repository. Defaults to the connection's owner.
127
+ """
128
+ conn.repo_query(owner, repo_name, "pages", method="DELETE")
@@ -0,0 +1,458 @@
1
+ """
2
+ Resolution of Salt profile configuration into GitHub connections,
3
+ shared between the ``github``, ``github_org`` and ``github_repo``
4
+ execution modules as well as the ``github`` resource type.
5
+
6
+ Profiles are resolved directly from ``opts``, mirroring ``config.get``'s
7
+ lookup order: minion configuration, then grains, then pillar, then
8
+ master configuration (which reaches the minion via the master's
9
+ ``pillar_opts`` setting, rendered under ``pillar["master"]``). SDB URIs
10
+ in profile values are rendered on access, like ``config.get`` renders
11
+ them. ``config.get`` itself cannot serve as the backend since it is
12
+ unavailable to parts of the resource subsystem (type discovery runs
13
+ before the minion's module loader exists).
14
+ """
15
+
16
+ import logging
17
+ from pathlib import Path
18
+
19
+ from salt.exceptions import CommandExecutionError
20
+
21
+ from saltext.github.utils.gh.cache import MISS
22
+ from saltext.github.utils.gh.cache import PersistentCache
23
+ from saltext.github.utils.gh.client import API_URL_DEFAULT
24
+ from saltext.github.utils.gh.client import GitHubConnection
25
+ from saltext.github.utils.gh.client import build_app_auth
26
+ from saltext.github.utils.gh.client import get_app_connection_ident
27
+ from saltext.github.utils.gh.client import get_connection_ident
28
+ from saltext.github.utils.gh.client import resolve_app_installation_id
29
+
30
+ log = logging.getLogger(__name__)
31
+
32
+ _UNSET = object()
33
+
34
+
35
+ def _render_value(value, opts, utils=None):
36
+ """
37
+ Render ``sdb://`` URIs in scalar configuration values, mirroring
38
+ what ``config.get`` does for profile values.
39
+ """
40
+ if isinstance(value, str) and value.startswith("sdb://"):
41
+ # Only required to resolve SDB URIs
42
+ import salt.utils.sdb # pylint: disable=import-outside-toplevel
43
+
44
+ return salt.utils.sdb.sdb_get(value, opts, utils=utils)
45
+ return value
46
+
47
+
48
+ def get_config_value(profile, config_name, *, opts, context=None, utils=None, default=_UNSET):
49
+ """
50
+ Return a profile's configuration value based on the supplied
51
+ configuration name. See the module docstring for the lookup order
52
+ and SDB handling; the first scope carrying the requested value wins.
53
+
54
+ profile
55
+ Profile name that contains configuration information.
56
+
57
+ config_name
58
+ Configuration item name to look up.
59
+
60
+ opts
61
+ The minion configuration (``__opts__``).
62
+
63
+ context
64
+ Pass ``__context__`` to cache rendered values, saving repeated
65
+ SDB lookups.
66
+
67
+ utils
68
+ Pass ``__utils__`` when available to avoid building a fresh
69
+ utils loader for SDB rendering.
70
+
71
+ default
72
+ Value to return when the profile does not carry the item.
73
+ Without it, a missing item raises a ``CommandExecutionError``.
74
+ """
75
+ cache = None
76
+ if context is not None:
77
+ cache = context.setdefault("gh_profile", {}).setdefault(profile, {})
78
+ if cache is None or config_name not in cache:
79
+ pillar = opts.get("pillar") or {}
80
+ master_pillar = pillar.get("master")
81
+ scopes = (
82
+ opts,
83
+ opts.get("grains") or {},
84
+ pillar,
85
+ master_pillar if isinstance(master_pillar, dict) else {},
86
+ )
87
+ configs = [
88
+ scope[profile]
89
+ for scope in scopes
90
+ if isinstance(scope.get(profile), dict) and scope[profile]
91
+ ]
92
+ if not configs:
93
+ raise CommandExecutionError(
94
+ f"Authentication information could not be found for the '{profile}' profile."
95
+ )
96
+ value = None
97
+ for config in configs:
98
+ found = config.get(config_name)
99
+ if found is not None:
100
+ value = _render_value(found, opts, utils=utils)
101
+ break
102
+ if cache is not None:
103
+ cache[config_name] = value
104
+ else:
105
+ value = cache[config_name]
106
+
107
+ if value is None:
108
+ if default is not _UNSET:
109
+ return default
110
+ raise CommandExecutionError(
111
+ f"The '{config_name}' parameter was not found in the '{profile}' profile."
112
+ )
113
+ return value
114
+
115
+
116
+ def get_api_url(profile, *, opts, context=None, utils=None):
117
+ """
118
+ Return the configured GitHub API base URL, defaulting to the public one.
119
+
120
+ profile
121
+ Profile name that contains configuration information.
122
+
123
+ opts
124
+ The minion configuration (``__opts__``).
125
+
126
+ context
127
+ Pass ``__context__`` to cache rendered values.
128
+
129
+ utils
130
+ Pass ``__utils__`` when available (SDB rendering).
131
+ """
132
+ return get_config_value(
133
+ profile, "api_url", opts=opts, context=context, utils=utils, default=API_URL_DEFAULT
134
+ ).rstrip("/")
135
+
136
+
137
+ def get_owner(profile, *, opts, context=None, utils=None):
138
+ """
139
+ Return the configured default repository owner: the profile's
140
+ ``owner``, falling back to the legacy ``org_name`` alias. Returns
141
+ ``None`` when neither is set, making the connection default to the
142
+ token's user.
143
+
144
+ profile
145
+ Profile name that contains configuration information.
146
+
147
+ opts
148
+ The minion configuration (``__opts__``).
149
+
150
+ context
151
+ Pass ``__context__`` to cache rendered values.
152
+
153
+ utils
154
+ Pass ``__utils__`` when available (SDB rendering).
155
+ """
156
+ for key in ("owner", "org_name"):
157
+ owner = get_config_value(
158
+ profile, key, opts=opts, context=context, utils=utils, default=None
159
+ )
160
+ if owner is not None:
161
+ return owner
162
+ return None
163
+
164
+
165
+ def get_conn(profile, *, opts, context, utils=None):
166
+ """
167
+ Return a :class:`~saltext.github.utils.gh.client.GitHubConnection`
168
+ for a profile, cached in ``context`` for performance.
169
+
170
+ Unless the profile disables it (:ghconf:`cache`), the connection
171
+ carries a :class:`~saltext.github.utils.gh.cache.PersistentCache`
172
+ for slow-changing API data, surviving across processes.
173
+
174
+ profile
175
+ Profile name that contains configuration information.
176
+
177
+ opts
178
+ The minion configuration (``__opts__``).
179
+
180
+ context
181
+ Pass ``__context__``. Caches the connection and rendered
182
+ profile values.
183
+
184
+ utils
185
+ Pass ``__utils__`` when available (SDB rendering).
186
+ """
187
+ profile_key = f"github.profile.{profile}"
188
+ if profile_key in context:
189
+ return context[profile_key]
190
+
191
+ token = get_config_value(
192
+ profile, "token", opts=opts, context=context, utils=utils, default=None
193
+ )
194
+ app_id = get_config_value(
195
+ profile, "app_id", opts=opts, context=context, utils=utils, default=None
196
+ )
197
+ api_url = get_api_url(profile, opts=opts, context=context, utils=utils)
198
+ owner = get_owner(profile, opts=opts, context=context, utils=utils)
199
+ permissions = get_config_value(
200
+ profile, "permissions", opts=opts, context=context, utils=utils, default=None
201
+ )
202
+ if token is not None and app_id is not None:
203
+ raise CommandExecutionError(
204
+ f"The '{profile}' profile specifies both 'token' and 'app_id', "
205
+ "which are mutually exclusive."
206
+ )
207
+ if token is not None:
208
+ if permissions is not None:
209
+ raise CommandExecutionError(
210
+ f"The 'permissions' parameter is only valid for GitHub App ('app_id') "
211
+ f"profiles, but the '{profile}' profile uses token authentication."
212
+ )
213
+ # Hash the token to keep the secret out of context dumps
214
+ ident = get_connection_ident(token, api_url)
215
+ elif app_id is not None:
216
+ if not owner:
217
+ raise CommandExecutionError(
218
+ f"GitHub App authentication requires the 'owner' parameter "
219
+ f"in the '{profile}' profile."
220
+ )
221
+ if permissions is not None and not isinstance(permissions, dict):
222
+ raise CommandExecutionError(
223
+ f"The 'permissions' parameter of the '{profile}' profile must be a "
224
+ "mapping of permission name to access level."
225
+ )
226
+ # Derived from the app's identity, not its short-lived
227
+ # installation tokens - persistent cache banks survive rotation.
228
+ # Differently restricted profiles must not share connections.
229
+ ident = get_app_connection_ident(app_id, owner, api_url, permissions)
230
+ else:
231
+ raise CommandExecutionError(
232
+ f"The '{profile}' profile is missing authentication credentials. "
233
+ "Specify either 'token' or 'app_id' + 'private_key'/'private_key_path'."
234
+ )
235
+ conn_key = f"github.conn.{ident}"
236
+
237
+ # This config is HTTP connection-independent. We should reuse a client, if it exists.
238
+ cache_enabled = get_config_value(
239
+ profile, "cache", opts=opts, context=context, utils=utils, default=True
240
+ )
241
+
242
+ if conn_key in context:
243
+ other_conn = context[conn_key]
244
+ store = ...
245
+ if bool(other_conn.store) is not cache_enabled:
246
+ store = PersistentCache(opts, ident) if cache_enabled else None
247
+ context[profile_key] = context[conn_key].with_(owner=owner, store=store)
248
+ else:
249
+ store = PersistentCache(opts, ident) if cache_enabled else None
250
+ auth = token
251
+ if auth is None:
252
+ auth = _get_app_auth(
253
+ profile,
254
+ app_id,
255
+ owner=owner,
256
+ api_url=api_url,
257
+ permissions=permissions,
258
+ store=store,
259
+ opts=opts,
260
+ context=context,
261
+ utils=utils,
262
+ )
263
+ context[profile_key] = context[conn_key] = GitHubConnection(
264
+ auth,
265
+ owner,
266
+ api_url=api_url,
267
+ ident=ident,
268
+ store=store,
269
+ )
270
+ return context[profile_key]
271
+
272
+
273
+ def _get_app_auth(
274
+ profile, app_id, *, owner, api_url, permissions, store, opts, context, utils=None
275
+ ):
276
+ """
277
+ Build the PyGithub auth object for a GitHub App profile. When the
278
+ profile does not pin :ghconf:`installation_id`, the app's
279
+ installation on ``owner`` is discovered via the API (cached in
280
+ ``store``, when available).
281
+ """
282
+ private_key = get_config_value(
283
+ profile, "private_key", opts=opts, context=context, utils=utils, default=None
284
+ )
285
+ private_key_path = get_config_value(
286
+ profile, "private_key_path", opts=opts, context=context, utils=utils, default=None
287
+ )
288
+ if (private_key is None) is (private_key_path is None):
289
+ raise CommandExecutionError(
290
+ f"GitHub App authentication requires exactly one of 'private_key' or "
291
+ f"'private_key_path', the '{profile}' profile specifies "
292
+ f"{'both' if private_key is not None else 'neither'}."
293
+ )
294
+ if private_key_path is not None:
295
+ try:
296
+ private_key = Path(private_key_path).read_text(encoding="utf-8")
297
+ except OSError as err:
298
+ raise CommandExecutionError(
299
+ f"Failed reading 'private_key_path' of the '{profile}' profile: {err}"
300
+ ) from err
301
+ installation_id = get_config_value(
302
+ profile, "installation_id", opts=opts, context=context, utils=utils, default=None
303
+ )
304
+ if installation_id is None and store is not None:
305
+ installation_id = store.get_meta("installation_id")
306
+ if installation_id is MISS:
307
+ installation_id = None
308
+ if installation_id is None:
309
+ installation_id = resolve_app_installation_id(app_id, private_key, owner, api_url)
310
+ if store is not None:
311
+ store.set_meta("installation_id", installation_id)
312
+ return build_app_auth(app_id, private_key, installation_id, permissions)
313
+
314
+
315
+ def resource_decl(opts):
316
+ """
317
+ Return the ``github`` resource type's declaration from the resource
318
+ pillar subtree (``{}`` when unset or not a mapping).
319
+
320
+ opts
321
+ The minion configuration (``__opts__``).
322
+ """
323
+ # Local import: the resource subsystem only exists in Salt >= 3008,
324
+ # while this module is also imported on earlier releases.
325
+ import salt.utils.resources # pylint: disable=import-outside-toplevel
326
+
327
+ decl = salt.utils.resources.pillar_resources_tree(opts).get("github")
328
+ return decl if isinstance(decl, dict) else {}
329
+
330
+
331
+ def resource_profile(opts):
332
+ """
333
+ Return the default profile name configured in the ``github``
334
+ resource declaration, defaulting to ``github``.
335
+
336
+ opts
337
+ The minion configuration (``__opts__``).
338
+ """
339
+ return resource_decl(opts).get("profile") or "github"
340
+
341
+
342
+ def resource_owners(opts):
343
+ """
344
+ Return the owners named in the ``github`` resource declaration as a
345
+ list (an empty one when unset). The declaration's ``owners`` may be
346
+ a plain list of owner names or a mapping of owner name to per-owner
347
+ settings (``profile``, ``repos``, ``exclude``, ``include_archived``).
348
+
349
+ opts
350
+ The minion configuration (``__opts__``).
351
+ """
352
+ owners = resource_decl(opts).get("owners")
353
+ if isinstance(owners, dict):
354
+ return list(owners)
355
+ return list(owners or [])
356
+
357
+
358
+ def _owner_settings(opts, owner):
359
+ """
360
+ Return one owner's settings mapping from the declaration's
361
+ ``owners``, matched case-insensitively (``{}`` when the owners are
362
+ a plain list or the owner carries no settings).
363
+ """
364
+ owners = resource_decl(opts).get("owners")
365
+ if isinstance(owners, dict) and owner is not None:
366
+ for name, settings in owners.items():
367
+ if name.lower() == owner.lower() and isinstance(settings, dict):
368
+ return settings
369
+ return {}
370
+
371
+
372
+ def resource_owner_setting(opts, owner, key, default=None):
373
+ """
374
+ Return a declaration setting for one owner: the owner's own value
375
+ from the ``owners`` mapping when set, otherwise the
376
+ declaration-level value, otherwise ``default``.
377
+
378
+ opts
379
+ The minion configuration (``__opts__``).
380
+
381
+ owner
382
+ Owner (organization or user) login.
383
+
384
+ key
385
+ Setting name (``profile``, ``repos``, ``exclude``,
386
+ ``include_archived``).
387
+
388
+ default
389
+ Value to return when neither the owner nor the declaration
390
+ carries the setting.
391
+ """
392
+ value = _owner_settings(opts, owner).get(key)
393
+ if value is None:
394
+ value = resource_decl(opts).get(key)
395
+ return value if value is not None else default
396
+
397
+
398
+ def resource_owner_profile(opts, owner):
399
+ """
400
+ Return the profile name to use for one owner's repositories: the
401
+ owner's ``profile`` override from the declaration's ``owners``
402
+ mapping when present, otherwise the declaration's default profile.
403
+ Owner names are matched case-insensitively.
404
+
405
+ opts
406
+ The minion configuration (``__opts__``).
407
+
408
+ owner
409
+ Owner (organization or user) login.
410
+ """
411
+ return resource_owner_setting(opts, owner, "profile", "github")
412
+
413
+
414
+ def resource_profiles(opts):
415
+ """
416
+ Return all distinct profile names referenced by the ``github``
417
+ resource declaration: the default one plus any per-owner overrides.
418
+
419
+ opts
420
+ The minion configuration (``__opts__``).
421
+ """
422
+ profiles = [resource_profile(opts)]
423
+ owners = resource_decl(opts).get("owners")
424
+ if isinstance(owners, dict):
425
+ for settings in owners.values():
426
+ if isinstance(settings, dict) and settings.get("profile"):
427
+ if settings["profile"] not in profiles:
428
+ profiles.append(settings["profile"])
429
+ return profiles
430
+
431
+
432
+ def resource_conn(opts, context, *, profile=None, owner=None, utils=None):
433
+ """
434
+ Return the :class:`~saltext.github.utils.gh.client.GitHubConnection`
435
+ for a ``github`` resource context, resolved from ``opts``.
436
+
437
+ opts
438
+ The minion configuration (``__opts__``).
439
+
440
+ context
441
+ Cache mapping for the connection (``__context__``).
442
+
443
+ profile
444
+ Profile name override. When unset, the profile is resolved from
445
+ the resource declaration: the targeted ``owner``'s override when
446
+ declared, otherwise the declaration's default profile
447
+ (``github`` when unset).
448
+
449
+ owner
450
+ Owner the connection is for, used to resolve per-owner profile
451
+ overrides. Ignored when ``profile`` is passed.
452
+
453
+ utils
454
+ Pass ``__utils__`` when available (SDB rendering).
455
+ """
456
+ return get_conn(
457
+ profile or resource_owner_profile(opts, owner), opts=opts, context=context, utils=utils
458
+ )
@@ -0,0 +1,99 @@
1
+ """
2
+ Operations on GitHub repository pull requests.
3
+ """
4
+
5
+ import logging
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+
10
+ def list_all(
11
+ conn,
12
+ repo_name,
13
+ *,
14
+ state="open",
15
+ head=None,
16
+ base=None,
17
+ sort="created",
18
+ direction="desc",
19
+ per_page=None,
20
+ owner=None,
21
+ ):
22
+ """
23
+ Return the raw data of all pull requests in a repository matching the
24
+ search options.
25
+
26
+ conn
27
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
28
+
29
+ repo_name
30
+ Repository whose pull requests to list.
31
+
32
+ state
33
+ Filter returned pull requests by their state. Can be either
34
+ ``open``, ``closed``, or ``all``. Default is ``open``.
35
+
36
+ head
37
+ Filter pull requests by head user and branch name in the format
38
+ ``user:ref-name``.
39
+
40
+ base
41
+ Filter pulls by base branch name, e.g. ``gh-pages``.
42
+
43
+ sort
44
+ Field to sort results by. Either ``created``, ``updated``,
45
+ ``popularity`` (comment count), or ``long-running`` (age,
46
+ filtering by pull requests updated within the last month).
47
+ Default is ``created``.
48
+
49
+ direction
50
+ Sort direction. Either ``asc`` or ``desc``. Default is ``desc``.
51
+
52
+ per_page
53
+ Pagination size, maximum 100.
54
+
55
+ owner
56
+ Owner of the repository. Defaults to the connection's owner.
57
+ """
58
+ params = {}
59
+
60
+ # Build API arguments, as necessary.
61
+ if head:
62
+ params["head"] = head
63
+ if base:
64
+ params["base"] = base
65
+ if per_page:
66
+ params["per_page"] = per_page
67
+
68
+ # Only pass the following API args if they're not the defaults listed.
69
+ if state and state != "open":
70
+ params["state"] = state
71
+ if sort and sort != "created":
72
+ params["sort"] = sort
73
+ if direction and direction != "desc":
74
+ params["direction"] = direction
75
+
76
+ return conn.repo_query(owner, repo_name, "pulls", params=params)
77
+
78
+
79
+ def format_pr(pr_):
80
+ r"""
81
+ Format API return information into a more manageable
82
+ and useful dictionary for pull request information.
83
+
84
+ Legacy function, only used by deprecated callers.
85
+
86
+ pr\_
87
+ Pull request to format.
88
+ """
89
+ ret = {
90
+ "id": pr_.get("id"),
91
+ "pr_number": pr_.get("number"),
92
+ "state": pr_.get("state"),
93
+ "title": pr_.get("title"),
94
+ "user": pr_.get("user").get("login"),
95
+ "html_url": pr_.get("html_url"),
96
+ "base_branch": pr_.get("base").get("ref"),
97
+ }
98
+
99
+ return ret