Всем привет!

В этой статье я бы снова хотел поговорить про SIL. Мы все знаем, что у SIL есть большое количество функций, которые значительно облегчают автоматизацию наших действий в Atlassian Jira и Confluence.

Мы пишем SIL скрипты в пункте меню SIL Manager и большинство из нас не уделяет значение остальным пунктам меню. Я говорю вот об этих пунктах меню:



В этой статье я пройдусь по каждому пункту меню и расскажу, что можно получить от каждого пункта.

Хочу также отметить, что мы сейчас говорим про SIL engine, а это значит, что все эти возможности доступны Вам бесплатно.

Custom Field Usage


Это меню предоставляет информацию о том, как каждое кастомное поле используется в Вашем экземпляре Jira. Информацию от вендора можно почитать здесь.
Вы можете увидеть все поля в Вашей Jira, если перейдете в шестеренка -> Issues -> Custom Fields.



Вот так выглядит экран, если Вы зайдете в меню Custom Field Usage:



Как Вы видите, Вы можете выбрать любое кастомное поле и получить информацию по нему. Для того, чтобы отфильтровать имеющиеся поля, просто начните вводить символы и список кастомных полей будет отфильтрован по этим символам.



После того, как Вы увидите свое поле, нажмите на него:



Вы сможете увидеть следующую информацию по этому полю:

  • SIL алиасы
  • Экраны и проекты, в которых поле используется.
  • Номера строк скриптов, в которых это поле используется.

На момент написания статьи есть вот такой баг CADS-6237, который говорит о том, что информация об использовании поля в скриптах не выводится на экране. Так оно и есть. У меня есть эта инфомрация, потому что я модифицировал код.

Redirect Page Configuration


Эта опция позволяет умно управлять редиректом на страницы в Jira. Вы можете найти информацию от вендора здесь. Сказать по правде, мне понадобились часы, чтобы понять, зачем нужна эта опция и как ее использовать, поэтому я объясню эту опцию на примере.
Вот пример.

Допустим в нашей Jira каждый сотрудник каждый месяц вводит счет на получение денег в виде тикета в проекте INV.



Как вы видите, Alexey Matveev завел два счета за Март и Апрель.

Но отдел кадров работает не в Jira, а в какой-то внешней системе, и у них в этой внешней системе есть страничка на каждого сотрудника с линком в Jira, который ведет к тикету сотрудника с последним счетом.

Как будет выглядеть этот линк?

Конечно, мы можем сделать линк вот таким http://localhost:2990/jira/browse/INV-2. Но INV-2 будет последним счетом за Апрель. В мае будет уже тикет с другим счетом. Мы могли бы каждый месяц менять линк на странице сотрудника отдела кадров, но это слишком сложно. Нужно что-то попроще.

И как раз Redirect Page Configuration приходит нам на помощь.

Давайте сконфигурируем.

В нашей системе отдела кадров линк будет выглядеть вот так:

http://localhost:2990/jira/plugins/servlet/kredi?userName=Alexey+Matveev

Мы обращаемся не к какому-то тикету, а к сервлету plugins/servlet/kredi, который и сделает редирект к необходимому нам тикету. Мы будем передавать в качестве параметра полное имя пользователя и на основании этого параметра наш сервлет сделает редирект на нужный тикет.
Ссылку мы сделали, теперь нужно сделать логику. А логику мы как раз и делаем в меню Redirect Page Configuration. Откроем меню и введем вот такой код:

string userName = argv["userName"];

if (isNull(userName)) {
    return "/plugins/servlet/kredierror?customErrorTitle=User Not Provided&customErrorMessage=Provide user with userName parameter";
}
if (isNull(getUserByFullName(userName))) {
    return "/plugins/servlet/kredierror?customErrorTitle=User Not Found&customErrorMessage=User " + userName + " not found";
}
string [] k = selectIssues("project = INV and reporter = " + getUserByFullName(userName).username + " order by \"Invoice Date\" desc");
if (size(k) == 0) {
   return "/plugins/servlet/kredierror?customErrorTitle=Invoice Not Found&customErrorMessage=No invoices for "+ userName; 
}
return "/browse/" + k[0];

