Автоматическая проверка хеш-суммы файлов в Gitlab CI на примере Hugo
При деплое часто приходится сравнивать хеш-суммы файлов. Например, при развёртывании Hugo сайта через Gitlab CI. Заметка не позиционируется как прямое руководство к действию, а скорее как указание на то, с чем мне пришлось столкнутся. Быть может, кому-то она послужит источником полезной информации.
Официальный пример Hugo от Gitlab Pages предлагает такой способ:
image: alpine
variables:
  HUGO_VERSION: '0.23'
  HUGO_SHA: 'c9cf515067f396807161466c9968f10e61f762f49d766215db37b01402ca7ca7'
before_script:
  - apk update && apk add openssl ca-certificates
  - wget -O ${HUGO_VERSION}.tar.gz https://github.com/spf13/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz
  - echo "${HUGO_SHA}  ${HUGO_VERSION}.tar.gz" | sha256sum -c
  - tar xf ${HUGO_VERSION}.tar.gz && mv hugo* /usr/bin/hugo
  - hugo version
test:
  script:
  - hugo
  except:
  - master
pages:
  script:
  - hugo
  artifacts:
    paths:
    - public
  only:
  - master
Посмотреть на этот файл можно и в Gitlab
Ничего сложного, простой типичный Gitlab CI скрипт. Но если для кого-то это представляет трудности, то кратко здесь происходит следующее: мы берём последний доступный docker-образ alpine linux, скачиваем дополнительные пакеты для корректной работы с SSL. Потом скачиваем архив Hugo с номером версии из переменной HUGO_VERSION, затем сравниваем SHA256-сумму этого файла c SHA256-суммой из переменной HUGO_SHA. После этого распаковываем и перемещаем файл hugo по пути /usr/bin/hugo и вызываем команду hugo version. Так мы проверяем, что Hugo работает, а заодно и номер версии узнаем. После происходит процесс тестирования и непосредственно сам деплой.
В чём минус такого решения? Каждый раз, когда нам необходимо обновить Hugo, приходится:
- изменять номер версии в переменной 
HUGO_VERSION - вычислять хеш-сумму скачиваемого архива с HUGO в переменную 
HUGO_SHA 
Учитывая, что в последнее время новые мажорные билды Hugo выходят слишком уж часто (приблизительно раз в месяц), этот процесс хотелось и стоило бы упростить до одного действия. А когда за неделю вышло сразу несколько минорных исправлений с исправлением кучи багфиксов, я понял, что надо срочно автоматизировать сравнение хеш-сумм, тем более, что начиная с версии v0.20.3, к каждому билду Hugo стали генерировать дополнительный текстовый файл с хешсуммами в формате SHA-256, серьёзно упростив задачу.
Для начала набросаем краткий план действий:
- Скачиваем файл hugo_checksums.txt
 - Grep’аем название нашего билда
 - Отрезаем вторую часть (с названием билда), разделённую от первой знаком табуляции, оставляем только хешсумму и кладём её в переменную.
 - Сравниваем хешсумму из переменной с хешсуммой самого архива Hugo.
 - Удаляем файл hugo_checksums.txt
 
Думаю, со скачиванием и с grep всё понятно без лишних объяснений, а вот чтобы отсечь лишнее, мы воспользуемся командой cut с ключом -f со значением 1:
cut -f 1
Конкретно эта команда означает то, что мы сохраняем только кусочек строки, до первого разделителя. По-умолчанию cut использует в качестве разделителя знак табуляции и это подходит для нашего файла hugo_checksums.txt. В случае если бы в файле использовался другой разделитель, его можно было явно задать ключом -d. Подробнее всегда можно почитать через man cut или в других источниках.
А вот чтобы заполучить последовательный результат выполнения нескольких команд в переменную, нужно использовать следующий синтаксис:
variable=$(command1 | command2)
Конкретно в нашем случае должно получится такое:
checksum=$(grep -i "hugo_${HUGO_VERSION}_Linux-64bit.tar.gz" hugo_checksums.txt | cut -f 1)
В итоге, в переменной checksum будет хранится контрольная хеш-сумма нашего архива. А дальше остаётся только добавить нашу переменную в строку сравнения sha256 и удалить файл hugo_checksums.txt.
Финальная версия файла gitlab-ci.yml после всех наших изменений будет выглядеть примерно так:
image: alpine
variables:
  HUGO_VERSION: '0.23'
before_script:
  - apk update && apk add openssl ca-certificates
  - wget https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_checksums.txt
  - wget -O ${HUGO_VERSION}.tar.gz https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz
  - checksum=$(grep -i "hugo_${HUGO_VERSION}_Linux-64bit.tar.gz" hugo_checksums.txt | cut -f 1)
  - echo "$checksum  ${HUGO_VERSION}.tar.gz" | sha256sum -c
  - rm hugo_checksums.txt
  - tar xf ${HUGO_VERSION}.tar.gz && mv hugo* /usr/bin/hugo
  - hugo version
test:
  script:
  - hugo
  except:
  - master
pages:
  script:
  - hugo
  artifacts:
    paths:
    - public
  only:
  - master
Теперь достаточно изменить номер версии в файле gitlab-ci.yml и сравнение хеш-суммы произойдёт при билде автоматически. Главное, чтобы разработчики Hugo ничего не «поломали» в последующих версиях. В последнее время они частенько проворачивают подобные трюки с изменением форматов своих билдов.