Автоматический номер версии как в setup.py(setuptools) И в исходном коде?
СИТУАЦИЯ:
У меня есть библиотека python, которая управляется git и в комплекте с distutils/setuptools. И я хочу автоматически генерировать номер версии на основе тегов git, как для setup.py sdist
, так и для отдельных команд, а также для самой библиотеки.
Для первой задачи я могу использовать git describe
или аналогичные решения (см. Как получить версию, определенную в setup.py(setuptools) в моем пакете?).
И когда, например, я нахожусь в теге "0,1" и вызывается "setup.py sdist", я получаю "mylib-0.1.tar.gz"; или "mylib-0.1-3-abcd.tar.gz", если я изменил код после тегов. Это нормально.
ПРОБЛЕМА:
Проблема возникает, когда я хочу, чтобы этот номер версии был доступен для самой библиотеки, поэтому он мог отправить ее в HTTP-заголовке User-Agent как "mylib/0.1-3-adcd".
Если я добавлю команду setup.py version
, как в Как я могу получить версию, определенную в setup.py(setuptools) в моем пакете?, то эта версия .ppy генерируется ПОСЛЕ создания тега, поскольку он использует тег в качестве значения. Но в этом случае мне нужно сделать еще одну фиксацию после того, как тег версии сделан, чтобы сделать код согласованным. Который, по очереди, требует нового тега для дальнейшего связывания.
ВОПРОС:
Как разбить этот круг зависимостей (generate-commit-tag-generate-commit-tag -...)?
Ответы
Ответ 1
Вы также можете изменить зависимость: поместите версию в mylib/__init__.py
, проанализируйте этот файл в файле setup.py, чтобы получить параметр версии, и используйте git tag $(setup.py -version) в командной строке для создания вашего тега.
git tag -a v$(python setup.py --version) -m 'description of version'
Есть ли что-то более сложное, что вы хотите сделать, что я не понял?
Ответ 2
Классическая проблема при использовании расширения ключевых слов;)
Ключ должен понять, что ваш тег является частью процесса управления выпуском, а не частью процесса разработки (и управления версиями).
Другими словами, вы не можете включать данные управления релизами в репозиторий разработки, из-за цикла, который вы проиллюстрируете в своем вопросе.
При создании пакета (который является "частью управления версиями" ) вам необходимо записать эту информацию в файл, который ваша библиотека будет искать и использовать (если указанный файл существует) для своего HTTP-заголовка User-Agent.
Ответ 3
Следуя решению OGHaza в аналогичный вопрос SO, я сохраняю файл _version.py, который я анализирую в setup.py. С помощью строки версии оттуда, тег git в setup.py. Затем я установил переменную версии установки в комбинацию строки версии плюс хэш-код git commit. Итак, вот соответствующая часть setup.py:
from setuptools import setup, find_packages
from codecs import open
from os import path
import subprocess
here = path.abspath(path.dirname(__file__))
import re, os
VERSIONFILE=os.path.join(here,"_version.py")
verstrline = open(VERSIONFILE, "rt").read()
VSRE = r"^__version__ = ['\"]([^'\"]*)['\"]"
mo = re.search(VSRE, verstrline, re.M)
if mo:
verstr = mo.group(1)
else:
raise RuntimeError("Unable to find version string in %s." % (VERSIONFILE,))
if os.path.exists(os.path.join(here, '.git')):
cmd = 'git rev-parse --verify --short HEAD'
git_hash = subprocess.check_output(cmd)
# tag git
gitverstr = 'v' + verstr
tags = subprocess.check_output('git tag')
if not gitverstr in tags:
cmd = 'git tag -a %s %s -m "tagged by setup.py to %s"' % (gitverstr, git_hash, verstr)
subprocess.check_output(cmd)
# use the git hash in the setup
verstr += ', git hash: %s' % git_hash
setup(
name='a_package',
version = verstr,
....
Ответ 4
Поскольку эта тема все еще жива и иногда попадает на результаты поиска, я хотел бы упомянуть еще одно решение, которое впервые появилось в 2012 году и теперь более или менее пригодно для использования:
https://github.com/warner/python-versioneer
Он работает по-разному, чем все упомянутые решения: вы добавляете теги git вручную, а библиотека (и setup.py) читает теги и динамически строит строку версии.
В строке версии содержится последний тег, расстояние от этого тега, текущий хеш-фиксация, "грязность" и другая информация. Он имеет несколько разных форматов.
Но у него по-прежнему нет имени ветки для так называемых "пользовательских сборок"; и расстояние фиксации иногда может сбивать с толку, когда две ветки основаны на одной и той же фиксации, поэтому лучше пометить и отпустить только одну выбранную ветвь (мастер).