Scripting API: Issues

Part of the Scripting API reference. Issues | Jira Entities | Utilities | Smart Values

Issues

Work with Jira issues - search, create, update, transition, and more.

Static methods

Method Description API calls
Issues.get(key, options?) Get issue by key. Returns a RichIssue 1
Issues.search(jql, options?) Search issues by JQL. Returns SearchResult 1
Issues.searchAll(jql, options?) Search all matching issues (auto-pagination). Returns SearchResult 1 (count) + N (pages)
Issues.count(jql) Count issues matching JQL 1
Issues.create(project, issueType, fields?) Create a new issue 1 (+1 field cache)
Issues.link(key1, linkType, key2) Link two issues 1
// Get an issue
const issue = Issues.get("TEST-1")
log(issue.summary)
log(issue.status)

// Search issues
const results = Issues.search("project = TEST AND status = Open", {
  maxResults: 10,
  fields: ["summary", "status"],
  includeTotal: true
})
log(`Found: ${results.total}`)
for (const issue of results.issues) {
  log(`${issue.key}: ${issue.summary}`)
}

// Search all (auto-pagination)
const all = Issues.searchAll("project = TEST AND status = Open")
log(`Total: ${all.issues.length}`)

// Count
const count = Issues.count("project = TEST")

// Create an issue
const created = Issues.create("TEST", "Task", {
  summary: "New task",
  description: "Task description"
})
log(created.key)

// Link issues
Issues.link("TEST-1", "Blocks", "TEST-2")

RichIssue properties

Core properties:

Property Description
key Issue key (e.g., "TEST-1")
id Issue ID
summary Summary text
status Status name
statusCategory Status category name (e.g., “To Do”, “In Progress”, “Done”)
assignee Assignee display name
assigneeId Assignee account ID
reporter Reporter display name
priority Priority name
issueType Issue type name
project Project key
labels Labels array
components Components array (names)
fixVersions Fix versions array (names)
created Created date string
updated Updated date string
dueDate Due date string (null if not set)
resolutionDate Resolution date string (null if unresolved)
description Description text
parent Parent issue key (null if no parent)
links Array of linked issues
fields Raw fields object

Computed properties (calculated automatically, no API call):

Property Type Description
age number Days since creation
staleDays number Days since last update
isOverdue boolean Whether past due date
isAssigned boolean Whether assigned
isResolved boolean Whether in resolved status category

Typed wrapper properties:

Property Type Description
assigneeUser User/null Assignee as User wrapper
reporterUser User Reporter as User wrapper
projectObj Project Project as Project wrapper

RichIssue methods

Method Description API calls
issue.update(fields) Update issue fields 1
issue.transition(nameOrStatus, options?) Transition to a status 2
issue.addComment(textOrAdf) Add a comment (plain text or ADF) 1
issue.getComments() Get all comments 1
issue.getTransitions() Get available transitions 1
issue.assign(accountId) Assign to a user 1
issue.unassign() Remove assignee 1
issue.addWatcher(accountId) Add a watcher 1
issue.link(linkType, targetKey) Link to another issue 1
issue.addLabel(label) Add a label 1
issue.removeLabel(label) Remove a label 1
issue.field(nameOrId) Get a field value by name or ID (with smart resolution) 0
issue.delete() Delete the issue 1
issue.reload() Reload issue data from Jira 1
issue.clone(overrides?) Clone the issue 1
const issue = Issues.get("TEST-1")

// Update fields
issue.update({ summary: "Updated title", priority: { name: "High" } })

// Transition
issue.transition("Done")
issue.transition("In Progress", { comment: "Starting work" })

// Comments
issue.addComment("Plain text comment")
const comments = issue.getComments()

// Assignment
const user = Users.current()
issue.assign(user.accountId)
issue.unassign()

// Clone with overrides
const copy = issue.clone({ summary: "Copy of " + issue.summary })

// Reload fresh data
issue.reload()

SearchResult

Property / Method Description
results.issues Array of RichIssue objects
results.keys Array of issue keys
results.total Total matching count (requires includeTotal: true, +1 API call)
results.hasMore Whether more pages exist
results.nextPageToken Token for next page
results.nextPage() Fetch next page
results.map(fn) Map over issues
results.filter(fn) Filter issues
results.groupBy(key) Group issues by property
results.countBy(key) Count issues by property value
results.forEach(fn) Execute async function for each issue (returns report)
results.updateAll(fields) Update all issues with the same fields (returns report)
results.transitionAll(status, options?) Transition all issues (returns report)

Search options

Option Type Default Description
fields string[] all Fields to return
maxResults number 50 Issues per page (max 100)
nextPageToken string - Token for next page
expand string[] - Expand options
includeTotal boolean false Include total count (+1 API call)

searchAll Options

Option Type Default Description
fields string[] all Fields to return
maxResults number 100 Issues per page (max 100)
maxPages number 10 Max pages to load
expand string[] - Expand options
const results = Issues.search("project = TEST", { maxResults: 50 })

// Iterate
const keys = results.keys
const summaries = results.map(i => i.summary)
const bugs = results.filter(i => i.issueType === "Bug")
const byStatus = results.groupBy("status")

// Pagination
if (results.hasMore) {
  const page2 = results.nextPage()
}

Smart field resolution

Field names in plain objects are automatically resolved to Jira field IDs:

// 'Story Points' -> 'customfield_10016'
Issues.create("PROJ", "Story", { "Story Points": 5, summary: "My story" })

This works in Issues.create(), issue.update(), and other methods that accept field objects.

Field auto-transform

Common fields are automatically transformed to Jira API format:

Input Transformation
priority: 'High' priority: { name: 'High' }
assignee: 'accountId' assignee: { accountId: '...' }
description: 'text' description: { type: 'doc', ... } (ADF)
labels: 'single' labels: ['single']
components: 'Backend' components: [{ name: 'Backend' }]

ChainablePromise

Issues.get() returns a chainable promise - methods can be chained before await:

Issues.get("PROJ-1").update({ summary: "New" }).addComment("Updated!")

Bulk operation reports

forEach(), updateAll(), and transitionAll() return a report object:

Property Description
success Number of successfully processed issues
failed Number of failed issues
errors Array of error details
const result = Issues.search('project = TEST AND status = Open')

// Update all
const report = result.updateAll({ priority: 'Medium' })
log(`Updated ${report.success}, failed ${report.failed}`)

// Transition all
const report2 = result.transitionAll('In Progress')

// Custom processing
const report3 = result.forEach((issue) => {
  issue.addComment('Batch processed')
})

Next steps