Skip to content

[command] import issues from file#16

Merged
capcom6 merged 2 commits into
masterfrom
commands/import-issues
May 5, 2026
Merged

[command] import issues from file#16
capcom6 merged 2 commits into
masterfrom
commands/import-issues

Conversation

@capcom6
Copy link
Copy Markdown
Contributor

@capcom6 capcom6 commented May 4, 2026

Summary by CodeRabbit

  • New Features
    • Bitbucket export import to bulk import issues, comments and attachments (preserves original metadata)
    • Task "kind" categorization added: Bug, Enhancement, Task, Proposal (API, DB and responses updated)
    • Import CLI with flags for project, file, default-user and a --dry-run preview mode
  • Chores
    • Database migration to add task.kind column

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 4, 2026

Warning

Rate limit exceeded

@capcom6 has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 42 minutes and 5 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f5604cb6-6d31-47ae-9280-aa5b0ff5213f

📥 Commits

Reviewing files that changed from the base of the PR and between d254621 and 26a9deb.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • go.mod
  • internal/app.go
  • internal/commands/commands.go
  • internal/commands/importer/config.go
  • internal/commands/importer/import.go
  • internal/commands/importer/importer.go
  • internal/commands/serve/serve.go
  • internal/comments/models.go
  • internal/comments/repository.go
  • internal/comments/service.go
  • internal/db/migrations/20260429000000_add_task_kind.sql
  • internal/server/docs/docs.go
  • internal/server/tasks/dto.go
  • internal/tasks/domain.go
  • internal/tasks/models.go
  • internal/tasks/repository.go
  • internal/tasks/service.go
  • pkg/bitbucket/issues.go
📝 Walkthrough

Walkthrough

Adds a Bitbucket issue importer CLI subcommand, refactors CLI command wiring into internal/commands, introduces a kind field for tasks (Bug, Enhancement, Task, Proposal) with DB migration, and adds import-specific constructors and Import methods for tasks and comments that preserve original metadata.

Changes

Importer + Task Kind + CLI refactor

Layer / File(s) Summary
Dependency & CLI foundation
go.mod, internal/app.go, internal/commands/commands.go
Bumps go.uber.org/zap → v1.28.0 and pins github.com/go-core-fx/fxutil → v0.0.1. Replaces inline serve wiring in internal/app.go with commands.Commands(version). Adds commands.Commands(version) returning serve.Command(...) and importer.Command(...).
Serve command wiring
internal/commands/serve/serve.go
Moves serve CLI into serve package and exposes Command(version); run logic starts/stops FX app and wraps start/stop errors.
Importer CLI & config
internal/commands/importer/import.go, internal/commands/importer/config.go
Adds import CLI command builder and importer.Config with flags --file, --project, --default-user, and --dry-run; run builds and runs an FX app supplying parsed config.
Bitbucket export types
pkg/bitbucket/issues.go
Adds JSON models: Issue, User, Comment, and top-level Export.
Importer implementation
internal/commands/importer/importer.go
Implements importer runnable: parses export file, resolves default user, normalizes priority/status/kind, imports issues as tasks and comments as comments, supports dry-run, maintains mapping from external issue IDs → internal task IDs, and triggers shutdown when done.
Task Kind domain, models, migration
internal/tasks/domain.go, internal/tasks/models.go, internal/db/migrations/20260429000000_add_task_kind.sql
Introduces Kind type and constants; adds Kind to Task, TaskInput, TaskUpdate; validation helpers. DB migration adds non-null ENUM kind with default 'Task'. Adds newTaskImport constructor that preserves timestamps and explicit persisted fields.
Task repository/service updates
internal/tasks/repository.go, internal/tasks/service.go
Adds Repository.Import to insert imported tasks (bypassing auto-number generation) with unique-violation mapping; Update now sets kind when provided. Exposes Service.Import delegating to repository import.
Comment import changes
internal/comments/models.go, internal/comments/repository.go, internal/comments/service.go
Adds newCommentImport constructor and Repository.Import/Service.Import to create comments preserving original timestamps and returning domain records; insert errors are wrapped with import-specific messages.
API DTOs & docs
internal/server/tasks/dto.go, internal/server/docs/docs.go
Task DTOs (TaskCreateRequest, TaskUpdateRequest, TaskResponse) now include kind with enum validation and default; OpenAPI/Swagger template updated to expose kind in create/update/response schemas.

Sequence Diagram

sequenceDiagram
    actor CLI as CLI User
    participant CLIApp as CLI App
    participant FX as FX Application
    participant Importer as Importer Runnable
    participant Parser as Bitbucket Parser
    participant TaskSvc as Task Service
    participant CommentSvc as Comment Service
    participant DB as Database

    CLI->>CLIApp: run "import --file=export.json --project=slug --default-user=1"
    CLIApp->>FX: start import command (supplies config)
    FX->>Importer: Run(ctx)
    Importer->>Parser: parseExportFile(export.json)
    Parser-->>Importer: Export{Issues, Comments}
    Importer->>Importer: resolveUser(defaultUser)
    loop For each Issue
        Importer->>Importer: normalizePriority/Status/Kind
        Importer->>TaskSvc: Import(task with explicit metadata)
        TaskSvc->>DB: INSERT task (preserve timestamps/number)
        DB-->>TaskSvc: inserted task
        TaskSvc-->>Importer: created task (store mapping)
    end
    loop For each Comment
        Importer->>Importer: lookup task ID by issue ID
        alt task found
            Importer->>CommentSvc: Import(comment)
            CommentSvc->>DB: INSERT comment (preserve timestamps)
            DB-->>CommentSvc: inserted comment
            CommentSvc-->>Importer: comment created
        else task missing
            Importer->>Importer: log warning and skip
        end
    end
    Importer->>FX: signal Shutdown
    FX-->>CLIApp: return import counts
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 46.15% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main purpose of the PR: adding a new command to import issues from a file, which aligns with the substantial changes across commands, importer, and related modules.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 42 minutes and 5 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the codex label May 4, 2026
@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 4, 2026

🤖 Pull request artifacts

Platform File
🐳 Docker GitHub Container Registry
🍎 Darwin arm64 backend_Darwin_arm64.tar.gz
🍎 Darwin x86_64 backend_Darwin_x86_64.tar.gz
🐧 Linux arm64 backend_Linux_arm64.tar.gz
🐧 Linux i386 backend_Linux_i386.tar.gz
🐧 Linux x86_64 backend_Linux_x86_64.tar.gz
🪟 Windows arm64 backend_Windows_arm64.zip
🪟 Windows i386 backend_Windows_i386.zip
🪟 Windows x86_64 backend_Windows_x86_64.zip

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/tasks/repository.go (1)

179-207: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

kind updates are accepted but never persisted

TaskUpdate.Kind is now wired through DTO/domain, but Repository.Update never applies kind in the SQL SET clause, so PATCH requests that only change kind are silently ignored.

💡 Proposed fix
 	if update.Status != nil {
 		query = query.Set("status = ?", *update.Status)
 	}
+	if update.Kind != nil {
+		query = query.Set("kind = ?", *update.Kind)
+	}
 	if update.AssigneeID != nil {
 		if *update.AssigneeID == 0 {
 			query = query.Set("assignee_id = NULL")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/tasks/repository.go` around lines 179 - 207, The Update
implementation in Repository (in internal/tasks/repository.go, around the code
constructing query in Update) never applies TaskUpdate.Kind to the SQL SET
clause so kind changes are not persisted; add a branch similar to
Title/Description that checks if update.Kind != nil and then call query =
query.Set("kind = ?", *update.Kind) (or if your domain allows an empty/nil
string to clear the field, handle that by setting "kind = NULL" when
*update.Kind == ""), ensuring the property is included before executing the
update.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@internal/commands/importer/import.go`:
- Around line 74-87: Replace the current select that listens on app.Done() with
code that reads the shutdown signal from app.Wait(): block on ctx.Done() or sig
:= <-app.Wait(), then after sig is received save its ShutdownSignal.ExitCode;
call stop via app.Stop(stopCtx) as before, and finally if
sig.ShutdownSignal.ExitCode is non-zero return an error representing that exit
code (e.g., fmt.Errorf with the code) so importer.Run() failures are propagated
instead of returning nil. Ensure you reference ctx, app.Wait(), sig (the value
from app.Wait()), sig.ShutdownSignal.ExitCode, and app.Stop(...) when
implementing this change.

In `@internal/commands/importer/importer.go`:
- Around line 224-237: The resolveUser function currently only supports numeric
IDs but its comment claims it supports username/email; make the behavior and
docs consistent by updating the function to be ID-only: change the doc comment
for resolveUser to state "finds a user by ID only", and when
strconv.Atoi(userStr) fails return a clear error like "user must be an ID"
(preserve wrapping of the parse error), and keep using usersSvc.GetByID(ctx,
int64(userID)) to fetch the user; refer to resolveUser and users.Service.GetByID
in your changes so callers and docs are no longer misleading.

In `@internal/db/migrations/20260429000000_add_task_kind.sql`:
- Line 4: The new column addition ADD COLUMN `kind` VARCHAR(255) NOT NULL
DEFAULT 'Task' is too permissive; change the migration to constrain `kind` to
the allowed domain (like existing `status`/`priority`) by using a SQL ENUM
(e.g., CREATE TYPE task_kind AS ENUM(...)) or a strict CHECK constraint (e.g.,
CHECK(kind IN (...))) and set the DEFAULT to a valid member; update the ALTER
TABLE/ADD COLUMN statement to reference that enum/type or include the CHECK, and
ensure any backfill/rollback logic in the migration handles existing rows and
uses the same constraint name (reference the `kind` column and the migration
that adds it).

In `@internal/server/tasks/dto.go`:
- Around line 209-218: The toTaskInput conversion is passing an empty kind
string into tasks.TaskInput when req.Kind is omitted; update the mapping so Kind
is set to the documented default (tasks.Task) when req.Kind is empty — for
example, after computing kind := tasks.Kind(req.Kind) coalesce or check
emptiness and set Kind: lo.CoalesceOrEmpty(kind, tasks.Task) (or equivalent
conditional) so the returned tasks.TaskInput.Kind never remains "" and defaults
to tasks.Task.

In `@internal/tasks/domain.go`:
- Around line 139-143: TaskInput.Validate currently only checks Status; add
validation for the Kind enum in the same validation block by calling the enum
validator (e.g., i.Kind.IsValid()) and returning fmt.Errorf("%w: invalid kind
value", ErrValidationFailed) on failure; place this check adjacent to the
existing Status validation in the TaskInput.Validate method so create-time
domain validation enforces Kind from non-HTTP code paths as well.

In `@pkg/bitbucket/issues.go`:
- Around line 36-37: Change the Comment model to make UpdatedOn nullable (use
*time.Time instead of time.Time) so JSON nulls are preserved during
unmarshalling (update the struct field UpdatedOn in the Comment type). Then
update the importer logic that reads comment timestamps (where it currently
assumes Comment.UpdatedOn is a time.Time) to handle a nil UpdatedOn by falling
back to the comment's CreatedOn value when setting the import audit timestamp.
Ensure any uses of Comment.UpdatedOn check for nil before dereferencing.

---

Outside diff comments:
In `@internal/tasks/repository.go`:
- Around line 179-207: The Update implementation in Repository (in
internal/tasks/repository.go, around the code constructing query in Update)
never applies TaskUpdate.Kind to the SQL SET clause so kind changes are not
persisted; add a branch similar to Title/Description that checks if update.Kind
!= nil and then call query = query.Set("kind = ?", *update.Kind) (or if your
domain allows an empty/nil string to clear the field, handle that by setting
"kind = NULL" when *update.Kind == ""), ensuring the property is included before
executing the update.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 862408b5-b679-404a-9318-74c0d9fecebf

📥 Commits

Reviewing files that changed from the base of the PR and between 872741b and 8dd8c98.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • go.mod
  • internal/app.go
  • internal/commands/commands.go
  • internal/commands/importer/config.go
  • internal/commands/importer/import.go
  • internal/commands/importer/importer.go
  • internal/commands/serve/serve.go
  • internal/comments/models.go
  • internal/comments/repository.go
  • internal/comments/service.go
  • internal/db/migrations/20260429000000_add_task_kind.sql
  • internal/server/docs/docs.go
  • internal/server/tasks/dto.go
  • internal/tasks/domain.go
  • internal/tasks/models.go
  • internal/tasks/repository.go
  • internal/tasks/service.go
  • pkg/bitbucket/issues.go

Comment thread internal/commands/importer/import.go
Comment thread internal/commands/importer/importer.go Outdated
Comment thread internal/db/migrations/20260429000000_add_task_kind.sql Outdated
Comment thread internal/server/tasks/dto.go Outdated
Comment thread internal/tasks/domain.go
Comment thread pkg/bitbucket/issues.go Outdated
@capcom6 capcom6 force-pushed the commands/import-issues branch from d254621 to 26a9deb Compare May 4, 2026 07:49
@capcom6 capcom6 merged commit 4cb07ac into master May 5, 2026
7 checks passed
@capcom6 capcom6 deleted the commands/import-issues branch May 5, 2026 03:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant