c2cciutils 1.7.0.dev334__py3-none-any.whl → 1.7.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of c2cciutils might be problematic. Click here for more details.

c2cciutils/pr_checks.py DELETED
@@ -1,286 +0,0 @@
1
- """
2
- The pull request checking functions.
3
-
4
- Commits, messages and labels.
5
- """
6
-
7
- import os
8
- import re
9
- import subprocess # nosec
10
- from tempfile import NamedTemporaryFile
11
- from typing import Any, Optional
12
-
13
- import requests
14
- import yaml
15
-
16
- import c2cciutils.configuration
17
-
18
-
19
- def _commit_intro(need_separator: bool, commit: dict[str, Any]) -> bool:
20
- head = commit["commit"]["message"].split("\n")[0]
21
- if need_separator:
22
- print("-" * 30)
23
- print(f'{commit["commit"]["tree"]["sha"]}: {head}')
24
- return True
25
-
26
-
27
- def print_event(github_event: dict[str, Any], **kwargs: Any) -> bool:
28
- """
29
- Print the github object.
30
- """
31
- del kwargs
32
- print(yaml.dump(github_event, default_flow_style=False, Dumper=yaml.SafeDumper))
33
- return True
34
-
35
-
36
- def commits_messages(
37
- config: c2cciutils.configuration.PullRequestChecksCommitsMessagesConfiguration,
38
- commits: list[dict[str, Any]],
39
- **kwargs: Any,
40
- ) -> bool:
41
- """
42
- Check the commits messages.
43
-
44
- - They should start with a capital letter.
45
- - They should not be too short.
46
- - They should not be a squash or fixup commit.
47
- - They should not be a merge commit.
48
- - They should not be a revert commit.
49
- """
50
- del kwargs
51
-
52
- need_separator = False
53
- success = True
54
- first_capital = re.compile(r"^[^a-z]")
55
- commit_hash = set()
56
- for commit in commits:
57
- need_head = True
58
- commit_hash.add(commit["sha"])
59
- message_lines = commit["commit"]["message"].split("\n")
60
- head = message_lines[0]
61
- if config.get(
62
- "check_fixup", c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_FIXUP_DEFAULT
63
- ) and head.startswith("fixup! "):
64
- if need_head:
65
- need_separator = _commit_intro(need_separator, commit)
66
- need_head = False
67
- print("::error::Fixup message not allowed")
68
- success = False
69
- if config.get(
70
- "check_squash", c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_SQUASH_DEFAULT
71
- ) and head.startswith("squash! "):
72
- if need_head:
73
- need_separator = _commit_intro(need_separator, commit)
74
- need_head = False
75
- print("::error::Squash message not allowed")
76
- success = False
77
- if (
78
- config.get(
79
- "check_first_capital",
80
- c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_FIRST_CAPITAL_DEFAULT,
81
- )
82
- and first_capital.match(head) is None
83
- ):
84
- if need_head:
85
- need_separator = _commit_intro(need_separator, commit)
86
- need_head = False
87
- print("::error::The first letter of message head should be a capital")
88
- success = False
89
- min_length = config.get(
90
- "min_head_length",
91
- c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_MIN_HEAD_LENGTH_DEFAULT,
92
- )
93
- if min_length > 0 and len(head) < min_length:
94
- if need_head:
95
- need_separator = _commit_intro(need_separator, commit)
96
- need_head = False
97
- print(f"The message head should be at least {min_length} characters long")
98
- success = False
99
- if (
100
- config.get(
101
- "check_no_merge_commits",
102
- c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_NO_MERGE_COMMITS_DEFAULT,
103
- )
104
- and len(commit["parents"]) != 1
105
- ):
106
- if need_head:
107
- need_separator = _commit_intro(need_separator, commit)
108
- need_head = False
109
- print("::error::The merge commit are not allowed")
110
- success = False
111
- if config.get(
112
- "check_no_own_revert",
113
- c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_NO_OWN_REVERT_DEFAULT,
114
- ) and (
115
- head.startswith("Revert ")
116
- and len(message_lines) == 3
117
- and message_lines[2].startswith("This reverts commit ")
118
- ):
119
- revert_commit_hash = message_lines[2][len("This reverts commit ") : -1]
120
- if revert_commit_hash in commit_hash:
121
- if need_head:
122
- need_separator = _commit_intro(need_separator, commit)
123
- need_head = False
124
- print(f"Revert own commits is not allowed ({revert_commit_hash})")
125
- success = False
126
- continue
127
- return success
128
-
129
-
130
- def commits_spell(
131
- config: c2cciutils.configuration.PullRequestChecksCommitsSpellingConfiguration,
132
- full_config: c2cciutils.configuration.Configuration,
133
- commits: list[dict[str, Any]],
134
- **kwargs: Any,
135
- ) -> bool:
136
- """Check the spelling of the commits body."""
137
- del kwargs
138
-
139
- spellcheck_cmd = c2cciutils.get_codespell_command(full_config)
140
-
141
- success = True
142
- need_separator = False
143
- for commit in commits:
144
- with NamedTemporaryFile("w+t", encoding="utf-8", suffix=".yaml") as temp_file:
145
- if config.get(
146
- "only_head", c2cciutils.configuration.PULL_REQUEST_CHECKS_COMMITS_MESSAGES_ONLY_HEAD_DEFAULT
147
- ):
148
- head = commit["commit"]["message"].split("\n")[0]
149
- temp_file.write(head)
150
- else:
151
- temp_file.write(commit["commit"]["message"])
152
- temp_file.flush()
153
- spell = subprocess.run( # nosec # pylint: disable=subprocess-run-check
154
- spellcheck_cmd + [temp_file.name], capture_output=True
155
- )
156
- if spell.returncode != 0:
157
- need_separator = _commit_intro(need_separator, commit)
158
- print("::error::Code spell error")
159
- print(spell.stderr)
160
- print(spell.stdout)
161
- success = False
162
- return success
163
-
164
-
165
- def pull_request_spell(
166
- config: c2cciutils.configuration.PullRequestChecksPullRequestSpellingConfiguration,
167
- full_config: c2cciutils.configuration.Configuration,
168
- github_event: dict[str, Any],
169
- **kwargs: Any,
170
- ) -> bool:
171
- """Check the spelling of the pull request title and message."""
172
- del kwargs
173
-
174
- spellcheck_cmd = c2cciutils.get_codespell_command(full_config)
175
-
176
- with NamedTemporaryFile("w+t") as temp_file:
177
- temp_file.write(github_event["event"]["pull_request"]["title"])
178
- temp_file.write("\n")
179
- if not config.get(
180
- "only_head", c2cciutils.configuration.PULL_REQUEST_CHECKS_ONLY_HEAD_DEFAULT
181
- ) and github_event["event"]["pull_request"].get("body"):
182
- temp_file.write("\n")
183
- temp_file.write(github_event["event"]["pull_request"]["body"])
184
- temp_file.write("\n")
185
- temp_file.flush()
186
- spell = subprocess.run( # nosec # pylint: disable=subprocess-run-check
187
- spellcheck_cmd + [temp_file.name], capture_output=True
188
- )
189
- if spell.returncode != 0:
190
- print("::error::Code spell error in pull request")
191
- print(spell.stderr)
192
- print(spell.stdout)
193
- return False
194
- return True
195
-
196
-
197
- def pull_request_labels(github_event: dict[str, Any], **kwargs: Any) -> bool:
198
- """Check it the label are set correctly for the changelog generation."""
199
- del kwargs
200
-
201
- if github_event["actor"] == "renovate[bot]":
202
- return True
203
-
204
- if not os.path.exists(".github/changelog-config.yaml"):
205
- return True
206
-
207
- required_labels = []
208
- with open(".github/changelog-config.yaml", encoding="utf-8") as changelog_config_file:
209
- changelog_config = yaml.load(changelog_config_file, Loader=yaml.SafeLoader)
210
- for section in changelog_config.values():
211
- if "labels" in section:
212
- required_labels.extend(section["labels"])
213
-
214
- print(f"Required one onf the following labels: {', '.join(required_labels)}")
215
-
216
- if required_labels:
217
- labels = [
218
- label["name"]
219
- for label in github_event["event"]["pull_request"]["labels"]
220
- if label["name"] in required_labels
221
- ]
222
- if len(labels) == 0:
223
- print(f"::error::No required label found: {', '.join(required_labels)}")
224
- return False
225
- if len(labels) > 1:
226
- print(f"::error::Too many required labels found: {', '.join(labels)}")
227
- return False
228
- return True
229
-
230
-
231
- GET_ISSUE_RE = [
232
- re.compile(r"^([A-Z]{3,6}-[0-9]+)-.*$"),
233
- re.compile(r"^([a-z]{3,6}-[0-9]+)-.*$"),
234
- re.compile(r"^.*-([A-Z]{3,6}-[0-9]+)$"),
235
- re.compile(r"^.*-([a-z]{3,6}-[0-9]+)$"),
236
- ]
237
-
238
-
239
- def _get_issue_number(name: str) -> Optional[str]:
240
- for re_ in GET_ISSUE_RE:
241
- match = re_.match(name)
242
- if match is not None:
243
- return match.group(1)
244
- return None
245
-
246
-
247
- def add_issue_link(github_event: dict[str, Any], **kwargs: Any) -> bool:
248
- """Add a comment with the link to Jira if needed."""
249
- del kwargs
250
-
251
- issue_number = _get_issue_number(github_event["event"]["pull_request"]["head"]["ref"])
252
-
253
- if issue_number is None:
254
- return True
255
-
256
- issue_number = issue_number.upper()
257
-
258
- body = github_event["event"]["pull_request"].get("body") or ""
259
- if issue_number in body.upper():
260
- return True
261
-
262
- comments_response = requests.get(
263
- github_event["event"]["pull_request"]["_links"]["comments"]["href"],
264
- timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
265
- headers=c2cciutils.add_authorization_header({}),
266
- )
267
- c2cciutils.check_response(comments_response)
268
- comments = comments_response.json()
269
-
270
- for comment in comments:
271
- if issue_number in comment.get("body", "").upper():
272
- return True
273
-
274
- response = requests.post(
275
- github_event["event"]["pull_request"]["_links"]["comments"]["href"],
276
- headers={
277
- "Accept": "application/vnd.github+json",
278
- "Authorization": f"Bearer {github_event['token']}",
279
- },
280
- json={"body": f"See also: [{issue_number}](https://jira.camptocamp.com/browse/{issue_number})"},
281
- timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
282
- )
283
-
284
- if not response.ok:
285
- print(f"Unable to add the comment: {response.text}")
286
- return response.ok
@@ -1,41 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- """
4
- The audit main function.
5
- """
6
-
7
- import argparse
8
- import os
9
- import sys
10
-
11
- import c2cciutils.audit
12
- import c2cciutils.env
13
-
14
-
15
- def main() -> None:
16
- """
17
- Run the audit.
18
- """
19
- parser = argparse.ArgumentParser(description="Run the audit of c2cciutils.")
20
- parser.add_argument("--branch", help="The branch to audit, not defined means autodetect")
21
- parser.add_argument("--check", help="Runs only the specified check")
22
- parser.add_argument("--fix", action="store_true", help="Fix issues")
23
-
24
- args = parser.parse_args()
25
-
26
- full_config = c2cciutils.get_config()
27
- c2cciutils.env.print_environment(full_config)
28
-
29
- config = full_config.get("audit", {})
30
- success = True
31
- for key, conf in config.items():
32
- if conf is not False and (args.check is None or args.check == key):
33
- audit = getattr(c2cciutils.audit, key)
34
- print(f"Run audit {key}")
35
- success &= audit({} if conf is True else conf, full_config, args)
36
- if not success and os.environ.get("TEST") != "TRUE":
37
- sys.exit(1)
38
-
39
-
40
- if __name__ == "__main__":
41
- main()
@@ -1,78 +0,0 @@
1
- #!/usr/bin/env python3
2
-
3
- """
4
- The pull request checker main function.
5
- """
6
-
7
- import argparse
8
- import json
9
- import os
10
- import sys
11
- import traceback
12
-
13
- import requests
14
-
15
- import c2cciutils
16
- import c2cciutils.env
17
- import c2cciutils.pr_checks
18
-
19
-
20
- def main() -> None:
21
- """
22
- Run the checks.
23
- """
24
- parser = argparse.ArgumentParser(description="Run the pull request checks of c2cciutils.")
25
- parser.add_argument("--stop", action="store_true", help="stop on first error")
26
- parser.add_argument("--check", help="runs only the specified check")
27
-
28
- args = parser.parse_args()
29
-
30
- full_config = c2cciutils.get_config()
31
- c2cciutils.env.print_environment(full_config)
32
-
33
- github_event = json.loads(os.environ["GITHUB_EVENT"])
34
-
35
- commits_response = requests.get(
36
- github_event["event"]["pull_request"]["_links"]["commits"]["href"],
37
- timeout=int(os.environ.get("C2CCIUTILS_TIMEOUT", "30")),
38
- headers=c2cciutils.add_authorization_header({}),
39
- )
40
- c2cciutils.check_response(commits_response)
41
- commits = commits_response.json()
42
-
43
- config = full_config["pr-checks"]
44
-
45
- check_args = {
46
- "args": args,
47
- "full_config": full_config,
48
- "commits": commits,
49
- "github_event": github_event,
50
- }
51
-
52
- success = True
53
- for key, conf in config.items():
54
- if conf is not False and (args.check is None or args.check == key):
55
- check = getattr(c2cciutils.pr_checks, key)
56
- print(f"::group::Run check {key}")
57
- try:
58
- if not check(config={} if conf is True else conf, **check_args):
59
- success = False
60
- print("::endgroup::")
61
- if args.stop:
62
- sys.exit(1)
63
- print("::error::With error")
64
- else:
65
- print("::endgroup::")
66
- except Exception: # pylint: disable=broad-except
67
- traceback.print_exc()
68
- success = False
69
- print("::endgroup::")
70
- if args.stop:
71
- sys.exit(1)
72
- print("::error::With exception")
73
- if not success:
74
- sys.exit(1)
75
-
76
-
77
- if __name__ == "__main__":
78
- main()