Skip to content

Commit bfc56b6

Browse files
committed
fix: ruff CI-breaking lint errors and wrong activity type (CM-1318)
Signed-off-by: Uroš Marolt <uros@marolt.me>
1 parent 7e086b0 commit bfc56b6

6 files changed

Lines changed: 58 additions & 82 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
DOCKERFILE="./services/docker/Dockerfile.mailing_list_integration"
2+
CONTEXT="../"
3+
REPO="sjc.ocir.io/axbydjxa5zuh/mailing-list-integration"
4+
SERVICES="mailing-list-integration"

scripts/cli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1189,7 +1189,7 @@ while test $# -gt 0; do
11891189
exit
11901190
;;
11911191
clean-start-fe-dev)
1192-
IGNORED_SERVICES=("frontend" "python-worker" "job-generator" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker" "cache-worker" "categorization-worker" "cron-service" "data-sink-worker" "git-integration" "integration-run-worker" "integration-stream-worker" "nango-webhook-api" "nango-worker" "script-executor-worker" "search-sync-api" "search-sync-worker" "security-best-practices-worker" "snowflake-connectors-worker")
1192+
IGNORED_SERVICES=("frontend" "python-worker" "job-generator" "webhook-api" "profiles-worker" "organizations-enrichment-worker" "merge-suggestions-worker" "members-enrichment-worker" "exports-worker" "entity-merging-worker" "cache-worker" "categorization-worker" "cron-service" "data-sink-worker" "git-integration" "mailing-list-integration" "integration-run-worker" "integration-stream-worker" "nango-webhook-api" "nango-worker" "script-executor-worker" "search-sync-api" "search-sync-worker" "security-best-practices-worker" "snowflake-connectors-worker")
11931193
CLEAN_START=1
11941194
DEV=1
11951195
start

services/apps/mailing_list_integration/src/crowdmail/enums.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from enum import Enum
1+
from enum import StrEnum
22

33

4-
class ErrorCode(str, Enum):
4+
class ErrorCode(StrEnum):
55
"""Standard Error codes"""
66

77
UNKNOWN = "unknown"
@@ -18,7 +18,7 @@ class ErrorCode(str, Enum):
1818
SERVER_ERROR = "server-error-remote"
1919

2020

21-
class ListState(str, Enum):
21+
class ListState(StrEnum):
2222
"""Mailing list processing states"""
2323

2424
PENDING = "pending"
@@ -36,34 +36,34 @@ class ListPriority(int):
3636
NORMAL = 2
3737

3838

39-
class IntegrationResultType(str, Enum):
39+
class IntegrationResultType(StrEnum):
4040
ACTIVITY = "activity"
4141

4242

43-
class IntegrationResultState(str, Enum):
43+
class IntegrationResultState(StrEnum):
4444
PENDING = "pending"
4545

4646

47-
class DataSinkWorkerQueueMessageType(str, Enum):
47+
class DataSinkWorkerQueueMessageType(StrEnum):
4848
PROCESS_INTEGRATION_RESULT = "process_integration_result"
4949

5050

51-
class ActivityType(str, Enum):
51+
class ActivityType(StrEnum):
5252
"""Groupsio-compatible activity types (platform=groupsio)"""
5353

5454
MESSAGE = "message"
5555
MEMBER_JOIN = "member_join"
5656
MEMBER_LEAVE = "member_leave"
5757

5858

59-
class ExecutionStatus(str, Enum):
59+
class ExecutionStatus(StrEnum):
6060
"""Service execution status"""
6161

6262
SUCCESS = "success"
6363
FAILURE = "failure"
6464

6565

66-
class OperationType(str, Enum):
66+
class OperationType(StrEnum):
6767
"""Service operation types for metrics tracking"""
6868

6969
MIRROR = "Mirror"

services/apps/mailing_list_integration/src/crowdmail/services/mirror/mirror_service.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,12 @@
3333
# (stderr substrings, exception to raise) — checked in order, first match wins
3434
ERROR_CLASSIFICATIONS = [
3535
(
36-
{"Connection refused", "Network is unreachable", "Connection timed out", "Could not resolve host"},
36+
{
37+
"Connection refused",
38+
"Network is unreachable",
39+
"Connection timed out",
40+
"Could not resolve host",
41+
},
3742
NetworkError,
3843
),
3944
({"429", "Too Many Requests"}, RateLimitError),

services/apps/mailing_list_integration/src/crowdmail/services/parse/noteren.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import subprocess
2020
import sys
2121

22+
from crowdmail.enums import ActivityType
23+
2224
# We want to always be using utf-8
2325
email.charset.add_charset("utf-8", None)
2426

@@ -33,9 +35,7 @@
3335

3436
# run a command and take the output.
3537
# Shamelessly taken from 'b4' by Konstantin Ryabitsev <konstantin@linuxfoundation.org>
36-
def _run_command(
37-
cmdargs: list, stdin: bytes | None = None
38-
) -> tuple[int, bytes, bytes]:
38+
def _run_command(cmdargs: list, stdin: bytes | None = None) -> tuple[int, bytes, bytes]:
3939
logging.debug(cmdargs)
4040
sp = subprocess.Popen(
4141
cmdargs, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE
@@ -68,9 +68,7 @@ def get_email_from_git(git_dir: str, git_id: str) -> tuple[bytes, str]:
6868
git_blob_id = out.decode().rstrip() # strip the trailing \n
6969

7070
if git_blob_id == "":
71-
logging.error(
72-
'git commit id %s was not found in the git repo "%s"', git_id, git_dir
73-
)
71+
logging.error('git commit id %s was not found in the git repo "%s"', git_id, git_dir)
7472
sys.exit(1)
7573

7674
logging.debug("git_blob_id =%s", git_blob_id)
@@ -216,9 +214,9 @@ def parse_email(
216214
# Do NOT use headersonly=True here, as that prevents the parser from
217215
# building the multipart structure, which we will properly walk later on
218216
# and pick out the text/plain part of the message.
219-
e = email.parser.BytesParser(
220-
policy=emlpolicy, _class=email.message.EmailMessage
221-
).parsebytes(message)
217+
e = email.parser.BytesParser(policy=emlpolicy, _class=email.message.EmailMessage).parsebytes(
218+
message
219+
)
222220

223221
logging.debug(e)
224222

@@ -354,7 +352,7 @@ def parse_email(
354352
"body": json_body,
355353
"url": "https://lore.kernel.org/r/" + msgid,
356354
"isContribution": True,
357-
"type": "email-message",
355+
"type": ActivityType.MESSAGE,
358356
"attributes": attributes,
359357
"member": member,
360358
}
@@ -418,7 +416,9 @@ def cmd():
418416
parser.add_argument(
419417
"--git-dir", help="Git directory of the lore repo to dig out of", required=True
420418
)
421-
parser.add_argument("--segment-id", help="CDP segment id to attach the activity to", required=True)
419+
parser.add_argument(
420+
"--segment-id", help="CDP segment id to attach the activity to", required=True
421+
)
422422
parser.add_argument(
423423
"--integration-id", help="CDP integration id to attach the activity to", required=True
424424
)

services/apps/mailing_list_integration/src/test/test_noteren.py

Lines changed: 27 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,7 @@
2323
from crowdmail.services.parse import noteren
2424

2525
HERE = os.path.dirname(os.path.abspath(__file__))
26-
NOTEREN = os.path.join(
27-
HERE, "..", "crowdmail", "services", "parse", "noteren.py"
28-
)
26+
NOTEREN = os.path.join(HERE, "..", "crowdmail", "services", "parse", "noteren.py")
2927
SEGMENT_ID = "11111111-1111-1111-1111-111111111111"
3028
INTEGRATION_ID = "22222222-2222-2222-2222-222222222222"
3129

@@ -34,25 +32,19 @@
3432
# Fixtures
3533
# --------------------------------------------------------------------------
3634

35+
3736
def _git(gitdir, *args, stdin=None):
3837
out = subprocess.run(
3938
["git", "--git-dir", str(gitdir)] + list(args),
4039
input=stdin,
41-
stdout=subprocess.PIPE,
42-
stderr=subprocess.PIPE,
40+
capture_output=True,
4341
check=True,
4442
)
4543
return out.stdout.decode().strip()
4644

4745

4846
def _make_email(msgid, subject, frm, body, date="Mon, 1 Jan 2024 12:00:00 +0000"):
49-
hdr = (
50-
f"From: {frm}\n"
51-
f"Subject: {subject}\n"
52-
f"Date: {date}\n"
53-
f"Message-ID: <{msgid}>\n"
54-
"\n"
55-
)
47+
hdr = f"From: {frm}\nSubject: {subject}\nDate: {date}\nMessage-ID: <{msgid}>\n\n"
5648
return (hdr + body).encode()
5749

5850

@@ -108,8 +100,7 @@ def inbox_repo(tmp_path):
108100
def _run_noteren(*args):
109101
return subprocess.run(
110102
[sys.executable, NOTEREN] + list(args),
111-
stdout=subprocess.PIPE,
112-
stderr=subprocess.PIPE,
103+
capture_output=True,
113104
text=True,
114105
)
115106

@@ -122,6 +113,7 @@ def _std_args():
122113
# Unit tests for helper functions
123114
# --------------------------------------------------------------------------
124115

116+
125117
def test_message_id_cleanup_strips_angles():
126118
assert noteren.message_id_cleanup("<abc@host>") == "abc@host"
127119
assert noteren.message_id_cleanup(" <abc@host> ") == "abc@host"
@@ -256,9 +248,7 @@ def fake_git_run(git_dir, args, stdin=None):
256248

257249

258250
def test_get_email_from_git_missing_commit_exits(monkeypatch):
259-
monkeypatch.setattr(
260-
noteren, "git_run_command", lambda *args, **kwargs: (0, b"", b"")
261-
)
251+
monkeypatch.setattr(noteren, "git_run_command", lambda *args, **kwargs: (0, b"", b""))
262252
with pytest.raises(SystemExit):
263253
noteren.get_email_from_git("/tmp/repo.git", "deadbeef")
264254

@@ -275,9 +265,7 @@ def fake_git_run(git_dir, args, stdin=None):
275265

276266

277267
def _parse_email(raw, source, channel, git_id, blob_id):
278-
return noteren.parse_email(
279-
raw, source, channel, git_id, blob_id, SEGMENT_ID, INTEGRATION_ID
280-
)
268+
return noteren.parse_email(raw, source, channel, git_id, blob_id, SEGMENT_ID, INTEGRATION_ID)
281269

282270

283271
def test_parse_email_extracts_attributes_and_reference():
@@ -351,13 +339,7 @@ def test_parse_email_invalid_date_leaves_timestamp_empty():
351339

352340

353341
def test_parse_email_falls_back_to_raw_body(monkeypatch):
354-
raw = (
355-
b"From: A <a@example.com>\n"
356-
b"Subject: s\n"
357-
b"Message-ID: <msg@example.com>\n"
358-
b"\n"
359-
b"line one\n"
360-
)
342+
raw = b"From: A <a@example.com>\nSubject: s\nMessage-ID: <msg@example.com>\n\nline one\n"
361343
monkeypatch.setattr(noteren, "get_body", lambda msg: None)
362344
parsed = _parse_email(raw, "src", "chan", "commit1", "blob1")
363345
assert "line one\n" in parsed["activityData"]["body"]
@@ -400,9 +382,7 @@ def test_parse_id_writes_json(monkeypatch):
400382

401383

402384
def test_parse_range_calls_parse_id_for_each_commit(monkeypatch):
403-
monkeypatch.setattr(
404-
noteren, "git_run_command", lambda *args, **kwargs: (0, b"c1\nc2\n", b"")
405-
)
385+
monkeypatch.setattr(noteren, "git_run_command", lambda *args, **kwargs: (0, b"c1\nc2\n", b""))
406386
seen = []
407387
monkeypatch.setattr(
408388
noteren,
@@ -542,9 +522,7 @@ def test_cmd_without_output_uses_stdout(monkeypatch):
542522

543523

544524
def test_cmd_verbose_enables_debug_logging(monkeypatch):
545-
monkeypatch.setattr(
546-
noteren, "parse_id", lambda *args, **kwargs: None
547-
)
525+
monkeypatch.setattr(noteren, "parse_id", lambda *args, **kwargs: None)
548526
called = {}
549527
monkeypatch.setattr(
550528
noteren.logging,
@@ -627,10 +605,9 @@ def test_cmd_rejects_both_id_and_range(monkeypatch):
627605
# CLI / integration tests
628606
# --------------------------------------------------------------------------
629607

608+
630609
def test_cli_requires_id_or_range(inbox_repo):
631-
r = _run_noteren(
632-
"--source=s", "--channel=c", "--git-dir", inbox_repo["gitdir"], *_std_args()
633-
)
610+
r = _run_noteren("--source=s", "--channel=c", "--git-dir", inbox_repo["gitdir"], *_std_args())
634611
assert r.returncode != 0
635612
assert "--git-range or --git-id" in r.stderr
636613

@@ -729,6 +706,7 @@ def test_cli_unknown_commit_fails(inbox_repo):
729706
# Additional edge-case unit tests
730707
# --------------------------------------------------------------------------
731708

709+
732710
def test_get_body_returns_none_when_no_text_parts():
733711
"""A message that contains only text/html must cause get_body to return None."""
734712
msg = noteren.email.message.EmailMessage()
@@ -753,21 +731,13 @@ def test_get_body_raw_blank_body_after_headers():
753731

754732
def test_run_command_returns_nonzero_exit_code():
755733
"""_run_command must surface a non-zero return code from the child process."""
756-
rc, out, err = noteren._run_command(
757-
[sys.executable, "-c", "import sys; sys.exit(42)"]
758-
)
734+
rc, out, err = noteren._run_command([sys.executable, "-c", "import sys; sys.exit(42)"])
759735
assert rc == 42
760736

761737

762738
def test_parse_email_no_message_id_gives_empty_source_id():
763739
"""A message without a Message-ID header must yield sourceId == ''."""
764-
raw = (
765-
b"From: A <a@example.com>\n"
766-
b"Subject: s\n"
767-
b"Date: Mon, 1 Jan 2024 12:00:00 +0000\n"
768-
b"\n"
769-
b"body\n"
770-
)
740+
raw = b"From: A <a@example.com>\nSubject: s\nDate: Mon, 1 Jan 2024 12:00:00 +0000\n\nbody\n"
771741
parsed = _parse_email(raw, "src", "chan", "c1", "b1")
772742
assert parsed["activityData"]["sourceId"] == ""
773743

@@ -851,7 +821,7 @@ def test_parse_email_multipart_alternative_uses_text_plain():
851821
b"Date: Mon, 1 Jan 2024 12:00:00 +0000\n"
852822
b"Message-ID: <multi@example.com>\n"
853823
b"MIME-Version: 1.0\n"
854-
b"Content-Type: multipart/alternative; boundary=\"boundary\"\n"
824+
b'Content-Type: multipart/alternative; boundary="boundary"\n'
855825
b"\n"
856826
b"--boundary\n"
857827
b"Content-Type: text/plain; charset=utf-8\n"
@@ -886,13 +856,7 @@ def test_parse_email_url_contains_message_id():
886856

887857
def test_parse_email_url_with_no_message_id():
888858
"""When Message-ID is absent the url must end with a trailing slash and empty id."""
889-
raw = (
890-
b"From: A <a@example.com>\n"
891-
b"Subject: s\n"
892-
b"Date: Mon, 1 Jan 2024 12:00:00 +0000\n"
893-
b"\n"
894-
b"body\n"
895-
)
859+
raw = b"From: A <a@example.com>\nSubject: s\nDate: Mon, 1 Jan 2024 12:00:00 +0000\n\nbody\n"
896860
parsed = _parse_email(raw, "src", "chan", "c1", "b1")
897861
assert parsed["activityData"]["url"] == "https://lore.kernel.org/r/"
898862

@@ -956,19 +920,22 @@ def _c1_argv(inbox_repo):
956920
"noteren.py",
957921
"--source=https://example.com/0.git",
958922
"--channel=test-list",
959-
"--git-dir", inbox_repo["gitdir"],
960-
"--segment-id", SEGMENT_ID,
961-
"--integration-id", INTEGRATION_ID,
962-
"--git-id", inbox_repo["c1"],
923+
"--git-dir",
924+
inbox_repo["gitdir"],
925+
"--segment-id",
926+
SEGMENT_ID,
927+
"--integration-id",
928+
INTEGRATION_ID,
929+
"--git-id",
930+
inbox_repo["c1"],
963931
]
964932

965933

966934
def test_main_entry_point_via_subprocess(inbox_repo):
967935
"""Running noteren.py as __main__ must work end-to-end."""
968936
r = subprocess.run(
969937
[sys.executable, NOTEREN] + _c1_argv(inbox_repo)[1:],
970-
stdout=subprocess.PIPE,
971-
stderr=subprocess.PIPE,
938+
capture_output=True,
972939
text=True,
973940
)
974941
assert r.returncode == 0, r.stderr

0 commit comments

Comments
 (0)