Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE git."repositoryProcessing" DROP COLUMN IF EXISTS "stuckRequiresReOnboard";
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This migration drops the stuckRequiresReOnboard column but doesn’t address existing rows that may still be in the removed state='stuck'. Since the app side removes the STUCK enum value, it’s worth adding a companion UPDATE in this migration (or a separate one) to rewrite any repositoryProcessing.state='stuck' rows to a supported state (e.g. pending_reonboard) to avoid leaving orphan/legacy states in production data.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Migration doesn't convert existing stuck state rows

Medium Severity

The migration drops the stuckRequiresReOnboard column but doesn't update existing rows where state = 'stuck'. Since the STUCK enum value is removed from RepositoryState and STUCK is removed from states_to_exclude in acquire_recurrent_repo, these orphaned rows will be picked up as regular recurrent repos instead of being properly queued for re-onboarding (pending_reonboard). This means they go through a normal processing attempt (which may fail for the same reason they were stuck) and get marked FAILED, rather than being cleanly re-onboarded as the PR intends. The migration needs an UPDATE statement to convert existing state = 'stuck' rows to 'pending_reonboard'.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 179c84d. Configure here.

2 changes: 0 additions & 2 deletions services/apps/git_integration/src/crowdgit/database/crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
rp.branch,
rp."maintainerFile",
rp."lastMaintainerRunAt",
rp."stuckRequiresReOnboard",
rp."reOnboardingCount"
"""

Expand Down Expand Up @@ -166,7 +165,6 @@ async def acquire_recurrent_repo() -> Repository | None:
states_to_exclude = (
RepositoryState.PENDING,
RepositoryState.PROCESSING,
RepositoryState.STUCK,
RepositoryState.PENDING_REONBOARD,
RepositoryState.AUTH_REQUIRED,
)
Comment on lines 165 to 170
Copy link

Copilot AI Apr 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

states_to_exclude no longer filters out the legacy stuck state. If there are still rows with state='stuck', they’ll now be picked up by the recurrent acquisition query. That can be fine, but it’s safer to explicitly migrate/normalize those rows to pending_reonboard (or another supported state) so the behavior is deterministic and doesn’t depend on historical data lingering in the table.

Copilot uses AI. Check for mistakes.
Expand Down
2 changes: 0 additions & 2 deletions services/apps/git_integration/src/crowdgit/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ class ErrorCode(str, Enum):
CLEANUP_FAILED = "cleanup-failed"
PARENT_REPO_INVALID = "parent-repo-invalid"
REONBOARDING_REQUIRED = "reonboarding-required"
STUCK_REPO = "stuck-repo"
REPO_AUTH_REQUIRED = "repo-auth-required"
RATE_LIMITED = "rate-limited"
ACCESS_FORBIDDEN = "access-forbidden"
Expand All @@ -37,7 +36,6 @@ class RepositoryState(str, Enum):
COMPLETED = "completed"
FAILED = "failed"
REQUIRES_PARENT = "requires_parent" # fork repo without valid parent repo in out system
STUCK = "stuck" # requires manual resolution
PENDING_REONBOARD = "pending_reonboard" # re-onboarding deferred until weekend
AUTH_REQUIRED = "auth_required" # private repo or repo requiring authentication

Expand Down
6 changes: 0 additions & 6 deletions services/apps/git_integration/src/crowdgit/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,12 +116,6 @@ class ReOnboardingRequiredError(CrowdGitError):
error_code: ErrorCode = ErrorCode.REONBOARDING_REQUIRED


@dataclass
class StuckRepoError(CrowdGitError):
error_message = "Repos stuck in processing state for a long time"
error_code: ErrorCode = ErrorCode.STUCK_REPO


@dataclass
class RepoAuthRequiredError(CrowdGitError):
error_message: str = "Repository requires authentication (likely private or deleted)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,6 @@ class Repository(BaseModel):
parent_repo: Repository | None = Field(
None, description="The parent repository (in case of fork) object from our database"
)
stuck_requires_re_onboard: bool = Field(
default=False,
description="Indicates if the stuck repository is resolved by a re-onboarding",
)
re_onboarding_count: int = Field(
default=0,
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}",
Expand All @@ -71,7 +67,6 @@ def from_db(cls, db_data: dict[str, Any]) -> Repository:
"maintainerFile": "maintainer_file",
"lastMaintainerRunAt": "last_maintainer_run_at",
"forkedFrom": "forked_from",
"stuckRequiresReOnboard": "stuck_requires_re_onboard",
"reOnboardingCount": "re_onboarding_count",
}
for db_field, model_field in field_mapping.items():
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
ParentRepoInvalidError,
ReOnboardingRequiredError,
RepoAuthRequiredError,
StuckRepoError,
)

# Import configured loguru logger from crowdgit.logger
Expand Down Expand Up @@ -117,14 +116,9 @@ async def _ensure_repo_not_stuck(self, repository: Repository):
# handling
if repo_stuck:
logger.warning(
f"Repo {repository.url} is stuck for {processing_duration_hours} hours!"
f"Repo {repository.url} is stuck for {processing_duration_hours} hours — queuing for re-onboarding"
)
if repository.stuck_requires_re_onboard:
logger.warning(
f"Repo {repository.url} is stuck due to force-push or dangling commit. Will be re-onboarded"
)
raise ReOnboardingRequiredError()
raise StuckRepoError()
raise ReOnboardingRequiredError()

async def _process_repositories(self):
"""
Expand Down Expand Up @@ -258,11 +252,6 @@ async def _process_single_repository(self, repository: Repository):

logger.info("Incremental processing completed successfully")
processing_state = RepositoryState.COMPLETED
except StuckRepoError:
logger.error(
f"Repo {repository.url} is stuck for unkown reason, marking it as stuck until manually resolved!"
)
processing_state = RepositoryState.STUCK
except ReOnboardingRequiredError:
logger.info(f"Repo {repository.url} needs re-onboarding, deferring until weekend")
processing_state = RepositoryState.PENDING_REONBOARD
Expand Down
Loading