Интерпретируйте задание Hudson как успешное, даже если одна из вызванных программ завершается с ошибкой

#bash #hudson #bazaar

#bash #хадсон #базар

Вопрос:

У меня есть задание Hudson, которое периодически объединяет изменения из вышестоящего репозитория bazaar.

В настоящее время, когда нет изменений в восходящем потоке, Hudson сообщает об этом задании как о сбое, поскольку команда фиксации bzr возвращается с ошибкой. Мой скрипт выглядит примерно так:

 bzr branch lp:~lorinh/project/my-local-branch
cd my-local-branch
REV_UPSTREAM=`bzr version-info lp:project --custom --template="{revno}"`
bzr merge lp:project
bzr commit -m "merged upstream version ${REV_UPSTREAM}" 
./run_tests.sh 
bzr push lp:~lorinh/project/my-local-branch
  

Если в merge нет изменений, вывод консоли Hudson выглядит примерно так:

   bzr branch lp:~lorinh/project/my-local-branch
Branched 807 revision(s).    
  bzr merge lp:project
Nothing to do.
  bzr commit -m merged upstream version 733
Committing to: /var/lib/hudson/jobs/merge-upstream/workspace/myproject/
aborting commit write group: PointlessCommit(No changes to commit)
bzr: ERROR: No changes to commit. Use --unchanged to commit anyhow.
Sending e-mails to: me@example.com
Finished: FAILURE
  

Проблема в том, что я не хочу, чтобы Hudson сообщал об этом как о сбое. Как мне изменить мои команды, чтобы скрипт завершался при неудачной фиксации, но это не интерпретировалось Hudson как ошибка? Я попытался изменить команду фиксации на:

 bzr commit -m "merged upstream version ${REV_UPSTREAM}" || exit 
  

Но это не сработало.

(Примечание: я понимаю, что мог бы использовать «SCM опроса» Хадсона вместо «периодической сборки». Однако в bazaar, если кто-то выполняет push с локальными коммит-кодами, которые были выполнены до самых последних изменений, то Hudson не обнаружит изменения в репозитории.)

Ответ №1:

Вы были очень близки! Вот исправленная версия того, что вы пытались:

 bzr commit -m "merged upstream version ${REV_UPSTREAM}" || exit 0
  

Теперь это делает то, что вы просили, но не идеально. Я вернусь к этому позже.

Обратите внимание на крошечное важное изменение по сравнению с вашей версией — теперь мы четко указываем, что мы должны завершить работу с кодом 0 (успех), если команда bzr этого не делает. В вашей версии exit (без аргумента) завершит ваш скрипт, но вернет код завершения последней выполненной команды — в данном случае фиксации bzr.

Подробнее о выходе

Как мы узнаем об этом поведении exit? exit Команда является встроенной оболочкой — для поиска документации по ней мы используем команду help:

 help exit
  

Который на моей машине сообщает мне:

 exit: exit [n]
Exit the shell.

Exits the shell with a status of N.  If N is omitted, the exit status
is that of the last command executed.
  

Вот неплохое руководство по выходу и кодам выхода в оболочке bash

Коды Hudson и exit

Хадсон следует этому общему соглашению о интерпретации кода выхода 0 как успешного, а любого другого кода как сбоя. Ваша сборка будет помечена как сбой, если выполняемый ею сценарий сборки завершается с ненулевым кодом.

Почему ваш скрипт останавливается после фиксации bzr

Если, как вы говорите, у вас есть следующее, и ваш скрипт останавливается после фиксации bzr…

 bzr commit -m "merged upstream version ${REV_UPSTREAM}" 
./run_tests.sh 
  

… Я подозреваю, что ваш скрипт имеет такую инструкцию, как set -e или вызывается с чем-то вроде bash -e build_script.sh

Любой из них сообщает командной оболочке о немедленном завершении, если команда завершается с ненулевым статусом, и о передаче того же кода завершения «сбой». (Есть тонкости — см. сноску 1).

Отключение выхода при ошибке

