← Назад к статьям

ScriptRunner: начало работы и базовые скрипты

ScriptRunner — это мощный плагин для Jira, который открывает практически безграничные возможности автоматизации. За годы работы я написал сотни скриптов: от простых автоматических действий до сложных интеграций. В этой статье разберу основы работы со ScriptRunner и покажу практические примеры, с которых можно начать.

Что такое ScriptRunner и зачем он нужен

ScriptRunner расширяет функциональность Jira через выполнение Groovy-скриптов. С его помощью можно автоматизировать практически любое действие в Jira, которое делается вручную через интерфейс или API.

Типичные задачи, которые решает ScriptRunner:

  • Автоматизация workflow через кастомные пост-функции и валидаторы
  • Массовые операции с задачами
  • Интеграции с внешними системами
  • Сложные вычисления в кастомных полях
  • Обработка событий Jira
  • Создание кастомных REST-эндпоинтов

Без ScriptRunner многие из этих задач либо невозможны, либо требуют разработки плагинов, что значительно сложнее и дороже.

Установка и первые шаги

ScriptRunner устанавливается как обычный плагин через UPM (Universal Plugin Manager). После установки в меню появится пункт "ScriptRunner".

Script Console — ваш главный инструмент

Script Console — это место, где вы будете писать и запускать скрипты. Находится в: Administration → ScriptRunner → Script Console.

В Script Console можно писать скрипты и запускать их сразу, видеть результаты выполнения. Это идеальная среда для экспериментов и отладки.

Основы Groovy для Jira

ScriptRunner использует язык Groovy, который похож на Java, но проще. Если вы знаете Java или другой похожий язык, вы быстро освоитесь. Если нет — Groovy достаточно простой для изучения.

Базовый синтаксис

Groovy не требует точек с запятой, автоматически определяет типы, имеет упрощённый синтаксис. Вот простой пример:

def number = 10
def text = "Hello"
def result = number * 2

log.warn("Result: ${result}")

def — это ключевое слово для определения переменной без указания типа. log — это объект для логирования, доступный в ScriptRunner.

Работа с коллекциями

Groovy отлично работает с коллекциями (списки, карты). Вот примеры:

def list = [1, 2, 3, 4, 5]
def doubled = list.collect { it * 2 }  // [2, 4, 6, 8, 10]

def filtered = list.findAll { it > 3 }  // [4, 5]

def map = [name: "John", age: 30]
log.warn("Name: ${map.name}")

Это базовые конструкции, которые часто используются в скриптах для Jira.

Работа с задачами в ScriptRunner

Основной объект в Jira — это Issue (задача). Вот как с ним работать в ScriptRunner.

Получение задачи по ключу

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.IssueManager

def issueManager = ComponentAccessor.getIssueManager()
def issue = issueManager.getIssueObject("PROJ-123")

log.warn("Issue: ${issue.summary}")
log.warn("Status: ${issue.status.name}")

ComponentAccessor — это точка доступа к сервисам Jira. Через него можно получить любые сервисы: IssueManager, UserManager, CustomFieldManager и т.д.

Чтение значений полей

def customFieldManager = ComponentAccessor.getCustomFieldManager()
def assigneeField = customFieldManager.getCustomFieldObjectByName("Assignee")

def assignee = issue.getCustomFieldValue(assigneeField)
log.warn("Assignee: ${assignee?.displayName}")

Обратите внимание на ?. — это оператор безопасного доступа в Groovy. Если assignee равен null, выражение вернёт null вместо ошибки.

Изменение задачи

import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser

def userManager = ComponentAccessor.getUserManager()
def currentUser = userManager.getUserByKey("admin")

def mutableIssue = issueManager.getIssueObject(issue.id) as MutableIssue
mutableIssue.setSummary("Новый заголовок")
mutableIssue.setAssignee(currentUser)

issueManager.updateIssue(currentUser, mutableIssue, com.atlassian.jira.event.type.EventDispatchOption.ISSUE_UPDATED, false)

Важно: для изменения задачи нужно получить MutableIssue и использовать updateIssue с указанием пользователя и параметров обновления.

Работа с кастомными полями

Кастомные поля — это частая задача в скриптах. Вот как с ними работать.

Получение кастомного поля

def customFieldManager = ComponentAccessor.getCustomFieldManager()

// По ID (customfield_10001)
def fieldById = customFieldManager.getCustomFieldObject(10001L)

// По имени
def fieldByName = customFieldManager.getCustomFieldObjectByName("My Custom Field")

// По ключу (если известен)
def fieldByKey = customFieldManager.getCustomFieldObjectByKey("com.atlassian.jira.ext.commitacceptance:github-pull-requests")

