Skip to content

Commit 05df663

Browse files
authored
feat(git-integration): track re-onboarding counts and unreachable commits [CM-815] (#3679)
1 parent b7a2b2b commit 05df663

6 files changed

Lines changed: 51 additions & 7 deletions

File tree

backend/src/database/migrations/U1765185575__addReOnboardingCountToGitRepos.sql

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
-- Add reOnboardingCount column to git.repositories table
2+
-- This column tracks the number of times a repository has been re-onboarded.
3+
-- It is used to identify unreachable commits by matching against activity.attributes.cycle=onboarding-{reOnboardingCount}
4+
ALTER TABLE git.repositories
5+
ADD COLUMN "reOnboardingCount" INTEGER default 0 NOT NULL;
6+
7+
COMMENT ON COLUMN git.repositories."reOnboardingCount" IS 'Tracks the number of times this repository has been re-onboarded. Used to identify unreachable commits via activity.attributes.cycle matching pattern onboarding-{reOnboardingCount}';

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

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async def insert_repository(url: str, priority: int = 0) -> str:
3232
async def get_repository_by_url(url: str) -> dict[str, Any] | None:
3333
"""Get repository by URL"""
3434
sql_query = """
35-
SELECT id, url, state, priority, "lastProcessedAt", "lockedAt", "createdAt", "updatedAt", "maintainerFile", "forkedFrom", "stuckRequiresReOnboard"
35+
SELECT id, url, state, priority, "lastProcessedAt", "lockedAt", "createdAt", "updatedAt", "maintainerFile", "forkedFrom", "stuckRequiresReOnboard", "reOnboardingCount"
3636
FROM git.repositories
3737
WHERE url = $1 AND "deletedAt" IS NULL
3838
"""
@@ -49,7 +49,7 @@ async def get_recently_processed_repository_by_url(url: str) -> Repository | Non
4949
Used to check if a repository needs reprocessing based on the update interval.
5050
"""
5151
sql_query = """
52-
SELECT id, url, state, priority, "lastProcessedAt", "lockedAt", "createdAt", "updatedAt", "maintainerFile", "forkedFrom", "segmentId", "stuckRequiresReOnboard"
52+
SELECT id, url, state, priority, "lastProcessedAt", "lockedAt", "createdAt", "updatedAt", "maintainerFile", "forkedFrom", "segmentId", "stuckRequiresReOnboard", "reOnboardingCount"
5353
FROM git.repositories
5454
WHERE url = $1
5555
AND "deletedAt" IS NULL
@@ -88,7 +88,7 @@ async def acquire_onboarding_repo() -> Repository | None:
8888
LIMIT 1
8989
FOR UPDATE SKIP LOCKED
9090
)
91-
RETURNING id, url, state, priority, "lastProcessedAt", "lastProcessedCommit", "lockedAt", "createdAt", "updatedAt", "segmentId", "integrationId", "maintainerFile", "lastMaintainerRunAt", "branch", "forkedFrom", "stuckRequiresReOnboard"
91+
RETURNING id, url, state, priority, "lastProcessedAt", "lastProcessedCommit", "lockedAt", "createdAt", "updatedAt", "segmentId", "integrationId", "maintainerFile", "lastMaintainerRunAt", "branch", "forkedFrom", "stuckRequiresReOnboard", "reOnboardingCount"
9292
"""
9393
return await acquire_repository(
9494
onboarding_repo_sql_query,
@@ -138,7 +138,7 @@ async def acquire_recurrent_repo() -> Repository | None:
138138
LIMIT 1
139139
FOR UPDATE SKIP LOCKED
140140
)
141-
RETURNING id, url, state, priority, "lastProcessedAt", "lastProcessedCommit", "lockedAt", "createdAt", "updatedAt", "segmentId", "integrationId", "maintainerFile", "lastMaintainerRunAt", "branch", "forkedFrom", "stuckRequiresReOnboard"
141+
RETURNING id, url, state, priority, "lastProcessedAt", "lastProcessedCommit", "lockedAt", "createdAt", "updatedAt", "segmentId", "integrationId", "maintainerFile", "lastMaintainerRunAt", "branch", "forkedFrom", "stuckRequiresReOnboard", "reOnboardingCount"
142142
"""
143143
states_to_exclude = (
144144
RepositoryState.PENDING,
@@ -220,6 +220,16 @@ async def update_last_processed_commit(repo_id: str, commit_hash: str, branch: s
220220
return str(result)
221221

222222

223+
async def increase_re_onboarding_count(repo_id: str):
224+
sql_query = """
225+
UPDATE git.repositories
226+
SET "reOnboardingCount" = "reOnboardingCount" + 1,
227+
"updatedAt" = NOW()
228+
WHERE id = $1
229+
"""
230+
return await execute(sql_query, (repo_id,))
231+
232+
223233
async def mark_repo_as_processed(repo_id: str, repo_state: RepositoryState):
224234
sql_query = """
225235
UPDATE git.repositories

services/apps/git_integration/src/crowdgit/models/repository.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ class Repository(BaseModel):
4545
default=False,
4646
description="Indicates if the stuck repository is resolved by a re-onboarding",
4747
)
48+
re_onboarding_count: int = Field(
49+
...,
50+
description="Tracks the number of times this repository has been re-onboarded. Used to identify unreachable commits via activity.attributes.cycle matching pattern onboarding-{reOnboardingCount}",
51+
)
4852
created_at: datetime = Field(..., description="Creation timestamp")
4953
updated_at: datetime = Field(..., description="Last update timestamp")
5054

@@ -72,6 +76,7 @@ def from_db(cls, db_data: dict[str, Any]) -> Repository:
7276
"lastMaintainerRunAt": "last_maintainer_run_at",
7377
"forkedFrom": "forked_from",
7478
"stuckRequiresReOnboard": "stuck_requires_re_onboard",
79+
"reOnboardingCount": "re_onboarding_count",
7580
}
7681
for db_field, model_field in field_mapping.items():
7782
if db_field in repo_data:

services/apps/git_integration/src/crowdgit/services/commit/commit_service.py

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ def create_activity(
354354
member: dict,
355355
source_id: str,
356356
segment_id: str,
357+
re_onboarding_count: int,
357358
source_parent_id: str = "",
358359
) -> dict:
359360
"""
@@ -366,6 +367,8 @@ def create_activity(
366367
member: Member information dictionary
367368
source_id: Source ID for the activity
368369
segment_id: Segment identifier
370+
re_onboarding_count: Number of times the repository has been re-onboarded.
371+
Used to set activity.attributes.cycle when > 0.
369372
source_parent_id: Parent source ID (optional)
370373
371374
Returns:
@@ -416,7 +419,7 @@ def create_activity(
416419
# Pre-calculate commit attributes to avoid repeated lookups
417420
insertions = commit.get("insertions", 0)
418421
deletions = commit.get("deletions", 0)
419-
return {
422+
activity = {
420423
"type": activity_type,
421424
"timestamp": timestamp,
422425
"sourceId": source_id,
@@ -436,6 +439,9 @@ def create_activity(
436439
"member": processed_member,
437440
"segmentId": segment_id,
438441
}
442+
if re_onboarding_count > 0:
443+
activity["attributes"]["cycle"] = f"onboarding-{re_onboarding_count}"
444+
return activity
439445

440446
def extract_activities(self, commit_message: list[str]) -> list[dict[str, dict[str, str]]]:
441447
"""
@@ -500,7 +506,12 @@ def prepare_activity_for_db_and_queue(
500506
return activity_db, activity_kafka
501507

502508
def create_activities_from_commit(
503-
self, remote: str, commit: dict[str, Any], segment_id: str, integration_id: str
509+
self,
510+
remote: str,
511+
commit: dict[str, Any],
512+
segment_id: str,
513+
integration_id: str,
514+
re_onboarding_count: int,
504515
) -> tuple[list[tuple], list[dict[str, Any]]]:
505516
"""
506517
Create activities from a commit with improved efficiency.
@@ -510,6 +521,8 @@ def create_activities_from_commit(
510521
commit: The commit dictionary containing commit data
511522
segment_id: Segment identifier
512523
integration_id: Integration identifier
524+
re_onboarding_count: Number of times the repository has been re-onboarded.
525+
Used to set activity.attributes.cycle when > 0.
513526
514527
Returns:
515528
Tuple of (activities_db, activities_queue) lists
@@ -537,6 +550,7 @@ def create_activities_from_commit(
537550
member=author,
538551
source_id=commit_hash,
539552
segment_id=segment_id,
553+
re_onboarding_count=re_onboarding_count,
540554
)
541555
activity_db, activity_kafka = self.prepare_activity_for_db_and_queue(
542556
activity, segment_id, integration_id
@@ -565,6 +579,7 @@ def create_activities_from_commit(
565579
source_id=committer_source_id,
566580
source_parent_id=commit_hash,
567581
segment_id=segment_id,
582+
re_onboarding_count=re_onboarding_count,
568583
)
569584
activity_db, activity_kafka = self.prepare_activity_for_db_and_queue(
570585
activity, segment_id, integration_id
@@ -599,6 +614,7 @@ def create_activities_from_commit(
599614
source_id=source_id,
600615
source_parent_id=commit_hash,
601616
segment_id=segment_id,
617+
re_onboarding_count=re_onboarding_count,
602618
)
603619
activity_db, activity_kafka = self.prepare_activity_for_db_and_queue(
604620
activity, segment_id, integration_id
@@ -704,7 +720,11 @@ async def process_commits_chunk(
704720
commit = self._construct_commit_dict(commit_lines, numstats_text)
705721
if self._validate_commit_data(commit):
706722
activity_db_records, activity_kafka = self.create_activities_from_commit(
707-
batch_info.remote, commit, repository.segment_id, repository.integration_id
723+
batch_info.remote,
724+
commit,
725+
repository.segment_id,
726+
repository.integration_id,
727+
repository.re_onboarding_count,
708728
)
709729
activities_db.extend(activity_db_records)
710730
activities_queue.extend(activity_kafka)

services/apps/git_integration/src/crowdgit/worker/repository_worker.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from crowdgit.database.crud import (
55
acquire_repo_for_processing,
66
get_recently_processed_repository_by_url,
7+
increase_re_onboarding_count,
78
mark_repo_as_processed,
89
release_repo,
910
update_last_processed_commit,
@@ -262,6 +263,7 @@ async def _process_single_repository(self, repository: Repository):
262263
branch=None,
263264
)
264265
processing_state = RepositoryState.PENDING
266+
await increase_re_onboarding_count(repository.id)
265267
except ParentRepoInvalidError as e:
266268
logger.error(f"Parent repo validation failed: {repr(e)}")
267269
processing_state = RepositoryState.REQUIRES_PARENT

0 commit comments

Comments
 (0)