Detailed tests of pypi.py
=========================

.. :doctest:

Note on test setup: we don't use the "big" setup/teardown methods here.

    >>> from zest.releaser import pypi
    >>> import pkg_resources


Parsing the configuration file
------------------------------

For pypi uploads and uploads to multiple servers, a configuration file
needs to be available:

    >>> pypi.DIST_CONFIG_FILE
    '.pypirc'

This is the default.  For testing purposes, you *can* pass in a config file's
name yourself.  We'll do that in the rest of these tests.

A missing file doesn't lead to an error:

    >>> pypiconfig = pypi.PypiConfig(config_filename='non/existing', use_setup_cfg=False)
    >>> pypiconfig.config is None
    True

There are two styles of ``.pypirc`` files.  The old one just for pypi:

    >>> pypirc_old = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_old.txt')
    >>> print(open(pypirc_old).read())
    [server-login]
    username:pipo_de_clown
    password:asjemenou
    <BLANKLINE>
    [zest.releaser]
    extra-message = [ci skip]
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_old)
    >>> pypiconfig.is_old_pypi_config()
    True
    >>> pypiconfig.is_new_pypi_config()
    False

And the new format that allows multiple uploads:

    >>> pypirc_new = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_new.txt')
    >>> print(open(pypirc_new).read())
    [distutils]
    index-servers =
        pypi
        plone.org
        mycompany
    <BLANKLINE>
    [pypi]
    username:user
    password:password
    <BLANKLINE>
    [plone.org]
    repository:http://plone.org/products
    username:ploneuser
    password:password
    <BLANKLINE>
    [mycompany]
    repository:http://my.company/products
    username:user
    password:password
    <BLANKLINE>
    [zest.releaser]
    extra-message = [ci skip]
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_new)
    >>> pypiconfig.is_old_pypi_config()
    False
    >>> pypiconfig.is_new_pypi_config()
    True

A file with both is also possible:

    >>> pypirc_both = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_both.txt')
    >>> print(open(pypirc_both).read())
    [server-login]
    username:bdfl
    password:secret
    <BLANKLINE>
    [distutils]
    index-servers =
      pypi
      local
    <BLANKLINE>
    [pypi]
    username:bdfl
    password:secret
    <BLANKLINE>
    [local]
    repository:http://localhost:8080/test/products
    username:bdfl
    password:secret
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_both)
    >>> pypiconfig.is_old_pypi_config()
    True
    >>> pypiconfig.is_new_pypi_config()
    True

Parse the new format again and query a list of distutils servers:

    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_new)
    >>> from pprint import pprint
    >>> pprint(sorted(pypiconfig.distutils_servers()))
    ['mycompany', 'plone.org', 'pypi']

If we have an old config file, the distutils server list is empty:

    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_old)
    >>> pypiconfig.distutils_servers()
    []

And with a file with both an "old" and a "new" set of sections, the pypi entry
is filtered out of the distutils servers list as that's handled by the "old"
part:

    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_both)
    >>> pprint(sorted(pypiconfig.distutils_servers()))
    ['local']


Asking for making a release or not
----------------------------------

Some people hardly ever want to make a full release of a package to
pypi; a subversion tag may be enough.  They can tell zest.releaser to
use a different default answer when it asks to make a checkout for a
release.  This means you can usually just press Enter on all questions
that zest.releaser asks.

We try to read a [zest.releaser] section, either in pypirc or
setup.cfg and look  for a ``release`` option.  We can
ask for the result like this, which by default is True:

    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_both)
    >>> pypiconfig.want_release()
    True

We have a pypirc for this:

    >>> pypirc_no_release = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_no_release.txt')
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_no_release)
    >>> pypiconfig.want_release()
    False

We can also specify to always do that checkout during a release:

    >>> pypirc_yes_release = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_yes_release.txt')
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_yes_release)
    >>> pypiconfig.want_release()
    True


Creating a wheel
----------------

When the ``wheel`` package is installed, we could create shiny new
Python wheels, next to the standard old-style source distributions.
This seems good, but not for every package.  So you have to explicitly
turn it on.

If the package is installed, we set a constant:

    >>> from zest.releaser.pypi import USE_WHEEL
    >>> USE_WHEEL
    True

We try to read a [zest.releaser] section, either in pypirc or
setup.cfg and check for a ``create-wheel`` option.  In this case we
explicitly disable checking for a setup.cfg, because when running the
tests with ``tox`` the current directory is the base directory of
zest.releaser, which now contains a setup.cfg.

We can ask for the result like this, which by default is False:

    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_both, use_setup_cfg=False)
    >>> pypiconfig.create_wheel()
    False

We have a pypirc for this where we implicitly set it to False:

    >>> pypirc_no_release = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_no_release.txt')
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_no_release, use_setup_cfg=False)
    >>> pypiconfig.create_wheel()
    False

We can also specify to always create it:

    >>> pypirc_yes_release = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_yes_release.txt')
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_yes_release, use_setup_cfg=False)
    >>> pypiconfig.create_wheel()
    True


Fixing setup.cfg
----------------

A setup.cfg file can be used to influence the release process.  This
may contain options that are not advisable in the released package but
should only be used during development.  We can clean that up.  First
we prepare a directory.

    >>> pypi.SETUP_CONFIG_FILE
    'setup.cfg'
    >>> import os
    >>> import shutil
    >>> import tempfile
    >>> tempdir = tempfile.mkdtemp()
    >>> os.chdir(tempdir)

Without a setup.cfg there is no config:

    >>> setup_config = pypi.SetupConfig()
    >>> setup_config.config is None
    True
    >>> setup_config.has_bad_commands()
    False
    >>> setup_config.fix_config()
    >>> os.path.exists(pypi.SETUP_CONFIG_FILE)
    False

Now we add a setup.cfg with some good and some bad commands:

    >>> SETUP_CFG = """
    ... [zest.releaser]
    ... release = no
    ...
    ... [egg_info]
    ... tag_build = dev
    ... tag_svn_revision = true"""
    >>> with open(pypi.SETUP_CONFIG_FILE, 'w') as f:
    ...     _ = f.write(SETUP_CFG)
    >>> setup_config = pypi.SetupConfig()
    >>> setup_config.has_bad_commands()
    True

Fixing the config also prints the new config:

    >>> setup_config.fix_config()
    [zest.releaser]
    release = no
    <BLANKLINE>
    [egg_info]
    tag_build =
    tag_svn_revision = false
    >>> os.path.exists(pypi.SETUP_CONFIG_FILE)
    True
    >>> print(''.join(open(pypi.SETUP_CONFIG_FILE).readlines()))
    [zest.releaser]
    release = no
    <BLANKLINE>
    [egg_info]
    tag_build =
    tag_svn_revision = false

We try that again with this fixed up config file as input:

    >>> setup_config = pypi.SetupConfig()
    >>> setup_config.has_bad_commands()
    False
    >>> setup_config.fix_config()
    >>> os.path.exists(pypi.SETUP_CONFIG_FILE)
    True
    >>> print(''.join(open(pypi.SETUP_CONFIG_FILE).readlines()))
    [zest.releaser]
    release = no
    <BLANKLINE>
    [egg_info]
    tag_build =
    tag_svn_revision = false


No-input mode
-------------

In some cases you want no questions asked. Zest.releaser should just do its
job without asking for versions or confirmations. You can enable this
behaviour with a ``--no-input`` commandline option, but also by adding
``no-input = yes`` to the ``[zest.releaser]`` section in ``.pypirc`` or
``setup.cfg``.

The default is False:

    >>> pypiconfig.no_input()
    False

Enable the option in ``.pypirc``:

    >>> pypirc_no_input = pkg_resources.resource_filename(
    ...     'zest.releaser.tests', 'pypirc_no_input.txt')
    >>> pypiconfig = pypi.PypiConfig(config_filename=pypirc_no_input)

Now the option should be set to True:

    >>> pypiconfig.no_input()
    True

Let's enable the option also in setup.cfg:

    >>> SETUP_CFG = """
    ... [zest.releaser]
    ... no-input = yes
    ... """
    >>> with open(pypi.SETUP_CONFIG_FILE, 'w') as f:
    ...     _ = f.write(SETUP_CFG)
    >>> pypiconfig = pypi.PypiConfig()

The option should be set to True here as well:

    >>> pypiconfig.no_input()
    True


Python version file pointer
---------------------------

In some cases you want to point at a Python file with a ``__version__`` marker
in it. For that, there's the ``python-file-with-version`` option.

The default is None:

    >>> setup_config.python_file_with_version()

Enable the option:

    >>> SETUP_CFG = """
    ... [zest.releaser]
    ... python-file-with-version = reinout/maurits.py
    ... """
    >>> with open(pypi.SETUP_CONFIG_FILE, 'w') as f:
    ...    _ = f.write(SETUP_CFG)
    >>> setup_config = pypi.SetupConfig()
    >>> setup_config.python_file_with_version()
    'reinout/maurits.py'