Хотя такое поведение завершения при ошибке чрезвычайно полезно, иногда мы хотели бы временно отключить его. Вы нашли один способ, в

 bzr commit whatever || true
  

Мы также можем отключить проверку ошибок с помощью set e.

Вот шаблон, который может оказаться полезным. В нем мы будем:

  1. Отключить выход при ошибке (с помощью set e )
  2. запустите команду, которая может привести к ошибке bzr commit whatever
  3. запишите ее код выхода ($?) для последующей проверки
  4. Повторно включите выход при ошибке (с set -e )
  5. Тестируйте и действуйте в соответствии с кодом завершения любых команд

Давайте реализуем это. Снова мы завершим 0 (успех), если команда bzr завершилась с ошибкой.

 set  e
bzr commit whatever
commit_status=$?
set -e
if [[ "$commit_status" != "0" ]]; then
  echo "bzr commit finds nothing to do.  Build will stop, with success"
  exit 0
fi
echo "On we go with the rest of the build script..."
  

Обратите внимание, что мы как можно меньше заключаем в скобки set e / set -e. Если в нашем скрипте в этом разделе есть опечатки, они не остановят скрипт и возникнет хаос. Прочитайте раздел «Как избежать set -e» в сообщении «Недостаточно известные функции оболочки POSIX» для получения дополнительных идей.

Что не так с foo || exit 0 ?

Как я упоминал ранее, есть проблема с нашим первым предложенным решением. Мы говорили, что когда bzr commit значение ненулевое (т. Е. Оно не фиксируется нормально), мы всегда останавливаемся и указываем на успех. Это произойдет, даже если bzr commit произойдет сбой по какой-либо другой причине (и с каким-либо другим ненулевым кодом выхода): возможно, вы допустили опечатку в вызове вашей команды, или bzr не может подключиться к репозиторию.

По крайней мере, в некоторых из этих случаев вы, вероятно, захотите, чтобы сборка была помечена как сбой, чтобы вы могли что-то с этим сделать.

К лучшему решению

Мы хотим уточнить, какие ненулевые коды выхода мы ожидаем от bzr, и что мы будем делать с каждым.

Если вы посмотрите на шаблон set e / set -e выше, не должно быть сложно расширить условную логику (if) выше во что-то, что может иметь дело с рядом конкретных кодов выхода из bzr, а также с универсальным для непредвиденных кодов выхода, которые (я предлагаю) завершают сборку с ошибкой и сообщают о некорректном коде и команде.

Чтобы узнать коды выхода для любой команды, прочитайте документы или запустите команду, а затем выполните echo $? в качестве следующей команды. $? содержит код завершения предыдущей команды.

Примечание 1: Поведение при выходе из системы при ошибке, переключаемое с помощью set -e, имеет некоторые тонкости, с которыми вам нужно ознакомиться, касающиеся поведения, когда команды находятся в конвейерах, условных операторах и других конструкциях.

Комментарии:

1. Браво! Отличный анализ исходной проблемы и улучшенное решение. Это был бы мой ответ для объяснения кодов ошибок.

Ответ №2:

учитывая, что bzr, похоже, выдает неправильный код выхода (на основе вашего bzr ... || exit примера), одним из решений является захват выходных данных bzr и последующее сканирование на предмет ОШИБКИ или другого.

  bzr commit -m "merged upstream version ${REV_UPSTREAM}" 2>amp;1 | tee /tmp/bzr_tmp.$$

 case $( < /tmp/bzr_tmp.$$ ) in
   *ERROR* ) 
     printf "error running bzr, found error msg = $(< /tmp/bzr_tmp.$$)n"
     exit 1
   ;;
   * )
     : # everything_OK this case target
       # just to document the default action of 'nothing' ;-)
   ;;
 esac
  

Немного более простым целевым регулярным выражением, основанным на вашем примере выходных данных, было бы *FAILURE ) ... .

$( < file ) это более новая функция командной оболочки, которую вы можете представить как $(cat file) , но она более эффективна в использовании ресурсов процесса, поскольку ей не нужно запускать новый процесс ( cat ) для создания дампа файла.

Я надеюсь, что это поможет.