v3.14.1592-beta2: все, что вы хотели знать о семантическом версионировании

в 11:09, , рубрики: dll hell, semantic versioning, semver, voximplant, Блог компании Voximplant, взрыв мозга, информационная безопасность, Настройка Linux, Программирование, Разработка веб-сайтов

v3.14.1592-beta2: все, что вы хотели знать о семантическом версионировании - 1Усилия и деньги, вкладываемые в продвижение языка Go, часто приносят пользу и другим разработчикам. В конце прошлого года на сайте gopheracademy была опубликована очень удачная статья о семантическом версионировании. Том самом, которое используется в npm, начинается с домика ^ и все ломает. Под катом спрятан перевод, который поможет вам быстро осмотреть сад граблей версионирования и как сейчас принято им пользоваться. И немного примеров на Go. Передаем слово автору!

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

Прежде чем рассказывать о специфичных для Go вещах, давайте посмотрим, что такое семантическое версионирование (примечание переводчика: ради этой части и был затеян перевод).

v3.14.1592-beta2: все, что вы хотели знать о семантическом версионировании - 2

На иллюстрации показаны семантические части строки версии. Чаще всего вы будете видеть только первые три цифры, разделенные точками ".". Полностью же семантическая версия может состоять из следующих частей:

  • “Major” номер версии. Увеличивается (и не всегда на 1, вспомните PHP 5 -> 7), когда API библиотеки или приложения меняется обратно несовместимым образом.
  • “Minor” номер версии. Увеличивается, когда в API добавляются новые функции без нарушения обратной совместимости (примечание переводчика: вот здесь самое зло. К примеру, npm по умолчанию сохраняет версию с префиксом “^”, что означает “любая версия с такой же major”. Авторы npm резонно полагают, что если при смене minor обратная совместимость не теряется, то можно смело обновлять. Сюрприз: множество разработчиков библиотек просто не знают, что такое семантическое версионирование и ломают обратную совместимость, как получится. Результат – на компьютере автора все работает, а при установке “с чистого листа” на другом компьютере мы получаем новые версии зависимостей с поломанной обратной совместимостью). При увеличении номера “major” принято сбрасывать “minor” в 0, то есть за версией 4.27… последует версия 5.0… а не 5.28
  • “Patch” номер версии. Увеличивается при исправлении багов, рефакторинге и прочих изменениях, которые ничего не ломают, но и новых фичей не добавляют. При увеличении “Major” или “Minor” принято сбрасывать “Patch” в 0 (примечание переводчика: очень часто его называют “build number” и просто увеличивают на единицу с каждый билдом continuous integration, никогда не сбрасывая. Это позволяет легко отличать билды друг от друга во время тестирования и анализа сообщений ошибок от пользователей. Минус такого подхода в том, что довольно скоро цифра становится пятизначной. Но многих это не беспокоит).
  • Строка “pre-release”: необязательный, разделенный точками список, отделенный от трех номеров версии знаком минус. Например: “1.2.3-beta.2”. Используется вместо тегов, чтобы “помечать” определенные вехи в разработке. Обычно это “alpha”, “beta”, “release candidate” (“rc”) и производные от них.
  • Завершает строку семантической версии метаданные системы сборки. Так же, как и список “pre-release” тегов, он разделен точками ., но отделяет от номеров или тегов его не минус, а плюс. Данную информацию принято игнорировать (примечание переводчика: по феншую номер билда должен идти сюда – но мало кто так делает, очень длинные строки получаются).

Несмотря на то, что в спецификации ничего не говорится о префиксе “v”, он часто используется перед строкой семантической версии, например, “v.12.3”. Так же, как и метаданные, его принято игнорировать.

Все это и многое другое можно найти в официальной спецификации: http://semver.org/

Благодаря продуманной спецификации, строки семантических версий можно легко распарсить, сортировать, и, главное, сравнивать друг с другом и с диапазонами «допустимых» версий. Чем, собственно, и занимаются большинство менеджеров зависимостей, таких как npm.

Парсинг семантических версий в Go

Для Go доступно несколько пакетов для работы с семантическими версиями. В этой статье я рассмотрю вот этот: github.com/Masterminds/semver. Он соответствует спецификации, поддерживает необязательный префикс “v”, сортировку, работу с диапазонами и ограничениями. При этом с ограничениями этот пакет работает так же, как большинство решений для других языков программирования, таких как JavaScript, Rust и другие.
Пример ниже парсит строку семантической версии и выводит либо “major” версию, либо сообщение об ошибке:

v, err := semver.NewVersion("1.2.3-beta.1+build345")
if err != nil {
    fmt.Println(err)
} else {
    fmt.Println(v.Major())
}

Возвращаемое значение является экземпляром semver.Version, который содержит некоторое количество полезных методов. Если переданная строка не является семантической версией, то возвращается ошибка semver.ErrInvalidSemVer.

Но реальная польза этой библиотеки заключается не в возможности парсить строки, а в возможности проводить сложные действия над семантическими действиями.

Сортировка семантических версий

С помощью библиотеки semver вы можете сортировать семантические версии средствами стандартной библиотеки. Например:

raw := []string{"1.2.3", "1.0", "1.0.0-alpha.1" "1.3", "2", "0.4.2",}
vs := make([]*semver.Version, len(raw))
for i, r := range raw {
    v, err := semver.NewVersion(r)
    if err != nil {
        t.Errorf("Error parsing version: %s", err)
    }

    vs[i] = v
}
sort.Sort(semver.Collection(vs))

В этом примере набор семантических версий преобразуется в экземпляры semver.Version, которые затем складываются в semver.Collection. А у semver.Collection есть все необходимое для использования со стандартной библиотекой sort. Это очень удобно для правильной сортировки pre-release информации и игнорирования мета-тегов.

Диапазоны, Ограничения и Wildcards

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

c, err := semver.NewConstraint(">= 1.2.3, < 2.0.0, != 1.4.5")
if err != nil {
    fmt.Println("Error parsing constraint:", err)
    return
}

v, err := semver.NewVersion("1.3")
if err != nil {
    fmt.Println("Error parsing version:", err)
    return
}

a := c.Check(v)
fmt.Println("Version within constraint:", a)

Для тех, кто знаком с диапазонами версий по другим языкам и тулзам, библиотека предлагает хорошо знакомую нотацию:

  • ^1.2.3 обозначает совместимость на уровне “major” версии. Это синтаксический сахар для записи “>= 1.2.3, < 2.0.0”. Используется для указания “самой свежей версии зависимости, все еще совместимой по API”.
  • ~1.2.3 обозначает совместимость на уровне “patch” версии. Это синтаксический сахар для “>= 1.2.3, < 1.3.0”. Используется для указания нужной версии с последними багфиксами, но без серьезных изменений.
  • “1.2.3 — 3.4.5” обозначает точный диапазон версий, включая начальную и конечную. Это синтаксический сахар для “>= 1.2.3, <= 3.4.5”.
  • Также библиотека поддерживает “wildcards” с помощью символов “x”, ”X” или “*”. Вы можете указать версию как “2.x”, “1.2.x” или даже как “*”. И все эти нотации можно спокойно комбинировать друг с другом.

Начните использовать семантические версии прямо сейчас

И ваши волосы станут мягкими и шелковистыми! Если в вашем проекте есть работа с версиями, то предлагаю не терять время и начать пользоваться стандартом семантического версионирования. Для Go есть описанная выше библиотека github.com/Masterminds/semver, большинству современных языков и тулчейнов тоже есть, что предложить. Особенно Node.js с npm.

Автор: Voximplant

Источник

Поделиться новостью

* - обязательные к заполнению поля