Rand Stats

Rmv::JIRA

zef:rmv

NAME

Rmv::JIRA - JIRA REST API v3 client for Raku

SYNOPSIS

use Rmv::JIRA::Client;

my $jira = Rmv::JIRA::Client.from-env;

# Fetch a ticket (all fields + human-readable names)
my %issue = $jira.get-ticket('PROJ-123');
say %issue<fields><summary>;

# Fetch specific fields only
my %issue = $jira.get-ticket('PROJ-123', fields => <summary status assignee>);

# Search with JQL
my %results = $jira.search-tickets('project = PROJ AND status = "In Progress"');
for %results<issues>.list -> %t {
    say "%t<key>: %t<fields><summary>";
}

DESCRIPTION

Rmv::JIRA is a thin Raku client for the JIRA REST API v3. It supports fetching issues (all fields or a subset), JQL search, issue creation, and structured error handling.

INSTALLATION

zef install --/precompile-install Rmv::JIRA

Note: the --/precompile-install flag is needed when dependencies are installed in the user-level ~/.raku repository rather than the system/rakubrew site repository.

CONFIGURATION

Authentication uses HTTP Basic auth with your Atlassian email and an API token. Set these environment variables before use:

VariableDescription
JIRA_URLBase URL of your JIRA instance, e.g. https://your-org.atlassian.net
JIRA_EMAILYour Atlassian account email address
JIRA_TOKENAn Atlassian API token (not your password)

Generate an API token at https://id.atlassian.com/manage-profile/security/api-tokens.

METHODS

Rmv::JIRA::Client.from-env()

Constructs a client from JIRA_URL, JIRA_EMAIL, and JIRA_TOKEN. Dies if any variable is missing.

my $jira = Rmv::JIRA::Client.from-env;

Rmv::JIRA::Client.new(:server-url, :email, :token)

Constructs a client with explicit credentials.

my $jira = Rmv::JIRA::Client.new(
    server-url => 'https://your-org.atlassian.net',
    email      => 'you@example.com',
    token      => 'your-api-token',
);

get-ticket(Str $key, :@fields --> Hash)

Fetches a single issue by key. By default returns all fields (*all) and expands the names map so you can look up human-readable field labels. Pass :fields to restrict to a subset.

my %issue = $jira.get-ticket('PROJ-123');
my %names  = %issue<names>;   # field-id => display name
my %fields = %issue<fields>;  # all field values

# Specific fields only
my %issue = $jira.get-ticket('PROJ-123', fields => <summary status assignee>);

search-tickets(Str $jql, :@fields, Int :$max-results = 50, Str :$next-page-token --> Hash)

Searches issues using JQL via POST /rest/api/3/search/jql. Returns the JIRA search response (issues, isLast, optional nextPageToken, etc.). The legacy /rest/api/3/search endpoint is no longer available on Jira Cloud.

my %res = $jira.search-tickets(
    'project = PROJ AND status != Done ORDER BY created DESC',
    max-results => 20,
);
say "Found: %res<total>";
for %res<issues>.list -> %t { say %t<key> }

create-ticket(:%fields --> Hash)

Creates an issue via POST /rest/api/2/issue/. Pass JIRA field values as a hash; they are wrapped as { fields: { ... } }. Returns the create response (key, id, self). Field keys and values must match what the target project's issue screen accepts (components, custom fields, etc. are caller responsibility). Create uses the v2 endpoint so plain-string description values work without Atlassian Document Format.

my %created = $jira.create-ticket(
    project     => { key => 'PROJ' },
    summary     => 'Fix the widget',
    description => 'Steps to reproduce...',
    issuetype   => { name => 'Task' },
);
say %created<key>;  # PROJ-99

request(Str $endpoint, Str :$method = 'GET', :$body, :%params --> Hash)

Low-level method for arbitrary JIRA REST API v3 calls.

my %me = $jira.request('/rest/api/3/myself');
say %me<displayName>;

ERROR HANDLING

Non-2xx responses throw X::Rmv::JIRA::Api:

my %issue = $jira.get-ticket('PROJ-123');
CATCH {
    when X::Rmv::JIRA::Api {
        say "HTTP $_.status(): $_.body()";
    }
}

AUTHOR

Rui Vieira ruidevieira@googlemail.com

COPYRIGHT AND LICENSE

Copyright 2026 Rui Vieira

Licensed under the Apache License, Version 2.0. See LICENSE for the full license text.