-
Notifications
You must be signed in to change notification settings - Fork 783
feat: Add GitLab backend for bidirectional issue sync #1290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
markthebest12
wants to merge
15
commits into
steveyegge:main
Choose a base branch
from
markthebest12:feat/gitlab-backend
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
TDD implementation of internal/gitlab/types.go: - Issue, User, Label, Milestone, IssueLink, Project types - SyncStats, SyncResult, Conflict for sync operations - Label prefix parsing for priority/status/type mapping - IsValidState helper for GitLab state validation All 8 tests passing. Relates to: se-devsvc/roz#4 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
TDD implementation of GitLab client for beads integration: - NewClient constructor with builder pattern (WithHTTPClient) - FetchIssues with pagination support via X-Next-Page header - FetchIssuesSince for incremental sync with updated_after param - CreateIssue for POST /projects/:id/issues - UpdateIssue for PUT /projects/:id/issues/:iid - GetIssueLinks for GET /projects/:id/issues/:iid/links - Retry logic with exponential backoff for rate limiting (429) - Proper error handling with status code context All 11 new tests pass (19 total in gitlab package). Closes steveyegge#5 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bidirectional mapping between GitLab issues and beads issues: - MappingConfig for configurable field mappings (priority, status, type, relations) - GitLabIssueToBeads for import/pull operations - BeadsIssueToGitLabFields for export/push operations - IssueLinksToDependencies for dependency conversion - Support for scoped labels (priority::*, status::*, type::*) - FilterNonScopedLabels to preserve custom labels All 11 mapping tests passing (30 total in gitlab package). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements Issue steveyegge#7 from the beads GitLab backend epic. Features: - bd gitlab status: Show GitLab configuration and sync status - bd gitlab sync: Sync issues with GitLab (--dry-run, --pull-only, --push-only) - bd gitlab projects: List accessible GitLab projects Configuration via bd config or environment variables: - gitlab.url / GITLAB_URL - gitlab.token / GITLAB_TOKEN - gitlab.project_id / GITLAB_PROJECT_ID Tests: 6 passing tests for config, validation, and command registration. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…IssueLink Code review identified these issues: - ProjectID now URL-encoded via projectPath() helper for path-based IDs - Added WithEndpoint() builder for custom API endpoints - Added FetchIssueByIID() for fetching single issues - Added CreateIssueLink() for creating issue dependencies All 15 client tests pass. Ready for sync implementation. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ction Added gitlab_sync.go with full sync implementation: - doPullFromGitLab: imports GitLab issues to beads with incremental sync - doPushToGitLab: creates/updates GitLab issues from local beads issues - detectGitLabConflicts: finds issues modified on both sides since last sync - resolveGitLabConflictsByTimestamp: resolves conflicts using newer-wins - parseGitLabSourceSystem: parses "gitlab:projectID:iid" format Updated gitlab.go: - runGitLabSync now uses sync functions with --pull-only/--push-only flags - Added proper error handling and progress output 8 new tests in gitlab_sync_test.go, all passing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix path-based project ID comparison in doPushToGitLab (skip numeric comparison when client.ProjectID contains "/" since we can't reliably compare "group/project" with numeric 789) - Add atomic counter to generateIssueID() to prevent collisions when generating multiple IDs rapidly - Add Warnings field to PullStats to track non-fatal issues like failed gitlab.last_sync saves - Add tests for conflict resolution (resolveGitLabConflictsByTimestamp) All 4 code review issues addressed with TDD. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add --prefer-local, --prefer-gitlab, and --prefer-newer flags to bd gitlab sync: - --prefer-local: Always keep local beads version on conflict - --prefer-gitlab: Always use GitLab version on conflict - --prefer-newer: Use most recently updated version (default) Features: - Unified resolveGitLabConflicts() function with strategy parameter - Flag validation (only one conflict strategy allowed) - Automatic conflict detection and resolution in bidirectional sync - 7 new tests for conflict resolution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Improve test coverage from 82.3% to 92.2% for internal/gitlab package: - types_test.go: Add tests for GetPriorityFromLabel, GetStatusFromLabel, GetTypeFromLabel helper functions (0% → 100%) - mapping_test.go: Add tests for priorityToLabel (42.9% → 100%) and IssueLinksToDependencies edge cases (73.3% → 100%) - client_test.go: Add error handling tests for UpdateIssue, GetIssueLinks, FetchIssueByIID, CreateIssueLink, CreateIssue, FetchIssuesSince All 379 new lines of tests pass. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add gitlab_integration_test.go with end-to-end tests: - TestGitLabSyncRoundtrip: Pull from GitLab, create local, push back - TestGitLabConflictStrategiesIntegration: prefer-local/gitlab/newer flags - TestGitLabConflictDetectionIntegration: Detect conflicts between local/GitLab - TestIncrementalSync: Full sync then incremental sync with last_sync timestamp Uses httptest mock servers and in-memory SQLite stores to test complete sync flows without external dependencies. Run with: go test -tags=integration ./cmd/bd/... Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
P0 steveyegge#1: Conflict detection now happens BEFORE push to prevent data loss. Previously: Pull -> Push -> Detect conflicts (wrong - conflicts overwritten) Now: Pull -> Detect conflicts -> Push (skip conflicting issues) P0 steveyegge#2: Added SyncContext struct for thread-safe sync operations. - SyncContext holds store, actor, dbPath, issueIDCounter - WithContext variants of all sync functions - globalContextIDCounter for cross-context uniqueness - Enables concurrent sync operations without race conditions Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add safeguards to prevent infinite loops in FetchIssues and FetchIssuesSince: 1. MaxPages constant (1000) prevents runaway pagination from malformed X-Next-Page headers that never return empty 2. Context cancellation check at start of each pagination loop iteration allows graceful shutdown and returns partial results when cancelled between requests Fixes potential DoS from malformed GitLab responses and improves responsiveness to cancellation signals. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Fix swallowed json.Marshal error during retry (client.go line 114)
Now logs the error and continues to next retry attempt instead of
silently ignoring with _.
- Add GetIssue() helper to IssueConversion for type-safe access
Returns *types.Issue from interface{} field, nil if wrong type.
Avoids import cycle by keeping interface{} but providing safe accessor.
- Eliminate duplicate mapping definitions between types.go and mapping.go
Export PriorityMapping, StatusMapping, TypeMapping from types.go as
single source of truth. DefaultMappingConfig now uses these exports.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
P2 Issue steveyegge#9: Remove deprecated resolveGitLabConflictsByTimestamp function - Delete unused function that was superseded by resolveGitLabConflicts - Remove associated tests that tested the deprecated function P3 Issue steveyegge#10: Document cross-project link limitation - Add doc comment to CreateIssueLink clarifying same-project constraint - Note that cross-project links will error at GitLab API level P3 Issue steveyegge#11: Fix ID collision on restart - Add 4 random bytes to generateIssueID to prevent collisions - Counter resets on process restart, random component ensures uniqueness - Add test to verify random component is present P3 Issue steveyegge#12: Document error handling philosophy - Add Error Handling Contract comment at top of gitlab_sync.go - Documents fatal vs non-fatal error handling approach - Clarifies that stats track error counts for reporting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changes based on PR steveyegge#1290 code review: 1. Wire up SyncContext in runGitLabSync - SyncContext was created but not actually used in the main entry point 2. Delete legacy non-WithContext functions - removes code duplication and eliminates dead code maintenance burden. All sync operations now use WithContext variants exclusively 3. Fix --prefer-local behavior - conflicting issues now go to forceUpdateIDs (to force push) instead of skipUpdateIDs. This ensures local changes actually win when that strategy is selected 4. Document conflict detection 1-second tolerance - explains the timestamp comparison window and its limitations for clock skew 5. Document UUID alternative for ID generation - notes that distributed deployments may need UUIDs instead of the current timestamp+counter+random approach Test updates: - All tests now use WithContext functions - Removed global store manipulation from tests - All 18 GitLab tests pass Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
internal/gitlab/client.go) for issue operationsinternal/gitlab/mapping.go)bd gitlabcommand with sync, status, and projects subcommands (cmd/bd/gitlab.go)--prefer-local,--prefer-gitlab,--prefer-newer(default)updated_afterparameterFeatures
Test Plan
🤖 Generated with Claude Code