Досталась по работе задача прикрутить к CI поддержку нескольких веток разработки. Например ветка development это текущий код, который давно поддерживается, но уже есть планы перевести его в разряд наследия и начать с чистого листа в лучших AI практиках.
Разработчики заводят новую ветку development-X.Y в которую заливается код "не имеющий ничего общего" с кодом в ветке development. Проблема в том что CI не поддерживает такой сценарий и как только будет выпущена версия X.Y.0, то собьётся версионирование в ветке development чего нужно избежать.
За версионирование в CI отвечает shell портянка строк на 200. Благо к ней есть тесты, написанные для bats и это большое благо, иначе количество сюрпризов повысилось бы кратно.
Вот несколько интересных граблей, на которые наступил в процессе:
Добавил новый параметр для фильтрации версий local filter="$10" - тесты отвалились, т.к. в значении переменной filter было "имя_сценария0", а не "0.[0-9]+" как должно было быть. Дело в том что bash трактует "$10" как обращение к первому параметру к которому в строке добавили ноль. Чтобы этого не происходило нужно писать local filter="${10}". Забавно что shellcheck на такое не ругается.
Когда добрался до сравнения версий, которое было сделано в виде хака version() { echo "$@" | awk -F. '{ printf("%d%03d%03d\n", $1,$2,$3); }'; } нашёл "спящую" ошибку, которая проявится спустя какое-то время. При использовании такой функции версия 0.48.0 на выходе имела вид 0048000, но если в начале числа стоит 0, то bash воспринимает его как восьмеричное число и ловит ошибку -bash: [[: 0048000: value too great for base (error token is "0048000").
$ cat /tmp/test.sh
#!/bin/bash
function version { echo "$@" | awk -F. '{ printf("%d%03d%03d\n", $1,$2,$3); }'; }
if [[ "$(version 0.48.0)" -lt "$(version 0.99.0)" ]]; then
echo TRUE
else
echo FALSE
fi
$ bash /tmp/test.sh
/tmp/test.sh: line 5: [[: 0048000: value too great for base (error token is "0048000")
FALSE
Если переписать этот код на синтаксис POSIX, то начинает работать
$ cat /tmp/test.sh
#!/bin/bash
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d\n", $1,$2,$3); }'; }
if [ "$(version 0.48.0)" -lt "$(version 0.99.0)" ]; then
echo OK
else
echo FAIL
fi
$ bash /tmp/test.sh
TRUE
$ dash /tmp/test.sh
TRUE
Не нравится мне код у которого поведение зависит от фазы луны. Переписал эту функциональность на базе команды sort -V. Из коробки эта команда не умеет SemVer и в результате получается что 0.1.0-rc.0 новее чем 0.1.0, но если принудительно добавить к релизным версиям суффикс, то релиз-кандидаты становятся ниже релизов.
Для POSIX shell функции сравнения выглядят так:
latest_semver() { echo "$@" | tr ' ' '\n' | sed '/-/!{s/$/_/}' | sort -V | sed 's/_$//' | tail -1; }
version_gt() { test "$1" != "$2" && test "$(latest_semver "$@")" = "$1"; }
version_lt() { test "$1" != "$2" && test "$(latest_semver "$@")" = "$2"; }
version_ge() { test "$1" = "$2" || version_gt "$1" "$2"; }
version_le() { test "$1" = "$2" || version_lt "$1" "$2"; }
Такие функции будут корректно обрабатывать сравнение релизных версий, релиз-кандидатов и альфа / бета версий.
Комментариев нет:
Отправить комментарий