Прежде чем вы прочитаете

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

Напротив, это означает возможность поучиться на большом и зрелом проекте Golang, потребляемом другими проектами.

Это один из немногих проектов моно-репо Golang по книге (из https://github.com/golang/go/wiki/Module).

И как авторы / сопровождающие проектов вы можете узнать, как люди преобразовались в большое монорепо, и как потребитель, вы можете узнать, как их использовать.

Кроме того, если возникнут проблемы с использованием библиотеки, как, например, в этой истории, вы узнаете, как ее взломать и заставить работать, пока она не будет исправлена ​​в официальном выпуске.

Приятного чтения!

История (Вступление)

В SumUp мы используем различные проекты экосистемы Golang, в основном:

  • Kubernetes - в основном Kubernetes client-go и другие библиотеки API.
  • HashiCorp - в основном Consul API, Vault API и consul-template (в виде библиотеки)

Недавно мы открыли исходный код небольшого клиента / оболочки для клиента Vault в наших пакетах Golang по адресу



Одна конкретная фиксация привела к возникновению множества конфликтов модулей golang, таких как

Какая была конкретная фиксация?



Важная часть, которая была изменена, - это добавление

github.com/hashicorp/vault/api v1.0.1

Раньше мы зависели от

github.com/hashicorp/vault v1.1.2

Подождите, почему мы начали это изменение?

В официальном репозитории Hashicorp / Vault я увидел, что были предприняты усилия по полной миграции на модули Golang и внедрению множества более мелких модулей. Практически это означает, что api и sdk пакеты Vault разделены на отдельные модули, в результате github.com/hashicorp/vault становится моно-репозиторием, содержащим несколько модулей.

Работа была начата в



Для сторонних пользователей (таких как мы) это означает, что мы можем полагаться на конкретный пакет и модуль и эффективно сокращать наши зависимости до минимума t.

У нас все пошло не так с тех пор, как мы использовали https://github.com/hashicorp/consul-template в качестве библиотеки, предоставляющей API для другого проекта, который является своего рода загрузчиком, обертывающим шаблон consul и выполняющим предварительную настройку перед запуском consul. -шаблон.

Однако для того, чтобы это работало для нашего внутреннего проекта, необходимо было сделать по крайней мере одну правильную вещь - перенести hashicorp / consul-template в модули Golang и исправить конфликты между hashicorp / consul-template и последней версией официальный выпуск hashicorp / vault.

Все усилия возвращаются в



Понимание того, как Hashicorp Vault сегодня использует модули go для создания монорепозитория

Прежде всего, обязательно ознакомьтесь с https://github.com/golang/go/wiki/Modules#faqs--multi-module-repositories.

Хотя ответы на часто задаваемые вопросы могут быть полезны, всем, кто хочет погрузиться в дополнительную сложность монорепозитория (надеюсь, по какой-то веской причине!), Просмотр https://github.com/hashicorp/vault поможет чтобы начать ваши усилия.

Все, что они сделали для github.com/hashicorp/vault/go.mod, доступно по адресу:



Важно отметить, что есть 3 модуля:

  • корень github.com/hashicorp/vault
  • SDK github.com/hashicorp/vault/sdk
  • API (клиент) github.com/hashicorp/vault/api

Начнем с sdk, так как он самый чистый:



Важно, чтобы SDK не зависел ни от чего github.com/hashicorp/vault/**/*.

Это, как описано в README.md:

пакет, содержащий код, полезный для разработки плагинов Vault.

github.com/hashicorp/vault (корень) выполняет две важные функции:

replace github.com/hashicorp/vault/api => ./api
replace github.com/hashicorp/vault/sdk => ./sdk

(Что такое заменить? Https://github.com/golang/go/wiki/Modules#when-should-i-use-the-replace-directive)

Это означает, что внутренне github.com/hashicorp/vault не будет пытаться загрузить api и sdk как отдельные пакеты, а вместо этого будет использовать локальные копии, которые доступны относительно в файловой системе.

Плюсы в голове:

  • то, что вы видите, - это то, с чем вы работаете.
  • более простое управление зависимостями, так как вы не загружаете другие пакеты по сети / проводу

Минусы:

  • требует понимания замены
  • требует немного больше дисциплины

api:



Имеет только один replace для sdk, который он использует

replace github.com/hashicorp/vault/sdk => ../sdk

Опять же, здесь применимы плюсы и минусы, описанные ранее о корневом модуле.

Хорошо, а почему этот перерыв на hashicorp/consul-template?

Следить за этим было довольно весело, но это было что-то вроде:

  • зная, как ведет себя разрешение модуля Golang.
  • один «плохой» выпуск, нарушивший совместимость модуля golang для модуля в монорепозитории github.com/hashicorp/vault.

Итак, как ведет себя разрешение модуля Golang?

Не повторяя уже описательную документацию, прочтите.



Итак, одна плохая версия нарушила совместимость модуля golang ... как?

Во-первых, убедитесь, что вы прочитали



В случае с HashiCorp Vault здесь есть 2 релиза (первый - самый последний):

Однако atv1.1.2, файлов api/go.mod и api/go.sum нет.

(О проблеме сообщается по адресу https://github.com/hashicorp/vault/issues/6634)

Это означает, что когда hashicorp/consul-template зависит от vault/[email protected] (помечено как api/v1.0.1), Golang обнаружит неоднозначный путь импорта

build github.com/syndbg/consul-template: cannot load github.com/hashicorp/vault/api: ambiguous import: found github.com/hashicorp/vault/api in multiple modules:
       github.com/hashicorp/vault v1.1.2 (/home/syndbg/go/1.12.4/pkg/mod/github.com/hashicorp/[email protected]/api)
        github.com/hashicorp/vault/api v1.0.1 (/home/syndbg/go/1.12.4/pkg/mod/github.com/hashicorp/vault/[email protected])

На мой взгляд, сообщение легко понять неправильно.

Настройка решения

Мы собираемся проанализировать



Это моя ветвь hashicorp/consul-template, включающая ранее упомянутый PR для модулей golang и дополнительные исправления, необходимые для решения сложных конфликтов зависимостей модуля golang для других проектов, использующих его. (я очень хочу, чтобы это было объединено с апстримом в несколько PR, и я работаю над этим).

Продолжая вышеупомянутый неоднозначный импорт, мы должны сделать только одну вещь - указать golang использовать версию github.com/hashicorp/vault, в которой есть файлы api/go.mod и api/go.sum.

Ниже мы проанализируем два подхода к решению проблемы. Одно я считаю наивным, другое - оптимальным.

Наивное решение

План:

  1. Создайте вилку github.com/hashicorp/vault.
  2. Найдите ближайший (следующий в истории git) коммит, у которого есть api/go.mod. Чтобы сэкономить ваше время, этот коммит - 6ec1bcfb20c2efcd9769cfb2816943bcec135010 ( https://github.com/hashicorp/vault/commit/6ec1bcfb20c2efcd9769cfb2816943bcec135010).
  3. Создать новый api/<semantic version>. Это выпуск модуля API. Вы можете пропустить это? Нет, это не сработает, потому что replace (go.mod’s) не примет тег git без точного совпадения пути импорта, если он имеет допустимую семантическую версию. Вы можете обмануть его с помощью «виртуальной / поддельной» семантической версии (объяснено в оптимальном решении).
  4. Создать новый <semantic version>. Это выпуск корневого модуля. Да, но будет лучше, если вы продолжите выпускать новые выпуски для всех модулей, когда один из модулей, находящихся в одном монорепо, изменится. Эта цель для симметрии упоминается в https://github.com/golang/go/wiki/Modules#is-it-possible-to-add-a-module-to-a-multi. -модуль-репозиторий
  5. Используйте replace в github.com/syndbg/consul-template go.mod, чтобы использовать мой разветвленный github.com/syndbg/vault.

Выполнение:

  1. Я использую https://github.com/syndbg/vault/
  2. Я выбрал фиксацию 6ec1bcfb20c2efcd9769cfb2816943bcec135010 как наиболее близкую к исходной версии, которая не будет включать изменения кода / побочные эффекты по сравнению с исходной версией git.
  3. Создаю https://github.com/syndbg/vault/tree/api/v1.1.2-FIXED
  4. Создаю https://github.com/syndbg/vault/tree/v1.1.2-FIXED
  5. Https://github.com/syndbg/consul-template/blob/614af8a9256630b9142a683832f469c244863c8a/go.mod
replace github.com/hashicorp/vault/api => github.com/syndbg/vault/api v1.1.2-FIXED 
replace github.com/hashicorp/vault => github.com/syndbg/vault v1.1.2-FIXED 
replace github.com/hashicorp/consul/api => github.com/hashicorp/consul/api v1.0.1 
replace github.com/hashicorp/consul/sdk => github.com/hashicorp/consul/sdk v0.1.0 
replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.4.5-0.20190327125456-4243c3ae42cf

К сожалению, github.com/hashicorp/consul также подвержен этой же проблеме, так что вы тоже увидите это здесь :).

И это работает. go build и go test сейчас работают.

Оптимальным решением

Создание вилок - определенно не самый оптимальный подход, не так ли?

Это создает значительные накладные расходы для всех. И, к сожалению, если это повлияет на большее количество модулей, у вас будет N вилок. Это просто нехорошо поддерживать.

Что ж, есть способ получше!

Как я уже упоминал, взлом go.mod «виртуальных / фальшивых» семантических выпусков - это правильный путь.

Опять же, чтобы не повторять и без того хорошую документацию модулей Golang, прочтите:

Важный вывод - это формат псевдоверсии vX.0.0-yyyymmddhhmmss-abcdefabcdef.

Это означает, что мы можем replace использовать ранее идентифицированный коммит, содержащий api/go.mod, вместо того, чтобы создавать вилку, новые теги и т. д.

Выполнение:

  1. Поцарапайте Naive solution
  2. Держите github.com/hashicorp/vault под рукой и смотрите дату создания коммита https://github.com/hashicorp/vault/commit/6ec1bcfb20c2efcd9769cfb2816943bcec135010.

Вы можете либо клонировать репозиторий локально, либо

> git clone [email protected]/hashicorp/vault.git
> cd ./vault
> git show 6ec1bcfb20c2efcd9769cfb2816943bcec135010
commit 6ec1bcfb20c2efcd9769cfb2816943bcec135010
Merge: 94132fd6f 008250162
Author: Jeff Mitchell <[email protected]>
Date:   Thu Apr 18 18:49:49 2019 -0400
Merge branch '1.1.2' into master-oss
....

Или просмотрите его в веб-интерфейсе Github, наведя курсор на commited days ago (https://stackoverflow.com/a/20500458)

В любом случае, мы знаем, что это дата 18 апреля, 18:49:49 2019 -0400.

3. Преобразуйте имеющуюся у нас информацию о git commit sha и дате создания в действительную версию мода pseudo go.

Убедитесь, что:

  • вы следите за форматом :)
  • дата создания указана в формате UTC.
  • длина git commit sha составляет 12 символов. Это то, что использует мод go.

Конечный результат

v0.0.0–20190418224949–6ec1bcfb20c2

4. https://github.com/syndbg/consul-template/blob/a7b8a979e98b37cabc5c45fa286060b22be1911b/go.mod

replace github.com/hashicorp/vault/api => github.com/hashicorp/vault/api v0.0.0-20190418224949-6ec1bcfb20c2 
replace github.com/hashicorp/vault => github.com/hashicorp/vault v0.0.0-20190418224949-6ec1bcfb20c2
replace github.com/hashicorp/consul/api => github.com/hashicorp/consul/api v1.0.1 
replace github.com/hashicorp/consul/sdk => github.com/hashicorp/consul/sdk v0.1.0 
replace github.com/hashicorp/consul => github.com/hashicorp/consul v1.4.5-0.20190327125456-4243c3ae42cf

Как упоминалось ранее, к сожалению, github.com/hashicorp/consul также подвержен этой же проблеме, поэтому вы также увидите ее здесь.

И это работает. go build и go test сейчас работают.

Вилки не требуются!

Вывод

Я надеюсь, что это был полезный опыт обучения и полезный обходной путь для потребителей этих библиотек, предоставляющих API, пока не будет выпущен официальный релиз :)

Я что-то не так понял:

  • плюсы и минусы go.mod подхода HashiCorp Vault?
  • «Внутренняя работа» разрешения модуля go (и зависимостей)?

Не стесняйтесь поправлять меня!