mirror of
https://github.com/kennethreitz/pipenv.git
synced 2026-06-05 14:50:16 +00:00
9e0d6bc1e3
- Fix `PIPENV_PYTHON` envvar which auto-recreated environments due to `auto_envvar_prefix`, now it is not pulled from the environment automatically - Fix formatting of some news entries - Automate release via `inv release.release` (will be aliased) Signed-off-by: Dan Ryan <dan@danryan.co>
238 lines
7.7 KiB
Python
238 lines
7.7 KiB
Python
# -*- coding=utf-8 -*-
|
|
import datetime
|
|
import pathlib
|
|
import os
|
|
import re
|
|
import sys
|
|
|
|
import invoke
|
|
|
|
from parver import Version
|
|
from towncrier._builder import (
|
|
find_fragments, render_fragments, split_fragments
|
|
)
|
|
from towncrier._settings import load_config
|
|
|
|
from pipenv.__version__ import __version__
|
|
from pipenv.vendor.vistir.contextmanagers import temp_environ
|
|
|
|
from .vendoring import _get_git_root, drop_dir
|
|
|
|
|
|
VERSION_FILE = 'pipenv/__version__.py'
|
|
ROOT = pathlib.Path(".").parent.parent.absolute()
|
|
PACKAGE_NAME = "pipenv"
|
|
|
|
|
|
def log(msg):
|
|
print('[release] %s' % msg)
|
|
|
|
|
|
def get_version_file(ctx):
|
|
return _get_git_root(ctx).joinpath(VERSION_FILE)
|
|
|
|
|
|
def find_version(ctx):
|
|
version_file = get_version_file(ctx).read_text()
|
|
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",version_file, re.M)
|
|
if version_match:
|
|
return version_match.group(1)
|
|
raise RuntimeError("Unable to find version string.")
|
|
|
|
|
|
def get_history_file(ctx):
|
|
return _get_git_root(ctx).joinpath('HISTORY.txt')
|
|
|
|
|
|
def get_dist_dir(ctx):
|
|
return _get_git_root(ctx) / 'dist'
|
|
|
|
|
|
def get_build_dir(ctx):
|
|
return _get_git_root(ctx) / 'build'
|
|
|
|
|
|
def _render_log():
|
|
"""Totally tap into Towncrier internals to get an in-memory result.
|
|
"""
|
|
config = load_config(ROOT)
|
|
definitions = config['types']
|
|
fragments, fragment_filenames = find_fragments(
|
|
pathlib.Path(config['directory']).absolute(),
|
|
config['sections'],
|
|
None,
|
|
definitions,
|
|
)
|
|
rendered = render_fragments(
|
|
pathlib.Path(config['template']).read_text(encoding='utf-8'),
|
|
config['issue_format'],
|
|
split_fragments(fragments, definitions),
|
|
definitions,
|
|
config['underlines'][1:],
|
|
False, # Don't add newlines to wrapped text.
|
|
)
|
|
return rendered
|
|
|
|
|
|
@invoke.task
|
|
def release(ctx, dry_run=False):
|
|
drop_dist_dirs(ctx)
|
|
bump_version(ctx, dry_run=dry_run)
|
|
version = find_version(ctx)
|
|
tag_content = _render_log()
|
|
if dry_run:
|
|
ctx.run('towncrier --draft > CHANGELOG.draft.rst')
|
|
log('would remove: news/*')
|
|
log('would remove: CHANGELOG.draft.rst')
|
|
log(f'Would commit with message: "Release v{version}"')
|
|
else:
|
|
ctx.run('towncrier')
|
|
ctx.run("git add CHANGELOG.rst news/")
|
|
ctx.run("git rm CHANGELOG.draft.rst")
|
|
ctx.run(f'git commit -m "Release v{version}"')
|
|
|
|
tag_content = tag_content.replace('"', '\\"')
|
|
if dry_run:
|
|
log(f"Generated tag content: {tag_content}")
|
|
markdown = ctx.run("pandoc CHANGELOG.draft.rst -f rst -t markdown", hide=True).stdout.strip()
|
|
content = clean_mdchangelog(ctx, markdown)
|
|
log(f"would generate markdown: {content}")
|
|
else:
|
|
generate_markdown(ctx)
|
|
clean_mdchangelog(ctx)
|
|
ctx.run(f'git tag -a v{version} -m "Version v{version}\n\n{tag_content}"')
|
|
build_dists(ctx)
|
|
if dry_run:
|
|
dist_pattern = f'{PACKAGE_NAME.replace("-", "[-_]")}-*'
|
|
artifacts = list(ROOT.joinpath('dist').glob(dist_pattern))
|
|
filename_display = '\n'.join(f' {a}' for a in artifacts)
|
|
log(f"Would upload dists: {filename_display}")
|
|
else:
|
|
upload_dists(ctx)
|
|
bump_version(ctx, dev=True)
|
|
|
|
|
|
def drop_dist_dirs(ctx):
|
|
log('Dropping Dist dir...')
|
|
drop_dir(get_dist_dir(ctx))
|
|
log('Dropping build dir...')
|
|
drop_dir(get_build_dir(ctx))
|
|
|
|
|
|
@invoke.task
|
|
def build_dists(ctx):
|
|
drop_dist_dirs(ctx)
|
|
for py_version in ['3.6', '2.7']:
|
|
env = {'PIPENV_PYTHON': py_version}
|
|
with ctx.cd(ROOT.as_posix()), temp_environ():
|
|
executable = ctx.run("python -c 'import sys; print(sys.executable)'", hide=True).stdout.strip()
|
|
log('Building sdist using %s ....' % executable)
|
|
os.environ["PIPENV_PYTHON"] = py_version
|
|
ctx.run('pipenv install --dev', env=env)
|
|
ctx.run('pipenv run pip install -e . --upgrade --upgrade-strategy=eager', env=env)
|
|
log('Building wheel using python %s ....' % py_version)
|
|
if py_version == '3.6':
|
|
ctx.run('pipenv run python setup.py sdist bdist_wheel', env=env)
|
|
else:
|
|
ctx.run('pipenv run python setup.py bdist_wheel', env=env)
|
|
|
|
|
|
@invoke.task(build_dists)
|
|
def upload_dists(ctx, repo="pypi"):
|
|
dist_pattern = f'{PACKAGE_NAME.replace("-", "[-_]")}-*'
|
|
artifacts = list(ROOT.joinpath('dist').glob(dist_pattern))
|
|
filename_display = '\n'.join(f' {a}' for a in artifacts)
|
|
print(f'[release] Will upload:\n{filename_display}')
|
|
try:
|
|
input('[release] Release ready. ENTER to upload, CTRL-C to abort: ')
|
|
except KeyboardInterrupt:
|
|
print('\nAborted!')
|
|
return
|
|
|
|
arg_display = ' '.join(f'"{n}"' for n in artifacts)
|
|
ctx.run(f'twine upload --repository="{repo}" {arg_display}')
|
|
|
|
|
|
|
|
@invoke.task
|
|
def generate_markdown(ctx):
|
|
log('Generating markdown from changelog...')
|
|
ctx.run('pandoc CHANGELOG.rst -f rst -t markdown -o CHANGELOG.md')
|
|
|
|
|
|
@invoke.task
|
|
def generate_changelog(ctx, commit=False, draft=False):
|
|
log('Generating changelog...')
|
|
if draft:
|
|
commit = False
|
|
log('Writing draft to file...')
|
|
ctx.run('towncrier --draft > CHANGELOG.draft.rst')
|
|
else:
|
|
ctx.run('towncrier')
|
|
if commit:
|
|
log('Committing...')
|
|
ctx.run('git add CHANGELOG.rst')
|
|
ctx.run('git rm CHANGELOG.draft.rst')
|
|
ctx.run('git commit -m "Update changelog."')
|
|
|
|
|
|
@invoke.task
|
|
def clean_mdchangelog(ctx, content=None):
|
|
changelog = None
|
|
if not content:
|
|
changelog = _get_git_root(ctx) / "CHANGELOG.md"
|
|
content = changelog.read_text()
|
|
content = re.sub(r"([^\n]+)\n?\s+\[[\\]+(#\d+)\]\(https://github\.com/pypa/[\w\-]+/issues/\d+\)", r"\1 \2", content, flags=re.MULTILINE)
|
|
if changelog:
|
|
changelog.write_text(content)
|
|
else:
|
|
return content
|
|
|
|
|
|
@invoke.task
|
|
def tag_version(ctx, push=False):
|
|
version = find_version(ctx)
|
|
version = Version.parse(version)
|
|
log('Tagging revision: v%s' % version.normalize())
|
|
ctx.run('git tag v%s' % version.normalize())
|
|
if push:
|
|
log('Pushing tags...')
|
|
ctx.run('git push origin master')
|
|
ctx.run('git push --tags')
|
|
|
|
|
|
@invoke.task
|
|
def bump_version(ctx, dry_run=False, dev=False, pre=False, tag=None, commit=False):
|
|
current_version = Version.parse(__version__)
|
|
today = datetime.date.today()
|
|
tomorrow = today + datetime.timedelta(days=1)
|
|
next_month = datetime.date.today().replace(month=today.month+1, day=1)
|
|
next_year = datetime.date.today().replace(year=today.year+1, month=1, day=1)
|
|
if pre and not tag:
|
|
print('Using "pre" requires a corresponding tag.')
|
|
return
|
|
if not (dev or pre or tag):
|
|
new_version = current_version.replace(release=today.timetuple()[:3]).clear(pre=True, dev=True)
|
|
if pre and dev:
|
|
raise RuntimeError("Can't use 'pre' and 'dev' together!")
|
|
if dev or pre:
|
|
new_version = current_version.replace(release=tomorrow.timetuple()[:3]).clear(pre=True, dev=True)
|
|
if dev:
|
|
new_version = new_version.bump_dev()
|
|
else:
|
|
new_version = new_version.bump_pre(tag=tag)
|
|
log('Updating version to %s' % new_version.normalize())
|
|
version = find_version(ctx)
|
|
log('Found current version: %s' % version)
|
|
if dry_run:
|
|
log('Would update to: %s' % new_version.normalize())
|
|
else:
|
|
log('Updating to: %s' % new_version.normalize())
|
|
version_file = get_version_file(ctx)
|
|
file_contents = version_file.read_text()
|
|
version_file.write_text(file_contents.replace(version, str(new_version.normalize())))
|
|
if commit:
|
|
ctx.run('git add {0}'.format(version_file.as_posix()))
|
|
log('Committing...')
|
|
ctx.run('git commit -s -m "Bumped version."')
|