Documentation
¶
Overview ¶
Package jira — Board service for /rest/agile/1.0.
Wire shapes and field semantics live in the boards HTTP contract and data-model.md. This file holds the Board struct, BoardScope helper, BoardService interface, and the drain/resolve implementations.
Index ¶
- Constants
- Variables
- func Bool(v bool) *bool
- func DefaultBoardMissingMessage(profile, name string) string
- func DefaultIssueListFields() []string
- func DrainSearch(ctx context.Context, svc SearchService, req *SearchRequest, opts DrainOptions) ([]*Issue, DrainInfo, error)
- func Int(v int) *int
- func JQLValue(value string) string
- func MaxAttachmentUploadBytes() int64
- func NormalizeBoardName(name string) string
- func ParseDuration(input string, workdaySeconds int) (int, error)
- func RESTPath(parts ...string) string
- func SortIssueLinks(links []IssueLinkView)
- func StatusCounts(issues []*Issue) map[string]int
- func String(v string) *string
- type APIError
- type AmbiguousBoardError
- type AmbiguousUserError
- type Attachment
- type AttachmentService
- type AvatarURLs
- type Board
- type BoardDrainOptions
- type BoardDrainResult
- type BoardScope
- type BoardService
- type BoardsCacheFile
- type Client
- func (c *Client) BaseURL() *url.URL
- func (c *Client) Do(req *http.Request, out any) (*Response, error)
- func (c *Client) NewRawRequest(ctx context.Context, method, path string, body io.Reader) (*http.Request, error)
- func (c *Client) NewRequest(ctx context.Context, method, path string, body any) (*http.Request, error)
- func (c *Client) SignRequest(req *http.Request)
- type Comment
- type CommentAddRequest
- type CommentBody
- type CommentDrainOptions
- type CommentDrainResult
- type CommentPage
- type CommentService
- type Component
- type CurrentUser
- type DrainInfo
- type DrainOptions
- type Epic
- type EpicService
- type ErrorType
- type FieldSchema
- type FileSource
- type Issue
- type IssueCloneRequest
- type IssueCreateRequest
- type IssueDeleteOptions
- type IssueFields
- type IssueGetOptions
- type IssueLink
- type IssueLinkRequest
- type IssueLinkService
- type IssueLinkType
- type IssueLinkTypeService
- type IssueLinkView
- type IssueListOptions
- type IssueMoveRequest
- type IssueRef
- type IssueService
- type IssueUpdateRequest
- type LabelService
- type ListCommentsOptions
- type ListOptions
- type LossyCommentWarning
- type Option
- type PermissionEntry
- type PermissionsResponse
- type Priority
- type ProjectFieldSchema
- type ProjectSchemaCache
- func (c *ProjectSchemaCache) Get(profile, projectKey, issueType string) (*ProjectFieldSchema, bool)
- func (c *ProjectSchemaCache) InvalidateAll()
- func (c *ProjectSchemaCache) InvalidateProfile(profile string)
- func (c *ProjectSchemaCache) Set(profile, projectKey, issueType string, schema *ProjectFieldSchema)
- type ProjectService
- type ProjectSummary
- type QueryOptions
- type Rate
- type RemoteLinkRequest
- type Response
- type SearchRequest
- type SearchResult
- type SearchService
- type Status
- type StatusCategory
- type Transition
- type TransitionRequest
- type User
- type UserService
- type Visibility
- type VisibilityChange
- type VisibilityFlags
- type VisibilityMode
- type WatcherService
- type WatchersResponse
- type Worklog
- type WorklogAddRequest
- type WorklogPage
- type WorklogService
Constants ¶
const DefaultWorkdaySeconds = 28800
Variables ¶
var ErrBoardNotFound = errors.New("board not found in cache")
ErrBoardNotFound is returned by ResolveOne when the cache contains no board matching the supplied name (case-insensitive exact match). CLI maps to exit 2 (not_found).
var ErrUserNotFound = errors.New("user not found")
ErrUserNotFound is returned by ResolveUser when /user/search yields zero matches for the supplied query. The CLI surface maps this to exit 2 per the constitution error contract (resource-not-found).
var IssueListFields = append([]string(nil), defaultIssueListFields...)
Functions ¶
func DefaultBoardMissingMessage ¶
DefaultBoardMissingMessage returns the pinned wording the CLI emits when `default_board` references a name that does not resolve in the boards cache. Both arguments are interpolated verbatim — `profile` is the active profile name (e.g. "default" / "work"), `name` is the configured default_board value. Wording is pinned so the contract test can assert on it; any change here is a spec change too.
func DefaultIssueListFields ¶
func DefaultIssueListFields() []string
func DrainSearch ¶
func DrainSearch(ctx context.Context, svc SearchService, req *SearchRequest, opts DrainOptions) ([]*Issue, DrainInfo, error)
DrainSearch pulls every page from a SearchService.JQL call, respecting the configured bounds. Unbounded=true bypasses the bounds entirely; this is what the CLI's --unbounded flag wires.
func MaxAttachmentUploadBytes ¶
func MaxAttachmentUploadBytes() int64
func NormalizeBoardName ¶
NormalizeBoardName strips leading/trailing whitespace from board names while preserving internal whitespace and Unicode verbatim. Called by the cache prime path before persisting each board, so the cache file holds clean names while the wire shape is left untouched.
func SortIssueLinks ¶
func SortIssueLinks(links []IssueLinkView)
func StatusCounts ¶
Types ¶
type APIError ¶
type APIError struct {
StatusCode int
Type ErrorType
Message string
// ErrorMessages mirrors the Jira ErrorCollection.errorMessages array
// (general, non-field-scoped human messages). Nil when the body
// carried none. Never used as a branch target — wording is not
// contractual.
ErrorMessages []string
// FieldErrors mirrors the Jira ErrorCollection.errors map
// (field-name -> single human message). Nil when the body carried
// none.
FieldErrors map[string]string
// UpstreamStatus is the integer ErrorCollection.status field when the
// body carried one. Zero when absent.
UpstreamStatus int
// RetryAfterSeconds is the Retry-After header value on a 429
// response. Zero when the header was absent — callers fall back to
// exponential backoff with jitter.
RetryAfterSeconds int
// RateLimitRemaining is the X-RateLimit-Remaining header value when
// Jira sends it. Zero can mean either absent or exhausted; callers use
// it as diagnostic context only.
RateLimitRemaining int
// Cause preserves transport/body/JSON failures for errors.Is/As while
// keeping the public APIError message stable.
Cause error
}
APIError is the typed error returned for any non-2xx Jira REST response or transport failure. Beyond the HTTP status and a display message it preserves the schema-backed fields of Jira Cloud's ErrorCollection body (errorMessages[], errors map, status) and the rate-limit Retry-After header, all as optional metadata. Jira exposes no stable machine error code, so APIError carries none — callers derive a normalized code from the HTTP status.
type AmbiguousBoardError ¶
AmbiguousBoardError is returned by ResolveOne when 2+ boards match the supplied name (e.g. same name in different projects). The cmd layer renders Candidates in the disambiguation envelope. CLI maps to exit 3 (validation).
func (*AmbiguousBoardError) Error ¶
func (e *AmbiguousBoardError) Error() string
type AmbiguousUserError ¶
AmbiguousUserError is returned by ResolveUser when /user/search yields 2+ matches and we refuse to pick a winner. Candidates carries every returned User so the CLI can render the disambiguation envelope.
func (*AmbiguousUserError) Error ¶
func (e *AmbiguousUserError) Error() string
type Attachment ¶
type Attachment struct {
ID *string `json:"id,omitempty"`
Self *string `json:"self,omitempty"`
Filename *string `json:"filename,omitempty"`
MimeType *string `json:"mimeType,omitempty"`
Size *int64 `json:"size,omitempty"`
Author *User `json:"author,omitempty"`
Created *string `json:"created,omitempty"`
// Content is Atlassian's signed download URL. The CLI doesn't expose
// this in the --json envelope (the download command goes through
// /attachment/content/{id} instead), but it's preserved for callers
// that want to embed the URL directly.
Content *string `json:"content,omitempty"`
}
Attachment is a file attached to a Jira issue. Pointer-typed nullable fields follow the rest of pkg/jira (Issue, Comment, …) so JSON round-tripping preserves "field absent" vs "field present and empty".
Wire shape: GET /rest/api/3/issue/{key}?fields=attachment returns `fields.attachment[]` populated with this shape; POST .../attachments returns an array of these directly.
type AttachmentService ¶
type AttachmentService interface {
List(ctx context.Context, key string) ([]Attachment, *Response, error)
Add(ctx context.Context, key string, files []FileSource) ([]Attachment, *Response, error)
Delete(ctx context.Context, attachmentID string) (*Response, error)
Download(ctx context.Context, attachmentID string) (io.ReadCloser, *Response, error)
}
AttachmentService exposes Atlassian's attachment endpoints. Mutation methods follow the same pointer-based response convention as IssueService so callers can distinguish "no field" from "empty field".
Design notes:
- Add uses multipart/form-data with X-Atlassian-Token: no-check and form field name "file" — both required by Atlassian.
- Delete is global by attachment id (Atlassian's endpoint is /attachment/{id}, not nested under the issue).
- Download streams via io.Copy in the caller; this method returns the raw response body.
func NewAttachmentService ¶
func NewAttachmentService(client *Client) AttachmentService
NewAttachmentService binds an AttachmentService to the given client.
type AvatarURLs ¶
type AvatarURLs struct {
Size16 string `json:"16x16,omitempty"`
Size24 string `json:"24x24,omitempty"`
Size32 string `json:"32x32,omitempty"`
Size48 string `json:"48x48,omitempty"`
}
AvatarURLs maps Jira's standard avatar size keys to URLs.
type Board ¶
type Board struct {
ID *int `json:"id,omitempty"`
Self *string `json:"self,omitempty"`
Name *string `json:"name,omitempty"`
Type *string `json:"type,omitempty"`
ProjectKeys []string `json:"project_keys"`
}
Board is a Jira agile board fetched via /rest/agile/1.0/board and (for the project list) /rest/agile/1.0/board/{id}/project. Pointer-typed nullable fields mirror Issue/Comment/Attachment: distinguishes "field absent" from "present and zero".
func DecodeBoardsCache ¶
DecodeBoardsCache parses the on-disk boards-cache payload. The earlier resolver tests stored the boards as a bare JSON array; the 003 prime path persists the BoardsCache envelope. This helper accepts both so the migration is invisible to callers.
type BoardDrainOptions ¶
BoardDrainOptions configures BoardService.ListAll. Defaults: PageSize 50, MaxPages 100, MaxResults 10 000. Set Unbounded to disable both bounds.
type BoardDrainResult ¶
type BoardDrainResult struct {
Boards []*Board
LastResp *Response
PagesFetched int
RateLimitHit *APIError
Truncated bool
TruncatedReason string
}
BoardDrainResult carries the outcome of ListAll: every board fetched, the rate-limit APIError that aborted the walk if one fired (partial-success), and the truncation reason if a bound stopped the walk short of isLast.
type BoardScope ¶
BoardScope is what BoardService.ResolveOne returns: the resolved board plus the precedence path that selected it (one of "flag", "default_board", "none").
func (BoardScope) JQLClause ¶
func (s BoardScope) JQLClause() (string, bool)
JQLClause emits `project in (P1, P2, ...)` from the board's cached project keys. The bool result is the canonical "did this scope produce a clause?" signal — every consumer that needs to branch on emission (envelope's `applied` flag, JQL prepender) reads it from here so no caller has to re-derive `len(ProjectKeys) > 0`.
type BoardService ¶
type BoardService interface {
List(ctx context.Context, opts *ListOptions) ([]Board, *Response, error)
ListAll(ctx context.Context, opts BoardDrainOptions) (BoardDrainResult, error)
ProjectsForBoard(ctx context.Context, boardID int) ([]string, *Response, error)
ResolveOne(ctx context.Context, profile, name string) (BoardScope, error)
}
BoardService groups the agile board endpoints used by the boards cache primer, the `boards list` command, and the --board resolver.
func NewBoardService ¶
func NewBoardService(client *Client) BoardService
NewBoardService binds a BoardService to the supplied client.
type BoardsCacheFile ¶
type BoardsCacheFile struct {
FetchedAt string `json:"fetched_at"`
TTLSeconds int `json:"ttl_seconds"`
Truncated bool `json:"truncated"`
TruncatedReason string `json:"truncated_reason"`
PagesFetched int `json:"pages_fetched,omitempty"`
RetryAfterSeconds int `json:"retry_after_seconds,omitempty"`
Items []Board `json:"items"`
}
BoardsCacheFile is the on-disk envelope persisted under `${XDG_CACHE_HOME:-~/.cache}/jira-cli/<profile>/boards.json` per data-model.md > BoardsCache. Carried inside the generic cache.Entry's Data field so the existing internal/cache machinery (atomic write, 0600 perms, TTL freshness) round-trips it unchanged.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
func NewClientE ¶
func (*Client) BaseURL ¶
BaseURL exposes the resolved base URL so services that need to build fully-qualified URLs without going through NewRequest (multipart, streaming download) can ResolveReference against the same root the rest of the package uses.
func (*Client) NewRawRequest ¶
func (*Client) NewRequest ¶
func (*Client) SignRequest ¶
SignRequest applies the active profile's Jira Cloud auth to req: HTTP Basic with the account email and API token. Services that build requests outside NewRequest (multipart upload, raw-body posts, streaming download) MUST call this rather than re-implementing the basic-auth selection inline so the auth surface stays consistent.
type Comment ¶
type Comment struct {
ID *string `json:"id,omitempty"`
Self *string `json:"self,omitempty"`
Body *adf.Document `json:"body,omitempty"`
Author *User `json:"author,omitempty"`
UpdateAuthor *User `json:"updateAuthor,omitempty"`
Created *string `json:"created,omitempty"`
Updated *string `json:"updated,omitempty"`
Visibility *Visibility `json:"visibility,omitempty"`
}
type CommentAddRequest ¶
type CommentBody ¶
type CommentBody struct {
ADF *adf.Document
// DryRun short-circuits the HTTP call. The service returns a synthetic
// {ID: "DRY-RUN"} Comment so callers can keep their envelope flow.
DryRun bool
}
CommentBody carries the comment payload. Exactly one of ADF or Markdown must be supplied; the cmd-layer binding converts Markdown → ADF before constructing the body.
type CommentDrainOptions ¶
CommentDrainOptions configures CommentService.ListAll. Mirrors DrainOptions on the search side so consumer-side opt-in walks have consistent runaway protection. Defaults: PageSize 50, MaxPages 100, MaxResults 10_000. Set Unbounded to disable both bounds (the CLI requires --unbounded; the TUI never sets it).
type CommentDrainResult ¶
type CommentDrainResult struct {
Comments []*Comment
LastResp *Response
PagesFetched int
RateLimitHit *APIError
Truncated bool
TruncatedReason string
}
CommentDrainResult carries the outcome of ListAll: every comment fetched, the final page's response (for envelope pagination metadata), and the rate-limit APIError that aborted the walk if one fired (partial-success semantics — exit 0 with a structured warning). Truncated reports whether one of the configured bounds stopped the walk short of isLast.
type CommentPage ¶
type CommentPage struct {
Comments []*Comment `json:"comments,omitempty"`
}
type CommentService ¶
type CommentService interface {
List(ctx context.Context, key string, opts *ListCommentsOptions) ([]*Comment, *Response, error)
ListAll(ctx context.Context, key string, opts CommentDrainOptions) (CommentDrainResult, error)
Add(ctx context.Context, key string, body *CommentBody) (*Comment, *Response, error)
AddWithVisibility(ctx context.Context, key string, body *CommentBody, vis VisibilityChange) (*Comment, *Response, error)
Edit(ctx context.Context, key, commentID string, body *CommentBody, vis VisibilityChange) (*Comment, *Response, error)
Delete(ctx context.Context, key, commentID string) (*Response, error)
}
CommentService groups the Jira-issue comment endpoints. Split out of IssueService per plan.md "Service Architecture" — comments deserve a service of their own now that the lifecycle covers list / add / edit / delete instead of just add.
All methods use the underlying *Client's auth, debug, retry, and rate-limit hooks. Pagination on List follows the same ListOptions shape the rest of pkg/jira already exposes.
func NewCommentService ¶
func NewCommentService(client *Client) CommentService
NewCommentService constructs a CommentService bound to the given client.
type CurrentUser ¶
type CurrentUser struct {
Self string `json:"self,omitempty"`
AccountID string `json:"accountId,omitempty"`
AccountType string `json:"accountType,omitempty"`
EmailAddress string `json:"emailAddress,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Active bool `json:"active,omitempty"`
TimeZone string `json:"timeZone,omitempty"`
Locale string `json:"locale,omitempty"`
AvatarURLs AvatarURLs `json:"avatarUrls,omitempty"`
}
User identity returned by /rest/api/3/myself. Subset of the full response — only the fields we use for assign-to-me, profile bootstrap and `whoami`.
type DrainInfo ¶
DrainInfo describes how DrainSearch terminated. Truncated reports whether a bound stopped consumption short of isLast.
type DrainOptions ¶
DrainOptions configures DrainSearch — the bounded `--all` consumer.
Defaults: max-pages 100, max-results-total 10,000. Override either with explicit positive values; set Unbounded to disable both (CLI requires --unbounded; the TUI never sets it).
type EpicService ¶
type EpicService interface {
List(context.Context, *ListOptions) ([]*Issue, *Response, error)
Get(context.Context, string, *IssueGetOptions) (*Issue, *Response, error)
AddIssue(context.Context, string, string) (*Response, error)
RemoveIssue(context.Context, string) (*Response, error)
IssuesInEpic(context.Context, string) ([]*Issue, *Response, error)
}
func NewEpicService ¶
func NewEpicService(client *Client) EpicService
type FieldSchema ¶
type FieldSchema struct {
ID string `json:"id"`
Name string `json:"name"`
Required bool `json:"required"`
Type string `json:"type"`
// Custom is the schema.custom token Jira reports for a custom
// field — the trailing identifier of
// com.atlassian.jira.plugin.system.customfieldtypes:* (e.g.
// "select", "datepicker", "float"). Empty for system fields and for
// custom fields whose type Jira does not expose. It is the branch
// key the mutation pipeline uses to encode a custom-field value.
Custom string `json:"custom,omitempty"`
}
type FileSource ¶
FileSource is what AttachmentService.Add accepts per file: a name (the filename Jira sees) plus a Reader carrying the bytes. Using io.Reader lets callers stream from *os.File without slurping into memory; the service implementation routes large payloads through io.Pipe .
type Issue ¶
type Issue struct {
ID *string `json:"id,omitempty"`
Key *string `json:"key,omitempty"`
Self *string `json:"self,omitempty"`
Fields *IssueFields `json:"fields,omitempty"`
Comments []*Comment `json:"comments,omitempty"`
Worklogs []*Worklog `json:"worklogs,omitempty"`
LinkedIssues []*Issue `json:"linked_issues,omitempty"`
Subtasks []*Issue `json:"subtasks,omitempty"`
}
func (*Issue) UnmarshalJSON ¶
type IssueCloneRequest ¶
type IssueCreateRequest ¶
type IssueDeleteOptions ¶
type IssueDeleteOptions struct {
DeleteSubtasks bool
}
IssueDeleteOptions controls deletion behavior. DeleteSubtasks=true removes the issue and all its subtasks atomically (Jira refuses the delete otherwise when subtasks exist).
type IssueFields ¶
type IssueFields struct {
Summary *string `json:"summary,omitempty"`
Description *adf.Document `json:"description,omitempty"`
Status *Status `json:"status,omitempty"`
Assignee *User `json:"assignee,omitempty"`
Reporter *User `json:"reporter,omitempty"`
Priority *Priority `json:"priority,omitempty"`
Labels []string `json:"labels,omitempty"`
Components []Component `json:"components,omitempty"`
Updated *string `json:"updated,omitempty"`
Comment *CommentPage `json:"comment,omitempty"`
Worklog *WorklogPage `json:"worklog,omitempty"`
IssueLinks []IssueLink `json:"issuelinks,omitempty"`
Subtasks []*Issue `json:"subtasks,omitempty"`
CustomFields map[string]json.RawMessage `json:"-"`
}
func (IssueFields) MarshalJSON ¶
func (f IssueFields) MarshalJSON() ([]byte, error)
func (*IssueFields) UnmarshalJSON ¶
func (f *IssueFields) UnmarshalJSON(data []byte) error
type IssueGetOptions ¶
type IssueGetOptions struct {
Expand []string
}
type IssueLinkRequest ¶
IssueLinkRequest creates an issue link via POST /rest/api/3/issueLink. Type is the link-type name (e.g., "Blocks", "Relates", "Cloners"). InwardIssue and OutwardIssue are issue keys; semantics depend on the type ("Blocks" → outwardIssue is blocked by inwardIssue).
type IssueLinkService ¶
type IssueLinkService interface {
List(context.Context, string) ([]IssueLinkView, *Response, error)
Create(context.Context, *IssueLinkRequest) (*Response, error)
Delete(context.Context, string) (*Response, error)
}
func NewIssueLinkService ¶
func NewIssueLinkService(client *Client) IssueLinkService
type IssueLinkType ¶
type IssueLinkTypeService ¶
type IssueLinkTypeService interface {
List(context.Context) ([]IssueLinkType, *Response, error)
}
func NewIssueLinkTypeService ¶
func NewIssueLinkTypeService(client *Client) IssueLinkTypeService
type IssueLinkView ¶
type IssueLinkView struct {
ID string `json:"id"`
Self string `json:"self,omitempty"`
Type IssueLinkType `json:"type"`
Direction string `json:"direction"`
OtherIssue IssueRef `json:"other_issue"`
}
type IssueListOptions ¶
type IssueListOptions struct {
ListOptions
JQL string
Fields []string
Expand []string
}
type IssueMoveRequest ¶
type IssueService ¶
type IssueService interface {
List(context.Context, *IssueListOptions) ([]*Issue, *Response, error)
Get(context.Context, string, *IssueGetOptions) (*Issue, *Response, error)
Create(context.Context, *IssueCreateRequest) (*Issue, *Response, error)
Update(context.Context, string, *IssueUpdateRequest) (*Issue, *Response, error)
Delete(context.Context, string, *IssueDeleteOptions) (*Response, error)
Clone(context.Context, string, *IssueCloneRequest) (*Issue, *Response, error)
Move(context.Context, string, *IssueMoveRequest) (*Issue, *Response, error)
Transitions(context.Context, string) ([]*Transition, *Response, error)
Transition(context.Context, string, *TransitionRequest) (*Response, error)
AddComment(context.Context, string, *CommentAddRequest) (*Comment, *Response, error)
// Link creates an issue link between two issues (Blocks, Relates,
// etc.). Jira's bulk-edit endpoint rejects issuelinks updates;
// links require this dedicated endpoint.
Link(context.Context, *IssueLinkRequest) (*Response, error)
// AddRemoteLink attaches a web link (URL + title) to an issue —
// the Jira "Web links" feature. Different endpoint from Link.
AddRemoteLink(context.Context, string, *RemoteLinkRequest) (*Response, error)
}
func NewIssueService ¶
func NewIssueService(client *Client) IssueService
type IssueUpdateRequest ¶
type LabelService ¶
LabelService surfaces Jira's global label list. Labels in Jira are not scoped to a project — they're a global string pool — so callers generally fetch once per profile and reuse via the local cache.
func NewLabelService ¶
func NewLabelService(client *Client) LabelService
NewLabelService constructs a LabelService bound to the given client.
type ListCommentsOptions ¶
type ListCommentsOptions struct {
ListOptions
// OrderBy lets callers override the default ordering. Empty string =
// "created" (oldest-first), matching Atlassian's native default.
OrderBy string
}
ListCommentsOptions controls pagination and ordering for comment list. Atlassian's `/issue/{key}/comment` endpoint returns oldest-first by default when `orderBy=created` is supplied; we send it explicitly so the contract is stable across instances.
type ListOptions ¶
func (ListOptions) QueryValues ¶
func (o ListOptions) QueryValues() url.Values
type LossyCommentWarning ¶
type LossyCommentWarning struct {
Type string `json:"type"`
CommentID string `json:"comment_id"`
LossyConstructs []string `json:"lossy_constructs"`
}
LossyCommentWarning is the structured warning shape emitted under envelope.warnings[] when a comment's ADF body lost fidelity during the Markdown render path. CommentID lets the consumer cross-reference the affected comment in data.comments[]; LossyConstructs lists the dropped node/mark types in sorted-unique order.
func CollectLossyCommentWarnings ¶
func CollectLossyCommentWarnings(comments []*Comment) []LossyCommentWarning
CollectLossyCommentWarnings walks comments[] and builds one warning per comment whose ADF body included nodes/marks the Markdown renderer couldn't fully express. Comments without a body are skipped silently — they're not lossy, just empty.
type Option ¶
type Option func(*Client)
func WithBaseURL ¶
func WithBasicAuth ¶
func WithDryRun ¶
WithDryRun causes Do to refuse any state-changing HTTP method (POST / PUT / PATCH / DELETE) so a --dry-run invocation cannot mutate Jira. Reads still pass through, so the same client can serve a dry-run preview that renders live data. This is the service-level safety net behind the command-layer dry-run branches: even a command path that forgets to gate a submission is stopped here.
func WithHTTPClient ¶
func WithHTTPTimeout ¶
func WithReadOnly ¶
WithReadOnly causes Do to refuse any non-safe HTTP method (POST / PUT / PATCH / DELETE) with a validation-typed APIError. Single point of control — the CLI sets this once based on env / per-profile config and every mutation in every command path is automatically gated.
type PermissionEntry ¶
type PermissionEntry struct {
ID string `json:"id,omitempty"`
Key string `json:"key,omitempty"`
Name string `json:"name,omitempty"`
Type string `json:"type,omitempty"`
Description string `json:"description,omitempty"`
HavePermission bool `json:"havePermission"`
}
PermissionEntry is a single result of /rest/api/3/mypermissions.
type PermissionsResponse ¶
type PermissionsResponse struct {
Permissions map[string]PermissionEntry `json:"permissions"`
}
PermissionsResponse wraps the /mypermissions envelope.
type ProjectFieldSchema ¶
type ProjectFieldSchema struct {
ProjectKey string `json:"project_key"`
IssueType string `json:"issue_type"`
Fields []FieldSchema `json:"fields,omitempty"`
}
type ProjectSchemaCache ¶
type ProjectSchemaCache struct {
// contains filtered or unexported fields
}
func NewProjectSchemaCache ¶
func NewProjectSchemaCache(ttl time.Duration) *ProjectSchemaCache
func (*ProjectSchemaCache) Get ¶
func (c *ProjectSchemaCache) Get(profile, projectKey, issueType string) (*ProjectFieldSchema, bool)
func (*ProjectSchemaCache) InvalidateAll ¶
func (c *ProjectSchemaCache) InvalidateAll()
func (*ProjectSchemaCache) InvalidateProfile ¶
func (c *ProjectSchemaCache) InvalidateProfile(profile string)
func (*ProjectSchemaCache) Set ¶
func (c *ProjectSchemaCache) Set(profile, projectKey, issueType string, schema *ProjectFieldSchema)
type ProjectService ¶
type ProjectService interface {
GetFieldSchema(context.Context, string, string) (*ProjectFieldSchema, *Response, error)
GetFieldSchemaForProfile(context.Context, string, string, string) (*ProjectFieldSchema, *Response, error)
// GetEditSchemaForProfile resolves the edit-screen field schema for
// one issue via GET /rest/api/3/issue/{idOrKey}/editmeta. The
// edit/move flows validate against this; createmeta covers
// create/clone. Cached per profile + issue key.
GetEditSchemaForProfile(context.Context, string, string) (*ProjectFieldSchema, *Response, error)
List(context.Context, *ListOptions) ([]ProjectSummary, *Response, error)
}
func NewProjectService ¶
func NewProjectService(client *Client, ttl time.Duration) ProjectService
type ProjectSummary ¶
type ProjectSummary struct {
ID string `json:"id"`
Key string `json:"key"`
Name string `json:"name"`
ProjectType string `json:"project_type,omitempty"`
Lead string `json:"lead,omitempty"`
}
ProjectSummary is the discovery shape for `jira cache projects` (and shell completion). Subset of /rest/api/3/project/search; only the keys agents and humans need.
type QueryOptions ¶
type QueryOptions struct {
ListOptions
JQL string
}
type RemoteLinkRequest ¶
RemoteLinkRequest creates a "web link" via POST /rest/api/3/issue/{key}/remotelink. Title is what the user sees; URL is where the link points.
type Response ¶
type Response struct {
Response *http.Response
StartAt int
MaxResults int
Total int
IsLast bool
NextPageToken string
TokenPage bool
Rate Rate
RawBody json.RawMessage
}
func (Response) NextCursor ¶
type SearchRequest ¶
type SearchResult ¶
type SearchService ¶
func NewSearchService ¶
func NewSearchService(client *Client) SearchService
type Status ¶
type Status struct {
Name *string `json:"name,omitempty"`
StatusCategory *StatusCategory `json:"statusCategory,omitempty"`
}
type StatusCategory ¶ added in v0.3.0
type StatusCategory struct {
Key *string `json:"key,omitempty"`
Name *string `json:"name,omitempty"`
}
StatusCategory is the workflow bucket a status belongs to. Key is one of "new", "indeterminate", or "done" — stable across projects and used to color statuses by category in human output.
type Transition ¶
type TransitionRequest ¶
type User ¶
type User struct {
AccountID *string `json:"accountId,omitempty"`
AccountType *string `json:"accountType,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
EmailAddress *string `json:"emailAddress,omitempty"`
Active *bool `json:"active,omitempty"`
Deleted *bool `json:"deleted,omitempty"`
}
type UserService ¶
type UserService interface {
Myself(context.Context) (*CurrentUser, *Response, error)
MyPermissions(ctx context.Context, projectKey string, keys []string) (*PermissionsResponse, *Response, error)
Search(ctx context.Context, query string) ([]*User, *Response, error)
ResolveAccountID(ctx context.Context, accountID string) (string, error)
ResolveUser(ctx context.Context, query string) (string, error)
}
UserService exposes user-identity endpoints.
func NewUserService ¶
func NewUserService(client *Client) UserService
NewUserService constructs a UserService bound to the given client.
type Visibility ¶
Visibility restricts a comment to a Jira role or a Jira group. Atlassian's data model treats Type/Value as mutually exclusive across role and group; the CLI's --visibility-role and --visibility-group flags enforce that exclusivity locally before any HTTP call ().
type VisibilityChange ¶
type VisibilityChange struct {
Mode VisibilityMode
Type string // "role" or "group"; only meaningful when Mode == VisibilityReplace
Value string // role/group name; only meaningful when Mode == VisibilityReplace
}
VisibilityChange is the typed, validated input to CommentService.Edit. Construct via ParseVisibilityChange so the mutex-flag rules are enforced before the wire body is built.
func ParseVisibilityChange ¶
func ParseVisibilityChange(flags VisibilityFlags) (VisibilityChange, error)
ParseVisibilityChange validates the flag combination and produces a VisibilityChange. Returns an error (mapped to exit 3 by the cmd layer) when:
- --visibility-role and --visibility-group are both supplied
- --clear-visibility is combined with either visibility-role or visibility-group
- --visibility-role is supplied with an empty value
- --visibility-group is supplied with an empty value
All three flags omitted → VisibilityKeep (preserve-when-omitted).
type VisibilityFlags ¶
VisibilityFlags is the cmd-layer's view of the three CLI flags. The *Set fields distinguish "flag was supplied" from "flag was supplied with empty value" — cobra's IsChanged() drives the booleans.
type VisibilityMode ¶
type VisibilityMode int
VisibilityMode is the discriminator on a VisibilityChange.
const ( // VisibilityKeep leaves the existing visibility untouched. The wire // body MUST omit the visibility key entirely so Atlassian preserves // whatever was previously set. VisibilityKeep VisibilityMode = iota // VisibilityReplace sets a new restriction (role or group). The wire // body sends `"visibility": {"type": ..., "value": ...}`. VisibilityReplace // VisibilityClear removes the existing restriction. The wire body // sends `"visibility": null` explicitly so Atlassian clears it. VisibilityClear )
type WatcherService ¶
type WatcherService interface {
List(ctx context.Context, issueKey string) (*WatchersResponse, *Response, error)
Add(ctx context.Context, issueKey, accountID string) (*Response, error)
Remove(ctx context.Context, issueKey, accountID string) (*Response, error)
}
WatcherService manages watchers on an issue.
func NewWatcherService ¶
func NewWatcherService(client *Client) WatcherService
NewWatcherService constructs a WatcherService bound to the given client.
type WatchersResponse ¶
type WatchersResponse struct {
IsWatching bool `json:"isWatching"`
WatchCount int `json:"watchCount"`
Watchers []*User `json:"watchers"`
}
WatchersResponse is the shape Atlassian returns from GET /rest/api/3/issue/{key}/watchers — the watcher list plus the caller-perspective `IsWatching` flag and instance-level `WatchCount`.
type WorklogAddRequest ¶
type WorklogPage ¶
type WorklogPage struct {
Worklogs []*Worklog `json:"worklogs,omitempty"`
}
type WorklogService ¶
type WorklogService interface {
List(context.Context, string, *ListOptions) ([]*Worklog, *Response, error)
Add(context.Context, string, *WorklogAddRequest) (*Worklog, *Response, error)
Delete(context.Context, string, string) (*Response, error)
}
func NewWorklogService ¶
func NewWorklogService(client *Client) WorklogService
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package customfield is the Jira custom-field type registry.
|
Package customfield is the Jira custom-field type registry. |