Автоматический номер версии как в файле setup.py (setuptools), так и в исходном коде? - PullRequest
37 голосов
/ 22 июля 2011

СИТУАЦИЯ:

У меня есть библиотека 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», если я изменил код после пометки.Это нормально.

ПРОБЛЕМА ЕСТЬ:

Проблема возникает, когда я хочу, чтобы этот номер версии был доступен для самой библиотеки, чтобы он мог отправить его в UserHTTP-заголовок агента как «mylib / 0.1-3-adcd».

Если я добавлю команду setup.py version, как в Как я могу получить версию, определенную в setup.py (setuptools) в моем пакете? , тогда этот version.py генерируется ПОСЛЕ создания тега, поскольку он использует тег в качестве значения.Но в этом случае мне нужно сделать еще один коммит после создания тега версии, чтобы код был согласованным.Что, в свою очередь, требует нового тега для дальнейшего связывания.

ВОПРОС:

Как разорвать этот круг зависимостей (generate-commit-tag-generateтег возьмут на -...)

Ответы [ 5 ]

29 голосов
/ 21 сентября 2011

Вы также можете отменить зависимость: поместите версию в mylib/__init__.py, проанализируйте этот файл в setup.py, чтобы получить параметр версии, и используйте git tag $ (setup.py --version) в командной строке, чтобы создатьваш тег.

git tag -a v$(python setup.py --version) -m 'description of version'

Есть ли что-нибудь более сложное, что вы хотите сделать, чего я не понял?

22 голосов
/ 22 июля 2011

Классическая проблема при игре с расширением ключевого слова ;)

Ключ в том, чтобы понять, что ваш тег является частью процесса управления релизами, а не частью процесса разработки (и управления версиями).

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

При создании пакета (который является «частью управления выпуском») вам необходимо записать эту информацию в файл, который ваша библиотека будет искать и использовать (если указанный файл существует) для своего HTTP-заголовка User-Agent.

7 голосов
/ 24 февраля 2016

Поскольку эта тема еще жива и иногда попадает в результаты поиска, я хотел бы упомянуть еще одно решение, которое впервые появилось в 2012 году и теперь более или менее пригодно для использования:

https://github.com/warner/python-versioneer

Он работает не так, как все упомянутые решения: вы добавляете теги git вручную, а библиотека (и setup.py) считывает теги и динамически создает строку версии.

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

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

4 голосов
/ 21 февраля 2016

Следуя решению О.Г.Хаза в аналогичном вопросе , я сохраняю файл _version.py, который анализирую в setup.py.Со строкой версии я делаю тэг в 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,
    ....
3 голосов
/ 26 января 2018

Идея Эрика заключалась в простом способе, на случай, если это пригодится, вот код, который я использовал (команда Фласка сделала это так):

import re
import ast

_version_re = re.compile(r'__version__\s+=\s+(.*)')

with open('app_name/__init__.py', 'rb') as f:
    version = str(ast.literal_eval(_version_re.search(
        f.read().decode('utf-8')).group(1)))

setup(
    name='app-name',
    version=version,
 .....
)
...