Skip to content

Add jira comments subcommand - #9

Open
calin-marian wants to merge 4 commits into
ainoya:mainfrom
dreamproduction:feat/jira-comments
Open

Add jira comments subcommand#9
calin-marian wants to merge 4 commits into
ainoya:mainfrom
dreamproduction:feat/jira-comments

Conversation

@calin-marian

Copy link
Copy Markdown

Summary

  • Add jira comments <issue-key> [--format=text|json] command to display issue comments
  • Text output shows timestamp, author, and ADF body rendered as plain text
  • JSON output passes through the raw API response
  • Include the comment field in jira issue --format=json for programmatic access to comments inline

Depends on #7.

Test plan

  • Verify jira comments <key> displays comments with correct date, author, and body
  • Verify jira comments <key> --format=json returns raw API response
  • Verify jira issue <key> --format=json now includes comments in the response
  • Verify jira issue <key> text output is unchanged
  • Verify jira help and global help list the new command

🤖 Generated with Claude Code

Rewrite HTML tag stripper to preserve links (as "text (url)") and images
(as "[image: url]") instead of stripping all tags. Add Atlassian Document
Format (ADF) renderer for Jira Cloud descriptions, handling text with link
marks, inlineCard/embedCard smart links, mentions, hard breaks, and media
nodes. Fix formatJiraIssue to handle ADF object descriptions in addition
to plain string descriptions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the Jira command-line tool by introducing a dedicated subcommand for viewing issue comments. It improves the user experience by providing a human-readable text output for comments and descriptions, which includes proper rendering of rich text content from Jira's Atlassian Document Format. Additionally, it expands the JSON output for issue details to include comments, facilitating more comprehensive programmatic integrations.

Highlights

  • New jira comments subcommand: A new subcommand jira comments <issue-key> has been added to display comments for a given Jira issue. It supports both text and JSON output formats.
  • ADF (Atlassian Document Format) rendering: The text output for jira comments and Jira issue descriptions now intelligently renders Atlassian Document Format (ADF) content into readable plain text, preserving links and images.
  • Enhanced jira issue --format=json output: The jira issue command, when used with --format=json, now includes the issue's comments directly in the JSON response for programmatic access.
Changelog
  • src/formatter.zig
    • Improved HTML tag stripping logic to preserve links and images in text output.
    • Added a new function writeAdfText to convert Jira's Atlassian Document Format (ADF) JSON structure into plain text, handling various node types like links, images, mentions, and block elements.
    • Updated the formatJiraIssue function to utilize writeAdfText for rendering Jira issue descriptions, supporting both plain string and ADF formats.
    • Introduced formatJiraComments function to format a list of Jira comments into a structured, readable text output.
  • src/main.zig
    • Extended the JiraCommand enum to include a new comments variant.
    • Updated the global and Jira-specific help messages to list the newly added jira comments subcommand.
    • Modified the handleJiraCommand for the issue subcommand to explicitly request the 'comment' field when the output format is JSON.
    • Implemented the logic for the new comments subcommand, fetching comments via the Jira API and formatting them using formatter.formatJiraComments for text output or printing raw JSON.
Activity
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request adds a jira comments subcommand and enhances the HTML and Jira ADF formatters. The changes are generally well-implemented. I've identified a few areas for improvement, including an issue with error handling that could lead to corrupted output, and some opportunities to improve code consistency and maintainability by using standard library functions and reducing magic strings and code duplication.

