状况:
我有一个python库,由git控制,并与distutils / setuptools捆绑在一起。我想基于git标签自动生成版本号,包括setup.py sdist
和类似命令,以及库本身。
对于第一项任务,我可以使用git describe
或类似解决方案(请参阅How can I get the version defined in setup.py (setuptools) in my package?)。
例如,当我在标签'0.1'并且要求'setup.py sdist'时,我得到'mylib-0.1.tar.gz';或'mylib-0.1-3-abcd.tar.gz'如果我在标记后更改了代码。这很好。
问题是:
当我想让这个版本号可用于库本身时,问题就出现了,所以它可以将它作为'mylib / 0.1-3-adcd'在User-Agent HTTP头中发送。
如果我在How can I get the version defined in setup.py (setuptools) in my package?中添加setup.py version
命令,则在生成标记后生成此version.py,因为它使用标记作为值。但是在这种情况下,我需要在制作版本标记之后再进行一次提交,以使代码保持一致。反过来,这需要一个新标签进行进一步捆绑。
问题是:
如何打破这个依赖圈(generate-commit-tag-generate-commit-tag -...)?
答案 0 :(得分:29)
您还可以反转依赖项:将版本放在mylib/__init__.py
中,在setup.py中解析该文件以获取版本参数,并在命令行上使用git tag $(setup.py --version)创建你的标签。
git tag -a v$(python setup.py --version) -m 'description of version'
你还有什么比这更复杂的我还没有理解?
答案 1 :(得分:22)
使用keyword expansion进行玩弄时的经典问题;)
关键是要意识到您的标记是发布管理过程的一部分,而不是开发(及其版本控制)过程的一部分。
换句话说,您不能在开发存储库中包含发布管理数据,因为您在问题中说明了循环。
在生成程序包(即“发布管理部分”)时,您需要将该信息写入您的库将查找并使用的文件(如果所述文件存在),以用于其User-Agent HTTP标头。
答案 2 :(得分:7)
由于这个主题仍然存在并且有时会出现在搜索结果中,我想提一下最初出现在2012年的另一种解决方案,现在或多或少可以使用:
https://github.com/warner/python-versioneer
它的工作方式与所有提到的解决方案不同:手动添加git标签,库(和setup.py)读取标签,并动态构建版本字符串。
版本字符串包括最新标记,与该标记的距离,当前提交哈希,“肮脏”以及其他一些信息。它有几种不同的版本格式。
但它仍然没有所谓的“自定义构建”的分支名称;当两个分支基于相同的提交时,提交距离有时会令人困惑,因此最好标记&仅释放一个选定的分支(主)。
答案 3 :(得分:4)
在similar SO question中关注OGHaza的解决方案后,我保存了一个我在setup.py中解析的文件_version.py。使用那里的版本字符串,我在setup.py中使用git标记。然后我将setup version变量设置为版本字符串和git commit hash的组合。所以这是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 :(得分:2)
正如另一个答案中所提到的,这与发布过程有关,而与开发过程无关,因此这本身不是git
的问题,而是发布工作过程的更多情况。
一个非常简单的变体是使用它:
python setup.py egg_info -b ".`date '+%Y%m%d'`git`git rev-parse --short HEAD`" build sdist
引号之间的部分用于自定义,但是我尝试遵循典型的Fedora / RedHat软件包名称。
值得注意的是,即使egg_info暗示了与.egg的关系,实际上它也是通过工具链使用的,例如bdist_wheel,也必须在开头指定。
通常,您的发行前和发行后版本应位于setup.py或任何类型的import version.py
之外。 here详细介绍了有关版本控制和egg_info的主题。
示例:
更复杂的方法是将发布工作流程编码为Makefile,这超出了此问题的范围,但是可以找到here和{{3 }}。您会在Makefile目标和setup.py命令之间找到很好的对应点。
答案 5 :(得分:1)
Eric的想法是一个简单的方法,以防这里有用的是我使用的代码(Flask的团队就是这样做的):
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,
.....
)
答案 6 :(得分:1)
如果发现versioneer太麻烦了,可以尝试bump2version。
只需在您的库的根目录中添加一个配置文件,该文件指示包含版本号的文件在哪里,然后通过其CLI输入:
bumpversion minor
发布次要版本(否则为patch
或major
)。
还有其他标志选项和配置选项,例如自动标记存储库,您可以查看其官方文档。