Код делает следующее:

  • получаем значение параметра userName, в котором содержится полное имя пользователя.
  • проверяем, что параметр передан, если не передан, то делаем редирект на страницу ошибок.
  • проверяем, что пользователь с таким полным именем заведен в Jira. Если нет, то делаем редирект на страницу ошибок.
  • выбираем последний тикет со счетом для этого пользователя. Если ни одного тикета не найдено, то делаем редирект на страницу ошибок.
  • делаем редирект на тикет с последним счетом.

Теперь проверим!

Сначал сделаем вот такой линк и перейдем по нему:

http://localhost:2990/jira/plugins/servlet/kredi?userName=Alexey+Matveev
Мы увидим вот такой экран:

Все верно! Это мой последний счет.
Теперь не передадим пользователя в качестве параметра:

http://localhost:2990/jira/plugins/servlet/kredi

И мы получили страницу с ошибкой:

Верно!
Теперь передадим пользователя, которого нет в Jira:

http://localhost:2990/jira/plugins/servlet/kredi?userName=Super+Man

Мы увидели страницу с ошибкой:



Опять все верно!

А теперь передадим пользователя, который не создал ни одного тикета со счетом:

http://localhost:2990/jira/plugins/servlet/kredi?userName=Tomas+Brook

И мы получили страницу с ошибкой:



Все работает правильно!

Таким образом, мы вывели всю логику по редиректу на правильную страницу в Jira. И это очень удобно, так в этом случае мы пишем всю логику на SIL, что гораздо проще, чем писать эту же логику во внешней системе.

Switch User


Этот пункт меню позволяет администратору работать под любым зарегистрированным пользователем в Jira без знания пароля этого пользователя. Вы можете почитать информацию от вендора здесь.

Это необходимо, например, когда пользователь говорит, что Jira ведет себя некорректно, а администратор не может это воспроизвести. В этом случае администратор может зайти в Jira под этим пользователем и посмотреть, что происходит.



Для того, чтобы быстро найти нужного Вам пользователя, просто начните вводить символы, которые есть в имени этого пользователя, и список будет отфильтрован по этим символам:



Выберите нужного пользователя и нажмите на кнопку Switch!.. Вы будет залогинены под этим пользователем.

Для того, чтобы залогиниться обратно под своим пользователем, выберите опцию Switch Back

To:



SIL Configuration


Это меню позволяет Вам конфигурировать SIL. Информацию от вендора можно почитать здесь.



SIL Home Directory позволяет Вам указать директорию, в которой будут храниться все скрипты. По умолчанию это JIRA_HOME/silprograms.

Charset позволяет Вам определить в какой кодировке будут храниться Ваши скрипты. Лучше оставить кодировку в UTF-8. Плохо представляю, для чего может понадобится эта настройка.

SIL Cache size позволяет указать количество скриптов, код которых был переведен в Java байт код и хранится в SIL кэше.

А зачем нам SIL кэш?

Вот пример кода на SIL:

string message = "My message";
runnerLog(message);

Для того, чтобы выполнить этот код, нам необходимо перевести его в Java байт код. SIL содержит большое количество конструкций: структуры, функции, циклы, условия, присвоение и так далее, поэтому для того, чтобы все это перевести в Java байт код, нужно время, и SIL кэш, как раз позволяет Вам экономить это время. Код конвертируется в Java байт код один раз и сохраняется в кэш. Если этот код нужно выполнить снова, то берется уже готовый Java байт код из SIL кэша.

Поэтому если у Вас тысячи скриптов SIL, то имеет смысл увеличить размер кэша.

Datasources


Этот пункт меню позволяет Вам конфигурировать источники данных для баз данных и использовать эти источники в Вашем коде.

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



Давайте сконфигурируем источник базы данных.

