Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 10 additions & 5 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ install:
- conda config --add channels conda-forge # For sphinxcontrib.autoprogram
- conda update -q conda
- conda info -a
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION requests cryptography sphinx pyflakes sphinxcontrib-autoprogram pytest sphinx-issues
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION requests cryptography sphinx pyflakes sphinxcontrib-autoprogram pytest sphinx-issues pyyaml
- source activate test-environment

script:
Expand All @@ -31,12 +31,17 @@ script:
cd docs;
make html;
cd ..;
python -m doctr deploy --key-path deploy_key.enc .;
python -m doctr deploy --key-path deploy_key.enc --gh-pages-docs docs;
python -m doctr deploy --no-require-master --built-docs docs/_build/html --key-path deploy_key.enc "docs-$TRAVIS_BRANCH";
python -m doctr deploy --no-require-master --key-path deploy_key.enc --no-sync --command "echo test" docs;
python -m doctr deploy --sync .;
python -m doctr deploy --sync --gh-pages-docs docs;
python -m doctr deploy --sync --no-require-master --built-docs docs/_build/html "docs-$TRAVIS_BRANCH";
python -m doctr deploy --no-require-master --command "echo test" docs;
fi
- if [[ "${TESTS}" == "true" ]]; then
pyflakes doctr;
py.test doctr;
fi
doctr:
key-path: deploy_key.enc
require-master: true
sync: False
lubalubadubdub: False
8 changes: 7 additions & 1 deletion docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@ Current
- The ``--gh-pages-docs`` flag of ``doctr deploy`` has been deprecated.
Specify the deploy directory like ``doctr deploy .`` or ``doctr deploy docs``.
There is also no longer a default deploy directory. (:issue:`128`)

- ``setup_GitHub_push`` now takes a ``branch_whitelist`` parameter instead of
of a ``require_master``
- ``.travis.yml`` can be used to store some of doctr configuration in addition
to the command line flags. Write doctr configuration under the ``doctr`` key.
:issue:`137`
- All boolean command line flags now have a their counterpart that can overwrite
the config values set in ``.travis.yml``

1.4.1 (2017-01-11)
==================
Expand Down
39 changes: 39 additions & 0 deletions docs/commandline.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,42 @@

.. autoprogram:: doctr.__main__:get_parser()
:prog: doctr


Configuration
-------------

In addition to command line arguments you can configure ``doctr`` using the
``.travis.yml`` files. Command line arguments take precedence over the value
present in the configuration file.

The configuration parameters available from the ``.travis.yml`` file mirror
their command line siblings except doubledashes ``--`` and ``--no-`` prefix are
dropped.

Use a ``doctr`` section in your ``travis.yml`` file to store your doctr
configuration:

.. code:: yaml

- language: python
- script:
- set -e
- py.test
- cd docs
- make html
- cd ..
- doctr deploy .
- doctr:
- key-path : 'path/to/key/from/repo/root/path.key'
- deploy-repo : 'myorg/myrepo'


The following options are available from the configuration file and not from
the command line:

``branches``:
A list of regular expression that matches branches on which ``doctr`` should
still deploy the documentation. For example ``.*\.x`` will deploy all
branches like ``3.x``, ``4.x`` ...

133 changes: 116 additions & 17 deletions doctr/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@

import sys
import os
import os.path
import argparse
import shlex
import subprocess
import yaml
import json

from pathlib import Path

from textwrap import dedent

Expand All @@ -35,7 +40,69 @@
get_current_repo, sync_from_log, find_sphinx_build_dir, run)
from . import __version__

def get_parser():
def make_parser_with_config_adder(parser, config):
"""factory function for a smarter parser:

return an utility function that pull default from the config as well.

Pull the default for parser not only from the ``default`` kwarg,
but also if an identical value is find in ``config`` where leading
``--`` or ``--no`` is removed.

If the option is a boolean flag, automatically register an opposite,
exclusive option by prepending or removing the `--no-`. This is useful
to overwrite config in ``.travis.yml``

Mutate the config object and remove know keys in order to detect unused
options afterwoard.
"""

