From 9973511c541d7e9c9f25a919c4a187e2cae66f78 Mon Sep 17 00:00:00 2001 From: JinWang An Date: Mon, 28 Dec 2020 13:45:41 +0900 Subject: [PATCH] Imported Upstream version 4.0.0 --- AUTHORS | 7 + ChangeLog | 48 ++ PKG-INFO | 19 +- README.rst | 8 +- doc/source/conf.py | 22 +- .../{testing.rst => contributor/index.rst} | 9 + doc/source/index.rst | 551 +----------------- doc/source/reference/index.rst | 8 + doc/source/{ => user}/compatibility.rst | 0 doc/source/user/features.rst | 312 ++++++++++ doc/source/{ => user}/history.rst | 2 +- doc/source/user/index.rst | 12 + doc/source/{ => user}/packagers.rst | 8 +- doc/source/{ => user}/semver.rst | 0 doc/source/user/using.rst | 412 +++++++++++++ pbr.egg-info/PKG-INFO | 19 +- pbr.egg-info/SOURCES.txt | 23 +- pbr/builddoc.py | 56 +- pbr/core.py | 122 ++-- pbr/packaging.py | 83 ++- pbr/testr_command.py | 8 +- pbr/tests/test_hooks.py | 28 - pbr/tests/test_packaging.py | 154 ++++- pbr/tests/test_setup.py | 115 ---- pbr/tests/test_util.py | 8 +- pbr/tests/test_version.py | 13 + pbr/tests/testpackage/setup.cfg | 9 +- pbr/tests/testpackage/test-requirements.txt | 1 + pbr/util.py | 155 +---- pbr/version.py | 1 + ...ate-pyN-requirements-364655c38fa5b780.yaml | 5 + ...str-nose-integration-56e3e11248d946fc.yaml | 10 + ...remove-command-hooks-907d9c2325f306ca.yaml | 6 + .../notes/v_version-457b38c8679c5868.yaml | 5 + releasenotes/source/conf.py | 53 ++ releasenotes/source/index.rst | 8 + releasenotes/source/unreleased.rst | 5 + setup.cfg | 10 +- test-requirements.txt | 17 +- tools/tox_install.sh | 30 - tools/tox_releasenotes.sh | 28 + tox.ini | 15 +- 42 files changed, 1399 insertions(+), 1006 deletions(-) rename doc/source/{testing.rst => contributor/index.rst} (92%) create mode 100644 doc/source/reference/index.rst rename doc/source/{ => user}/compatibility.rst (100%) create mode 100644 doc/source/user/features.rst rename doc/source/{ => user}/history.rst (62%) create mode 100644 doc/source/user/index.rst rename doc/source/{ => user}/packagers.rst (96%) rename doc/source/{ => user}/semver.rst (100%) create mode 100644 doc/source/user/using.rst create mode 100644 releasenotes/notes/deprecate-pyN-requirements-364655c38fa5b780.yaml create mode 100644 releasenotes/notes/deprecate-testr-nose-integration-56e3e11248d946fc.yaml create mode 100644 releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml create mode 100644 releasenotes/notes/v_version-457b38c8679c5868.yaml create mode 100644 releasenotes/source/conf.py create mode 100644 releasenotes/source/index.rst create mode 100644 releasenotes/source/unreleased.rst delete mode 100755 tools/tox_install.sh create mode 100755 tools/tox_releasenotes.sh diff --git a/AUTHORS b/AUTHORS index 17edd01..542e223 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,6 +3,7 @@ Akihiro Motoki Alex Gaynor Alexander Makarov Alfredo Moralejo +Andreas Jaeger Andreas Jaeger Andrew Bogott Angus Salkeld @@ -37,6 +38,7 @@ Eric Windisch Erik M. Bray Eugene Kirpichov Florian Wilhelm +Gaetan Semet Gage Hugo Gary Kotton Giampaolo Lauria @@ -47,8 +49,10 @@ Ionuț Arțăriși James E. Blair James Polley Jason Kölker +Jason R. Coombs Jay Pipes Jeremy Stanley +Joe D'Andrea Joe Gordon Joe Gordon Joe Heck @@ -80,6 +84,7 @@ Octavian Ciuhandu Ondřej Nový Paul Belanger Rajaram Mallya +Rajath Agasthya Ralf Haferkamp Randall Nortman Rick Harris @@ -117,6 +122,7 @@ YAMAMOTO Takashi Yaguang Tang Yuriy Taraday Zhongyue Luo +Zuul alexpilotti cbjchen@cn.ibm.com dineshbhor @@ -125,4 +131,5 @@ lifeless melanie witt nizam weiweigu +zhangyangyang zhangyanxian diff --git a/ChangeLog b/ChangeLog index 405660f..bbc9c10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,58 @@ CHANGES ======= +4.0.0 +----- + +* builddoc: Treat '[pbr] autodoc\_tree\_excludes' as a multi-line opt +* update parse test to use reliable comparison +* Make docs on env vars a little clearer +* Updated from global requirements +* Updated from global requirements +* future-proof invocation of apidoc +* emit warning correctly +* Updated from global requirements +* deprecations: Deprecate support for '-py{N}' requirements +* doc: Minor rework of usage doc +* doc: Rework features doc +* Support v version +* Deprecate testr and nose integration +* tests: Increase coverage of requirements parsing +* trivial: Move packaging tests to test\_packaging +* Put test-requirements into an extra named 'test' +* Support Description-Content-Type metadata +* Avoid tox\_install.sh for constraints support +* Test on Python 3.6 +* Support PEP 345 Project-URL metadata +* Remove setting of version/release from releasenotes +* Updated from global requirements +* Use 'build\_reno' setuptools extension if available +* Remove unnecessary 'if True' +* Discover Distribution through the class hierarchy +* Add reno for release notes management +* Remove support for command hooks +* Remove dead code +* Deprecate support for Sphinx < 1.6 +* builddoc: Use '[sphinx\_build] builders' with Sphinx < 1.6 +* Remove win32/nt checks for wrapper script gen +* Updated from global requirements +* Remove py26 support +* Updated from global requirements +* Updated from global requirements +* Updated from global requirements +* Update URLs in documents according to document migration +* Updated from global requirements +* gitignore: Ignore .venv +* switch from oslosphinx to openstackdocstheme +* Trivial: Fix docstring +* turn on warning-as-error flag for doc build +* rearrange existing documentation using the new standard layout + 3.1.1 ----- * Restore previous IP binding +* docs: Don't specify pbr version in 'setup.py' 3.1.0 ----- diff --git a/PKG-INFO b/PKG-INFO index 8bde250..1339ea8 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,11 +1,14 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: pbr -Version: 3.1.1 +Version: 4.0.0 Summary: Python Build Reasonableness -Home-page: http://docs.openstack.org/developer/pbr/ +Home-page: https://docs.openstack.org/pbr/latest/ Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: UNKNOWN +Project-URL: Bug Tracker, https://bugs.launchpad.net/pbr/ +Project-URL: Documentation, https://docs.openstack.org/pbr/ +Project-URL: Source Code, https://git.openstack.org/cgit/openstack-dev/pbr/ Description: Introduction ============ @@ -39,10 +42,10 @@ Description: Introduction them as quickly as possible. * License: Apache License, Version 2.0 - * Documentation: http://docs.openstack.org/developer/pbr - * Source: http://git.openstack.org/cgit/openstack-dev/pbr - * Bugs: http://bugs.launchpad.net/pbr - * Change Log: https://docs.openstack.org/developer/pbr/history.html + * Documentation: https://docs.openstack.org/pbr/latest/ + * Source: https://git.openstack.org/cgit/openstack-dev/pbr + * Bugs: https://bugs.launchpad.net/pbr + * Change Log: https://docs.openstack.org/pbr/latest/user/history.html .. _d2to1: https://pypi.python.org/pypi/d2to1 .. _distutils2: https://pypi.python.org/pypi/Distutils2 @@ -60,9 +63,9 @@ Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Description-Content-Type: text/x-rst; charset=UTF-8 diff --git a/README.rst b/README.rst index 4c4ebba..9c1df73 100644 --- a/README.rst +++ b/README.rst @@ -31,10 +31,10 @@ when that library itself will alter how the setup is processed. As Metadata them as quickly as possible. * License: Apache License, Version 2.0 -* Documentation: http://docs.openstack.org/developer/pbr -* Source: http://git.openstack.org/cgit/openstack-dev/pbr -* Bugs: http://bugs.launchpad.net/pbr -* Change Log: https://docs.openstack.org/developer/pbr/history.html +* Documentation: https://docs.openstack.org/pbr/latest/ +* Source: https://git.openstack.org/cgit/openstack-dev/pbr +* Bugs: https://bugs.launchpad.net/pbr +* Change Log: https://docs.openstack.org/pbr/latest/user/history.html .. _d2to1: https://pypi.python.org/pypi/d2to1 .. _distutils2: https://pypi.python.org/pypi/Distutils2 diff --git a/doc/source/conf.py b/doc/source/conf.py index f0a78ec..cc7f4b3 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -8,14 +8,19 @@ sys.path.insert(0, os.path.abspath('../..')) # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc'] -# make oslosphinx optional to not increase the needed dependencies +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo'] +# make openstackdocstheme optional to not increase the needed dependencies try: - import oslosphinx + import openstackdocstheme + extensions.append('openstackdocstheme') except ImportError: - pass -else: - extensions.append('oslosphinx') + openstackdocstheme = None + +# openstackdocstheme options +repository_name = 'openstack/pbr' +bug_project = 'pbr' +bug_tag = '' +html_last_updated_fmt = '%Y-%m-%d %H:%M' # autodoc generation is a bit aggressive and a nuisance when doing heavy # text edit cycles. @@ -50,7 +55,10 @@ exclude_trees = [] # The theme to use for HTML and HTML Help pages. Major themes that come with # Sphinx are currently 'default' and 'sphinxdoc'. -html_theme = 'default' +if openstackdocstheme is not None: + html_theme = 'openstackdocs' +else: + html_theme = 'default' # Output file base name for HTML help builder. htmlhelp_basename = '%sdoc' % project diff --git a/doc/source/testing.rst b/doc/source/contributor/index.rst similarity index 92% rename from doc/source/testing.rst rename to doc/source/contributor/index.rst index eccb1e3..b7b4a75 100644 --- a/doc/source/testing.rst +++ b/doc/source/contributor/index.rst @@ -1,3 +1,12 @@ +============== + Contributing +============== + +Basic Details +============= + +.. include:: ../../../CONTRIBUTING.rst + Running the Tests for pbr ========================= diff --git a/doc/source/index.rst b/doc/source/index.rst index 4ff2d7a..60cd461 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -2,555 +2,36 @@ pbr - Python Build Reasonableness ================================= -A library for managing setuptools packaging needs in a consistent manner. +A library for managing *setuptools* packaging needs in a consistent manner. -`pbr` reads and then filters the `setup.cfg` data through a setup hook to -fill in default values and provide more sensible behaviors, and then feeds -the results in as the arguments to a call to `setup.py` - so the heavy -lifting of handling python packaging needs is still being done by -`setuptools`. +*pbr* reads and then filters the ``setup.cfg`` data through a setup hook to +fill in default values and provide more sensible behaviors, and then feeds the +results in as the arguments to a call to ``setup.py`` - so the heavy lifting of +handling Python packaging needs is still being done by *setuptools*. -Note that we don't support the `easy_install` aspects of setuptools: while -we depend on setup_requires, for any install_requires we recommend that they -be installed prior to running `setup.py install` - either by hand, or by using -an install tool such as `pip`. +Note that we don't support the ``easy_install`` aspects of *setuptools*: while +we depend on ``setup_requires``, for any ``install_requires`` we recommend that +they be installed prior to running ``setup.py install`` - either by hand, or by +using an install tool such as *pip*. -What It Does -============ - -PBR can and does do a bunch of things for you: +*pbr* can and does do a bunch of things for you: * **Version**: Manage version number based on git revisions and tags * **AUTHORS**: Generate AUTHORS file from git log * **ChangeLog**: Generate ChangeLog from git log * **Manifest**: Generate a sensible manifest from git files and some standard files -* **Sphinx Autodoc**: Generate autodoc stub files for your whole module * **Requirements**: Store your dependencies in a pip requirements file * **long_description**: Use your README file as a long_description * **Smart find_packages**: Smartly find packages under your root package +* **Sphinx Autodoc**: Generate autodoc stub files for your whole module -Version -------- - -Versions can be managed two ways - postversioning and preversioning. -Postversioning is the default, and preversioning is enabled by setting -``version`` in the setup.cfg ``metadata`` section. In both cases version -strings are inferred from git. - -If the currently checked out revision is tagged, that tag is used as -the version. - -If the currently checked out revision is not tagged, then we take the -last tagged version number and increment it to get a minimum target -version. - -We then walk git history back to the last release. Within each commit we look -for a Sem-Ver: pseudo header, and if found parse it looking for keywords. -Unknown symbols are not an error (so that folk can't wedge pbr or break their -tree), but we will emit an info level warning message. Known symbols: -``feature``, ``api-break``, ``deprecation``, ``bugfix``. A missing -Sem-Ver line is equivalent to ``Sem-Ver: bugfix``. The ``bugfix`` symbol causes -a patch level increment to the version. The ``feature`` and ``deprecation`` -symbols cause a minor version increment. The ``api-break`` symbol causes a -major version increment. - -If postversioning is in use, we use the resulting version number as the target -version. - -If preversioning is in use we check that the version set in the metadata -section of `setup.cfg` is greater than the version we infer using the above -method. If the inferred version is greater than the preversioning value we -raise an error, otherwise we use the version from `setup.cfg` as the target. - -We then generate dev version strings based on the commits since the last -release and include the current git sha to disambiguate multiple dev versions -with the same number of commits since the release. - -.. note:: - - `pbr` expects git tags to be signed for use in calculating versions - -The versions are expected to be compliant with :doc:`semver`. - -The ``version.SemanticVersion`` class can be used to query versions of a -package and present it in various forms - ``debian_version()``, -``release_string()``, ``rpm_string()``, ``version_string()``, or -``version_tuple()``. - -AUTHORS and ChangeLog ---------------------- - -Why keep an `AUTHORS` or a `ChangeLog` file when git already has all of the -information you need? `AUTHORS` generation supports filtering/combining based -on a standard `.mailmap` file. - -Manifest --------- - -Just like `AUTHORS` and `ChangeLog`, why keep a list of files you wish to -include when you can find many of these in git. `MANIFEST.in` generation -ensures almost all files stored in git, with the exception of `.gitignore`, -`.gitreview` and `.pyc` files, are automatically included in your -distribution. In addition, the generated `AUTHORS` and `ChangeLog` files are -also included. In many cases, this removes the need for an explicit -'MANIFEST.in' file - -Sphinx Autodoc --------------- - -Sphinx can produce auto documentation indexes based on signatures and -docstrings of your project but you have to give it index files to tell it -to autodoc each module: that's kind of repetitive and boring. PBR will scan -your project, find all of your modules, and generate all of the stub files for -you. - -Sphinx documentation setups are altered to generate man pages by default. They -also have several pieces of information that are known to setup.py injected -into the sphinx config. - -See the pbr_ section for details on configuring your project for autodoc. - -Requirements ------------- - -You may not have noticed, but there are differences in how pip -`requirements.txt` files work and how distutils wants to be told about -requirements. The pip way is nicer because it sure does make it easier to -populate a virtualenv for testing or to just install everything you need. -Duplicating the information, though, is super lame. To solve this issue, `pbr` -will let you use `requirements.txt`-format files to describe the requirements -for your project and will then parse these files, split them up appropriately, -and inject them into the `install_requires`, `tests_require` and/or -`dependency_links` arguments to `setup`. Voila! - -You can also have a requirement file for each specific major version of Python. -If you want to have a different package list for Python 3 then just drop a -`requirements-py3.txt` and it will be used instead. - -Finally, it is possible to specify groups of optional dependencies, or -`"extra" requirements`_, in your `setup.cfg` rather than `setup.py`. - -long_description ----------------- - -There is no need to maintain two long descriptions- and your README file is -probably a good long_description. So we'll just inject the contents of your -README.rst, README.txt or README file into your empty long_description. Yay -for you. - -Usage -===== - -`pbr` is a setuptools plugin and so to use it you must use setuptools and call -``setuptools.setup()``. While the normal setuptools facilities are available, -pbr makes it possible to express them through static data files. - -.. _setup_py: - -setup.py +Contents -------- -`pbr` only requires a minimal `setup.py` file compared to a standard setuptools -project. This is because most configuration is located in static configuration -files. This recommended minimal `setup.py` file should look something like this:: - - #!/usr/bin/env python - - from setuptools import setup - - setup( - setup_requires=['pbr>=1.9', 'setuptools>=17.1'], - pbr=True, - ) - -.. note:: - - It is necessary to specify ``pbr=True`` to enabled `pbr` functionality. - -.. note:: - - While one can pass any arguments supported by setuptools to `setup()`, - any conflicting arguments supplied in `setup.cfg` will take precedence. - -setup.cfg ---------- - -The `setup.cfg` file is an ini-like file that can mostly replace the `setup.py` -file. It is based on the distutils2_ `setup.cfg` file. A simple sample can be -found in `pbr`'s own `setup.cfg` (it uses its own machinery to install -itself):: - - [metadata] - name = pbr - author = OpenStack Foundation - author-email = openstack-dev@lists.openstack.org - summary = OpenStack's setup automation in a reusable form - description-file = README - home-page = https://launchpad.net/pbr - license = Apache-2 - classifier = - Development Status :: 4 - Beta - Environment :: Console - Environment :: OpenStack - Intended Audience :: Developers - Intended Audience :: Information Technology - License :: OSI Approved :: Apache Software License - Operating System :: OS Independent - Programming Language :: Python - keywords = - setup - distutils - - [files] - packages = - pbr - data_files = - etc/pbr = etc/* - etc/init = - pbr.packaging.conf - pbr.version.conf - - [entry_points] - console_scripts = - pbr = pbr.cmd:main - pbr.config.drivers = - plain = pbr.cfg.driver:Plain - -`pbr` provides its own section in these documents, ostensibly called ``pbr``, -and provides a custom version of Sphinx's ``build_sphinx`` section. Most other -sections are provided by setuptools and may influence either the build itself -or the output of various `setuptools commands`__. The remaining sections are -provided by libraries that provide setuptools extensions, such as -``extract_mesages`` (provided by `Babel`__). Some of these are described below. - -__ https://setuptools.readthedocs.io/en/latest/setuptools.html#command-reference -__ http://babel.pocoo.org/en/latest/setup.html -__ http://www.sphinx-doc.org/en/stable/setuptools.html - -.. note:: - - Comments may be used in `setup.cfg`, however all comments should start with - a `#` and may be on a single line, or in line, with at least one white space - character immediately preceding the `#`. Semicolons are not a supported - comment delimiter. For instance:: - - [section] - # A comment at the start of a dedicated line - key = - value1 # An in line comment - value2 - # A comment on a dedicated line - value3 - -files -~~~~~ - -The ``files`` section defines the install location of files in the package -using three fundamental keys: ``packages``, ``namespace_packages``, and -``data_files``. - -``packages`` - - A list of top-level packages that should be installed. The behavior of - packages is similar to ``setuptools.find_packages`` in that it recurses the - python package hierarchy below the given top level and installs all of it. If - ``packages`` is not specified, it defaults to the value of the ``name`` field - given in the ``[metadata]`` section. - -``namespace_packages`` - - Similar to ``packages``, but is a list of packages that provide namespace - packages. - -``data_files`` - - A list of files to be installed. The format is an indented block that - contains key value pairs which specify target directory and source file to - install there. More than one source file for a directory may be indicated - with a further indented list. Source files are stripped of leading - directories. Additionally, `pbr` supports a simple file globbing syntax for - installing entire directory structures, thus:: - - [files] - data_files = - etc/pbr = etc/pbr/* - etc/neutron = - etc/api-paste.ini - etc/dhcp-agent.ini - etc/init.d = neutron.init - - will result in `/etc/neutron` containing `api-paste.ini` and `dhcp-agent.ini`, - both of which pbr will expect to find in the `etc` directory in the root of - the source tree. Additionally, `neutron.init` from that dir will be installed - in `/etc/init.d`. All of the files and directories located under `etc/pbr` in - the source tree will be installed into `/etc/pbr`. - - Note that this behavior is relative to the effective root of the environment - into which the packages are installed, so depending on available permissions - this could be the actual system-wide `/etc` directory or just a top-level - `etc` subdirectory of a virtualenv. - -pbr -~~~ - -The ``pbr`` section controls `pbr` specific options and behaviours. - -``autodoc_tree_index_modules`` - - A boolean option controlling whether `pbr` should generate an index of - modules using `sphinx-apidoc`. By default, all files except `setup.py` are - included, but this can be overridden using the ``autodoc_tree_excludes`` - option. - -``autodoc_tree_excludes`` - - A list of modules to exclude when building documentation using - `sphinx-apidoc`. Defaults to ``[setup.py]``. Refer to the `sphinx-apidoc man - page`_ for more information. - -``autodoc_index_modules`` - - A boolean option controlling whether `pbr` should itself generates - documentation for Python modules of the project. By default, all found Python - modules are included; some of them can be excluded by listing them in - ``autodoc_exclude_modules``. - -``autodoc_exclude_modules`` - - A list of modules to exclude when building module documentation using `pbr`. - `fnmatch` style pattern (e.g. `myapp.tests.*`) can be used. - -``api_doc_dir`` - - A subdirectory inside the ``build_sphinx.source_dir`` where - auto-generated API documentation should be written, if - ``autodoc_index_modules`` is set to True. Defaults to ``"api"``. - -.. note:: - - When using ``autodoc_tree_excludes`` or ``autodoc_index_modules`` you may - also need to set ``exclude_patterns`` in your Sphinx configuration file - (generally found at `doc/source/conf.py` in most OpenStack projects) - otherwise Sphinx may complain about documents that are not in a toctree. - This is especially true if the ``[sphinx_build] warning-is-error`` option is - set. See the `Sphinx build configuration file`_ documentation for more - information on configuring Sphinx. - -.. versionchanged:: 2.0 - - The ``pbr`` section used to take a ``warnerrors`` option that would enable - the ``-W`` (Turn warnings into errors.) option when building Sphinx. This - feature was broken in 1.10 and was removed in pbr 2.0 in favour of the - ``[build_sphinx] warning-is-error`` provided in Sphinx 1.5+. - -build_sphinx -~~~~~~~~~~~~ - -The ``build_sphinx`` section is a version of the ``build_sphinx`` setuptools -plugin provided with Sphinx. This plugin extends the original plugin to add the -following: - -- Automatic generation of module documentation using the apidoc__ tool - -- Automatic configuration of the `project`, `version` and `release` settings - using information from `pbr` itself - -- Support for multiple builders using the ``builders`` configuration option - - .. note:: - - Sphinx 1.6 adds support for multiple builders using the default `builder` - option. You should refer to this file for more information. - -The version of ``build_sphinx`` provided by `pbr` provides a single additional -option. - -``builders`` - - A space or comma separated list of builders to run. For example, to build - both HTML and man page documentation, you would define the following in your - `setup.cfg`: - - .. code-block:: ini - - [build_sphinx] - builders = html,man - source-dir = doc/source - build-dir = doc/build - all-files = 1 - -``source_dir`` - - The path to the source directory where the Sphinx documentation tree - is. - -For information on the remaining options, refer to the `Sphinx -documentation`__. In addition, the ``autodoc_index_modules``, -``autodoc_tree_index_modules``, ``autodoc_exclude_modules`` and -``autodoc_tree_excludes`` options in the ``pbr`` section will affect the output -of the automatic module documentation generation. - -.. versionchanged:: 3.0 - - The ``build_sphinx`` plugin used to default to building both HTML and man - page output. This is no longer the case, and you should explicitly set - ``builders`` to ``html man`` if you wish to retain this behavior. - -__ http://www.sphinx-doc.org/en/stable/man/sphinx-apidoc.html -__ http://www.sphinx-doc.org/en/stable/setuptools.html - -entry_points -~~~~~~~~~~~~ - -The ``entry_points`` section defines entry points for generated console scripts -and python libraries. This is actually provided by `setuptools`__ but is -documented here owing to its importance. - -The general syntax of specifying entry points is a top level name indicating -the entry point group name, followed by one or more key value pairs naming -the entry point to be installed. For instance:: - - [entry_points] - console_scripts = - pbr = pbr.cmd:main - pbr.config.drivers = - plain = pbr.cfg.driver:Plain - fancy = pbr.cfg.driver:Fancy - -Will cause a console script called `pbr` to be installed that executes the -`main` function found in `pbr.cmd`. Additionally, two entry points will be -installed for `pbr.config.drivers`, one called `plain` which maps to the -`Plain` class in `pbr.cfg.driver` and one called `fancy` which maps to the -`Fancy` class in `pbr.cfg.driver`. - -__ https://setuptools.readthedocs.io/en/latest/setuptools.html#options - -Requirements ------------- - -Requirement files should be given one of the below names. This order is also -the order that the requirements are tried in (where `N` is the Python major -version number used to install the package): - -* requirements-pyN.txt -* tools/pip-requires-py3 -* requirements.txt -* tools/pip-requires - -Only the first file found is used to install the list of packages it contains. - -.. note:: - - The 'requirements-pyN.txt' file is deprecated - 'requirements.txt' should - be universal. You can use `Environment markers`_ for this purpose. - -Extra requirements -~~~~~~~~~~~~~~~~~~ - -Groups of optional dependencies, or `"extra" requirements`_, can be described -in your `setup.cfg`, rather than needing to be added to `setup.py`. An example -(which also demonstrates the use of environment markers) is shown below. - -Environment markers -~~~~~~~~~~~~~~~~~~~ - -Environment markers are `conditional dependencies`_ which can be added to the -requirements (or to a group of extra requirements) automatically, depending -on the environment the installer is running in. They can be added to -requirements in the requirements file, or to extras defined in `setup.cfg`, -but the format is slightly different for each. - -For ``requirements.txt``:: - - argparse; python_version=='2.6' - -This will result in the package depending on ``argparse`` only if it's being -installed into Python 2.6 - -For extras specified in `setup.cfg`, add an ``extras`` section. For instance, -to create two groups of extra requirements with additional constraints on the -environment, you can use:: - - [extras] - security = - aleph - bet:python_version=='3.2' - gimel:python_version=='2.7' - testing = - quux:python_version=='2.7' - - -Testing -------- - -`pbr` overrides the ``setuptools`` hook ``test`` (i.e. ``setup.py test``). The -following sequence is followed: - -#. If a ``.testr.conf`` file exists and `testrepository - `__ is installed, `pbr` - will use it as the test runner. See the ``testr`` documentation - for more details. - - .. note:: - - This is separate to ``setup.py testr`` (note the extra ``r``) which - is provided directly by the ``testrepository`` package. Be careful - as there is some overlap of command arguments. - -#. Although deprecated, if ``[nosetests]`` is defined in ``setup.cfg`` - and `nose `__ is installed, - the ``nose`` runner will be used. - -#. In other cases no override will be installed and the ``test`` - command will revert to `setuptools - `__. - -A typical usage would be in ``tox.ini`` such as:: - - [tox] - minversion = 2.0 - skipsdist = True - envlist = py33,py34,py35,py26,py27,pypy,pep8,docs - - [testenv] - usedevelop = True - setenv = - VIRTUAL_ENV={envdir} - CLIENT_NAME=pbr - deps = . - -r{toxinidir}/test-requirements.txt - commands = - python setup.py test --testr-args='{posargs}' - -The argument ``--coverage`` will set ``PYTHON`` to ``coverage run`` to -produce a coverage report. ``--coverage-package-name`` can be used to -modify or narrow the packages traced. - -Additional Docs -=============== - .. toctree:: - :maxdepth: 1 - - packagers - semver - testing - compatibility - api/modules - history - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` + :maxdepth: 2 -.. _"extra" requirements: - https://www.python.org/dev/peps/pep-0426/#extras-optional-dependencies -.. _conditional dependencies: - https://www.python.org/dev/peps/pep-0426/#environment-markers -.. _distutils2: http://alexis.notmyidea.org/distutils2/setupcfg.html -.. _sphinx-apidoc man page: http://sphinx-doc.org/man/sphinx-apidoc.html -.. _Sphinx build configuration file: http://sphinx-doc.org/config.html + user/index + reference/index + contributor/index diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst new file mode 100644 index 0000000..68a9c32 --- /dev/null +++ b/doc/source/reference/index.rst @@ -0,0 +1,8 @@ +=================== + pbr API Reference +=================== + +.. toctree:: + :glob: + + api/* diff --git a/doc/source/compatibility.rst b/doc/source/user/compatibility.rst similarity index 100% rename from doc/source/compatibility.rst rename to doc/source/user/compatibility.rst diff --git a/doc/source/user/features.rst b/doc/source/user/features.rst new file mode 100644 index 0000000..4ccac4f --- /dev/null +++ b/doc/source/user/features.rst @@ -0,0 +1,312 @@ +========== + Features +========== + +To understand what *pbr* can do for you, it's probably best to look at two +projects: one using pure *setuptools*, and another using *pbr*. First, let's +look at the *setuptools* project. + +.. code-block:: none + + $ tree -L 1 + . + ├── AUTHORS + ├── CHANGES + ├── LICENSE + ├── MANIFEST.in + ├── README.rst + ├── requirements.txt + ├── setup.cfg + ├── setup.py + └── somepackage + + $ cat setup.py + setuptools.setup( + name='mypackage', + version='1.0.0', + description='A short description', + long_description="""A much longer description...""", + author="John Doe", + author_email='john.doe@example.com', + license='BSD', + ) + +Here's a similar package using *pbr*: + +.. code-block:: none + + $ tree -L 1 + . + ├── LICENSE + ├── README.rst + ├── setup.cfg + ├── setup.py + └── somepackage + + $ cat setup.py + setuptools.setup( + pbr=True + ) + + $ cat setup.cfg + [metadata] + name = mypackage + description = A short description + description-file = README.rst + author = John Doe + author-email = john.doe@example.com + license = BSD + +From this, we note a couple of the main features of *pbr*: + +- Extensive use of ``setup.cfg`` for configuration +- Automatic package metadata generation (``version``) +- Automatic metadata file generation (``AUTHOR``, ``ChangeLog``, + ``MANIFEST.in``) + +In addition, there are other things that you don't see here but which *pbr* +will do for you: + +- Helpful extensions to *setuptools* commands + +setup.cfg +--------- + +.. admonition:: Summary + + *pbr* uses ``setup.cfg`` for all configuration, though ``setup.py`` is + still required. + +One of the main features of *distutils2* was the use of a ``setup.cfg`` +INI-style configuration file. This was used to define a package's metadata and +other options that were normally supplied to the ``setup()`` function. + +Recent versions of `setuptools`__ have implemented some of this support, but +*pbr* still allows for the definition of the following sections in +``setup.cfg``: + +- ``files`` +- ``entry_points`` +- ``backwards_compat`` + +For more information on these sections, refer to :doc:`/user/using`. + +__ https://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files + +Package Metadata +---------------- + +.. admonition:: Summary + + *pbr* removes the need to define a lot of configuration in either + ``setup.py`` or ``setup.cfg`` by extracting this information from Git. + +Version +~~~~~~~ + +.. admonition:: Summary + + *pbr* will automatically configure your version for you by parsing + semantically-versioned Git tags. + +Versions can be managed two ways - *post-versioning* and *pre-versioning*. +*Post-versioning* is the default while *pre-versioning* is enabled by setting +``version`` in the ``setup.cfg`` ``metadata`` section. In both cases the actual +version strings are inferred from Git. + +If the currently checked out revision is tagged, that tag is used as +the version. + +If the currently checked out revision is not tagged, then we take the +last tagged version number and increment it to get a minimum target +version. + +.. note:: + + *pbr* supports both bare version tag (e.g. ``0.1.0``) and version prefixed + with ``v`` or ``V`` (e.g. ``v0.1.0``) + +We then walk Git history back to the last release. Within each commit we look +for a ``Sem-Ver:`` pseudo header and, if found, parse it looking for keywords. +Unknown symbols are not an error (so that folk can't wedge *pbr* or break their +tree), but we will emit an info-level warning message. The following symbols +are recognized: + +- ``feature`` +- ``api-break`` +- ``deprecation`` +- ``bugfix`` + +A missing ``Sem-Ver`` line is equivalent to ``Sem-Ver: bugfix``. The ``bugfix`` +symbol causes a patch level increment to the version. The ``feature`` and +``deprecation`` symbols cause a minor version increment. The ``api-break`` +symbol causes a major version increment. + +If *post-versioning* is in use, we use the resulting version number as the target +version. + +If *pre-versioning* is in use, we check that the version set in the metadata +section of ``setup.cfg`` is greater than the version we infer using the above +method. If the inferred version is greater than the *pre-versioning* value we +raise an error, otherwise we use the version from ``setup.cfg`` as the target. + +We then generate dev version strings based on the commits since the last +release and include the current Git SHA to disambiguate multiple dev versions +with the same number of commits since the release. + +.. note:: + + *pbr* expects Git tags to be signed for use in calculating versions. + +The versions are expected to be compliant with :doc:`semver`. + +The ``version.SemanticVersion`` class can be used to query versions of a +package and present it in various forms - ``debian_version()``, +``release_string()``, ``rpm_string()``, ``version_string()``, or +``version_tuple()``. + +Long Description +~~~~~~~~~~~~~~~~ + +.. admonition:: Summary + + *pbr* can extract the contents of a ``README`` and use this as your long + description + +There is no need to maintain two long descriptions and your ``README`` file is +probably a good long_description. So we'll just inject the contents of your +``README.rst``, ``README.txt`` or ``README`` file into your empty +``long_description``. + +You can also specify the exact file you want to use using the +``description-file`` parameter. + +Requirements +~~~~~~~~~~~~ + +.. admonition:: Summary + + *pbr* will extract requirements from ``requirements.txt`` files and + automatically populate the ``install_requires``, ``tests_require`` and + ``dependency_links`` arguments to ``setup`` with them. + +You may not have noticed, but there are differences in how pip +``requirements.txt`` files work and how *setuptools* wants to be told about +requirements. The *pip* way is nicer because it sure does make it easier to +populate a *virtualenv* for testing or to just install everything you need. +Duplicating the information, though, is super lame. To solve this issue, *pbr* +will let you use ``requirements.txt``-format files to describe the requirements +for your project and will then parse these files, split them up appropriately, +and inject them into the ``install_requires``, ``tests_require`` and/or +``dependency_links`` arguments to ``setup``. Voila! + +You can also have a requirement file for each specific major version of Python. +If you want to have a different package list for Python 3 then just drop a +``requirements-py3.txt`` and it will be used instead. + +Finally, it is possible to specify groups of optional dependencies, or +:ref:`"extra" requirements `, in your ``setup.cfg`` rather +than ``setup.py``. + +Automatic File Generation +------------------------- + +.. admonition:: Summary + + *pbr* can automatically generate a couple of files, which would normally + have to be maintained manually, by using Git data. + +AUTHORS, ChangeLog +~~~~~~~~~~~~~~~~~~ + +.. admonition:: Summary + + *pbr* will automatically generate an ``AUTHORS`` and a ``ChangeLog`` file + using Git logs. + +Why keep an ``AUTHORS`` or a ``ChangeLog`` file when Git already has all of the +information you need? ``AUTHORS`` generation supports filtering/combining based +on a standard ``.mailmap`` file. + +Manifest +~~~~~~~~ + +.. admonition:: Summary + + *pbr* will automatically generate a ``MANIFEST.in`` file based on the files + Git is tracking. + +Just like ``AUTHORS`` and ``ChangeLog``, why keep a list of files you wish to +include when you can find many of these in Git. ``MANIFEST.in`` generation +ensures almost all files stored in Git, with the exception of ``.gitignore``, +``.gitreview`` and ``.pyc`` files, are automatically included in your +distribution. In addition, the generated ``AUTHORS`` and ``ChangeLog`` files +are also included. In many cases, this removes the need for an explicit +``MANIFEST.in`` file, though one can be provided to exclude files that are +tracked via Git but which should not be included in the final release, such as +test files. + +.. note:: + + ``MANIFEST.in`` files have no effect on binary distributions such as wheels. + Refer to the `Python packaging tutorial`__ for more information. + +__ https://packaging.python.org/tutorials/distributing-packages/#manifest-in + +Setup Commands +-------------- + +``build_sphinx`` +~~~~~~~~~~~~~~~~ + +.. admonition:: Summary + + *pbr* will override the Sphinx ``build_sphinx`` command to use + *pbr*-provided package metadata and automatically generate API + documentation. + +Sphinx can produce auto documentation indexes based on signatures and +docstrings of your project but you have to give it index files to tell it to +*autodoc* each module: that's kind of repetitive and boring. *pbr* will scan +your project, find all of your modules, and generate all of the stub files for +you. + +In addition, Sphinx documentation setups are altered to have several pieces of +information that are known to ``setup.py`` injected into the Sphinx config. + +See the :ref:`pbr-setup-cfg` section of the configuration file for +details on configuring your project for *autodoc*. + +``test`` +~~~~~~~~ + +.. admonition:: Summary + + *pbr* will automatically alias the ``test`` command to use the testing tool + of your choice. + +.. deprecated:: 4.0 + +*pbr* overrides the *setuptools* ``test`` command if using `testrepository`__ +or `nose`__ (deprecated). + +- *pbr* will check for a ``.testr.conf`` file. If this exists and + *testrepository* is installed, the ``test`` command will alias the *testr* + test runner. If this is not the case... + + .. note:: + + This is separate to ``setup.py testr`` (note the extra ``r``) which is + provided directly by the ``testrepository`` package. Be careful as there is + some overlap of command arguments. + +- *pbr* will check if ``[nosetests]`` is defined in ``setup.cfg``. If this + exists and *nose* is installed, the ``test`` command will alias the *nose* + runner. If this is not the case... + +- In other cases no override will be installed and the ``test`` command will + revert to the `setuptools default`__. + +__ https://testrepository.readthedocs.io/en/latest/ +__ https://nose.readthedocs.io/en/latest/ +__ https://setuptools.readthedocs.io/en/latest/setuptools.html#test-build-package-and-run-a-unittest-suite diff --git a/doc/source/history.rst b/doc/source/user/history.rst similarity index 62% rename from doc/source/history.rst rename to doc/source/user/history.rst index 1d8f5cd..55439e7 100644 --- a/doc/source/history.rst +++ b/doc/source/user/history.rst @@ -2,4 +2,4 @@ Release History ================= -.. include:: ../../ChangeLog +.. include:: ../../../ChangeLog diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst new file mode 100644 index 0000000..7854dc5 --- /dev/null +++ b/doc/source/user/index.rst @@ -0,0 +1,12 @@ +=========== + Using pbr +=========== + +.. toctree:: + + features + using + packagers + semver + compatibility + history diff --git a/doc/source/packagers.rst b/doc/source/user/packagers.rst similarity index 96% rename from doc/source/packagers.rst rename to doc/source/user/packagers.rst index 29fc86e..a8faa31 100644 --- a/doc/source/packagers.rst +++ b/doc/source/user/packagers.rst @@ -20,7 +20,7 @@ to get confused about whether its in its own git repo or not, you can set :: - PBR_VERSION=1.2.3 + export PBR_VERSION=1.2.3 and all version calculation logic will be completely skipped and the supplied version will be considered absolute. @@ -67,7 +67,7 @@ is using, setting `SKIP_GIT_SDIST`: :: - SKIP_GIT_SDIST=1 + export SKIP_GIT_SDIST=1 will cause all logic around using git to find the files that should be in the source tarball to be skipped. Beware though, that because `pbr` packages @@ -85,14 +85,14 @@ repository for packaging source. If that is the case setting :: - SKIP_GENERATE_AUTHORS=1 + export SKIP_GENERATE_AUTHORS=1 will cause logic around generating AUTHORS using git information to be skipped. Similarly setting `SKIP_WRITE_GIT_CHANGELOG` :: - SKIP_WRITE_GIT_CHANGELOG=1 + export SKIP_WRITE_GIT_CHANGELOG=1 will cause logic around generating ChangeLog file using git information to be skipped. diff --git a/doc/source/semver.rst b/doc/source/user/semver.rst similarity index 100% rename from doc/source/semver.rst rename to doc/source/user/semver.rst diff --git a/doc/source/user/using.rst b/doc/source/user/using.rst new file mode 100644 index 0000000..d0ff3bd --- /dev/null +++ b/doc/source/user/using.rst @@ -0,0 +1,412 @@ +======= + Usage +======= + +*pbr* is a *setuptools* plugin and so to use it you must use *setuptools* and +call ``setuptools.setup()``. While the normal *setuptools* facilities are +available, *pbr* makes it possible to express them through static data files. + +.. _setup_py: + +``setup.py`` +------------ + +*pbr* only requires a minimal ``setup.py`` file compared to a standard +*setuptools* project. This is because most configuration is located in static +configuration files. This recommended minimal ``setup.py`` file should look +something like this:: + + #!/usr/bin/env python + + from setuptools import setup + + setup( + setup_requires=['pbr'], + pbr=True, + ) + +.. note:: + + It is necessary to specify ``pbr=True`` to enabled *pbr* functionality. + +.. note:: + + While one can pass any arguments supported by setuptools to ``setup()``, + any conflicting arguments supplied in ``setup.cfg`` will take precedence. + +.. _setup_cfg: + +``setup.cfg`` +------------- + +The ``setup.cfg`` file is an INI-like file that can mostly replace the +``setup.py`` file. It is similar to the ``setup.cfg`` file found in recent +versions of `setuptools`__. A simple sample can be found in *pbr*'s own +``setup.cfg`` (it uses its own machinery to install itself): + +:: + + [metadata] + name = pbr + author = OpenStack Foundation + author-email = openstack-dev@lists.openstack.org + summary = OpenStack's setup automation in a reusable form + description-file = README.rst + description-content-type = text/x-rst; charset=UTF-8 + home-page = https://launchpad.net/pbr + project_urls = + Bug Tracker = https://bugs.launchpad.net/pbr/ + Documentation = https://docs.openstack.org/pbr/ + Source Code = https://git.openstack.org/cgit/openstack-dev/pbr/ + license = Apache-2 + classifier = + Development Status :: 4 - Beta + Environment :: Console + Environment :: OpenStack + Intended Audience :: Developers + Intended Audience :: Information Technology + License :: OSI Approved :: Apache Software License + Operating System :: OS Independent + Programming Language :: Python + keywords = + setup + distutils + + [files] + packages = + pbr + data_files = + etc/pbr = etc/* + etc/init = + pbr.packaging.conf + pbr.version.conf + + [entry_points] + console_scripts = + pbr = pbr.cmd:main + pbr.config.drivers = + plain = pbr.cfg.driver:Plain + +Recent versions of `setuptools`_ provide many of the same sections as *pbr*. +However, *pbr* does provide a number of additional sections: + +- ``files`` +- ``entry_points`` +- ``backwards_compat`` +- ``pbr`` + +In addition, there are some modifications to other sections: + +- ``metadata`` +- ``build_sphinx`` + +For all other sections, you should refer to either the `setuptools`_ +documentation or the documentation of the package that provides the section, +such as the ``extract_mesages`` section provided by Babel__. + +.. note:: + + Comments may be used in ``setup.cfg``, however all comments should start + with a ``#`` and may be on a single line, or in line, with at least one + white space character immediately preceding the ``#``. Semicolons are not a + supported comment delimiter. For instance:: + + [section] + # A comment at the start of a dedicated line + key = + value1 # An in line comment + value2 + # A comment on a dedicated line + value3 + +__ http://setuptools.readthedocs.io/en/latest/setuptools.html#configuring-setup-using-setup-cfg-files +__ http://babel.pocoo.org/en/latest/setup.html + +``files`` +~~~~~~~~~ + +The ``files`` section defines the install location of files in the package +using three fundamental keys: ``packages``, ``namespace_packages``, and +``data_files``. + +``packages`` + A list of top-level packages that should be installed. The behavior of + packages is similar to ``setuptools.find_packages`` in that it recurses the + Python package hierarchy below the given top level and installs all of it. If + ``packages`` is not specified, it defaults to the value of the ``name`` field + given in the ``[metadata]`` section. + +``namespace_packages`` + Similar to ``packages``, but is a list of packages that provide namespace + packages. + +``data_files`` + A list of files to be installed. The format is an indented block that + contains key value pairs which specify target directory and source file to + install there. More than one source file for a directory may be indicated + with a further indented list. Source files are stripped of leading + directories. Additionally, *pbr* supports a simple file globbing syntax for + installing entire directory structures. For example:: + + [files] + data_files = + etc/pbr = etc/pbr/* + etc/neutron = + etc/api-paste.ini + etc/dhcp-agent.ini + etc/init.d = neutron.init + + This will result in ``/etc/neutron`` containing ``api-paste.ini`` and + ``dhcp-agent.ini``, both of which *pbr* will expect to find in the ``etc`` + directory in the root of the source tree. Additionally, ``neutron.init`` from + that directory will be installed in ``/etc/init.d``. All of the files and + directories located under ``etc/pbr`` in the source tree will be installed + into ``/etc/pbr``. + + Note that this behavior is relative to the effective root of the environment + into which the packages are installed, so depending on available permissions + this could be the actual system-wide ``/etc`` directory or just a top-level + ``etc`` subdirectory of a *virtualenv*. + +``entry_points`` +~~~~~~~~~~~~~~~~ + +The ``entry_points`` section defines entry points for generated console scripts +and Python libraries. This is actually provided by *setuptools* but is +documented here owing to its importance. + +The general syntax of specifying entry points is a top level name indicating +the entry point group name, followed by one or more key value pairs naming +the entry point to be installed. For instance:: + + [entry_points] + console_scripts = + pbr = pbr.cmd:main + pbr.config.drivers = + plain = pbr.cfg.driver:Plain + fancy = pbr.cfg.driver:Fancy + +Will cause a console script called *pbr* to be installed that executes the +``main`` function found in ``pbr.cmd``. Additionally, two entry points will be +installed for ``pbr.config.drivers``, one called ``plain`` which maps to the +``Plain`` class in ``pbr.cfg.driver`` and one called ``fancy`` which maps to +the ``Fancy`` class in ``pbr.cfg.driver``. + +``backwards_compat`` +~~~~~~~~~~~~~~~~~~~~~ + +.. todo:: Describe this section + +.. _pbr-setup-cfg: + +``pbr`` +~~~~~~~ + +The ``pbr`` section controls *pbr*-specific options and behaviours. + +``autodoc_tree_index_modules`` + + A boolean option controlling whether *pbr* should generate an index of + modules using ``sphinx-apidoc``. By default, all files except ``setup.py`` + are included, but this can be overridden using the ``autodoc_tree_excludes`` + option. + +``autodoc_tree_excludes`` + + A list of modules to exclude when building documentation using + ``sphinx-apidoc``. Defaults to ``[setup.py]``. Refer to the + `sphinx-apidoc man page`__ for more information. + +__ http://sphinx-doc.org/man/sphinx-apidoc.html + +``autodoc_index_modules`` + + A boolean option controlling whether *pbr* should itself generates + documentation for Python modules of the project. By default, all found Python + modules are included; some of them can be excluded by listing them in + ``autodoc_exclude_modules``. + +``autodoc_exclude_modules`` + + A list of modules to exclude when building module documentation using *pbr*. + *fnmatch* style pattern (e.g. ``myapp.tests.*``) can be used. + +``api_doc_dir`` + + A subdirectory inside the ``build_sphinx.source_dir`` where auto-generated + API documentation should be written, if ``autodoc_index_modules`` is set to + True. Defaults to ``"api"``. + +.. note:: + + When using ``autodoc_tree_excludes`` or ``autodoc_index_modules`` you may + also need to set ``exclude_patterns`` in your Sphinx configuration file + (generally found at ``doc/source/conf.py`` in most OpenStack projects) + otherwise Sphinx may complain about documents that are not in a toctree. + This is especially true if the ``[sphinx_build] warning-is-error`` option is + set. See the `Sphinx build configuration file`__ documentation for more + information on configuring Sphinx. + +__ http://sphinx-doc.org/config.html + +.. versionchanged:: 2.0 + + The ``pbr`` section used to take a ``warnerrors`` option that would enable + the ``-W`` (Turn warnings into errors.) option when building Sphinx. This + feature was broken in 1.10 and was removed in pbr 2.0 in favour of the + ``[build_sphinx] warning-is-error`` provided in Sphinx 1.5+. + +``metadata`` +~~~~~~~~~~~~ + +.. todo:: Describe this section + +.. _build_sphinx-setup-cfg: + +``build_sphinx`` +~~~~~~~~~~~~~~~~ + +.. versionchanged:: 3.0 + + The ``build_sphinx`` plugin used to default to building both HTML and man + page output. This is no longer the case, and you should explicitly set + ``builders`` to ``html man`` if you wish to retain this behavior. + +The ``build_sphinx`` section is a version of the ``build_sphinx`` *setuptools* +plugin provided with Sphinx. This plugin extends the original plugin to add the +following: + +- Automatic generation of module documentation using the ``sphinx-apidoc`` tool + +- Automatic configuration of the ``project``, ``version`` and ``release`` + settings using information from *pbr* itself + +- Support for multiple builders using the ``builders`` configuration option + + .. note:: + + Only applies to Sphinx < 1.6. See documentation on ``builders`` below. + +The version of ``build_sphinx`` provided by *pbr* provides a single additional +option. + +``builders`` + A comma separated list of builders to run. For example, to build both HTML + and man page documentation, you would define the following in your + ``setup.cfg``: + + .. code-block:: ini + + [build_sphinx] + builders = html,man + source-dir = doc/source + build-dir = doc/build + all-files = 1 + warning-is-error = 1 + + .. deprecated:: 3.2.0 + + Sphinx 1.6+ adds support for specifying multiple builders in the default + ``builder`` option. You should use this option instead. Refer to the + `Sphinx documentation`_ for more information. + +For information on the remaining options, refer to the `Sphinx documentation`_. +In addition, the ``autodoc_index_modules``, ``autodoc_tree_index_modules``, +``autodoc_exclude_modules`` and ``autodoc_tree_excludes`` options :ref:`in the +pbr section ` will affect the output of the automatic module +documentation generation. + +.. _Sphinx documentation: http://www.sphinx-doc.org/en/stable/setuptools.html + +Requirements +------------ + +Requirements files are used in place of the ``install_requires`` and +``extras_require`` attributes. Requirement files should be given one of the +below names. This order is also the order that the requirements are tried in +(where ``N`` is the Python major version number used to install the package): + +* ``requirements-pyN.txt`` +* ``tools/pip-requires-py3`` +* ``requirements.txt`` +* ``tools/pip-requires`` + +Only the first file found is used to install the list of packages it contains. + +.. note:: + + The ``requirements-pyN.txt`` file is deprecated - ``requirements.txt`` + should be universal. You can use `Environment markers`_ for this purpose. + +.. _extra-requirements: + +Extra requirements +~~~~~~~~~~~~~~~~~~ + +Groups of optional dependencies, or `"extra" requirements`__, can be described +in your ``setup.cfg``, rather than needing to be added to ``setup.py``. An +example (which also demonstrates the use of environment markers) is shown +below. + +__ https://www.python.org/dev/peps/pep-0426/#extras-optional-dependencies + +Environment markers +~~~~~~~~~~~~~~~~~~~ + +Environment markers are `conditional dependencies`__ which can be added to the +requirements (or to a group of extra requirements) automatically, depending on +the environment the installer is running in. They can be added to requirements +in the requirements file, or to extras defined in ``setup.cfg``, but the format +is slightly different for each. + +For ``requirements.txt``:: + + argparse; python_version=='2.6' + +This will result in the package depending on ``argparse`` only if it's being +installed into Python 2.6. + +For extras specified in ``setup.cfg``, add an ``extras`` section. For instance, +to create two groups of extra requirements with additional constraints on the +environment, you can use:: + + [extras] + security = + aleph + bet:python_version=='3.2' + gimel:python_version=='2.7' + testing = + quux:python_version=='2.7' + +__ https://www.python.org/dev/peps/pep-0426/#environment-markers + +Testing +------- + +.. deprecated:: 4.0 + +As described in :doc:`/user/features`, *pbr* may override the ``test`` command +depending on the test runner used. + +A typical usage would be in ``tox.ini`` such as:: + + [tox] + minversion = 2.0 + skipsdist = True + envlist = py33,py34,py35,py26,py27,pypy,pep8,docs + + [testenv] + usedevelop = True + setenv = + VIRTUAL_ENV={envdir} + CLIENT_NAME=pbr + deps = . + -r{toxinidir}/test-requirements.txt + commands = + python setup.py test --testr-args='{posargs}' + +The argument ``--coverage`` will set ``PYTHON`` to ``coverage run`` to produce +a coverage report. ``--coverage-package-name`` can be used to modify or narrow +the packages traced. + +.. _setuptools: http://www.sphinx-doc.org/en/stable/setuptools.html diff --git a/pbr.egg-info/PKG-INFO b/pbr.egg-info/PKG-INFO index 8bde250..1339ea8 100644 --- a/pbr.egg-info/PKG-INFO +++ b/pbr.egg-info/PKG-INFO @@ -1,11 +1,14 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: pbr -Version: 3.1.1 +Version: 4.0.0 Summary: Python Build Reasonableness -Home-page: http://docs.openstack.org/developer/pbr/ +Home-page: https://docs.openstack.org/pbr/latest/ Author: OpenStack Author-email: openstack-dev@lists.openstack.org License: UNKNOWN +Project-URL: Bug Tracker, https://bugs.launchpad.net/pbr/ +Project-URL: Documentation, https://docs.openstack.org/pbr/ +Project-URL: Source Code, https://git.openstack.org/cgit/openstack-dev/pbr/ Description: Introduction ============ @@ -39,10 +42,10 @@ Description: Introduction them as quickly as possible. * License: Apache License, Version 2.0 - * Documentation: http://docs.openstack.org/developer/pbr - * Source: http://git.openstack.org/cgit/openstack-dev/pbr - * Bugs: http://bugs.launchpad.net/pbr - * Change Log: https://docs.openstack.org/developer/pbr/history.html + * Documentation: https://docs.openstack.org/pbr/latest/ + * Source: https://git.openstack.org/cgit/openstack-dev/pbr + * Bugs: https://bugs.launchpad.net/pbr + * Change Log: https://docs.openstack.org/pbr/latest/user/history.html .. _d2to1: https://pypi.python.org/pypi/d2to1 .. _distutils2: https://pypi.python.org/pypi/Distutils2 @@ -60,9 +63,9 @@ Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 +Description-Content-Type: text/x-rst; charset=UTF-8 diff --git a/pbr.egg-info/SOURCES.txt b/pbr.egg-info/SOURCES.txt index 9041710..0ced9f2 100644 --- a/pbr.egg-info/SOURCES.txt +++ b/pbr.egg-info/SOURCES.txt @@ -10,13 +10,17 @@ setup.cfg setup.py test-requirements.txt tox.ini -doc/source/compatibility.rst doc/source/conf.py -doc/source/history.rst doc/source/index.rst -doc/source/packagers.rst -doc/source/semver.rst -doc/source/testing.rst +doc/source/contributor/index.rst +doc/source/reference/index.rst +doc/source/user/compatibility.rst +doc/source/user/features.rst +doc/source/user/history.rst +doc/source/user/index.rst +doc/source/user/packagers.rst +doc/source/user/semver.rst +doc/source/user/using.rst pbr/__init__.py pbr/builddoc.py pbr/core.py @@ -81,5 +85,12 @@ pbr/tests/testpackage/pbr_testpackage/wsgi.py pbr/tests/testpackage/pbr_testpackage/package_data/1.txt pbr/tests/testpackage/pbr_testpackage/package_data/2.txt pbr/tests/testpackage/src/testext.c +releasenotes/notes/deprecate-pyN-requirements-364655c38fa5b780.yaml +releasenotes/notes/deprecate-testr-nose-integration-56e3e11248d946fc.yaml +releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml +releasenotes/notes/v_version-457b38c8679c5868.yaml +releasenotes/source/conf.py +releasenotes/source/index.rst +releasenotes/source/unreleased.rst tools/integration.sh -tools/tox_install.sh \ No newline at end of file +tools/tox_releasenotes.sh \ No newline at end of file diff --git a/pbr/builddoc.py b/pbr/builddoc.py index c1a2e6f..167d13e 100644 --- a/pbr/builddoc.py +++ b/pbr/builddoc.py @@ -25,7 +25,19 @@ except ImportError: import io as cStringIO try: - from sphinx import apidoc + import sphinx + # NOTE(dhellmann): Newer versions of Sphinx have moved the apidoc + # module into sphinx.ext and the API is slightly different (the + # function expects sys.argv[1:] instead of sys.argv[:]. So, figure + # out where we can import it from and set a flag so we can invoke + # it properly. See this change in sphinx for details: + # https://github.com/sphinx-doc/sphinx/commit/87630c8ae8bff8c0e23187676e6343d8903003a6 + try: + from sphinx.ext import apidoc + apidoc_use_padding = False + except ImportError: + from sphinx import apidoc + apidoc_use_padding = True from sphinx import application from sphinx import setup_command except Exception as e: @@ -42,6 +54,7 @@ except Exception as e: raise ImportError(str(e)) from pbr import git from pbr import options +from pbr import version _rst_template = """%(heading)s @@ -117,7 +130,9 @@ class LocalBuildDoc(setup_command.BuildDoc): def _sphinx_tree(self): source_dir = self._get_source_dir() - cmd = ['apidoc', '.', '-H', 'Modules', '-o', source_dir] + cmd = ['-H', 'Modules', '-o', source_dir, '.'] + if apidoc_use_padding: + cmd.insert(0, 'apidoc') apidoc.main(cmd + self.autodoc_tree_excludes) def _sphinx_run(self): @@ -186,15 +201,34 @@ class LocalBuildDoc(setup_command.BuildDoc): "autodoc_exclude_modules", [None, ""])[1].split())) - # TODO(stephenfin): Deprecate this functionality once we depend on - # Sphinx 1.6, which includes a similar feature, in g-r - # https://github.com/sphinx-doc/sphinx/pull/3476 self.finalize_options() - if hasattr(self, "builder_target_dirs"): - # Sphinx >= 1.6.1 + + is_multibuilder_sphinx = version.SemanticVersion.from_pip_string( + sphinx.__version__) >= version.SemanticVersion(1, 6) + + # TODO(stephenfin): Remove support for Sphinx < 1.6 in 4.0 + if not is_multibuilder_sphinx: + log.warn('[pbr] Support for Sphinx < 1.6 will be dropped in ' + 'pbr 4.0. Upgrade to Sphinx 1.6+') + + # TODO(stephenfin): Remove this at the next MAJOR version bump + if self.builders != ['html']: + log.warn("[pbr] Sphinx 1.6 added native support for " + "specifying multiple builders in the " + "'[sphinx_build] builder' configuration option, " + "found in 'setup.cfg'. As a result, the " + "'[sphinx_build] builders' option has been " + "deprecated and will be removed in pbr 4.0. Migrate " + "to the 'builder' configuration option.") + if is_multibuilder_sphinx: + self.builder = self.builders + + if is_multibuilder_sphinx: + # Sphinx >= 1.6 return setup_command.BuildDoc.run(self) + # Sphinx < 1.6 - for builder in self.builders: + for builder in self.builder: self.builder = builder self.finalize_options() self._sphinx_run() @@ -208,6 +242,8 @@ class LocalBuildDoc(setup_command.BuildDoc): self.autodoc_tree_excludes = ['setup.py'] def finalize_options(self): + from pbr import util + # Not a new style class, super keyword does not work. setup_command.BuildDoc.finalize_options(self) @@ -228,8 +264,8 @@ class LocalBuildDoc(setup_command.BuildDoc): opt = 'autodoc_tree_excludes' option_dict = self.distribution.get_option_dict('pbr') if opt in option_dict: - self.autodoc_tree_excludes = option_dict[opt][1] - self.ensure_string_list(opt) + self.autodoc_tree_excludes = util.split_multiline( + option_dict[opt][1]) # handle Sphinx < 1.5.0 if not hasattr(self, 'warning_is_error'): diff --git a/pbr/core.py b/pbr/core.py index 71d1e56..a93253b 100644 --- a/pbr/core.py +++ b/pbr/core.py @@ -50,22 +50,9 @@ import os import sys import warnings -from setuptools import dist - from pbr import util -_saved_core_distribution = core.Distribution - - -def _monkeypatch_distribution(): - core.Distribution = dist._get_unpatched(core.Distribution) - - -def _restore_distribution_monkeypatch(): - core.Distribution = _saved_core_distribution - - if sys.version_info[0] == 3: string_type = str integer_types = (int,) @@ -94,63 +81,54 @@ def pbr(dist, attr, value): not work well with distributions that do use a `Distribution` subclass. """ + if not value: + return + if isinstance(value, string_type): + path = os.path.abspath(value) + else: + path = os.path.abspath('setup.cfg') + if not os.path.exists(path): + raise errors.DistutilsFileError( + 'The setup.cfg file %s does not exist.' % path) + + # Converts the setup.cfg file to setup() arguments try: - _monkeypatch_distribution() - if not value: - return - if isinstance(value, string_type): - path = os.path.abspath(value) - else: - path = os.path.abspath('setup.cfg') - if not os.path.exists(path): - raise errors.DistutilsFileError( - 'The setup.cfg file %s does not exist.' % path) - - # Converts the setup.cfg file to setup() arguments - try: - attrs = util.cfg_to_args(path, dist.script_args) - except Exception: - e = sys.exc_info()[1] - # NB: This will output to the console if no explicit logging has - # been setup - but thats fine, this is a fatal distutils error, so - # being pretty isn't the #1 goal.. being diagnosable is. - logging.exception('Error parsing') - raise errors.DistutilsSetupError( - 'Error parsing %s: %s: %s' % (path, e.__class__.__name__, e)) - - # Repeat some of the Distribution initialization code with the newly - # provided attrs - if attrs: - # Skips 'options' and 'licence' support which are rarely used; may - # add back in later if demanded - for key, val in attrs.items(): - if hasattr(dist.metadata, 'set_' + key): - getattr(dist.metadata, 'set_' + key)(val) - elif hasattr(dist.metadata, key): - setattr(dist.metadata, key, val) - elif hasattr(dist, key): - setattr(dist, key, val) - else: - msg = 'Unknown distribution option: %s' % repr(key) - warnings.warn(msg) - - # Re-finalize the underlying Distribution - core.Distribution.finalize_options(dist) - - # This bit comes out of distribute/setuptools - if isinstance(dist.metadata.version, integer_types + (float,)): - # Some people apparently take "version number" too literally :) - dist.metadata.version = str(dist.metadata.version) - - # This bit of hackery is necessary so that the Distribution will ignore - # normally unsupport command options (namely pre-hooks and post-hooks). - # dist.command_options is normally a dict mapping command names to - # dicts of their options. Now it will be a defaultdict that returns - # IgnoreDicts for the each command's options so we can pass through the - # unsupported options - ignore = ['pre_hook.*', 'post_hook.*'] - dist.command_options = util.DefaultGetDict( - lambda: util.IgnoreDict(ignore) - ) - finally: - _restore_distribution_monkeypatch() + attrs = util.cfg_to_args(path, dist.script_args) + except Exception: + e = sys.exc_info()[1] + # NB: This will output to the console if no explicit logging has + # been setup - but thats fine, this is a fatal distutils error, so + # being pretty isn't the #1 goal.. being diagnosable is. + logging.exception('Error parsing') + raise errors.DistutilsSetupError( + 'Error parsing %s: %s: %s' % (path, e.__class__.__name__, e)) + + # Repeat some of the Distribution initialization code with the newly + # provided attrs + if attrs: + # Skips 'options' and 'licence' support which are rarely used; may + # add back in later if demanded + for key, val in attrs.items(): + if hasattr(dist.metadata, 'set_' + key): + getattr(dist.metadata, 'set_' + key)(val) + elif hasattr(dist.metadata, key): + setattr(dist.metadata, key, val) + elif hasattr(dist, key): + setattr(dist, key, val) + else: + msg = 'Unknown distribution option: %s' % repr(key) + warnings.warn(msg) + + # Re-finalize the underlying Distribution + try: + super(dist.__class__, dist).finalize_options() + except TypeError: + # If dist is not declared as a new-style class (with object as + # a subclass) then super() will not work on it. This is the case + # for Python 2. In that case, fall back to doing this the ugly way + dist.__class__.__bases__[-1].finalize_options(dist) + + # This bit comes out of distribute/setuptools + if isinstance(dist.metadata.version, integer_types + (float,)): + # Some people apparently take "version number" too literally :) + dist.metadata.version = str(dist.metadata.version) diff --git a/pbr/packaging.py b/pbr/packaging.py index c8eedbd..38b4982 100644 --- a/pbr/packaging.py +++ b/pbr/packaging.py @@ -27,6 +27,7 @@ import email.errors import os import re import sys +import warnings import pkg_resources import setuptools @@ -45,6 +46,8 @@ from pbr import testr_command from pbr import version REQUIREMENTS_FILES = ('requirements.txt', 'tools/pip-requires') +PY_REQUIREMENTS_FILES = [x % sys.version_info[0] for x in ( + 'requirements-py%d.txt', 'tools/pip-requires-py%d')] TEST_REQUIREMENTS_FILES = ('test-requirements.txt', 'tools/test-requires') @@ -56,9 +59,8 @@ def get_requirements_files(): # - REQUIREMENTS_FILES with -py2 or -py3 in the name # (e.g. requirements-py3.txt) # - REQUIREMENTS_FILES - return (list(map(('-py' + str(sys.version_info[0])).join, - map(os.path.splitext, REQUIREMENTS_FILES))) - + list(REQUIREMENTS_FILES)) + + return PY_REQUIREMENTS_FILES + list(REQUIREMENTS_FILES) def append_text_list(config, key, text_list): @@ -77,9 +79,20 @@ def _any_existing(file_list): # Get requirements from the first file that exists def get_reqs_from_files(requirements_files): - for requirements_file in _any_existing(requirements_files): + existing = _any_existing(requirements_files) + + deprecated = [f for f in existing if f in PY_REQUIREMENTS_FILES] + if deprecated: + warnings.warn('Support for \'-pyN\'-suffixed requirements files is ' + 'deprecated in pbr 4.0 and will be removed in 5.0. ' + 'Use environment markers instead. Conflicting files: ' + '%r' % deprecated, + DeprecationWarning) + + for requirements_file in existing: with open(requirements_file, 'r') as fil: return fil.read().split('\n') + return [] @@ -259,8 +272,14 @@ try: """Fallback test runner if testr is a no-go.""" command_name = 'test' + description = 'DEPRECATED: Run unit tests using nose' def run(self): + warnings.warn('nose integration in pbr is deprecated. Please use ' + 'the native nose setuptools configuration or call ' + 'nose directly', + DeprecationWarning) + # Can't use super - base class old-style class commands.nosetests.run(self) @@ -390,8 +409,6 @@ class LocalDevelop(develop.develop): command_name = 'develop' def install_wrapper_scripts(self, dist): - if sys.platform == 'win32': - return develop.develop.install_wrapper_scripts(self, dist) if not self.exclude_scripts: for args in override_get_script_args(dist): self.write_script(*args) @@ -445,13 +462,7 @@ class LocalInstallScripts(install_scripts.install_scripts): # entry-points listed for this package. return - if os.name != 'nt': - get_script_args = override_get_script_args - else: - get_script_args = easy_install.get_script_args - executable = '"%s"' % executable - - for args in get_script_args(dist, executable, is_wininst): + for args in override_get_script_args(dist, executable, is_wininst): self.write_script(*args) @@ -532,11 +543,57 @@ class LocalSDist(sdist.sdist): command_name = 'sdist' + def checking_reno(self): + """Ensure reno is installed and configured. + + We can't run reno-based commands if reno isn't installed/available, and + don't want to if the user isn't using it. + """ + if hasattr(self, '_has_reno'): + return self._has_reno + + try: + # versions of reno witout this module will not have the required + # feature, hence the import + from reno import setup_command # noqa + except ImportError: + log.info('[pbr] reno was not found or is too old. Skipping ' + 'release notes') + self._has_reno = False + return False + + conf, output_file, cache_file = setup_command.load_config( + self.distribution) + + if not os.path.exists(os.path.join(conf.reporoot, conf.notespath)): + log.info('[pbr] reno does not appear to be configured. Skipping ' + 'release notes') + self._has_reno = False + return False + + self._files = [output_file, cache_file] + + log.info('[pbr] Generating release notes') + self._has_reno = True + + return True + + sub_commands = [('build_reno', checking_reno)] + sdist.sdist.sub_commands + def run(self): _from_git(self.distribution) # sdist.sdist is an old style class, can't use super() sdist.sdist.run(self) + def make_distribution(self): + # This is included in make_distribution because setuptools doesn't use + # 'get_file_list'. As such, this is the only hook point that runs after + # the commands in 'sub_commands' + if self.checking_reno(): + self.filelist.extend(self._files) + self.filelist.sort() + sdist.sdist.make_distribution(self) + try: from pbr import builddoc _have_sphinx = True diff --git a/pbr/testr_command.py b/pbr/testr_command.py index cd179a2..d143565 100644 --- a/pbr/testr_command.py +++ b/pbr/testr_command.py @@ -45,13 +45,14 @@ import distutils.errors import logging import os import sys +import warnings logger = logging.getLogger(__name__) class TestrReal(cmd.Command): - description = "Run unit tests using testr" + description = "DEPRECATED: Run unit tests using testr" user_options = [ ('coverage', None, "Replace PYTHON with coverage and merge coverage " @@ -100,6 +101,11 @@ class TestrReal(cmd.Command): def run(self): """Set up testr repo, then run testr.""" logger.debug("run called") + + warnings.warn('testr integration in pbr is deprecated. Please use ' + 'the \'testr\' setup command or call testr directly', + DeprecationWarning) + if not os.path.isdir(".testrepository"): self._run_testr("init") diff --git a/pbr/tests/test_hooks.py b/pbr/tests/test_hooks.py index 0759706..0fcf96c 100644 --- a/pbr/tests/test_hooks.py +++ b/pbr/tests/test_hooks.py @@ -39,9 +39,7 @@ # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS import os -import textwrap -from testtools import content from testtools import matchers from pbr.tests import base @@ -56,10 +54,6 @@ class TestHooks(base.BaseTestCase): cfg.set('global', 'setup-hooks', 'pbr_testpackage._setup_hooks.test_hook_1\n' 'pbr_testpackage._setup_hooks.test_hook_2') - cfg.set('build_ext', 'pre-hook.test_pre_hook', - 'pbr_testpackage._setup_hooks.test_pre_hook') - cfg.set('build_ext', 'post-hook.test_post_hook', - 'pbr_testpackage._setup_hooks.test_post_hook') def test_global_setup_hooks(self): """Test setup_hooks. @@ -72,28 +66,6 @@ class TestHooks(base.BaseTestCase): assert 'test_hook_1\ntest_hook_2' in stdout assert return_code == 0 - def test_command_hooks(self): - """Test command hooks. - - Simple test that the appropriate command hooks run at the - beginning/end of the appropriate command. - """ - - stdout, _, return_code = self.run_setup('egg_info') - assert 'build_ext pre-hook' not in stdout - assert 'build_ext post-hook' not in stdout - assert return_code == 0 - - stdout, stderr, return_code = self.run_setup('build_ext') - self.addDetailUniqueName('stderr', content.text_content(stderr)) - assert textwrap.dedent(""" - running build_ext - running pre_hook pbr_testpackage._setup_hooks.test_pre_hook for command build_ext - build_ext pre-hook - """) in stdout # flake8: noqa - self.expectThat(stdout, matchers.EndsWith('build_ext post-hook')) - assert return_code == 0 - def test_custom_commands_known(self): stdout, _, return_code = self.run_setup('--help-commands') self.assertFalse(return_code) diff --git a/pbr/tests/test_packaging.py b/pbr/tests/test_packaging.py index 9efcbd7..5512d5d 100644 --- a/pbr/tests/test_packaging.py +++ b/pbr/tests/test_packaging.py @@ -43,6 +43,7 @@ import email.errors import imp import os import re +import sys import sysconfig import tempfile import textwrap @@ -51,6 +52,7 @@ import fixtures import mock import pkg_resources import six +import testscenarios import testtools from testtools import matchers import virtualenv @@ -486,9 +488,47 @@ class TestPresenceOfGit(base.BaseTestCase): self.assertEqual(False, git._git_is_installed()) -class TestIndexInRequirements(base.BaseTestCase): +class ParseRequirementsTest(base.BaseTestCase): - def test_index_in_requirement(self): + def test_empty_requirements(self): + actual = packaging.parse_requirements([]) + self.assertEqual([], actual) + + def test_default_requirements(self): + """Ensure default files used if no files provided.""" + tempdir = tempfile.mkdtemp() + requirements = os.path.join(tempdir, 'requirements.txt') + with open(requirements, 'w') as f: + f.write('pbr') + # the defaults are relative to where pbr is called from so we need to + # override them. This is OK, however, as we want to validate that + # defaults are used - not what those defaults are + with mock.patch.object(packaging, 'REQUIREMENTS_FILES', ( + requirements,)): + result = packaging.parse_requirements() + self.assertEqual(['pbr'], result) + + def test_override_with_env(self): + """Ensure environment variable used if no files provided.""" + _, tmp_file = tempfile.mkstemp(prefix='openstack', suffix='.setup') + with open(tmp_file, 'w') as fh: + fh.write("foo\nbar") + self.useFixture( + fixtures.EnvironmentVariable('PBR_REQUIREMENTS_FILES', tmp_file)) + self.assertEqual(['foo', 'bar'], + packaging.parse_requirements()) + + def test_override_with_env_multiple_files(self): + _, tmp_file = tempfile.mkstemp(prefix='openstack', suffix='.setup') + with open(tmp_file, 'w') as fh: + fh.write("foo\nbar") + self.useFixture( + fixtures.EnvironmentVariable('PBR_REQUIREMENTS_FILES', + "no-such-file," + tmp_file)) + self.assertEqual(['foo', 'bar'], + packaging.parse_requirements()) + + def test_index_present(self): tempdir = tempfile.mkdtemp() requirements = os.path.join(tempdir, 'requirements.txt') with open(requirements, 'w') as f: @@ -498,10 +538,7 @@ class TestIndexInRequirements(base.BaseTestCase): result = packaging.parse_requirements([requirements]) self.assertEqual([], result) - -class TestNestedRequirements(base.BaseTestCase): - - def test_nested_requirement(self): + def test_nested_requirements(self): tempdir = tempfile.mkdtemp() requirements = os.path.join(tempdir, 'requirements.txt') nested = os.path.join(tempdir, 'nested.txt') @@ -512,6 +549,94 @@ class TestNestedRequirements(base.BaseTestCase): result = packaging.parse_requirements([requirements]) self.assertEqual(['pbr'], result) + @mock.patch('warnings.warn') + def test_python_version(self, mock_warn): + with open("requirements-py%d.txt" % sys.version_info[0], + "w") as fh: + fh.write("# this is a comment\nfoobar\n# and another one\nfoobaz") + self.assertEqual(['foobar', 'foobaz'], + packaging.parse_requirements()) + mock_warn.assert_called_once_with(mock.ANY, DeprecationWarning) + + @mock.patch('warnings.warn') + def test_python_version_multiple_options(self, mock_warn): + with open("requirements-py1.txt", "w") as fh: + fh.write("thisisatrap") + with open("requirements-py%d.txt" % sys.version_info[0], + "w") as fh: + fh.write("# this is a comment\nfoobar\n# and another one\nfoobaz") + self.assertEqual(['foobar', 'foobaz'], + packaging.parse_requirements()) + # even though we have multiple offending files, this should only be + # called once + mock_warn.assert_called_once_with(mock.ANY, DeprecationWarning) + + +class ParseRequirementsTestScenarios(base.BaseTestCase): + + versioned_scenarios = [ + ('non-versioned', {'versioned': False, 'expected': ['bar']}), + ('versioned', {'versioned': True, 'expected': ['bar>=1.2.3']}) + ] + + scenarios = [ + ('normal', {'url': "foo\nbar", 'expected': ['foo', 'bar']}), + ('normal_with_comments', { + 'url': "# this is a comment\nfoo\n# and another one\nbar", + 'expected': ['foo', 'bar']}), + ('removes_index_lines', {'url': '-f foobar', 'expected': []}), + ] + + scenarios = scenarios + testscenarios.multiply_scenarios([ + ('ssh_egg_url', {'url': 'git+ssh://foo.com/zipball#egg=bar'}), + ('git_https_egg_url', {'url': 'git+https://foo.com/zipball#egg=bar'}), + ('http_egg_url', {'url': 'https://foo.com/zipball#egg=bar'}), + ], versioned_scenarios) + + scenarios = scenarios + testscenarios.multiply_scenarios( + [ + ('git_egg_url', + {'url': 'git://foo.com/zipball#egg=bar', 'name': 'bar'}) + ], [ + ('non-editable', {'editable': False}), + ('editable', {'editable': True}), + ], + versioned_scenarios) + + def test_parse_requirements(self): + tmp_file = tempfile.NamedTemporaryFile() + req_string = self.url + if hasattr(self, 'editable') and self.editable: + req_string = ("-e %s" % req_string) + if hasattr(self, 'versioned') and self.versioned: + req_string = ("%s-1.2.3" % req_string) + with open(tmp_file.name, 'w') as fh: + fh.write(req_string) + self.assertEqual(self.expected, + packaging.parse_requirements([tmp_file.name])) + + +class ParseDependencyLinksTest(base.BaseTestCase): + + def setUp(self): + super(ParseDependencyLinksTest, self).setUp() + _, self.tmp_file = tempfile.mkstemp(prefix="openstack", + suffix=".setup") + + def test_parse_dependency_normal(self): + with open(self.tmp_file, "w") as fh: + fh.write("http://test.com\n") + self.assertEqual( + ["http://test.com"], + packaging.parse_dependency_links([self.tmp_file])) + + def test_parse_dependency_with_git_egg_url(self): + with open(self.tmp_file, "w") as fh: + fh.write("-e git://foo.com/zipball#egg=bar") + self.assertEqual( + ["git://foo.com/zipball#egg=bar"], + packaging.parse_dependency_links([self.tmp_file])) + class TestVersions(base.BaseTestCase): @@ -759,7 +884,7 @@ class TestRequirementParsing(base.BaseTestCase): expected_requirements = { None: ['bar', 'requests-aws>=0.1.4'], ":(python_version=='2.6')": ['quux<1.0'], - ":(python_version=='2.7')": ['Routes>=1.12.3,!=2.0,!=2.1', + ":(python_version=='2.7')": ['Routes!=2.0,!=2.1,>=1.12.3', 'requests-kerberos>=0.6'], 'test': ['foo'], "test:(python_version=='2.7')": ['baz>3.2', 'bar>3.3'] @@ -778,7 +903,20 @@ class TestRequirementParsing(base.BaseTestCase): generated_requirements = dict( pkg_resources.split_sections(requires)) - self.assertEqual(expected_requirements, generated_requirements) + # NOTE(dhellmann): We have to spell out the comparison because + # the rendering for version specifiers in a range is not + # consistent across versions of setuptools. + + for section, expected in expected_requirements.items(): + exp_parsed = [ + pkg_resources.Requirement.parse(s) + for s in expected + ] + gen_parsed = [ + pkg_resources.Requirement.parse(s) + for s in generated_requirements[section] + ] + self.assertEqual(exp_parsed, gen_parsed) def get_soabi(): diff --git a/pbr/tests/test_setup.py b/pbr/tests/test_setup.py index 0b9c81b..85d40eb 100644 --- a/pbr/tests/test_setup.py +++ b/pbr/tests/test_setup.py @@ -17,9 +17,6 @@ from __future__ import print_function import os -import sys -import tempfile -import testscenarios try: import cStringIO as io @@ -446,115 +443,3 @@ class APIAutoDocTest(base.BaseTestCase): self.assertTrue( os.path.exists( "contributor/api/fake_package.fake_private_module.rst")) - - -class ParseRequirementsTestScenarios(base.BaseTestCase): - - versioned_scenarios = [ - ('non-versioned', {'versioned': False, 'expected': ['bar']}), - ('versioned', {'versioned': True, 'expected': ['bar>=1.2.3']}) - ] - - scenarios = [ - ('normal', {'url': "foo\nbar", 'expected': ['foo', 'bar']}), - ('normal_with_comments', { - 'url': "# this is a comment\nfoo\n# and another one\nbar", - 'expected': ['foo', 'bar']}), - ('removes_index_lines', {'url': '-f foobar', 'expected': []}), - ] - - scenarios = scenarios + testscenarios.multiply_scenarios([ - ('ssh_egg_url', {'url': 'git+ssh://foo.com/zipball#egg=bar'}), - ('git_https_egg_url', {'url': 'git+https://foo.com/zipball#egg=bar'}), - ('http_egg_url', {'url': 'https://foo.com/zipball#egg=bar'}), - ], versioned_scenarios) - - scenarios = scenarios + testscenarios.multiply_scenarios( - [ - ('git_egg_url', - {'url': 'git://foo.com/zipball#egg=bar', 'name': 'bar'}) - ], [ - ('non-editable', {'editable': False}), - ('editable', {'editable': True}), - ], - versioned_scenarios) - - def test_parse_requirements(self): - tmp_file = tempfile.NamedTemporaryFile() - req_string = self.url - if hasattr(self, 'editable') and self.editable: - req_string = ("-e %s" % req_string) - if hasattr(self, 'versioned') and self.versioned: - req_string = ("%s-1.2.3" % req_string) - with open(tmp_file.name, 'w') as fh: - fh.write(req_string) - self.assertEqual(self.expected, - packaging.parse_requirements([tmp_file.name])) - - -class ParseRequirementsTest(base.BaseTestCase): - - def setUp(self): - super(ParseRequirementsTest, self).setUp() - (fd, self.tmp_file) = tempfile.mkstemp(prefix='openstack', - suffix='.setup') - - def test_parse_requirements_override_with_env(self): - with open(self.tmp_file, 'w') as fh: - fh.write("foo\nbar") - self.useFixture( - fixtures.EnvironmentVariable('PBR_REQUIREMENTS_FILES', - self.tmp_file)) - self.assertEqual(['foo', 'bar'], - packaging.parse_requirements()) - - def test_parse_requirements_override_with_env_multiple_files(self): - with open(self.tmp_file, 'w') as fh: - fh.write("foo\nbar") - self.useFixture( - fixtures.EnvironmentVariable('PBR_REQUIREMENTS_FILES', - "no-such-file," + self.tmp_file)) - self.assertEqual(['foo', 'bar'], - packaging.parse_requirements()) - - def test_get_requirement_from_file_empty(self): - actual = packaging.get_reqs_from_files([]) - self.assertEqual([], actual) - - def test_parse_requirements_python_version(self): - with open("requirements-py%d.txt" % sys.version_info[0], - "w") as fh: - fh.write("# this is a comment\nfoobar\n# and another one\nfoobaz") - self.assertEqual(['foobar', 'foobaz'], - packaging.parse_requirements()) - - def test_parse_requirements_right_python_version(self): - with open("requirements-py1.txt", "w") as fh: - fh.write("thisisatrap") - with open("requirements-py%d.txt" % sys.version_info[0], - "w") as fh: - fh.write("# this is a comment\nfoobar\n# and another one\nfoobaz") - self.assertEqual(['foobar', 'foobaz'], - packaging.parse_requirements()) - - -class ParseDependencyLinksTest(base.BaseTestCase): - - def setUp(self): - super(ParseDependencyLinksTest, self).setUp() - (fd, self.tmp_file) = tempfile.mkstemp(prefix="openstack", - suffix=".setup") - - def test_parse_dependency_normal(self): - with open(self.tmp_file, "w") as fh: - fh.write("http://test.com\n") - self.assertEqual( - ["http://test.com"], - packaging.parse_dependency_links([self.tmp_file])) - - def test_parse_dependency_with_git_egg_url(self): - with open(self.tmp_file, "w") as fh: - fh.write("-e git://foo.com/zipball#egg=bar") - self.assertEqual( - ["git://foo.com/zipball#egg=bar"], - packaging.parse_dependency_links([self.tmp_file])) diff --git a/pbr/tests/test_util.py b/pbr/tests/test_util.py index 048b2b9..370a7de 100644 --- a/pbr/tests/test_util.py +++ b/pbr/tests/test_util.py @@ -36,8 +36,12 @@ class TestExtrasRequireParsingScenarios(base.BaseTestCase): baz>=3.2 foo """, - 'expected_extra_requires': {'first': ['foo', 'bar==1.0'], - 'second': ['baz>=3.2', 'foo']} + 'expected_extra_requires': { + 'first': ['foo', 'bar==1.0'], + 'second': ['baz>=3.2', 'foo'], + 'test': ['requests-mock'], + "test:(python_version=='2.6')": ['ordereddict'], + } }), ('with_markers', { 'config_text': """ diff --git a/pbr/tests/test_version.py b/pbr/tests/test_version.py index 14c8d17..d861d57 100644 --- a/pbr/tests/test_version.py +++ b/pbr/tests/test_version.py @@ -84,6 +84,19 @@ class TestSemanticVersion(base.BaseTestCase): lambda: from_pip_string('1.2.3.post5.dev6'), matchers.raises(ValueError)) + def test_from_pip_string_v_version(self): + parsed = from_pip_string('v1.2.3') + expected = version.SemanticVersion(1, 2, 3) + self.expectThat(expected, matchers.Equals(parsed)) + + expected = version.SemanticVersion(1, 2, 3, 'a', 5, dev_count=6) + parsed = from_pip_string('V1.2.3.0a4.post6') + self.expectThat(expected, matchers.Equals(parsed)) + + self.expectThat( + lambda: from_pip_string('x1.2.3'), + matchers.raises(ValueError)) + def test_from_pip_string_legacy_nonzero_lead_in(self): # reported in bug 1361251 expected = version.SemanticVersion( diff --git a/pbr/tests/testpackage/setup.cfg b/pbr/tests/testpackage/setup.cfg index 242c9c6..bf4c26a 100644 --- a/pbr/tests/testpackage/setup.cfg +++ b/pbr/tests/testpackage/setup.cfg @@ -6,10 +6,15 @@ version = 0.1.dev author = OpenStack author-email = openstack-dev@lists.openstack.org home-page = http://pypi.python.org/pypi/pbr +project_urls = + Bug Tracker = https://bugs.launchpad.net/pbr/ + Documentation = https://docs.openstack.org/pbr/ + Source Code = https://git.openstack.org/cgit/openstack-dev/pbr/ summary = Test package for testing pbr description-file = README.txt CHANGES.txt +description-content-type = text/plain; charset=UTF-8 requires-python = >=2.5 requires-dist = @@ -51,7 +56,3 @@ optional = True # pbr_testpackage._setup_hooks.test_hook_1 # pbr_testpackage._setup_hooks.test_hook_2 commands = pbr_testpackage._setup_hooks.test_command - -[build_ext] -#pre-hook.test_pre_hook = pbr_testpackage._setup_hooks.test_pre_hook -#post-hook.test_post_hook = pbr_testpackage._setup_hooks.test_post_hook diff --git a/pbr/tests/testpackage/test-requirements.txt b/pbr/tests/testpackage/test-requirements.txt index f283aff..8755eb4 100644 --- a/pbr/tests/testpackage/test-requirements.txt +++ b/pbr/tests/testpackage/test-requirements.txt @@ -1 +1,2 @@ ordereddict;python_version=='2.6' +requests-mock diff --git a/pbr/util.py b/pbr/util.py index a117785..163feb8 100644 --- a/pbr/util.py +++ b/pbr/util.py @@ -101,9 +101,11 @@ D1_D2_SETUP_ARGS = { "maintainer": ("metadata",), "maintainer_email": ("metadata",), "url": ("metadata", "home_page"), + "project_urls": ("metadata",), "description": ("metadata", "summary"), "keywords": ("metadata",), "long_description": ("metadata", "description"), + "long_description_content_type": ("metadata", "description_content_type"), "download_url": ("metadata",), "classifiers": ("metadata", "classifier"), "platforms": ("metadata", "platform"), # ** @@ -148,6 +150,9 @@ MULTI_FIELDS = ("classifiers", "tests_require", "cmdclass") +# setup() arguments that can have mapping values in setup.cfg +MAP_FIELDS = ("project_urls",) + # setup() arguments that contain boolean values BOOL_FIELDS = ("use_2to3", "zip_safe", "include_package_data") @@ -193,9 +198,9 @@ def cfg_to_args(path='setup.cfg', script_args=()): This method uses an existing setup.cfg to generate a dictionary of keywords that can be used by distutils.core.setup(kwargs**). - :param file: + :param path: The setup.cfg path. - :parm script_args: + :param script_args: List of commands setup.py was called with. :raises DistutilsFileError: When the setup.cfg file is not found. @@ -264,8 +269,6 @@ def cfg_to_args(path='setup.cfg', script_args=()): if entry_points: kwargs['entry_points'] = entry_points - wrap_commands(kwargs) - # Handle the [files]/extra_files option files_extra_files = has_get_option(config, 'files', 'extra_files') if files_extra_files: @@ -323,6 +326,12 @@ def setup_cfg_to_setup_kwargs(config, script_args=()): in_cfg_value = split_csv(in_cfg_value) if arg in MULTI_FIELDS: in_cfg_value = split_multiline(in_cfg_value) + elif arg in MAP_FIELDS: + in_cfg_map = {} + for i in split_multiline(in_cfg_value): + k, v = i.split('=') + in_cfg_map[k.strip()] = v.strip() + in_cfg_value = in_cfg_map elif arg in BOOL_FIELDS: # Provide some flexibility here... if in_cfg_value.lower() in ('true', 't', '1', 'yes', 'y'): @@ -402,6 +411,13 @@ def setup_cfg_to_setup_kwargs(config, script_args=()): if 'extras' in config: requirement_pattern = '(?P[^:]*):?(?P[^#]*?)(?:\s*#.*)?$' extras = config['extras'] + # Add contents of test-requirements, if any, into an extra named + # 'test' if one does not already exist. + if 'test' not in extras: + from pbr import packaging + extras['test'] = "\n".join(packaging.parse_requirements( + packaging.TEST_REQUIREMENTS_FILES)).replace(';', ':') + for extra in extras: extra_requirements = [] requirements = split_multiline(extras[extra]) @@ -552,103 +568,6 @@ def get_entry_points(config): for option, value in config['entry_points'].items()) -def wrap_commands(kwargs): - dist = st_dist.Distribution() - - # This should suffice to get the same config values and command classes - # that the actual Distribution will see (not counting cmdclass, which is - # handled below) - dist.parse_config_files() - - # Setuptools doesn't patch get_command_list, and as such we do not get - # extra commands from entry_points. As we need to be compatable we deal - # with this here. - for ep in pkg_resources.iter_entry_points('distutils.commands'): - if ep.name not in dist.cmdclass: - if hasattr(ep, 'resolve'): - cmdclass = ep.resolve() - else: - # Old setuptools does not have ep.resolve, and load with - # arguments is depricated in 11+. Use resolve, 12+, if we - # can, otherwise fall back to load. - # Setuptools 11 will throw a deprication warning, as it - # uses _load instead of resolve. - cmdclass = ep.load(False) - dist.cmdclass[ep.name] = cmdclass - - for cmd, _ in dist.get_command_list(): - hooks = {} - for opt, val in dist.get_option_dict(cmd).items(): - val = val[1] - if opt.startswith('pre_hook.') or opt.startswith('post_hook.'): - hook_type, alias = opt.split('.', 1) - hook_dict = hooks.setdefault(hook_type, {}) - hook_dict[alias] = val - if not hooks: - continue - - if 'cmdclass' in kwargs and cmd in kwargs['cmdclass']: - cmdclass = kwargs['cmdclass'][cmd] - else: - cmdclass = dist.get_command_class(cmd) - - new_cmdclass = wrap_command(cmd, cmdclass, hooks) - kwargs.setdefault('cmdclass', {})[cmd] = new_cmdclass - - -def wrap_command(cmd, cmdclass, hooks): - def run(self, cmdclass=cmdclass): - self.run_command_hooks('pre_hook') - cmdclass.run(self) - self.run_command_hooks('post_hook') - - return type(cmd, (cmdclass, object), - {'run': run, 'run_command_hooks': run_command_hooks, - 'pre_hook': hooks.get('pre_hook'), - 'post_hook': hooks.get('post_hook')}) - - -def run_command_hooks(cmd_obj, hook_kind): - """Run hooks registered for that command and phase. - - *cmd_obj* is a finalized command object; *hook_kind* is either - 'pre_hook' or 'post_hook'. - """ - - if hook_kind not in ('pre_hook', 'post_hook'): - raise ValueError('invalid hook kind: %r' % hook_kind) - - hooks = getattr(cmd_obj, hook_kind, None) - - if hooks is None: - return - - for hook in hooks.values(): - if isinstance(hook, str): - try: - hook_obj = resolve_name(hook) - except ImportError: - err = sys.exc_info()[1] # For py3k - raise errors.DistutilsModuleError('cannot find hook %s: %s' % - (hook,err)) - else: - hook_obj = hook - - if not hasattr(hook_obj, '__call__'): - raise errors.DistutilsOptionError('hook %r is not callable' % hook) - - log.info('running %s %s for command %s', - hook_kind, hook, cmd_obj.get_command_name()) - - try : - hook_obj(cmd_obj) - except: - e = sys.exc_info()[1] - log.error('hook %s raised exception: %s\n' % (hook, e)) - log.error(traceback.format_exc()) - sys.exit(1) - - def has_get_option(config, section, option): if section in config and option in config[section]: return config[section][option] @@ -661,7 +580,7 @@ def split_multiline(value): value = [element for element in (line.strip() for line in value.split('\n')) - if element] + if element and not element.startswith('#')] return value @@ -674,21 +593,6 @@ def split_csv(value): return value -def monkeypatch_method(cls): - """A function decorator to monkey-patch a method of the same name on the - given class. - """ - - def wrapper(func): - orig = getattr(cls, func.__name__, None) - if orig and not hasattr(orig, '_orig'): # Already patched - setattr(func, '_orig', orig) - setattr(cls, func.__name__, func) - return func - - return wrapper - - # The following classes are used to hack Distribution.command_options a bit class DefaultGetDict(defaultdict): """Like defaultdict, but the get() method also sets and returns the default @@ -699,20 +603,3 @@ class DefaultGetDict(defaultdict): if default is None: default = self.default_factory() return super(DefaultGetDict, self).setdefault(key, default) - - -class IgnoreDict(dict): - """A dictionary that ignores any insertions in which the key is a string - matching any string in `ignore`. The ignore list can also contain wildcard - patterns using '*'. - """ - - def __init__(self, ignore): - self.__ignore = re.compile(r'(%s)' % ('|'.join( - [pat.replace('*', '.*') - for pat in ignore]))) - - def __setitem__(self, key, val): - if self.__ignore.match(key): - return - super(IgnoreDict, self).__setitem__(key, val) diff --git a/pbr/version.py b/pbr/version.py index 474faf1..5eb217a 100644 --- a/pbr/version.py +++ b/pbr/version.py @@ -149,6 +149,7 @@ class SemanticVersion(object): @classmethod def _from_pip_string_unsafe(klass, version_string): # Versions need to start numerically, ignore if not + version_string = version_string.lstrip('vV') if not version_string[:1].isdigit(): raise ValueError("Invalid version %r" % version_string) input_components = version_string.split('.') diff --git a/releasenotes/notes/deprecate-pyN-requirements-364655c38fa5b780.yaml b/releasenotes/notes/deprecate-pyN-requirements-364655c38fa5b780.yaml new file mode 100644 index 0000000..3ed9bc7 --- /dev/null +++ b/releasenotes/notes/deprecate-pyN-requirements-364655c38fa5b780.yaml @@ -0,0 +1,5 @@ +--- +deprecations: + - | + Support for ``pyN``-suffixed requirement files has been deprecated: + environment markers should be used instead. diff --git a/releasenotes/notes/deprecate-testr-nose-integration-56e3e11248d946fc.yaml b/releasenotes/notes/deprecate-testr-nose-integration-56e3e11248d946fc.yaml new file mode 100644 index 0000000..1356847 --- /dev/null +++ b/releasenotes/notes/deprecate-testr-nose-integration-56e3e11248d946fc.yaml @@ -0,0 +1,10 @@ +--- +deprecations: + - | + *testr* and *nose* integration has been deprecated. This feature allowed + *pbr* to dynamically configure the test runner used when running + ``setup.py test``. However, this target has fallen out of favour in both + the OpenStack and broader Python ecosystem, and both *testr* and *nose* + offer native setuptools commands that can be manually aliased to ``test`` + on a per-project basis, if necessary. This feature will be removed in a + future release. diff --git a/releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml b/releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml new file mode 100644 index 0000000..c6ce753 --- /dev/null +++ b/releasenotes/notes/remove-command-hooks-907d9c2325f306ca.yaml @@ -0,0 +1,6 @@ +--- +upgrade: + - | + Support for entry point command hooks has been removed. This feature was + poorly tested, poorly documented, and broken in some environments. + Support for global hooks is not affected. diff --git a/releasenotes/notes/v_version-457b38c8679c5868.yaml b/releasenotes/notes/v_version-457b38c8679c5868.yaml new file mode 100644 index 0000000..696ba41 --- /dev/null +++ b/releasenotes/notes/v_version-457b38c8679c5868.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Support version parsing of git tag with the ``v`` pattern + (or ``V``), in addition to ````. diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py new file mode 100644 index 0000000..56f7ecd --- /dev/null +++ b/releasenotes/source/conf.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# pbr Release Notes documentation build configuration file + + +# -- General configuration ------------------------------------------------ + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'openstackdocstheme', + 'reno.sphinxext', +] + +# The master toctree document. +master_doc = 'index' + +# Release notes are version independent +# The short X.Y version. +version = '' +# The full version, including alpha/beta/rc tags. +release = '' + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'openstackdocs' + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +html_last_updated_fmt = '%Y-%m-%d %H:%M' + + +# -- Options for openstackdocstheme --------------------------------------- + +repository_name = 'openstack-dev/pbr' +bug_project = 'pbr' +bug_tag = '' diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst new file mode 100644 index 0000000..e6e6346 --- /dev/null +++ b/releasenotes/source/index.rst @@ -0,0 +1,8 @@ +================= +pbr Release Notes +================= + +.. toctree:: + :maxdepth: 1 + + unreleased diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst new file mode 100644 index 0000000..875030f --- /dev/null +++ b/releasenotes/source/unreleased.rst @@ -0,0 +1,5 @@ +============================ +Current Series Release Notes +============================ + +.. release-notes:: diff --git a/setup.cfg b/setup.cfg index 899e5f3..2e153ea 100644 --- a/setup.cfg +++ b/setup.cfg @@ -5,7 +5,12 @@ author-email = openstack-dev@lists.openstack.org summary = Python Build Reasonableness description-file = README.rst -home-page = http://docs.openstack.org/developer/pbr/ +description-content-type = text/x-rst; charset=UTF-8 +home-page = https://docs.openstack.org/pbr/latest/ +project_urls = + Bug Tracker = https://bugs.launchpad.net/pbr/ + Documentation = https://docs.openstack.org/pbr/ + Source Code = https://git.openstack.org/cgit/openstack-dev/pbr/ requires-python = >=2.6 classifier = Development Status :: 5 - Production/Stable @@ -17,7 +22,6 @@ classifier = Operating System :: OS Independent Programming Language :: Python Programming Language :: Python :: 2 - Programming Language :: Python :: 2.6 Programming Language :: Python :: 2.7 Programming Language :: Python :: 3 Programming Language :: Python :: 3.3 @@ -37,6 +41,7 @@ autodoc_tree_index_modules = True autodoc_tree_excludes = setup.py pbr/tests/ +api_doc_dir = reference/api [entry_points] distutils.setup_keywords = @@ -50,6 +55,7 @@ console_scripts = all-files = 1 build-dir = doc/build source-dir = doc/source +warning-is-error = 1 [wheel] universal = 1 diff --git a/test-requirements.txt b/test-requirements.txt index 9df6553..de91490 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,13 +4,14 @@ coverage!=4.4,>=4.0 # Apache-2.0 fixtures>=3.0.0 # Apache-2.0/BSD hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -mock>=2.0 # BSD -python-subunit>=0.0.18 # Apache-2.0/BSD -sphinx!=1.6.1,>=1.5.1 # BSD -oslosphinx>=4.7.0 # Apache-2.0 -six>=1.9.0 # MIT +mock>=2.0.0 # BSD +python-subunit>=1.0.0 # Apache-2.0/BSD +sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD +openstackdocstheme>=1.18.1 # Apache-2.0 +reno>=2.5.0 # Apache-2.0 +six>=1.10.0 # MIT testrepository>=0.0.18 # Apache-2.0/BSD -testresources>=0.2.4 # Apache-2.0/BSD +testresources>=2.0.0 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD -testtools>=1.4.0 # MIT -virtualenv>=13.1.0 # MIT +testtools>=2.2.0 # MIT +virtualenv>=14.0.6 # MIT diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index e61b63a..0000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. - -CONSTRAINTS_FILE="$1" -shift 1 - -set -e - -# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get -# published to logs.openstack.org for easy debugging. -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ "$CONSTRAINTS_FILE" != http* ]]; then - CONSTRAINTS_FILE="file://$CONSTRAINTS_FILE" -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl "$CONSTRAINTS_FILE" --insecure --progress-bar --output "$localfile" - -pip install -c"$localfile" openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints "$localfile" -- "$CLIENT_NAME" - -pip install -c"$localfile" -U "$@" -exit $? diff --git a/tools/tox_releasenotes.sh b/tools/tox_releasenotes.sh new file mode 100755 index 0000000..fc64b99 --- /dev/null +++ b/tools/tox_releasenotes.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +rm -rf releasenotes/build + +sphinx-build -a -E -W \ + -d releasenotes/build/doctrees \ + -b html \ + releasenotes/source releasenotes/build/html +BUILD_RESULT=$? + +UNCOMMITTED_NOTES=$(git status --porcelain | \ + awk '$1 ~ "M|A|??" && $2 ~ /releasenotes\/notes/ {print $2}') + +if [ "${UNCOMMITTED_NOTES}" ] +then + cat <