devops-events-local 0.0.1b4163__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.
File without changes
File without changes
@@ -0,0 +1,18 @@
1
+ from logger_local.LoggerComponentEnum import LoggerComponentEnum
2
+
3
+
4
+ class ConstantsSrcDevopsEventsLocal:
5
+ """The constants of devops-events-local"""
6
+
7
+ # TODO you can check component_table or for any #request-to-open-component-id request.
8
+ # generic-webhook to call components-local to get the CODE and TEST componets ids
9
+ DEVOPS_EVENTS_LOCAL_PYTHON_CODE_COMPONENT_ID: int = 0
10
+ DEVOPS_EVENTS_LOCAL_PYTHON_CODE_COMPONENT_NAME = "devops-events-local-python-package"
11
+ DEVOPS_EVENTS_LOCAL_PYTHON_CODE_DEVELOPER_EMAIL_ADDRESS = "yuval.r@circ.zone"
12
+
13
+ DEVOPS_EVENTS_LOCAL_PYTHON_CODE_LOGGER_OBJECT = {
14
+ 'component_id': DEVOPS_EVENTS_LOCAL_PYTHON_CODE_COMPONENT_ID,
15
+ 'component_name': DEVOPS_EVENTS_LOCAL_PYTHON_CODE_COMPONENT_NAME,
16
+ 'component_category': LoggerComponentEnum.ComponentCategory.Code.value,
17
+ 'developer_email_address': DEVOPS_EVENTS_LOCAL_PYTHON_CODE_DEVELOPER_EMAIL_ADDRESS
18
+ }
@@ -0,0 +1,46 @@
1
+ import re
2
+ from typing import Any
3
+
4
+ from logger_local.LoggerLocal import Logger
5
+
6
+ from .constants_src_devops_events_local import ConstantsSrcDevopsEventsLocal
7
+ from .handle_slack_request import HandleSlackRequest
8
+
9
+ logger = Logger.create_logger(object=ConstantsSrcDevopsEventsLocal.DEVOPS_EVENTS_LOCAL_PYTHON_CODE_LOGGER_OBJECT)
10
+
11
+ LABEL_TO_FIELD = {"summary": "summary", "description": "description", "reponame": "repo_name",
12
+ "components": "components", "component": "components"}
13
+ MANDATORY_FIELD_LABELS = {"summary": "Summary", "description": "Description", "repo_name": "RepoName"}
14
+
15
+ # Slack wraps text in *bold*, _italic_, `code`, ```blocks``` and > quotes; allow them around the labels.
16
+ FORMATTING = r"[ \t>*_`]*"
17
+ TRAILING_FORMATTING = r"[ \t*_`]*"
18
+ LABEL = r"(?:summary|description|repo[ _]?name|components?)"
19
+ FIELD_PATTERN = re.compile(
20
+ rf"^{FORMATTING}(?P<label>{LABEL}){TRAILING_FORMATTING}:{TRAILING_FORMATTING}(?P<value>.*?){TRAILING_FORMATTING}"
21
+ rf"(?=\n{FORMATTING}{LABEL}{TRAILING_FORMATTING}:|\Z)",
22
+ re.IGNORECASE | re.MULTILINE | re.DOTALL)
23
+
24
+
25
+ class RequestToOpenAJiraWorkItemParseException(ValueError):
26
+ pass
27
+
28
+
29
+ # TODO What if the request arrives in email/Telegram/REST-API ...?
30
+ class HandleRequestToOpenAJiraWorkItem(HandleSlackRequest):
31
+ field_pattern = FIELD_PATTERN
32
+
33
+ def parse(self, text: str) -> dict[str, Any]:
34
+ """Split a #request-to-open-a-jira-issue Slack message into the fields jira_local expects:
35
+ summary, description, repo_name and components (list, may be empty)."""
36
+ fields: dict[str, Any] = {}
37
+ for match in self.field_pattern.finditer(self.clean_slack_text(text or "")):
38
+ field = LABEL_TO_FIELD[re.sub(r"[ _]", "", match.group("label").lower())]
39
+ fields.setdefault(field, match.group("value").strip())
40
+ missing_labels = [label for field, label in MANDATORY_FIELD_LABELS.items() if not fields.get(field)]
41
+ if missing_labels:
42
+ logger.warning(f"Request without {', '.join(missing_labels)}")
43
+ raise RequestToOpenAJiraWorkItemParseException(f"Missing {', '.join(missing_labels)}")
44
+ fields["components"] = [component.strip() for component in fields.get("components", "").split(",")
45
+ if component.strip()]
46
+ return fields
@@ -0,0 +1,30 @@
1
+ import html
2
+ import re
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any
5
+
6
+ # <https://url|label> -> label, <https://url> -> https://url (user/channel mentions <@U1>/<#C1> are kept)
7
+ SLACK_LINK_PATTERN = re.compile(r"<((?:https?|mailto):[^|>]+)(?:\|([^>]+))?>")
8
+
9
+
10
+ class HandleSlackRequest(ABC):
11
+ """A request posted in a Slack request channel, e.g. #request-to-open-a-jira-issue.
12
+ Each request type gives the pattern of its "Label: value" fields and parses them."""
13
+
14
+ field_pattern: re.Pattern
15
+
16
+ @staticmethod
17
+ def clean_slack_text(text: str) -> str:
18
+ text_without_links = SLACK_LINK_PATTERN.sub(lambda match: match.group(2) or match.group(1), text)
19
+ clean_text = html.unescape(text_without_links).replace("\r\n", "\n")
20
+ return clean_text
21
+
22
+ def has_request_fields(self, text: str) -> bool:
23
+ """True when the text has at least one field label (e.g. "Summary:"),
24
+ i.e. it is a request and not a chat reply."""
25
+ has_fields = self.field_pattern.search(self.clean_slack_text(text or "")) is not None
26
+ return has_fields
27
+
28
+ @abstractmethod
29
+ def parse(self, text: str) -> dict[str, Any]:
30
+ """The fields of the request, by their names in the target system"""
@@ -0,0 +1,2 @@
1
+ # Can _version.py created by git tag and pyproject.toml be used instead?
2
+ PACKAGE_VERSION = "0.0.0"
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: devops-events-local
3
+ Version: 0.0.1b4163
4
+ Summary: PyPI devops-events-local Python Package owned by Circlez.ai
5
+ Home-page: https://github.com/circles-zone/devops-events-local-python-package
6
+ Author: Circles
7
+ Author-email: info@circlez.ai
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Operating System :: OS Independent
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: python-sdk-remote
12
+ Requires-Dist: logger-local
13
+ Dynamic: author
14
+ Dynamic: author-email
15
+ Dynamic: classifier
16
+ Dynamic: description
17
+ Dynamic: description-content-type
18
+ Dynamic: home-page
19
+ Dynamic: requires-dist
20
+ Dynamic: summary
21
+
22
+ PyPI devops-events-local Python Package owned by Circlez.ai
23
+ GHA: https://github.com/circles-zone/devops-events-local-python-package/actions
@@ -0,0 +1,10 @@
1
+ devops_events_local/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ devops_events_local/src/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3
+ devops_events_local/src/constants_src_devops_events_local.py,sha256=dfU7lKciqZwsbIb16d-uPh2AV3hp1xaoASb3DCwyf1Q,936
4
+ devops_events_local/src/handle_request_to_open_a_jira_work_item.py,sha256=3drFGD1FOUP5YeBd0bvD7dW0zJ_43-RzMpWBK9AeI6k,2308
5
+ devops_events_local/src/handle_slack_request.py,sha256=qidXyw8d2npRYkIrtR8Eo_cTz_hfGvLegrPb3BDSgbs,1234
6
+ devops_events_local/src/version.py,sha256=zJxrMPsUnBUY2lnD3AQv6itQvLgWWewqoE2P42Au80w,99
7
+ devops_events_local-0.0.1b4163.dist-info/METADATA,sha256=LrTwIFWxcrqusuSC5D0a7jsQ81OHsT_moiPWOeLf0Rg,772
8
+ devops_events_local-0.0.1b4163.dist-info/WHEEL,sha256=mOdXR9C3wMVov7cSY8PY-XCzo3SmmWCHvGQr5csJoao,91
9
+ devops_events_local-0.0.1b4163.dist-info/top_level.txt,sha256=HEeKOc6_g-BHAsRM12SX8xmw_79pNxrUDycysWWE2SI,20
10
+ devops_events_local-0.0.1b4163.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (84.2.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ devops_events_local