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,116 @@
1
+ """
2
+ State core managing repository labels.
3
+ """
4
+
5
+ import logging
6
+
7
+ from saltext.github.utils.gh import labels as gh_labels
8
+ from saltext.github.utils.gh.exceptions import GitHubNotFoundError
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+
13
+ def present(conn, name, repo_name, *, color=None, description=None, owner=None, test=False):
14
+ """
15
+ Ensure a label is present in a repository and configured as
16
+ specified. Unspecified settings are left unmanaged.
17
+
18
+ conn
19
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
20
+
21
+ name
22
+ Name of the label.
23
+
24
+ repo_name
25
+ Name of the repository.
26
+
27
+ color
28
+ Hexadecimal color code for the label. A leading ``#``
29
+ is accepted.
30
+
31
+ description
32
+ Short description of the label.
33
+
34
+ owner
35
+ Owner of the repository. Defaults to the connection's owner.
36
+
37
+ test
38
+ Only project the changes without applying them (``test`` mode).
39
+ """
40
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
41
+
42
+ try:
43
+ current = gh_labels.get(conn, repo_name, name, owner=owner)
44
+ except GitHubNotFoundError:
45
+ current = None
46
+
47
+ if current is None:
48
+ ret["changes"]["created"] = name
49
+ if test:
50
+ ret["result"] = None
51
+ ret["comment"] = f"Label {name} would have been created"
52
+ return ret
53
+ gh_labels.create(conn, repo_name, name, color=color, description=description, owner=owner)
54
+ ret["comment"] = f"Label {name} has been created"
55
+ return ret
56
+
57
+ diff = {}
58
+ if color is not None and gh_labels.normalize_color(
59
+ current["color"]
60
+ ) != gh_labels.normalize_color(color):
61
+ diff["color"] = color
62
+ if description is not None and current.get("description") != description:
63
+ diff["description"] = description
64
+
65
+ if not diff:
66
+ ret["comment"] = f"Label {name} is already configured as specified"
67
+ return ret
68
+
69
+ ret["changes"]["old"] = {key: current.get(key) for key in diff}
70
+ ret["changes"]["new"] = diff
71
+ if test:
72
+ ret["result"] = None
73
+ ret["comment"] = f"Label {name} would have been updated"
74
+ return ret
75
+
76
+ gh_labels.update(conn, repo_name, name, owner=owner, **diff)
77
+ ret["comment"] = f"Label {name} has been updated"
78
+ return ret
79
+
80
+
81
+ def absent(conn, name, repo_name, *, owner=None, test=False):
82
+ """
83
+ Ensure a label is absent from a repository.
84
+
85
+ conn
86
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
87
+
88
+ name
89
+ Name of the label.
90
+
91
+ repo_name
92
+ Name of the repository.
93
+
94
+ owner
95
+ Owner of the repository. Defaults to the connection's owner.
96
+
97
+ test
98
+ Only project the changes without applying them (``test`` mode).
99
+ """
100
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
101
+
102
+ try:
103
+ gh_labels.get(conn, repo_name, name, owner=owner)
104
+ except GitHubNotFoundError:
105
+ ret["comment"] = f"Label {name} is already absent"
106
+ return ret
107
+
108
+ ret["changes"]["deleted"] = name
109
+ if test:
110
+ ret["result"] = None
111
+ ret["comment"] = f"Label {name} would have been removed"
112
+ return ret
113
+
114
+ gh_labels.delete(conn, repo_name, name, owner=owner)
115
+ ret["comment"] = f"Label {name} has been removed"
116
+ return ret
@@ -0,0 +1,177 @@
1
+ """
2
+ State core managing a repository's GitHub Pages site.
3
+ """
4
+
5
+ import logging
6
+
7
+ from saltext.github.utils import filter_unset
8
+ from saltext.github.utils.gh import pages as gh_pages
9
+ from saltext.github.utils.gh.exceptions import GitHubNotFoundError
10
+
11
+ log = logging.getLogger(__name__)
12
+
13
+
14
+ def present(
15
+ conn,
16
+ name,
17
+ repo_name,
18
+ *,
19
+ build_type=None,
20
+ source_branch=None,
21
+ source_path=None,
22
+ cname=None,
23
+ https_enforced=None,
24
+ owner=None,
25
+ test=False,
26
+ ):
27
+ """
28
+ Ensure GitHub Pages are enabled for a repository and configured as
29
+ specified. Unspecified settings are left unmanaged.
30
+
31
+ conn
32
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
33
+
34
+ name
35
+ State name (reported back unchanged).
36
+
37
+ repo_name
38
+ Name of the repository.
39
+
40
+ build_type
41
+ Process by which the site is built, either ``legacy``
42
+ (deploy from a branch) or ``workflow`` (GitHub Actions).
43
+
44
+ source_branch
45
+ For ``legacy`` builds, the repository branch to publish from.
46
+
47
+ source_path
48
+ For ``legacy`` builds, the repository directory to publish from,
49
+ either ``/`` or ``/docs``.
50
+
51
+ cname
52
+ Custom domain for the site.
53
+
54
+ https_enforced
55
+ Enforce HTTPS for the site.
56
+
57
+ owner
58
+ Owner of the repository. Defaults to the connection's owner.
59
+
60
+ test
61
+ Only project the changes without applying them (``test`` mode).
62
+ """
63
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
64
+
65
+ try:
66
+ current = gh_pages.get(conn, repo_name, owner=owner)
67
+ except GitHubNotFoundError:
68
+ current = None
69
+
70
+ if current is None:
71
+ ret["changes"]["created"] = repo_name
72
+ if test:
73
+ ret["result"] = None
74
+ ret["comment"] = f"Pages would have been enabled for {repo_name}"
75
+ return ret
76
+ gh_pages.create(
77
+ conn,
78
+ repo_name,
79
+ build_type=build_type,
80
+ source=gh_pages.build_source(source_branch, source_path),
81
+ owner=owner,
82
+ )
83
+ if cname is not None or https_enforced is not None:
84
+ extra = {"https_enforced": https_enforced}
85
+ if cname is not None:
86
+ extra["cname"] = cname
87
+ gh_pages.update(conn, repo_name, owner=owner, **extra)
88
+ ret["comment"] = f"Pages have been enabled for {repo_name}"
89
+ return ret
90
+
91
+ current_source = current.get("source") or {}
92
+ desired = filter_unset(
93
+ {
94
+ "build_type": build_type,
95
+ "source_branch": source_branch,
96
+ "source_path": source_path,
97
+ "cname": cname,
98
+ "https_enforced": https_enforced,
99
+ }
100
+ )
101
+ current_flat = {
102
+ "build_type": current.get("build_type"),
103
+ "source_branch": current_source.get("branch"),
104
+ "source_path": current_source.get("path"),
105
+ "cname": current.get("cname"),
106
+ "https_enforced": current.get("https_enforced"),
107
+ }
108
+ diff = {key: val for key, val in desired.items() if current_flat[key] != val}
109
+
110
+ if not diff:
111
+ ret["comment"] = f"Pages for {repo_name} are already configured as specified"
112
+ return ret
113
+
114
+ ret["changes"]["old"] = {key: current_flat[key] for key in diff}
115
+ ret["changes"]["new"] = diff
116
+ if test:
117
+ ret["result"] = None
118
+ ret["comment"] = f"Pages configuration for {repo_name} would have been updated"
119
+ return ret
120
+
121
+ update_kwargs = dict(diff)
122
+ if "source_branch" in diff or "source_path" in diff:
123
+ # The source is submitted as a single object, carry over the
124
+ # unchanged half
125
+ update_kwargs.setdefault("source_branch", current_flat["source_branch"])
126
+ update_kwargs.setdefault("source_path", current_flat["source_path"])
127
+ gh_pages.update(
128
+ conn,
129
+ repo_name,
130
+ build_type=update_kwargs.get("build_type"),
131
+ source=gh_pages.build_source(
132
+ update_kwargs.get("source_branch"), update_kwargs.get("source_path")
133
+ ),
134
+ cname=update_kwargs.get("cname", ...),
135
+ https_enforced=update_kwargs.get("https_enforced"),
136
+ owner=owner,
137
+ )
138
+ ret["comment"] = f"Pages configuration for {repo_name} has been updated"
139
+ return ret
140
+
141
+
142
+ def absent(conn, name, repo_name, *, owner=None, test=False):
143
+ """
144
+ Ensure GitHub Pages are disabled for a repository.
145
+
146
+ conn
147
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
148
+
149
+ name
150
+ State name (reported back unchanged).
151
+
152
+ repo_name
153
+ Name of the repository.
154
+
155
+ owner
156
+ Owner of the repository. Defaults to the connection's owner.
157
+
158
+ test
159
+ Only project the changes without applying them (``test`` mode).
160
+ """
161
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
162
+
163
+ try:
164
+ gh_pages.get(conn, repo_name, owner=owner)
165
+ except GitHubNotFoundError:
166
+ ret["comment"] = f"Pages are already disabled for {repo_name}"
167
+ return ret
168
+
169
+ ret["changes"]["deleted"] = repo_name
170
+ if test:
171
+ ret["result"] = None
172
+ ret["comment"] = f"Pages would have been disabled for {repo_name}"
173
+ return ret
174
+
175
+ gh_pages.delete(conn, repo_name, owner=owner)
176
+ ret["comment"] = f"Pages have been disabled for {repo_name}"
177
+ return ret
@@ -0,0 +1,249 @@
1
+ """
2
+ State core managing a repository's settings and team associations.
3
+ """
4
+
5
+ import logging
6
+
7
+ from salt.exceptions import CommandExecutionError
8
+
9
+ from saltext.github.utils.gh import repos as gh_repos
10
+ from saltext.github.utils.gh import teams as gh_teams
11
+ from saltext.github.utils.gh.exceptions import GitHubNotFoundError
12
+ from saltext.github.utils.gh.statecores import StateError
13
+ from saltext.github.utils.gh.statecores import differs
14
+
15
+ log = logging.getLogger(__name__)
16
+
17
+
18
+ def _repo_settings_diff(ret, target, managed):
19
+ """
20
+ Record the settings of an existing repository that need updating
21
+ in ``ret`` and return them.
22
+ """
23
+ update_params = {
24
+ param: value
25
+ for param, value in managed.items()
26
+ if value is not None and differs(target[param], value)
27
+ }
28
+ if update_params:
29
+ ret["changes"]["old"] = {param: target[param] for param in update_params}
30
+ ret["changes"]["new"] = update_params
31
+ return update_params
32
+
33
+
34
+ def _repo_teams_diff(ret, conn, name, teams, owner):
35
+ """
36
+ Record the team association changes of an existing repository in
37
+ ``ret`` and return them.
38
+ """
39
+ current_teams = {team["name"] for team in gh_repos.get_teams(conn, name, owner=owner)}
40
+ teams_added = sorted(set(teams) - current_teams)
41
+ teams_removed = sorted(current_teams - set(teams))
42
+ team_permissions = {}
43
+ for team_name in sorted(set(teams) & current_teams):
44
+ team_repos = gh_teams.list_repos(
45
+ conn, gh_teams.find(conn, team_name, owner=owner), owner=owner
46
+ )
47
+ current_permission = team_repos.get(name.lower(), {}).get("permission")
48
+ if current_permission != teams[team_name]:
49
+ team_permissions[team_name] = {"old": current_permission, "new": teams[team_name]}
50
+ if teams_added:
51
+ ret["changes"]["teams_added"] = teams_added
52
+ if teams_removed:
53
+ ret["changes"]["teams_removed"] = teams_removed
54
+ if team_permissions:
55
+ ret["changes"]["team_permissions"] = team_permissions
56
+ return teams_added, teams_removed, team_permissions
57
+
58
+
59
+ def _set_team_repo(conn, name, team_name, permission, owner):
60
+ """
61
+ Add a repository to a team or update the team's permission on it.
62
+ """
63
+ gh_teams.add_repo(
64
+ conn, gh_teams.find(conn, team_name, owner=owner), name, permission=permission, owner=owner
65
+ )
66
+
67
+
68
+ def present(
69
+ conn,
70
+ name,
71
+ *,
72
+ owner=None,
73
+ description=None,
74
+ homepage=None,
75
+ private=None,
76
+ has_issues=None,
77
+ has_wiki=None,
78
+ has_downloads=None,
79
+ auto_init=False,
80
+ gitignore_template=None,
81
+ license_template=None,
82
+ default_branch=None,
83
+ teams=None,
84
+ allow_privacy_change=False,
85
+ allow_create=True,
86
+ test=False,
87
+ ):
88
+ """
89
+ Ensure a repository is present and configured as specified.
90
+ Unspecified settings are left unmanaged.
91
+
92
+ conn
93
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
94
+
95
+ name
96
+ Name of the repository.
97
+
98
+ owner
99
+ Owner of the repository. Defaults to the connection's owner.
100
+
101
+ allow_privacy_change
102
+ Allow changing an existing repository's visibility (the
103
+ profile's :ghconf:`allow_repo_privacy_changes`). Defaults to false.
104
+
105
+ allow_create
106
+ Create the repository when it is missing. When disabled, a
107
+ missing repository raises instead (resource context, where the
108
+ repository's existence is a given). Defaults to true.
109
+
110
+ test
111
+ Only project the changes without applying them (``test`` mode).
112
+
113
+ For the remaining parameters, see the ``github_repo.present`` state.
114
+ """
115
+ ret = {
116
+ "name": name,
117
+ "changes": {},
118
+ "result": True,
119
+ "comment": f"Repo {name} is present as specified",
120
+ }
121
+
122
+ # This is an optimization to cache all of the owner's repos up front.
123
+ # The first use of this state will collect all of the repos and save a bunch
124
+ # of API calls for future use.
125
+ gh_repos.list_all(conn, owner=owner)
126
+
127
+ try:
128
+ target = gh_repos.get_info(conn, name, owner=owner)
129
+ except GitHubNotFoundError:
130
+ if not allow_create:
131
+ raise CommandExecutionError(f"Repo {name} does not exist") from None
132
+ target = None
133
+
134
+ update_params = {}
135
+ teams_added, teams_removed, team_permissions = [], [], {}
136
+ if target is None:
137
+ ret["changes"]["created"] = name
138
+ if teams:
139
+ ret["changes"]["teams_added"] = sorted(teams)
140
+ else:
141
+ update_params = _repo_settings_diff(
142
+ ret,
143
+ target,
144
+ {
145
+ "description": description,
146
+ "homepage": homepage,
147
+ "private": private,
148
+ "has_issues": has_issues,
149
+ "has_wiki": has_wiki,
150
+ "has_downloads": has_downloads,
151
+ "default_branch": default_branch,
152
+ },
153
+ )
154
+ if teams is not None:
155
+ teams_added, teams_removed, team_permissions = _repo_teams_diff(
156
+ ret, conn, name, teams, owner
157
+ )
158
+
159
+ if not ret["changes"]:
160
+ return ret
161
+
162
+ verb = "created" if target is None else "updated"
163
+ if test:
164
+ ret["result"] = None
165
+ ret["comment"] = f"Repo {name} would have been {verb}"
166
+ return ret
167
+
168
+ applied = {}
169
+ try:
170
+ if target is None:
171
+ gh_repos.create(
172
+ conn,
173
+ name,
174
+ owner=owner,
175
+ description=description,
176
+ homepage=homepage,
177
+ private=private,
178
+ has_issues=has_issues,
179
+ has_wiki=has_wiki,
180
+ has_downloads=has_downloads,
181
+ auto_init=auto_init,
182
+ gitignore_template=gitignore_template,
183
+ license_template=license_template,
184
+ )
185
+ applied["created"] = name
186
+ for team_name in sorted(teams or {}):
187
+ _set_team_repo(conn, name, team_name, teams[team_name], owner)
188
+ applied.setdefault("teams_added", []).append(team_name)
189
+ else:
190
+ if update_params:
191
+ gh_repos.update(
192
+ conn,
193
+ name,
194
+ owner=owner,
195
+ allow_privacy_change=allow_privacy_change,
196
+ **update_params,
197
+ )
198
+ applied["old"] = ret["changes"]["old"]
199
+ applied["new"] = ret["changes"]["new"]
200
+ for team_name in teams_added:
201
+ _set_team_repo(conn, name, team_name, teams[team_name], owner)
202
+ applied.setdefault("teams_added", []).append(team_name)
203
+ for team_name in teams_removed:
204
+ gh_teams.remove_repo(
205
+ conn, gh_teams.find(conn, team_name, owner=owner), name, owner=owner
206
+ )
207
+ applied.setdefault("teams_removed", []).append(team_name)
208
+ for team_name, permission in team_permissions.items():
209
+ _set_team_repo(conn, name, team_name, teams[team_name], owner)
210
+ applied.setdefault("team_permissions", {})[team_name] = permission
211
+ except CommandExecutionError as err:
212
+ raise StateError(str(err), changes=applied) from err
213
+ ret["comment"] = f"Repo {name} has been {verb}"
214
+ return ret
215
+
216
+
217
+ def absent(conn, name, *, owner=None, test=False):
218
+ """
219
+ Ensure a repository is absent.
220
+
221
+ conn
222
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
223
+
224
+ name
225
+ Name of the repository.
226
+
227
+ owner
228
+ Owner of the repository. Defaults to the connection's owner.
229
+
230
+ test
231
+ Only project the changes without applying them (``test`` mode).
232
+ """
233
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
234
+
235
+ try:
236
+ gh_repos.get_info(conn, name, owner=owner)
237
+ except GitHubNotFoundError:
238
+ ret["comment"] = f"Repo {name} does not exist"
239
+ return ret
240
+
241
+ ret["changes"]["deleted"] = name
242
+ if test:
243
+ ret["result"] = None
244
+ ret["comment"] = f"Repo {name} would have been deleted"
245
+ return ret
246
+
247
+ gh_repos.delete(conn, name, owner=owner)
248
+ ret["comment"] = f"Repo {name} has been deleted"
249
+ return ret
@@ -0,0 +1,115 @@
1
+ """
2
+ State core managing repository rulesets.
3
+ """
4
+
5
+ import logging
6
+
7
+ from saltext.github.utils.gh import rulesets as gh_rulesets
8
+
9
+ log = logging.getLogger(__name__)
10
+
11
+
12
+ def present(conn, name, repo_name, *, ruleset_params=None, owner=None, test=False):
13
+ """
14
+ Ensure a repository ruleset is present and configured as specified.
15
+ Only the parameters included in ``ruleset_params`` are compared,
16
+ server-populated fields are ignored.
17
+
18
+ conn
19
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
20
+
21
+ name
22
+ Ruleset name to manage.
23
+
24
+ repo_name
25
+ Name of the repository.
26
+
27
+ ruleset_params
28
+ Ruleset definition. Must contain at least ``enforcement``
29
+ when the ruleset needs to be created. ``name`` is pulled from
30
+ this state's ``name``.
31
+
32
+ owner
33
+ Owner of the repository. Defaults to the connection's owner.
34
+
35
+ test
36
+ Only project the changes without applying them (``test`` mode).
37
+ """
38
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
39
+
40
+ ruleset_params = dict(ruleset_params or {})
41
+ ruleset_params["name"] = name
42
+
43
+ rulesets = gh_rulesets.list_all(conn, "repo", owner=owner, repo_name=repo_name)
44
+ ruleset = next((rls for rls in rulesets or [] if rls["name"] == name), None)
45
+
46
+ if ruleset is None:
47
+ ret["changes"]["created"] = name
48
+ if test:
49
+ ret["result"] = None
50
+ ret["comment"] = f"Ruleset {name} would have been created"
51
+ return ret
52
+ gh_rulesets.create(conn, ruleset_params, "repo", owner=owner, repo_name=repo_name)
53
+ ret["comment"] = f"Ruleset {name} has been created"
54
+ return ret
55
+
56
+ ruleset_info = gh_rulesets.get(conn, ruleset["id"], "repo", owner=owner, repo_name=repo_name)
57
+
58
+ # Only diff the parameters that are being managed. The server
59
+ # response carries additional server-populated fields (id,
60
+ # timestamps, source, ...) that must not register as drift.
61
+ diff = {key: val for key, val in ruleset_params.items() if ruleset_info.get(key) != val}
62
+ if not diff:
63
+ ret["comment"] = f"Ruleset {name} is already configured as specified"
64
+ return ret
65
+
66
+ ret["changes"]["old"] = {key: ruleset_info.get(key) for key in diff}
67
+ ret["changes"]["new"] = diff
68
+ if test:
69
+ ret["result"] = None
70
+ ret["comment"] = f"Ruleset {name} would have been updated"
71
+ return ret
72
+
73
+ gh_rulesets.update(
74
+ conn, ruleset["id"], ruleset_params, "repo", owner=owner, repo_name=repo_name
75
+ )
76
+ ret["comment"] = f"Ruleset {name} has been updated"
77
+ return ret
78
+
79
+
80
+ def absent(conn, name, repo_name, *, owner=None, test=False):
81
+ """
82
+ Ensure a repository ruleset is absent.
83
+
84
+ conn
85
+ :class:`~saltext.github.utils.gh.client.GitHubConnection` to use.
86
+
87
+ name
88
+ Ruleset name to manage.
89
+
90
+ repo_name
91
+ Name of the repository.
92
+
93
+ owner
94
+ Owner of the repository. Defaults to the connection's owner.
95
+
96
+ test
97
+ Only project the changes without applying them (``test`` mode).
98
+ """
99
+ ret = {"name": name, "changes": {}, "result": True, "comment": ""}
100
+
101
+ rulesets = gh_rulesets.list_all(conn, "repo", owner=owner, repo_name=repo_name)
102
+ ruleset = next((rls for rls in rulesets or [] if rls["name"] == name), None)
103
+ if ruleset is None:
104
+ ret["comment"] = f"Ruleset {name} does not exist"
105
+ return ret
106
+
107
+ ret["changes"]["deleted"] = name
108
+ if test:
109
+ ret["result"] = None
110
+ ret["comment"] = f"Ruleset {name} would have been deleted"
111
+ return ret
112
+
113
+ gh_rulesets.delete(conn, ruleset["id"], "repo", owner=owner, repo_name=repo_name)
114
+ ret["comment"] = f"Ruleset {name} has been deleted"
115
+ return ret