Чтение значения кастомного поля

def value = issue.getCustomFieldValue(fieldByName)

// Проверка типа поля
if (fieldByName.getCustomFieldType() instanceof com.atlassian.jira.issue.fields.config.FieldConfig) {
    // Это поле типа Select List, User Picker и т.д.
    log.warn("Value: ${value}")
} else if (fieldByName.getCustomFieldType() instanceof com.atlassian.jira.issue.customfields.CustomFieldType) {
    // Другой тип поля
    log.warn("Value: ${value}")
}

Установка значения кастомного поля

def mutableIssue = issueManager.getIssueObject(issue.id) as MutableIssue

// Для текстового поля
mutableIssue.setCustomFieldValue(fieldByName, "Новое значение")

// Для User Picker
def newUser = userManager.getUserByKey("john.doe")
mutableIssue.setCustomFieldValue(fieldByName, newUser)

// Для Select List (значение должно существовать в опциях)
mutableIssue.setCustomFieldValue(fieldByName, "Option Value")

issueManager.updateIssue(currentUser, mutableIssue, com.atlassian.jira.event.type.EventDispatchOption.ISSUE_UPDATED, false)

Поиск задач через JQL

ScriptRunner позволяет выполнять JQL-запросы программно:

import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.web.bean.PagerFilter

def searchService = ComponentAccessor.getComponent(SearchService)
def jqlQuery = "project = PROJ AND status = Open"
def user = userManager.getUserByKey("admin")

def query = searchService.parseQuery(user, jqlQuery)
def results = searchService.search(user, query.query, PagerFilter.getUnlimitedFilter())

results.results.each { issue ->
    log.warn("Issue: ${issue.key} - ${issue.summary}")
}

Практический пример: автоматическое назначение

Вот пример скрипта, который автоматически назначает задачу на основе компонента:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.IssueManager
import com.atlassian.jira.issue.MutableIssue
import com.atlassian.jira.user.ApplicationUser

def issueManager = ComponentAccessor.getIssueManager()
def userManager = ComponentAccessor.getUserManager()
def componentManager = ComponentAccessor.getComponentManager()

def issue = issueManager.getIssueObject("PROJ-123") as MutableIssue
def components = issue.components

// Маппинг компонентов на пользователей
def componentToUserMap = [
    "Frontend": "frontend.dev",
    "Backend": "backend.dev",
    "Database": "db.admin"
]

def assignee = null
components.each { component ->
    def userName = componentToUserMap[component.name]
    if (userName) {
        assignee = userManager.getUserByKey(userName)
    }
}

if (assignee && issue.assignee != assignee) {
    issue.setAssignee(assignee)
    def currentUser = userManager.getUserByKey("admin")
    issueManager.updateIssue(currentUser, issue, com.atlassian.jira.event.type.EventDispatchOption.ISSUE_UPDATED, false)
    log.warn("Assigned ${issue.key} to ${assignee.displayName}")
}

Типичные ошибки новичков

Вот ошибки, которые часто допускают при начале работы со ScriptRunner:

Ошибка 1: Забыли импорты

Groovy требует явных импортов для многих классов. Если скрипт не компилируется, проверьте, все ли импорты добавлены.

Ошибка 2: Неправильное приведение типов

getIssueObject() возвращает Issue, но для изменения нужен MutableIssue. Не забудьте приведение типа: as MutableIssue.

Ошибка 3: Забыли updateIssue

Изменение MutableIssue не сохраняется автоматически. Обязательно вызывайте updateIssue() для сохранения изменений.

Ошибка 4: Null pointer exceptions

Всегда проверяйте на null или используйте безопасный доступ (?.). В Jira много объектов могут быть null.

Отладка скриптов

Отладка в ScriptRunner — это логирование. Используйте log.warn() для вывода информации:

log.warn("Variable value: ${variable}")
log.warn("Issue key: ${issue.key}")
log.warn("Field value: ${fieldValue}")

Логи можно посмотреть в: Administration → System → Logging and profiling → View Logging.

Выводы

ScriptRunner открывает огромные возможности для автоматизации Jira. Начните с простых скриптов, экспериментируйте в Script Console, изучайте API Jira через документацию.

Основы, которые нужно освоить: работа с Issue, кастомными полями, поиск через JQL, изменение задач. После этого можно переходить к более сложным задачам: слушатели событий, кастомные поля, REST API.

Не бойтесь экспериментировать — Script Console позволяет безопасно тестировать скрипты. Начинайте с простого и постепенно усложняйте.

Если нужна помощь с написанием скриптов — свяжитесь со мной.