Skip to content

fix(jtk): support unassigning issues via --assignee none#187

Merged
rianjs merged 2 commits intomainfrom
fix/177-unassign-issues
Mar 28, 2026
Merged

fix(jtk): support unassigning issues via --assignee none#187
rianjs merged 2 commits intomainfrom
fix/177-unassign-issues

Conversation

@rianjs
Copy link
Copy Markdown
Contributor

@rianjs rianjs commented Mar 28, 2026

Summary

  • Accept none, null, or empty string as assignee values to send null to Jira API
  • Works through both --assignee flag and --field assignee=none
  • Adds isNullValue() helper for consistent null detection
  • Updates FormatFieldValue() to return nil for user fields with null values

Closes #177

Examples

# Unassign via --assignee flag
jtk issues update PROJ-123 --assignee none

# Unassign via --field flag
jtk issues update PROJ-123 --field assignee=null

Test plan

  • Unit tests for isNullValue (none, null, empty, case variants)
  • Unit tests for FormatFieldValue with null user values
  • make build && make test passes

Accept "none", "null", or empty string as assignee values to clear the
assignee field. Works through both --assignee flag and --field assignee=none.

  jtk issues update PROJ-123 --assignee none
  jtk issues update PROJ-123 --field assignee=null

Closes #177
Copy link
Copy Markdown

@monit-reviewer monit-reviewer left a comment

Choose a reason for hiding this comment

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

Automated PR Review

Reviewed commit: 8343ef6

Approved with 2 non-blocking suggestions below. Address at your discretion.

Summary

Reviewer Findings
database:sql-reviewer 1
harness-engineering:architecture-reviewer 1
database:sql-reviewer (1 findings)

💡 Suggestion - tools/jtk/api/fields_test.go:231

FormatFieldValue test cases for the new null-user path cover 'none' and 'null' but not the empty string case (value: ""), which is also handled by the code at fields.go:114. The assignee_test.go TestIsNullValue tests cover empty string thoroughly — adding at least one empty-string case here would close the gap.

harness-engineering:architecture-reviewer (1 findings)

💡 Suggestion - tools/jtk/api/fields.go:113

Null-value detection logic (TrimSpace + ToLower, checking 'none'/'null'/empty) is duplicated identically in isNullValue() in assignee.go and inline here in FormatFieldValue(). Since the issues package already imports api, consider exporting IsNullValue from the api package and calling it from both sites. If the set of sentinel values ever changes, both locations must be updated otherwise.

2 info-level observations excluded. Run with --verbose to include.


Completed in 4m 41s | $0.72
Field Value
Reviewers hybrid-synthesis, database:sql-reviewer, security:code-auditor, harness-engineering:knowledge-reviewer, harness-engineering:enforcement-reviewer, harness-engineering:architecture-reviewer, harness-engineering:legibility-reviewer
Reviewed by pr-review-daemon · monit-pr-reviewer
Duration 4m 41s (Reviewers: 54s · Synthesis: 1m 08s)
Cost $0.72
Tokens 375.9k in / 18.4k out
Turns 54

}
return []string{value}
case "user":
lower := strings.ToLower(strings.TrimSpace(value))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Low (harness-engineering:architecture-reviewer): Null-value detection logic (TrimSpace + ToLower, checking 'none'/'null'/empty) is duplicated identically in isNullValue() in assignee.go and inline here in FormatFieldValue(). Since the issues package already imports api, consider exporting IsNullValue from the api package and calling it from both sites. If the set of sentinel values ever changes, both locations must be updated otherwise.

@@ -231,6 +231,30 @@ func TestFormatFieldValue(t *testing.T) {
value: "abc123",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Low (database:sql-reviewer): FormatFieldValue test cases for the new null-user path cover 'none' and 'null' but not the empty string case (value: ""), which is also handled by the code at fields.go:114. The assignee_test.go TestIsNullValue tests cover empty string thoroughly — adding at least one empty-string case here would close the gap.

@rianjs
Copy link
Copy Markdown
Contributor Author

rianjs commented Mar 28, 2026

TDD Assessment

Overall: PASS — test coverage is solid for the scope of this change.

What's tested

Area Tests Notes
isNullValue() helper TestIsNullValue (10 cases) Covers none, null, empty string, mixed-case variants, leading/trailing whitespace, and negative cases (me, email, account ID)
FormatFieldValue user field 2 new table cases Covers none and null returning nil; existing abc123 case validates the non-null path still works

What's not tested

  • runUpdate integration path — the if isNullValue(assignee) branch in update.go has no unit or integration test. The logic is simple (sets fields["assignee"] = nil), but the happy-path coverage for the flag-to-API-payload pipeline is missing.
  • Empty-string assignee via --assigneeisNullValue correctly returns true for "", but the guard in runUpdate is if assignee != "", so an empty string never reaches that branch. This is correct behavior, but there is no test asserting that the guard holds (no accidental unassign on a missing flag).
  • --field assignee=none path — the PR description calls this out as supported, and FormatFieldValue is tested, but there is no end-to-end test verifying the --field flag routes through FormatFieldValue and emits nil in the final payload.

Verdict

The unit-level coverage of both new functions (isNullValue, FormatFieldValue user-null branch) is thorough. The gap is at the command-integration level: runUpdate itself has no test exercising the unassign branch. For a feature that deliberately sends null to an external API, a single table-driven test on runUpdate (or a CLI integration test) that asserts fields["assignee"] == nil would close that gap and prevent future regressions.

@rianjs rianjs force-pushed the fix/177-unassign-issues branch from 4d0d4b5 to f5b893a Compare March 28, 2026 18:25
@rianjs rianjs merged commit a2c6c7a into main Mar 28, 2026
7 checks passed
@rianjs rianjs deleted the fix/177-unassign-issues branch March 28, 2026 18:26
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.

Removing assignees from jira tickets is awkward

2 participants