Skip to main content

Resources

Cookbook

Practical recipes built on confirmed capabilities. Validate and Dry Run each in your own instance before publishing.

Set a field based on another field (taskActionDone)

if (issue.field("Requirement Type").is("Roadmap Requirement")) {
issue.update({ Priority: "Medium" })
api.log("Priority set to Medium")
}

Block an update while a requirement is In Review (taskPreAction)

if (
issue.issueType.is("Requirement") &&
issue.status.is("In Review") &&
issue.anyFieldChanged()
) {
api.reject("Requirements cannot be updated while In Review")
}

Act only when a field changed to a specific value (event / taskActionDone)

if (issue.status.changedTo("Blocked")) {
issue.update({ Priority: "Highest" })
api.log("Escalated blocked issue")
}

Comment and mention the assignee on a status-category change (event)

if (
issue.anyStatusChanged() &&
issue.statusCategory.changedTo("in_progress") &&
issue.issueType.is("User Story")
) {
issue.addComment({
text: "Status moved into progress.",
mentions: [issue.assignee.mention()]
})
}

.mention() is pending re-verification in 1.1 — confirm with a Dry Run before relying on it.

Post-action external webhook (taskActionDone / event)

if (issue.status.changedTo("Done")) {
const response = await api.fetchExternal({
url: "https://example.com/hooks/ones-status",
method: "POST",
headers: { Authorization: "Bearer " + vars.get("WEBHOOK_TOKEN") },
body: { issueUUID: context.taskUUID, status: "Done" },
timeoutMs: 5000
})
api.log("Webhook status: " + response.statusCode)
}

Idempotent event listener (event)

const eventID = String(event.eventID || context.eventID || "")
const key = "event:" + eventID
if (eventID && (await api.storage.get(key))) {
return // already processed
}
if (issue.field("Found in Production").changedTo("Yes")) {
issue.update({ Priority: "Highest" })
}
if (eventID) {
await api.storage.set(key, true)
}

Scheduled query with issue.search (timer)

const issues = await issue.search({
where: { issueType: "Requirement", status: "In Review" },
select: ["Priority"],
limit: 100
})
for (const item of issues) {
api.log("In review: " + item.field("Priority").value)
}

Process multiple pages of issues with Cursor (timer or Run now)

let cursor = ""

do {
const issues = await issue.search({
where: { issueType: "Requirement", status: "In Review" },
limit: 100,
cursor
})

for (const item of issues) {
api.log("In review: " + item.key)
}

cursor = issues.pageInfo.hasNextPage
? issues.pageInfo.endCursor
: ""
} while (cursor)

limit controls how many issues each call returns. For continuous paging, pass the current page's pageInfo.endCursor to the next call.

Keep a child's planned end date within its parent (hierarchy) (taskPreAction)

if (context.action === "update" && issue.field("Planned end date").changed()) {
const next = issue.field("Planned end date").newValue
if (issue.hierarchy("Upstream").any.field("Planned end date").isBefore(next)) {
api.reject("The planned end date must not be later than the upstream (parent) issue.")
}
}

Block a transition until linked prerequisites are done (taskPreAction)

if (issue.status.changedTo("In Progress")) {
try {
if (!issue.linkedIssues("Prerequisites").all.statusCategory.is("done")) {
api.reject("Finish the prerequisite issues before starting this issue.")
}
} catch (e) {
api.reject("Cannot verify prerequisites — try again.")
}
}

Email owners about overdue issues on a schedule (timer; On-Premises only)

const overdue = await issue.search({
where: { status: "In Progress" },
select: ["Assignee"],
limit: 100
})
for (const item of overdue) {
api.notify({
channel: "email",
recipients: [item.assignee.value], // ONES user UUID
title: "An issue needs your attention",
message: "This issue has stayed in progress and may be overdue.",
issue: item.uuid
})
}

Delivery is not retried automatically — check Execute Log for the per-notification outcome. See api.notify.


Limitations & roadmap

Already native in ONES (no script needed) — several things that require ScriptRunner add-ons in Jira are built into ONES (conditional field display, dependent option filtering, parent/child roll-ups & calculated fields), so they don't need a script at all. See What becomes native configuration.

Not available yet

  • Conditional required/non-empty validation — e.g. "if field A = X, field B can't be empty," and pop-up prompts during form entry. (Value-based conditional validation — "if A = a, B can't be 1" — is supported via a taskPreAction validator.)

On the roadmap 🔜

  • SaaS deployment (On-Premises is available today)
  • Conditional required/non-empty validation / interactive in-form prompts
  • A dedicated Query UI (querying inside scripts via api.queryIssues(...) works today)
  • Permissions / roles (author vs. run, scoping)

To be defined ❓

  • Retention/export for version history, Execute Log, Event Log, and the system audit log

FAQ, glossary & feedback

FAQ (starter set — expand as questions come in)

  • Which languages can I use? JavaScript, TypeScript, or Groovy (Groovy is On-Premises only, via an external runner).
  • Will it run on-prem? Yes — On-Premises is available today; SaaS is coming soon.
  • Is it the same as Automation? No — Automation handles the everyday with no-code rules; ONEScript is the code layer beneath that picks up where no-code leaves off.
  • Can I test without changing data? Yes — use Dry Run, which never changes data. Run now is a live execution, appears only for an eligible latest published script, and requires confirmation.
  • How do I make a script run automatically? Publish it, then bind it under Automation → Trigger Bindings (or Timer Rules for schedules).
  • How do I inspect executions for one script or Timer Rule? Open Execute history from the script's More menu or the Timer Rule card. ONEScript opens the Execute Log filtered to that object.
  • Who can see what a script changed? The issue history (shown as "ONEScript updated …"), the Execute Log, and the system audit log.
  • Can I use an AI assistant to write scripts? Yes — download the AI Skill (Skill.md) and load it into your assistant. See Author with an AI assistant.

Glossary

  • Trigger Binding — connects a published script to a project/issue-type/action so it runs on events or workflow actions (under Automation).
  • Timer Rule — runs a script on a schedule (under Automation).
  • Dry Run — execute a script to see what it would do, without writing changes.
  • Run now — execute an eligible latest published version once against live data; it is neither a Dry Run nor a trigger.
  • Execute history — open the Execute Log filtered to a script or Timer Rule.
  • Cursor — the paging continuation returned by issue.search(...), used to read the next page.
  • Semantic syntax — the readable authoring style that resolves fields/statuses/options by display name.
  • Execute Log / Event Log — execution results, and event delivery/rule matching, respectively.
  • issue.search(...) — the canonical semantic query helper; find issues by conditions and read chosen fields. See Reference → Querying data.
  • ONESQL — ONES's query language, used inside scripts via api.queryIssues(...) as an advanced escape hatch.

Changelog

  • 1.1.3 — Added native Float and Selection scripted fields, Run now, Timer Rules in seconds/minutes/hours/days, exact execution-history entry points, Cursor paging for issue.search(...), and caller-mode issue search, update, comment, and status-transition operations under the current requester's permissions.
  • 1.1.1 — Added issue.worklog workflow guards, raw-JSON Dry Run by visible issue key, trusted Project / Issue Type scope resolution with immediate rule activation, and clearer REST endpoint, safe logging, and execution-capacity contracts.
  • 1.1.0 — Expanded semantic field syntax, issue.search(...), api.notify(...), linked / hierarchy helpers, and pre-change field reads.

Feedback (early preview). ONEScript is an early preview, shaped by the teams using it. Tell us what your scripts need — share your feedback →