#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.
Вот шаблон, который может оказаться полезным. В нем мы будем:
- Отключить выход при ошибке (с помощью
set e
) - запустите команду, которая может привести к ошибке
bzr commit whatever
- запишите ее код выхода ($?) для последующей проверки
- Повторно включите выход при ошибке (с
set -e
) - Тестируйте и действуйте в соответствии с кодом завершения любых команд
Давайте реализуем это. Снова мы завершим 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
) для создания дампа файла.
Я надеюсь, что это поможет.