Нажмите на кнопку Add Datasource и введите настройки для базы данных:



У меня на компьютере поднята еще одна Jira и я хочу получить данные из базы данных этой Jira.
Важно отметить, что SIL не содержит jdbc драйверов в своем дистрибутиве. Поэтому Вы должны обеспечить наличие этих драйверов в Jira сами. Вот здесь можно почитать, как это сделать.

Теперь нажмем на кнопку Save и источник базы данных с названием external_database будет создан:



Теперь давайте используем этот источник базы данных в нашем скрипте:

string [] results = sql("external_database", "select * from cwd_group");
runnerLog(results);

Я выполняю в этом скрипте sql запрос и получаю результат:



Mail Sender Configuration


Вот этот пункт меню меня заставил помучиться в свое время. Информацию от вендора Вы можете найти здесь.

Вы можете отправлять электронные сообщения с помощью sendEmail и в этом пункте меню Вы указываете параметры для этой функции.



My templates directory позволяет указать путь к шаблонам электронных сообщений.

Mail language on позволяет указать на основе Отправителя или Получателя будет определятся язык шаблона электронного сообщения. Если Вы используете шаблоны электронных сообщений, то Вы можете создать один и тот же шаблон для разных языков. Вы можете больше про это почитать здесь.

Send mail via позволяет указать, как будет отправлено электронное сообщение. Вот доступные опции:

  • Container Sender — сообщение будет отправлено через стандартную очередь электронных сообщений Jira.



А кроме того, Вы сможете увидеть сообщения об ошибках и сообщения отладки при отправке электронной почты в файле atlassian-jira-outgoing-mail.log. Для этого Вам нужно еще сконфигурировать логирование отправки сообщений электронной почты в Jira. Вы можете подробнее про конфигурирование логирования в Jira почитать здесь. Я предпочитаю использовать именно эту опцию.
  • Direct sender, custom — Вы можете указать Ваш собственный почтовый сервер для отправки сообщений:





В этом случае Вы не увидите сообщений об ошибках и отладочных сообщений в файле atlassian-jira-outgoing-mail.log, но увидите сообщения в файле atlassian-jira.log.
  • Direct sender, default — если Вы выберите эту опцию, то будет использоваться почтовый сервер, который сконфигурирован в Jira. В этом случае Вы не увидите сообщений об ошибках и отладочных сообщений в файле atlassian-jira-outgoing-mail.log, но увидите сообщения в файле atlassian-jira.log.
  • Null sender (log only) — почтовое сообщение будет записано только в лог файл atlassian-jira.log. Сообщение не будет отправлено получателю. И вот какой нас ожидает сюрприз. Уровень логирования для пакета com.keplerinfo по умолчанию ERROR, поэтому Вы не увидите никаких сообщений в логах, Вы не увидите сообщений в почтовом ящике получателя и эта опция устанавливается по умолчанию. В моем случае я потратил около часа, чтобы понять, что не так. Для того, чтобы увидеть сообщение в логах установите уровень логирования INFO для пакета com.keplerinfo. Как установить уровень логирования можно почитать здесь. Вот пример такого сообщения:



2020-05-24 14:19:53,601+0300 pool-42-thread-8 INFO admin 859x6032x1 aizaws 0:0:0:0:0:0:0:1 /rest/keplerrominfo/refapp/latest/async-script/runScriptFromEditor [c.k.r.sil.impl.MailConfigurationAccessor] NULL MAILER (log only mail sender) : Subject: aa, From: null, To: [alex@gmail.com], CC: [alex@bk.ru], Body:
aa

Asynchronous Runner


Вы можете почитать информацию от вендора здесь:

Threads устанавливает число тредов для SIL. По умолчанию число тредов 10 и это значит, что одновременно будут выполняться только 10 скриптов. Остальные встанут в очередь и будут ждать пока один из тредов освободится. Если у Вас выполняется большое количество скриптов одновременно, то увеличьте данный параметр.

