Skip to content

feat(jtk): add attachments command#50

Merged
rianjs merged 1 commit intomainfrom
feat/38-jtk-attachments
Jan 31, 2026
Merged

feat(jtk): add attachments command#50
rianjs merged 1 commit intomainfrom
feat/38-jtk-attachments

Conversation

@rianjs
Copy link
Copy Markdown
Contributor

@rianjs rianjs commented Jan 31, 2026

Summary

  • Add jtk attachments list <issue> to list attachments on an issue
  • Add jtk attachments add <issue> --file <path> to upload files
  • Add jtk attachments get <id> to download attachments
  • Add jtk attachments delete <id> to remove attachments
  • Add FlexibleID type to handle Jira API inconsistency (IDs as strings or numbers)

Test plan

  • Unit tests for FlexibleID unmarshaling (string, number, null, invalid)
  • Unit tests for GetIssueAttachments API method
  • Unit tests for GetAttachment API method
  • Unit tests for DeleteAttachment API method
  • Unit tests for DownloadAttachment (file and directory output)
  • Unit tests for FormatFileSize helper
  • All tests passing locally
  • Lint passing

Closes #38

🤖 Generated with Claude Code

Add complete attachment management functionality:
- `jtk attachments list <issue>` - List all attachments on an issue
- `jtk attachments add <issue> --file <path>` - Upload file(s) to an issue
- `jtk attachments get <id>` - Download an attachment by ID
- `jtk attachments delete <id>` - Delete an attachment by ID

Includes FlexibleID type to handle Jira API inconsistency where attachment
IDs can be returned as either strings or numbers.

Closes #38

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@rianjs rianjs merged commit 959047c into main Jan 31, 2026
7 checks passed
@rianjs rianjs deleted the feat/38-jtk-attachments branch January 31, 2026 11:15
@rianjs
Copy link
Copy Markdown
Contributor Author

rianjs commented Jan 31, 2026

TDD Assessment: jtk attachments Command

Summary

The test coverage for the API layer is good but incomplete. The CLI command layer has no tests, which is consistent with the rest of the codebase but represents a coverage gap for this new feature.

What's Well-Tested

API Layer (api/attachments.go):

Function Test Coverage Notes
FlexibleID.UnmarshalJSON Excellent String, number, large number, invalid type, null cases
GetIssueAttachments Good Happy path + empty key validation
GetAttachment Good Happy path + empty ID validation
DeleteAttachment Good Happy path + empty ID validation
DownloadAttachment Good File output, directory output, nil attachment, missing URL
FormatFileSize Excellent Bytes, KB, MB, GB edge cases

Coverage Gaps

1. AddAttachment is completely untested

This is the most significant gap. AddAttachment (lines 104-188) has complex multipart form handling, goroutine-based streaming, and error paths that are not exercised:

  • File open failure
  • Multipart writer errors
  • HTTP request creation failure
  • Goroutine error propagation via errChan
  • Response parsing
  • API error responses (4xx/5xx)

Testing this is admittedly harder due to the goroutine and multipart complexity, but it's also where bugs are most likely to hide.

2. No HTTP error response tests

The existing tests only cover happy paths and input validation. None test:

  • 404 responses for non-existent issues/attachments
  • 401/403 authentication/authorization errors
  • 500 server errors
  • Malformed JSON responses

Compare with transitions_test.go which includes error response cases.

3. CLI command layer is untested

internal/cmd/attachments/attachments.go has no tests. This is consistent with the codebase pattern (no *_test.go files exist in internal/cmd/**), so I'm not flagging this as a blocker. However, the command layer does have logic worth testing:

  • att.Created[:10] slice operation could panic on malformed dates
  • File existence checking in runAdd
  • Path resolution logic in runGet

Verdict

Acceptable for merge with the following caveats:

  1. The test quality matches or exceeds the existing codebase patterns
  2. The AddAttachment gap is notable but not blocking - this is complex code that may be better validated through integration testing
  3. Error path coverage could be improved in a follow-up

Recommendations (Non-blocking)

If you want to strengthen coverage before merge:

// Add to attachments_test.go

func TestAddAttachment_EmptyIssueKey(t *testing.T) {
    client, _ := New(ClientConfig{URL: "http://unused", Email: "test@example.com", APIToken: "token"})
    _, err := client.AddAttachment("", "/tmp/file.txt")
    assert.Error(t, err)
    assert.Contains(t, err.Error(), "issue key is required")
}

func TestAddAttachment_EmptyFilePath(t *testing.T) {
    client, _ := New(ClientConfig{URL: "http://unused", Email: "test@example.com", APIToken: "token"})
    _, err := client.AddAttachment("PROJ-123", "")
    assert.Error(t, err)
    assert.Contains(t, err.Error(), "file path is required")
}

func TestGetIssueAttachments_NotFound(t *testing.T) {
    server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.WriteHeader(http.StatusNotFound)
        w.Write([]byte(`{"errorMessages":["Issue does not exist"]}`))
    }))
    defer server.Close()
    // ... test 404 handling
}

These would take ~15 minutes to add and would catch real bugs (e.g., the input validation exists but isn't verified by tests).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(jtk): port attachments command

1 participant