Skip to content

Commit

Permalink
[Release] generate documentation, build distribution, test distributi…
Browse files Browse the repository at this point in the history
…ons (and upload and then test them)
  • Loading branch information
MinchinWeb committed Sep 1, 2015
1 parent fd3f212 commit 60f2426
Showing 1 changed file with 152 additions and 33 deletions.
185 changes: 152 additions & 33 deletions make_release.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''Eventaully, this file will execute the necessary steps.
'''Eventaully, this file will execute the necessary steps.
For now, it just prints what they are.'''

import os
Expand All @@ -10,18 +10,24 @@

import colorama
import semantic_version
from semantic_version import Version
from colorama import Fore, Style
from isort import SortImports
from minchin import text
from datetime import datetime

# also requires:
# - green
# - pip
# - setuptools
# - wheel
#
# assumes:
# - git on commandline
# - tests written for green
# - green available on command line
# - a valid `.pypirc` file with credentials for TestPyPI and PyPI
# - your project is already registered on TestPyPi and PyPI

__version__ = "0.1.0"

Expand All @@ -34,14 +40,26 @@ def here_directory():
return(Path.cwd())


def module_name():
return("colourettu")


def source_directory():
return(here_directory() / "colourettu")
return(here_directory() / module_name())


def test_directory():
return(here_directory() / 'tests')


def doc_directory():
return(here_directory() / 'docs')


def dist_directory():
return(here_directory() / 'dist')


def version_file():
return(source_directory() / "__init__.py")

Expand All @@ -50,6 +68,34 @@ def changelog_file():
return(here_directory() / 'docs' / "changelog.rst")


def other_dependancies(server, environment):
"""Installs things that need to be in place before installing the main package"""
server = server.lower()
# Pillow is not on TestPyPI
if server is "local":
pass
elif server in ["testpypi", "pypitest"]:
print(" **Install Pillow**")
subprocess.call([environment + '\\Scripts\\pip.exe', 'install', 'Pillow'], shell=True)
elif server is "pypi":
pass
else:
print(" **Nothing more to install**")


def server_url(server_name):
server_name = server_name.lower()
if server_name in ["testpypi", "pypitest"]:
return(r"https://testpypi.python.org/pypi")
elif server_name in ["pypi", ]:
return(r"https://pypi.python.org/pypi")
else:
# we really should throw an error here...
return()

# //-------------------------------------------------------------------------//


def git_check():
"""Check for uncomitted changes"""
git_status = subprocess.check_output(['git', 'status', '--porcelain'])
Expand All @@ -70,15 +116,15 @@ def sort_imports(my_dir):

def run_tests():
"""Run tests"""
text.clock_on_right('Run tests')
test_status = subprocess.check_call(['green', str(test_directory()), '-vv'])
if test_status is not 0:
exit(Fore.RED + 'Please make all tests pass to continue')


def update_version_number(update_level='patch'):
"""Update version number"""
text.clock_on_right('Update version number')
"""Update version number
Returns a semantic_version object"""

"""Find current version"""
temp_file = version_file().parent / ("~" + version_file().name)
Expand All @@ -89,10 +135,10 @@ def update_version_number(update_level='patch'):
if version_matches:
bare_version_str = version_matches.groups(0)[0]
if semantic_version.validate(bare_version_str):
current_version = semantic_version.Version(bare_version_str)
current_version = Version(bare_version_str)
print("{}Current version is {}".format(" "*4, current_version))
else:
current_version = semantic_version.Version.coerce(bare_version_str)
current_version = Version.coerce(bare_version_str)
if not text.query_yes_quit("{}I think the version is {}. Use it?".format(" "*4, current_version), default="yes"):
exit(Fore.RED + 'Please set an initial version number to continue')

Expand Down Expand Up @@ -122,7 +168,9 @@ def update_version_number(update_level='patch'):


def add_release_to_changelog(version):
"""Add release line at the top of the first list it finds"""
"""Add release line at the top of the first list it finds
Assumes your changelog in managed with `releases`"""
temp_file = changelog_file().parent / ("~" + changelog_file().name)
now = datetime.today()
release_added = False
Expand All @@ -147,29 +195,58 @@ def add_release_to_changelog(version):
os.remove(str(temp_file))


def run_sphinx():
"""Runs Sphinx via it's `make html` command"""
old_dir = here_directory()
os.chdir(str(doc_directory()))
doc_status = subprocess.check_call(['make', 'html'], shell=True)
os.chdir(str(old_dir)) # go back to former working directory
if doc_status is not 0:
exit(Fore.RED + 'Something broke generating your documentation...')


def build_distribution():
build_status = subprocess.check_call(['python', 'setup.py', 'sdist', 'bdist_egg', 'bdist_wheel'])
if build_status is not 0:
exit(Fore.RED + 'Something broke tyring to package your code...')


def check_local_install(version, ext, server="local"):
all_files = list(dist_directory().glob('*.{}'.format(ext)))
the_file = all_files[0]
for f in all_files[1:]:
if f.stat().st_mtime > the_file.stat().st_mtime:
the_file = f

environment = 'env-{}-{}-{}'.format(version, ext, server)
if server == "local":
pass
else:
# upload to server
print(" **Uploading**")
subprocess.call(['twine', 'upload', str(the_file), '-r', server])

if (here_directory() / environment).exists():
shutil.rmtree(environment) # remove directory if it exists
subprocess.call(['virtualenv', environment])
if server == "local":
subprocess.call([environment + '\\Scripts\\pip.exe', 'install', str(the_file)], shell=True)
else:
other_dependancies(server, environment)
print(" **Install from server**")
subprocess.call([environment + '\\Scripts\\pip.exe', 'install', '-i', server_url(server), module_name() + "==" + str(version)], shell=True)
print(" **Test version of install package**")
test_version = subprocess.check_output([environment + '\\Scripts\\python.exe', '-c', "exec(\"\"\"import {0}\\nprint({0}.__version__)\\n\"\"\")".format(module_name())], shell=True)
test_version = test_version.decode('ascii').strip()
# print(test_version, type(test_version), type(expected_version))
if (Version(test_version) == version):
print('{}{} install {} works!{}'.format(Fore.GREEN, server, ext, Style.RESET_ALL))
else:
exit('{}{} install {} broken{}'.format(Fore.RED, server, ext, Style.RESET_ALL))


def print_all_steps():
print('Add release to documenation')
print('Update documenation')
print(' cd docs')
print(' make html')
print(' index.html')
print(' cd ..')
print('Build distribution')
print(' python -m pip install pip -U')
print(' pip install setuptools wheel twine -U')
print(' python setup.py sdist bdist_egg bdist_wheel')
print('Test distribution')
# see https://hynek.me/articles/sharing-your-labor-of-love-pypi-quick-and-dirty/
# use `vex` for virtual envs?
print('Push to test PyPI')
print(' python setup.py sdist upload -r pypitest')
print(' pip install -i https://testpypi.python.org/pypi [package-name]')
print(' everything working?')
print('Push to real PyPI')
print(' python setup.py sdist upload -r pypi')
print(' python setup.py bdist_wheel upload -r pypi')
print(' everything working??')
print('Tag release')
print(' tag v(version number)')
print(' push tag')
Expand All @@ -179,31 +256,73 @@ def print_all_steps():
print(' git add -a')
print(' git commit -m "Documentation updated!"')
print(' cd ..\colourettu')
print('Push to git repo')
print('Push to git repo, including tags')

# swtich to twine https://pypi.python.org/pypi/twine/
# twine upload dist/*

# //-------------------------------------------------------------------------//


def main():
colorama.init()
text.title("Minchin 'Make Release' for Python v{}".format(__version__))
print()
text.subtitle("Configuration")
print("base dir -> {}".format(here_directory()))
print("source -> .\{}\\".format(source_directory().relative_to(here_directory())))
print("test dir -> .\{}\\".format(test_directory().relative_to(here_directory())))
print("doc dir -> .\{}\\".format(doc_directory().relative_to(here_directory())))
print("version file -> .\{}".format(version_file().relative_to(here_directory())))
print()

print()
text.subtitle("Git -- Clean directory?")
# git_check()
# text.clock_on_right('Sort import statements')

print()
text.subtitle("Sort Import Statements")
# sort_imports(source_directory())
# sort_imports(test_directory())

print()
text.subtitle("Run Tests")
# run_tests()
new_version = update_version_number('patch')
add_release_to_changelog(new_version)

print()
text.subtitle("Update Version Number")
# new_version = update_version_number('patch')
new_version = update_version_number('prerelease')

print()
text.subtitle("Add Release to Changelog")
# add_release_to_changelog(new_version)

print()
text.subtitle("Build Documentation")
# run_sphinx()

print()
text.subtitle("Build Distributions")
build_distribution()

# for server in ["local", "testpypi", "pypi"]:
for server in ["testpypi"]:
for file_format in ["zip", "whl"]:
print()
text.subtitle("Test {} Build {}".format(file_format, server))
check_local_install(new_version, file_format, server)
# tests will pass if the local version of colourettu can be imported
# source files should be moved to a 'src' directory, but this will require
# the module to be properly installed to run tests, generate docs, etc.
#
# uploads -- you cannot upload a file with the same name. Consider adding
# build information to version number to allow retries updating...
#
# registering -- does not attempt

# after everything is done
update_version_number('prerelease')
# update_version_number('prerelease')

if __name__ == '__main__':
main()

0 comments on commit 60f2426

Please sign in to comment.