Comment thread src/formatter.zig Outdated
result.append(allocator, c) catch {};
// Other tag - add space after for readability
if (close + 1 < html.len and html[close + 1] != ' ' and html[close + 1] != '\n') {
result.append(allocator, ' ') catch {};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The use of catch {} here and in several other places in this function (lines 109, 111, 113, 115, 117, 126) will silently ignore memory allocation errors when appending to the result ArrayList. This can lead to corrupted or truncated output without any indication of failure. Since stripHtmlTags is a failable function (returns ![]u8), it should propagate these errors by using try.

                    try result.append(allocator, ' ');

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in the base branch (1e12dd1, rebased into this PR). All catch {} calls in stripHtmlTags now use try to propagate allocation errors.

Comment thread src/formatter.zig Outdated
Comment on lines +19 to +22
while (p < tag_inner.len and (tag_inner[p] == ' ' or tag_inner[p] == '\t')) : (p += 1) {}
if (p >= tag_inner.len or tag_inner[p] != '=') continue;
p += 1;
while (p < tag_inner.len and (tag_inner[p] == ' ' or tag_inner[p] == '\t')) : (p += 1) {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The while loops to skip whitespace only check for space and tab characters (' ' or '\t'). However, other parts of the code (e.g., line 16, line 58) treat newline and carriage return as whitespace as well. For consistency and to handle all whitespace characters, it's better to use std.ascii.isWhitespace.

        while (p < tag_inner.len and std.ascii.isWhitespace(tag_inner[p])) : (p += 1) {}
        if (p >= tag_inner.len or tag_inner[p] != '=') continue;
        p += 1;
        while (p < tag_inner.len and std.ascii.isWhitespace(tag_inner[p])) : (p += 1) {}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in the base branch (1e12dd1). extractHtmlAttr now uses std.ascii.isWhitespace for all whitespace checks.

Comment thread src/formatter.zig
if (marks_val == .array) {
for (marks_val.array.items) |mark| {
if (mark != .object) continue;
const mt = if (mark.object.get("type")) |t| if (t == .string) t.string else null else null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

This pattern of extracting a string from a JSON value is repeated multiple times in writeAdfText (e.g., lines 215, 243, 254). To improve readability and reduce code duplication, consider creating a helper function.

For example:

fn getJsonString(obj: std.json.ObjectMap, key: []const u8) ?[]const u8 {
    const value = obj.get(key) orelse return null;
    if (value.* == .string) {
        return value.*.string;
    }
    return null;
}

Then you could simplify this line to:
if (getJsonString(mark.object, "type")) |mark_type| { ... }

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Acknowledged, but skipping this one. A helper would add an indirection layer without significant readability gain given how Zig handles optional chaining. The pattern is consistent across the codebase.

Comment thread src/main.zig Outdated
return;
}
const response = try jira.getIssue(args[1], null);
const issue_fields: ?[]const u8 = if (output_format == .json) "summary,description,status,assignee,reporter,labels,priority,created,updated,issuetype,comment" else null;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The long string of issue fields is a "magic string". It's better to define it as a constant at the top of handleJiraCommand or at the file level. This improves readability and makes it easier to manage if it needs to be changed or reused.

For example:

const JSON_ISSUE_FIELDS = "summary,description,status,assignee,reporter,labels,priority,created,updated,issuetype,comment";
// ...
const issue_fields: ?[]const u8 = if (output_format == .json) JSON_ISSUE_FIELDS else null;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in bd61129. Extracted to a named constant json_issue_fields.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 35d00854ab

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/formatter.zig Outdated
Comment on lines +273 to +275
stack[depth] = .{ .items = content_val.array.items, .idx = 0 };
depth += 1;
continue; // process children before emitting newline

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve block newlines when rendering ADF content

When a node has a content array, this continue skips the block-level newline logic below, so paragraph/list/heading boundaries are never emitted for the common case where those nodes contain children. In practice, multi-paragraph Jira descriptions and comment bodies rendered via writeAdfText get concatenated into a single run of text (e.g., paragraph 1 immediately followed by paragraph 2), which makes the new jira comments text output and ADF-backed issue descriptions hard to read.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Fixed in the base branch (1e12dd1, rebased into this PR). The DFS stack now tracks is_block per frame and emits newlines when block-node frames are exhausted, so paragraphs and headings in comments are properly separated.

calin-marian and others added 3 commits March 16, 2026 14:49
Fix off-by-one in extractHtmlAttr loop bound and use std.ascii.isWhitespace
for consistent whitespace checks. Propagate allocation errors in
stripHtmlTags instead of silently swallowing them. Fix writeAdfText to emit
newlines after block-level nodes by tracking is_block in the DFS stack,
so paragraphs and headings are properly separated. Add [image] fallback
for external media nodes missing a URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add `jira comments <issue-key>` command to display issue comments with
formatted ADF body text. Text output shows timestamp, author, and comment
body. JSON output passes through the raw API response. Also include the
comment field in `jira issue --format=json` output for programmatic use.
Extract JSON issue fields string to a named constant for readability.
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.

1 participant