суббота, 14 декабря 2013 г.

Нумерация сборок

Задача, казалось бы, более чем тривиальная, ан нет - при выпуске версий под разные платформы и в ней нашлась пара изюминок...

Когда мы работаем только с одним сборочным сервером - проблем вообще никаких в принципе нет.

Полная свобода для творчества - кто-то делает инкрементирующийся счетчик, кто-то пользуется предоставляемыми сервисами от CI-движка. Например, тот же Jenkins осуществляет нумерацию сборок сам, остается только пробрасывать его номера в продукт.

Мы в свое время, еще в его бытность Hudson'ом, пошли по другому пути - написали plugin, который выполнял все задачи по сборке, в том числе и вычисление следующего номера автоматически (почему-то считалось, что сборки должны нумероваться последовательно, неудавшиеся просто выкидывались из истории).

Все меняется тогда, когда CI-серверов становится больше одного - формально все хорошо, целевую платформу можно идентифицировать веткой, вот только нумерация сборок в этих ветках начинает сразу же разъезжаться, что приносит нешуточную неразбериху с QA, который традиционно в багрепортах в лучшем случае помнит номер сборки...

Решение подобралось достаточно быстро (на просторах Интернета можно найти массу подобных), но прижилось оно не сразу.

Какие вообще есть требования к нумерации?

  • Возрастание
  • Равномерность (это уже чисто Транзасовская фенечка)

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

Само решение на редкость примитивно:

  • Ставим метку на исходные тексты в момент ветвления
  • Для вычисления номера сборки после clone запускаем специальный сценарий
    который вычисляет количество коммитов от момента проставления метода до текущей ревизии
Простановка метки делается тривиально:
git tag -a -m "version 2.10" v2_10
Для Linux решение выглядит вообще в одну строчку:
#!/bin/sh
git describe --match v2_10|sed -r 's/TAG-([0-9]+)-.+/\1/'
Для Windows чуть пострашнее:
@echo off
call git describe --match v2_10  1>file.txt
local BUILDNO
for /F "tokens=1,2,3* delims=-" %%i in (file.txt) do set BUILDNO=%%j
del file.txt
if "%BUILDNO%" == "" set BUILDNO=9999
echo %BUILDNO%
Обычно мы пользуемся вариантом, встроенным прямо в систему сборки (CMake):
#
# Function for automatic builds generation.
#
function(get_uninav_build_num SRC_DIR RESULT_NAME)
    find_package(Git QUIET)
    set(GIT_TAG "build_2_10")
    if(GIT_FOUND)
        execute_process(
            COMMAND ${GIT_EXECUTABLE} describe --match ${GIT_TAG}
            WORKING_DIRECTORY ${SRC_DIR}
            OUTPUT_VARIABLE DESCRIBE_BUILD
            OUTPUT_STRIP_TRAILING_WHITESPACE)
        if(NOT DESCRIBE_BUILD)
            set(DESCRIBE_BUILD 9999)
        endif()
        string(REGEX REPLACE "${GIT_TAG}-" ""  DESCRIBE_BUILD "${DESCRIBE_BUILD}")
        string(REGEX MATCH "[0-9]+" TEMP_BUILD ${DESCRIBE_BUILD})
        set(${RESULT_NAME} ${TEMP_BUILD} PARENT_SCOPE)
    else()
        set(${RESULT_NAME} 9999 PARENT_SCOPE)
    endif()
endfunction()

set(BUILDNUM 9999)
get_uninav_build_num(${GIT_BASE} BUILDNUM)

message("Build number is: ${BUILDNUM}")
Как всегда, не обходится без недостатков, например, считаются все коммиты в merged ветках, но это легко переживаемая в наших условиях проблема, как только мы убеждаем всех, что сборки необязательно нумеруются через единицу.

Напоследок, немного статистики - по наблюдению за последними тремя предыдущими проектами группа из четырех-пяти человек за полгода (это типичное время проекта в нашей фирме) вносит в базу порядка 3000 коммитов, так что полученный номер сборки без проблем можно вставлять в VERSIONINFO для Windows.

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