def internal(arg, **kwargs):
invert = {
'store_true':'store_false',
'store_false':'store_true',
}
if arg.startswith('--no-'):
key = arg[5:]
else:
key = arg[2:]
if 'default' in kwargs:
if key in config:
kwargs['default'] = config[key]
del config[key]
action = kwargs.get('action')
if action in invert:
exclusive_grp = parser.add_mutually_exclusive_group()
exclusive_grp.add_argument(arg, **kwargs)
kwargs['action'] = invert[action]
kwargs['help'] = 'Inverse of "%s"' % arg
if arg.startswith('--no-'):
arg = '--%s' % arg[5:]
else:
arg = '--no-%s' % arg[2:]
exclusive_grp.add_argument(arg, **kwargs)
else:
parser.add_argument(arg, **kwargs)

return internal


def get_parser(config=None):
"""
return a parser suitable to parse CL arguments.

Parameters
----------

config: dict
Default values to fall back on, if not given.

Returns
-------

An argparse parser configured to parse the command lines arguments of
sys.argv which will default on values present in ``config``.
"""
# This uses RawTextHelpFormatter so that the description (the docstring of
# this module) is formatted correctly. Unfortunately, that means that
# parser help is not text wrapped (but all other help is).
Expand All @@ -45,47 +112,55 @@ def get_parser():
options available.
""",
)

if not config:
config={}
parser.add_argument('-V', '--version', action='version', version='doctr ' + __version__)

subcommand = parser.add_subparsers(title='subcommand', dest='subcommand')

deploy_parser = subcommand.add_parser('deploy', help="""Deploy the docs to GitHub from Travis.""")
deploy_parser.set_defaults(func=deploy)
deploy_parser.add_argument('deploy_directory', type=str, nargs='?',
help="""Directory to deploy the html documentation to on gh-pages.""")
deploy_parser.add_argument('--force', action='store_true', help="""Run the deploy command even
deploy_parser_add_argument = make_parser_with_config_adder(deploy_parser, config)
deploy_parser_add_argument('--force', action='store_true', help="""Run the deploy command even
if we do not appear to be on Travis.""")
deploy_parser.add_argument('--token', action='store_true', default=False,
deploy_parser_add_argument('deploy_directory', type=str, nargs='?',
help="""Directory to deploy the html documentation to on gh-pages.""")

deploy_parser_add_argument('--token', action='store_true', default=False,
help="""Push to GitHub using a personal access token. Use this if you
used 'doctr configure --token'.""")
deploy_parser.add_argument('--key-path', default='github_deploy_key.enc',
deploy_parser_add_argument('--key-path', default='github_deploy_key.enc',
help="""Path of the encrypted GitHub deploy key. The default is %(default)r.""")
deploy_parser.add_argument('--built-docs', default=None,
deploy_parser_add_argument('--built-docs', default=None,
help="""Location of the built html documentation to be deployed to
gh-pages. If not specified, Doctr will try to automatically detect build location""")
deploy_parser.add_argument('--tmp-dir', default=None,
deploy_parser_add_argument('--tmp-dir', default=None,
help=argparse.SUPPRESS)
deploy_parser.add_argument('--deploy-repo', default=None, help="""Repo to
deploy_parser_add_argument('--deploy-repo', default=None, help="""Repo to
deploy the docs to. By default, it deploys to the repo Doctr is run from.""")
deploy_parser.add_argument('--no-require-master', dest='require_master', action='store_false',
deploy_parser_add_argument('--no-require-master', dest='require_master', action='store_false',
default=True, help="""Allow docs to be pushed from a branch other than master""")
deploy_parser.add_argument('--command', default=None, help="""Command to
deploy_parser_add_argument('--command', default=None, help="""Command to
be run before committing and pushing. If the command creates
additional files that should be deployed, they should be added to the
index.""")
deploy_parser.add_argument('--no-sync', dest='sync', action='store_false',
deploy_parser_add_argument('--no-sync', dest='sync', action='store_false',
default=True, help="""Don't sync any files. This is generally used in
conjunction with the --command flag, for instance, if the command syncs
the files for you. Any files you wish to commit should be added to the
index.""")
deploy_parser.add_argument('--no-push', dest='push', action='store_false',
default=True, help="Run all the steps except the last push step."
deploy_parser_add_argument('--no-push', dest='push', action='store_false',
default=True, help="Run all the steps except the last push step. "
"Useful for debugging")
deploy_parser.add_argument('--gh-pages-docs', default=None,
deploy_parser_add_argument('--gh-pages-docs', default=None,
help="""!!DEPRECATED!! Directory to deploy the html documentation to on gh-pages.
The default is %(default)r. The deploy directory should be passed as
the first argument to 'doctr deploy'. This flag is kept for backwards
compatibility.""")

if config:
print('Warning, The following options in `.travis.yml` were not recognised:\n%s' % json.dumps(config, indent=2))

configure_parser = subcommand.add_parser('configure', help="Configure doctr. This command should be run locally (not on Travis).")
configure_parser.set_defaults(func=configure)
Expand All @@ -106,6 +181,23 @@ def get_parser():

return parser

def get_config():
"""
This load some configuration from the ``.travis.yml``, if file is present,
``doctr`` key if present.
"""
p = Path('.travis.yml')
if not p.exists():
return {}
with p.open() as f:
travis_config = yaml.safe_load(f.read())

config = travis_config.get('doctr', {})

if not isinstance(config, dict):
raise ValueError('config is not a dict: {}'.format(config))
return config

def process_args(parser):
args = parser.parse_args()

Expand All @@ -126,6 +218,8 @@ def deploy(args, parser):
parser.error("doctr does not appear to be running on Travis. Use "
"doctr deploy --force to run anyway.")

config = get_config()

if args.tmp_dir:
parser.error("The --tmp-dir flag has been removed (doctr no longer uses a temporary directory when deploying).")

Expand All @@ -145,9 +239,13 @@ def deploy(args, parser):

current_commit = subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('utf-8').strip()
try:

branch_whitelist = {'master'} if args.require_master else set({})
branch_whitelist.update(set(config.get('branches',set({}))))

can_push = setup_GitHub_push(deploy_repo, auth_type='token' if args.token else
'deploy_key', full_key_path=args.key_path,
require_master=args.require_master)
branch_whitelist=branch_whitelist)

if args.sync:
built_docs = args.built_docs or find_sphinx_build_dir()
Expand Down Expand Up @@ -284,7 +382,8 @@ def configure(args, parser):
""".format(encrypted_variable=encrypted_variable.decode('utf-8'), N=N)))

def main():
return process_args(get_parser())
config = get_config()
return process_args(get_parser(config=config))

if __name__ == '__main__':
sys.exit(main())
16 changes: 14 additions & 2 deletions doctr/travis.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import subprocess
import sys
import glob
import re

from cryptography.fernet import Fernet

Expand Down Expand Up @@ -132,7 +133,7 @@ def get_current_repo():
_, org, git_repo = remote_url.rsplit('.git', 1)[0].rsplit('/', 2)
return (org + '/' + git_repo)

def setup_GitHub_push(deploy_repo, auth_type='deploy_key', full_key_path='github_deploy_key.enc', require_master=True):
def setup_GitHub_push(deploy_repo, auth_type='deploy_key', full_key_path='github_deploy_key.enc', require_master=None, branch_whitelist=None):
"""
Setup the remote to push to GitHub (to be run on Travis).

Expand All @@ -144,14 +145,25 @@ def setup_GitHub_push(deploy_repo, auth_type='deploy_key', full_key_path='github

For ``auth_type='deploy_key'``, this sets up the remote with ssh access.
"""

if branch_whitelist is None:
branch_whitelist={'master'}

if require_master is not None:
import warnings
warnings.warn("`setup_GitHub_push`'s `require_master` argument in favor of `branch_whitelist=['master']`",
DeprecationWarning,
stacklevel=2)
branch_whitelist.add('master')

canpush = True
if auth_type not in ['deploy_key', 'token']:
raise ValueError("auth_type must be 'deploy_key' or 'token'")

TRAVIS_BRANCH = os.environ.get("TRAVIS_BRANCH", "")
TRAVIS_PULL_REQUEST = os.environ.get("TRAVIS_PULL_REQUEST", "")

if TRAVIS_BRANCH != "master" and require_master:
if any([re.compile(x).match(TRAVIS_BRANCH) for x in branch_whitelist]):
print("The docs are only pushed to gh-pages from master. To allow pushing from "
"a non-master branch, use the --no-require-master flag", file=sys.stderr)
print("This is the {TRAVIS_BRANCH} branch".format(TRAVIS_BRANCH=TRAVIS_BRANCH), file=sys.stderr)
Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
entry_points={'console_scripts': [ 'doctr = doctr.__main__:main']},
python_requires= '>=3.5',
install_requires=[
'pyyaml',
'requests',
'cryptography',
],
Expand Down