Time To Live (TTL) устанавливает время жизни треда. По умолчанию значение 1 час. Это означает, что если скрипт будет выполняться больше часа, то он будет убит и результаты работы скрипта будут только те, которые успели быть выполнены за этот час. Если у Вас есть долгоиграющие скрипты, то увеличьте этот параметр.

Checkpoint Interval определяет как часто SIL будет проверять, а есть ли скрипты, которые работают дольше, чем параметр TTL time. И если такие скрипты найдены, то они будут убиты.

Также на этом экране Вы можете увидеть все скрипты, которые в данный момент выполняются.

Remote Systems


Меню Remote Systems позволяет Вам:
  • Добавлять подключения к внешним экземплярам Jira и выполнять SIL скрипты на этих экземплярах.
  • Устанавливать разрешения для выполнения SIL скриптов через SIL REST API для пользователей, которые не являются администраторами Jira.

Вы можете почитать информацию от вендора здесь.

Давайте сначала создадим удаленное соединение к Jira и выполним на ней SIL скрипт.
У меня поднято два экземпляра Jira: localhost:2990/jira и localhost:8080.
Я создал вот такой скрипт на localhost:8080 и назвал этот скрипт test.sil:

logPrint("ERROR", "I am called from " + argv[0]);

Этот скрипт принимает параметр и выводит в лог atlassian-jira.log сообщение с этим параметром.
Теперь на localhost:2990/jira я создам удаленное подключение. Перейду в шестеренка -> Manage Apps -> Remote Systems, нажму кнопку Add Remote и введу данные Jira для localhost:8080:



Теперь нажму на кнопку Save button и на этом же экземпляре Jira(localhost:2990/jira) создам скрипт, который будет вызывать скрипт с localhost:8080:

call("my_ext_jira", "test.sil", "localhost:2990/jira")

Первый параметр это созданное мною удаленное подключение: my_ext_jira.
Второй параметр это имя скрипта, который будет выполнен на удаленной системе (localhost:8080): test.sil.

Третий параметр это строка, которая будет передана в test.sil: localhost:2990/jira.

Теперь выполним этот скрипт (тот, который на localhost:2990/jira) и посмотрим логи на удаленной системе (localhost:8080). Мы увидим вот такую строчку:

2020-05-25 08:30:57,944+0000 pool-38-thread-2 ERROR admin 510x101x1 3sauem 172.26.0.1 /rest/keplerrominfo/refapp/latest/async-script/runScript [c.k.s.lang.routines.LogPrintRoutine] I am called from localhost:2990/jira

Это означает, что мы успешно вызвали SIL скрипт на удаленной системе localhost:8080 с localhost:2990/jira.

Теперь давайте разберемся с разделом Security на экране, который мы видим после выбора пункта меню Remote Systems.

Предположим, что у нас есть два скрипта на localhost:2990/jira.
test.sil

call("my_ext_jira", "test.sil", "localhost:2990/jira")

test1.sil

runerLog("Hello World");

И есть у нас пользователь user1, у которого нет прав администратора.

Мы хотим вызывать инлайн скрипты и скрипты, которые находятся на файловой системе, этим пользователем.

Вот экран меню Remote Systems:



Мы будет работать с кнопками Grant execute inline, Grand read и Grant execute из раздела Security.

Сначала попробуем вызвать инлайн скрипт под пользователем user1. Будем вызывать инлайн скрипт с помощью вот такого SIL REST API метода.

http://localhost:2990/jira/rest/keplerrominfo/refapp/1.0/async-script/runScript

Вот с таким JSON:

{
   "source" : {
    "type": "INLINE",
    "code": "return 1;"
    }
}

И получим вот такую ошибку 403 Forbidden.

Теперь нажмем кнопку Grant execute inline и дадим грант пользователю user1:



И получим код ответа 200, что означает, что мы выполнили инлайн скрипт успешно.

Теперь давайте выполним скрипт test1.sil под пользователем user1. На этот раз JSON будет вот таким:

{
   "source": {
        "type": "FILE",
        "code": "test1.sil"
    }
}

И опять мы получим вот такую ошибку 403 Forbidden.

Теперь дадим права пользователю user1 выполнять скрипт test1.sil. Нажмем на кнопку Grant execute:



На этот раз код ответа 200. Все получилось.

LDAP Configuration


Вы можете настроить подключение к LDAP. Информацию вендора можно почитать здесь.

Я запускаю ldap сервер в докере вот отсюда.

docker run -p 389:389 -p 636:636 --name my-openldap-container --env LDAP_ADMIN_PASSWORD="adminadmin" --detach osixia/openldap:1.3.0

Сервер ldap запущен.

Теперь давайте нажмем на кнопку Add LDAP и сконфигурируем подключение:



Для поля Directory доступно значение только Active Directory. Но это не значит, что Вы можете подключиться только к Microsoft Active Directory. Вы можете подключиться к любому ldap серверу. Я подключился к open ldap.

Теперь давайте выберем пользователей из LDAP с помощью ldapUserList:

runnerLog(ldapUserList({"cn", "uid"}, "objectClass=*", "myldap"));

И мы получили результат:



Это означает, что все у нас получилось.

Script Storage


Этот пункт меню позволяет указать, где Вы будете хранить SIL скрипты. Информацию от вендора Вы можете почитать здесь.

По умолчанию скрипты хранятся в файловой системе (опция disk):



Вы можете выбрать, чтобы скрипты хранить в базе данных (опция database). В этом случае скрипты будут храниться в таблице AO_1B54DA_TSTEXT.

По моему мнению, все-таки, лучше хранить скрипты в файловой системе. В этом случае Вы сможете использовать систему контроля версий, например, Bitbucket.

Custom Fields Mapping


В этом пункте меню вы можете указать мэпинг типов кастомных полей в типы значений SIL. Вы можете почитать информацию от вендора здесь.



Например, посмотрим на кастомное поле Checkboxes. Значение этого поля мэпится в тип string[], что означает, что если Вы хотите прочитать значение из поля с типом Checkboxes, то Вы должны написать вот такой код:

string[] value =  #{My Checkbox Field};

А чтобы присвоить значение, вот такой код:

string[] value =  {"value1", "value2"};
#{My Checkbox Field} =  value;

Вы не можете изменить мэпинг для этого поля, потому что это стандартное поле. И Cprime уже указал корректный мэпинг.

Теперь давайте посмотрим на тип кастомного поля Grid. Этот тип мы получили из плагина Table Grid Next Generation. Cprime не предоставляет мэпинг для этого поля из коробки, поэтому ему присвоен мэпинг по умолчанию. Мэпинг по умолчанию это string. Но Вы можете поменять мэпинг по умолчанию на другой:



В некоторых случаях встроенных мэпингов не хватает и в этом случае Вы можете написать расширение к SIL со своим мэпингом. Подробнее как это делать можно почитать здесь.

Intergration Configuration


Вы можете создавать подключения к Slack и Stride в этом пункте меню. У вендора есть очень подробная инструкция, как это сделать вот здесь.

SIL Webhooks Configuration


Вы можете создать свое REST API, которое будет вызывать SIL скрипты. Почитать можно вот тут.

SIL Diagnostic


Этот пункт меню позволяет получить всеобъемлющую информацию о конфигурации SIL:



Большинство этой информации необходимо для разработчиков SIL, но я бы хотел обратить внимание на одну важную фичу на этом экране.

Вы может убивать SIL скрипты, которые в настоящее время запущены.

Предположим, что Вы написали и запустили скрипт, который создал бесконечный цикл. Без этой опции Вам бы пришлось ждать пока бы скрипт не работал бы дольше, чем время в параметре Time To Live (TTL), и не был бы убит. Но с этой опцией Вы можете не ждать этого момента.

Просто нажмите на кнопку Kill: