NAME
====

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

SYNOPSIS
========

```raku
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:

| Variable     | Description                                      |
|--------------|--------------------------------------------------|
| `JIRA_URL`   | Base URL of your JIRA instance, e.g. `https://your-org.atlassian.net` |
| `JIRA_EMAIL` | Your Atlassian account email address             |
| `JIRA_TOKEN` | An 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.

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

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

Constructs a client with explicit credentials.

```raku
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.

```raku
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.

```raku
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.

```raku
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.

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

ERROR HANDLING
==============

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

```raku
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.
