Skip to content

Commit ab0fdce

Browse files
committed
fix: resolve pr review comments
Signed-off-by: Yeganathan S <63534555+skwowet@users.noreply.github.com>
1 parent 0557f72 commit ab0fdce

4 files changed

Lines changed: 42 additions & 55 deletions

File tree

services/apps/git_integration/src/crowdgit/database/crud.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -543,7 +543,7 @@ def dump_affiliation_snapshot(affiliations: list[AffiliationInfoItem]) -> list[d
543543

544544
async def get_repo_affiliation_registry(repo_id: str):
545545
sql_query = """
546-
SELECT "filePath", "fileSha", "status", "snapshot", "lastRunAt"
546+
SELECT "filePath", "fileHash", "status", "snapshot", "lastRunAt"
547547
FROM git."repoAffiliationRegistry"
548548
WHERE "repoId" = $1
549549
"""
@@ -558,7 +558,7 @@ async def get_repo_affiliation_registry(repo_id: str):
558558

559559
return {
560560
"file_path": row.get("filePath"),
561-
"file_sha": row.get("fileSha"),
561+
"file_hash": row.get("fileHash"),
562562
"status": row.get("status"),
563563
"snapshot": snapshot,
564564
"last_run_at": row.get("lastRunAt"),
@@ -569,27 +569,27 @@ async def upsert_repo_affiliation_registry(
569569
repo_id: str,
570570
*,
571571
file_path: str | None,
572-
file_sha: str | None,
572+
file_hash: str | None,
573573
status: str,
574574
snapshot: list[AffiliationInfoItem] | None,
575575
) -> None:
576576
snapshot_json = dump_affiliation_snapshot(snapshot) if snapshot is not None else None
577577
sql_query = """
578578
INSERT INTO git."repoAffiliationRegistry" (
579-
"repoId", "filePath", "fileSha", "status", "snapshot", "lastRunAt", "updatedAt"
579+
"repoId", "filePath", "fileHash", "status", "snapshot", "lastRunAt", "updatedAt"
580580
)
581581
VALUES ($1, $2, $3, $4, $5, NOW(), NOW())
582582
ON CONFLICT ("repoId") DO UPDATE SET
583583
"filePath" = EXCLUDED."filePath",
584-
"fileSha" = EXCLUDED."fileSha",
584+
"fileHash" = EXCLUDED."fileHash",
585585
"status" = EXCLUDED."status",
586586
"snapshot" = EXCLUDED."snapshot",
587587
"lastRunAt" = NOW(),
588588
"updatedAt" = NOW()
589589
"""
590590
await execute(
591591
sql_query,
592-
(repo_id, file_path, file_sha, status, snapshot_json),
592+
(repo_id, file_path, file_hash, status, snapshot_json),
593593
)
594594

595595

@@ -663,7 +663,9 @@ async def find_many_organization_ids_by_identities(identities: list[dict]) -> li
663663
params: list[str | bool | int] = []
664664
param_index = 1
665665
for idx, identity in enumerate(identities):
666-
values_parts.append(f"(${param_index}, ${param_index + 1}, ${param_index + 2}, ${param_index + 3})")
666+
values_parts.append(
667+
f"(${param_index}, ${param_index + 1}, ${param_index + 2}, ${param_index + 3})"
668+
)
667669
params.extend(
668670
[
669671
idx,
@@ -806,4 +808,3 @@ async def insert_member_segment_affiliations(rows: list[dict]) -> int:
806808
],
807809
)
808810
return len(rows)
809-

services/apps/git_integration/src/crowdgit/errors.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class MaintainerIntervalNotElapsedError(CrowdGitError):
108108
class AffiliationFileNotFoundError(CrowdGitError):
109109
error_message: str = "No affiliation file found in this repository"
110110
error_code: ErrorCode = ErrorCode.NO_AFFILIATION_FILE
111-
ai_cost: int = 0
111+
ai_cost: float = 0.0
112112

113113

114114
@dataclass
@@ -121,7 +121,7 @@ class AffiliationAnalysisError(CrowdGitError):
121121
class AffiliationIntervalNotElapsedError(CrowdGitError):
122122
error_message: str = "Too soon since the last affiliation run"
123123
error_code: ErrorCode = ErrorCode.AFFILIATION_INTERVAL_NOT_ELAPSED
124-
ai_cost: int = 0
124+
ai_cost: float = 0.0
125125

126126

127127
@dataclass

services/apps/git_integration/src/crowdgit/services/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from crowdgit.services.base.base_service import BaseService
21
from crowdgit.services.affiliation.affiliation_service import AffiliationService
2+
from crowdgit.services.base.base_service import BaseService
33
from crowdgit.services.clone.clone_service import CloneService
44
from crowdgit.services.commit.commit_service import CommitService
55
from crowdgit.services.license.license_service import LicenseService

services/apps/git_integration/src/crowdgit/services/affiliation/affiliation_service.py

Lines changed: 30 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@
1414
find_many_member_ids_by_identities,
1515
find_many_organization_ids_by_identities,
1616
get_repo_affiliation_registry,
17-
insert_member_organizations,
18-
insert_member_segment_affiliations,
1917
save_service_execution,
2018
upsert_repo_affiliation_registry,
2119
)
@@ -82,7 +80,8 @@ async def read_text_file(file_path: str) -> str:
8280
return safe_decode(await f.read())
8381

8482
@staticmethod
85-
def compute_file_sha(content: str) -> str:
83+
def compute_file_hash(content: str) -> str:
84+
"""SHA-256 hex digest of UTF-8 file content (not a Git blob SHA)."""
8685
return hashlib.sha256(content.encode("utf-8")).hexdigest()
8786

8887
@staticmethod
@@ -163,9 +162,7 @@ async def list_root_text_files(self, repo_path: str) -> list[str]:
163162

164163
return sorted(files)
165164

166-
async def read_file_start_preview(
167-
self, repo_path: str, relative_path: str
168-
) -> str | None:
165+
async def read_file_start_preview(self, repo_path: str, relative_path: str) -> str | None:
169166
"""Read a short preview of a candidate file for the discovery AI prompt."""
170167
full_path = os.path.join(repo_path, relative_path)
171168
if not await aiofiles.os.path.isfile(full_path):
@@ -185,9 +182,7 @@ async def read_file_start_preview(
185182
self.logger.debug(f"Could not read preview for {relative_path}: {repr(error)}")
186183
return None
187184

188-
async def format_candidates_with_previews(
189-
self, repo_path: str, candidates: list[str]
190-
) -> str:
185+
async def format_candidates_with_previews(self, repo_path: str, candidates: list[str]) -> str:
191186
blocks: list[str] = []
192187
for relative_path in candidates:
193188
preview = await self.read_file_start_preview(repo_path, relative_path)
@@ -285,9 +280,7 @@ async def pick_affiliation_file_with_ai(
285280
f"Picking affiliation file with AI "
286281
f"(batch {batch_index}/{total_batches}, {len(batch)} candidates)"
287282
)
288-
candidates_with_previews = await self.format_candidates_with_previews(
289-
repo_path, batch
290-
)
283+
candidates_with_previews = await self.format_candidates_with_previews(repo_path, batch)
291284
prompt = self.get_file_picker_prompt(
292285
repo_url,
293286
candidates_with_previews=candidates_with_previews,
@@ -475,9 +468,13 @@ async def parse_affiliations(
475468
pydantic_model=AffiliationParseOutput,
476469
)
477470

478-
if parse_result.output.affiliations:
479-
raw_count = len(parse_result.output.affiliations)
480-
normalized = self.normalize_parsed_affiliations(parse_result.output.affiliations)
471+
affiliations = parse_result.output.affiliations
472+
if affiliations is not None:
473+
if not affiliations:
474+
raise AffiliationAnalysisError()
475+
476+
raw_count = len(affiliations)
477+
normalized = self.normalize_parsed_affiliations(affiliations)
481478

482479
if not normalized:
483480
raise AffiliationAnalysisError()
@@ -552,38 +549,31 @@ async def resolve_snapshot(
552549
registry: dict | None,
553550
file_path: str,
554551
content: str,
555-
file_sha: str,
552+
file_hash: str,
556553
repo_url: str = "",
557554
) -> tuple[list[AffiliationInfoItem], float]:
558555
"""
559556
Reuse the saved snapshot when the file is unchanged, otherwise re-parse.
560557
"""
561-
stored_sha = registry.get("file_sha") if registry else None
558+
stored_hash = registry.get("file_hash") if registry else None
562559
existing_snapshot = registry.get("snapshot") if registry else None
563560
needs_parse = (
564-
file_sha != stored_sha
565-
or existing_snapshot is None
566-
or not existing_snapshot
561+
file_hash != stored_hash or existing_snapshot is None or not existing_snapshot
567562
)
568563

569564
if not needs_parse:
570-
if existing_snapshot:
571-
applyable = self.normalize_parsed_affiliations(existing_snapshot)
565+
applyable = self.normalize_parsed_affiliations(existing_snapshot)
572566

573-
if applyable:
574-
self.logger.debug("Using cached snapshot, file unchanged")
575-
return applyable, 0.0
567+
if applyable:
568+
self.logger.debug("Using cached snapshot, file unchanged")
569+
return applyable, 0.0
576570

577-
self.logger.info("Cached snapshot had no usable rows, reparsing file")
578-
else:
579-
return existing_snapshot, 0.0
571+
self.logger.info("Cached snapshot had no usable rows, reparsing file")
580572

581573
affiliations, parse_cost = await self.parse_affiliations(file_path, content, repo_url)
582574
return affiliations, parse_cost
583575

584-
async def check_if_interval_elapsed(
585-
self, registry: dict | None
586-
) -> tuple[bool, float]:
576+
async def check_if_interval_elapsed(self, registry: dict | None) -> tuple[bool, float]:
587577
"""
588578
Check whether enough time has passed since the last affiliation run.
589579
@@ -696,7 +686,7 @@ async def apply_affiliations(
696686
seen_pairs: set[tuple[str, str]] = set()
697687
skipped_unresolved = 0
698688

699-
for (member_idx, org_idx) in row_identity_refs:
689+
for member_idx, org_idx in row_identity_refs:
700690
if member_idx is None or org_idx is None:
701691
skipped_unresolved += 1
702692
continue
@@ -739,9 +729,7 @@ async def apply_affiliations(
739729
existing_msas = segment_affiliations_by_member.get(member_id, [])
740730

741731
if not self.has_undated_affiliation_for_org(existing_mos, organization_id):
742-
mo_inserts.append(
743-
{"member_id": member_id, "organization_id": organization_id}
744-
)
732+
mo_inserts.append({"member_id": member_id, "organization_id": organization_id})
745733

746734
if self.has_undated_affiliation_for_org(existing_msas, organization_id):
747735
continue
@@ -755,7 +743,7 @@ async def apply_affiliations(
755743
}
756744
)
757745

758-
# TODO: Enable CDP writes after testing is complete
746+
# TODO: Enable CDP writes after testing (import insert_member_* from crud)
759747
# await insert_member_organizations(mo_inserts)
760748
# await insert_member_segment_affiliations(msa_inserts)
761749

@@ -795,21 +783,21 @@ async def process_affiliations(
795783
await upsert_repo_affiliation_registry(
796784
repository.id,
797785
file_path=None,
798-
file_sha=None,
786+
file_hash=None,
799787
status=AffiliationRegistryStatus.NOT_FOUND.value,
800788
snapshot=None,
801789
)
802790
raise AffiliationFileNotFoundError(ai_cost=ai_cost)
803791

804792
file_path_on_disk = os.path.join(batch_info.repo_path, latest_file_path)
805793
content = await self.read_text_file(file_path_on_disk)
806-
file_sha = self.compute_file_sha(content)
794+
file_hash = self.compute_file_hash(content)
807795

808796
affiliations, parse_cost = await self.resolve_snapshot(
809797
registry,
810798
latest_file_path,
811799
content,
812-
file_sha,
800+
file_hash,
813801
repository.url,
814802
)
815803
ai_cost += parse_cost
@@ -819,14 +807,12 @@ async def process_affiliations(
819807
await upsert_repo_affiliation_registry(
820808
repository.id,
821809
file_path=latest_file_path,
822-
file_sha=file_sha,
810+
file_hash=file_hash,
823811
status=AffiliationRegistryStatus.SUCCESS.value,
824812
snapshot=affiliations,
825813
)
826814

827-
self.logger.info(
828-
f"Finished with {len(affiliations)} rows from {latest_file_path}"
829-
)
815+
self.logger.info(f"Finished with {len(affiliations)} rows from {latest_file_path}")
830816

831817
except AffiliationIntervalNotElapsedError as e:
832818
execution_status = ExecutionStatus.FAILURE
@@ -847,7 +833,7 @@ async def process_affiliations(
847833
await upsert_repo_affiliation_registry(
848834
repository.id,
849835
file_path=latest_file_path,
850-
file_sha=None,
836+
file_hash=None,
851837
status=AffiliationRegistryStatus.ERROR.value,
852838
snapshot=registry.get("snapshot") if registry else None,
853839
)

0 commit comments

Comments
 (0)