Beispiel #1
0
def test_multiple_remotes(tmpdir, local, remote):
    """Test multiple remote URLs being carried over.

    :param tmpdir: pytest fixture.
    :param local: conftest fixture.
    :param remote: conftest fixture.
    """
    origin_push = tmpdir.ensure_dir('origin_push')
    pytest.run(origin_push, ['git', 'init', '--bare'])
    pytest.run(local, ['git', 'remote', 'set-url', '--push', 'origin', str(origin_push)])
    origin2_fetch = tmpdir.ensure_dir('origin2_fetch')
    pytest.run(origin2_fetch, ['git', 'init', '--bare'])
    pytest.run(local, ['git', 'remote', 'add', 'origin2', str(origin2_fetch)])
    origin2_push = tmpdir.ensure_dir('origin2_push')
    pytest.run(origin2_push, ['git', 'init', '--bare'])
    pytest.run(local, ['git', 'remote', 'set-url', '--push', 'origin2', str(origin2_push)])

    new_root = tmpdir.ensure_dir('new_root')
    clone(str(local), str(new_root), 'origin', 'master', '', None)

    output = pytest.run(new_root, ['git', 'remote', '-v'])
    actual = output.strip().splitlines()
    expected = [
        'origin\t{} (fetch)'.format(remote),
        'origin\t{} (push)'.format(origin_push),
        'origin2\t{} (fetch)'.format(origin2_fetch),
        'origin2\t{} (push)'.format(origin2_push),
    ]
    assert actual == expected
Beispiel #2
0
def test_no_exclude(tmpdir, local_docs):
    """Simple test without "git rm".

    :param tmpdir: pytest fixture.
    :param local_docs: conftest fixture.
    """
    new_root = tmpdir.ensure_dir('new_root')
    clone(str(local_docs), str(new_root), 'origin', 'master', '', None)
    assert new_root.join('conf.py').check(file=True)
    assert new_root.join('contents.rst').check(file=True)
    assert new_root.join('README').check(file=True)
    branch = pytest.run(new_root, ['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
    assert branch == 'master'
    pytest.run(local_docs, ['git', 'diff-index', '--quiet', 'HEAD', '--'])  # Exit 0 if nothing changed.
    pytest.run(new_root, ['git', 'diff-index', '--quiet', 'HEAD', '--'])  # Exit 0 if nothing changed.
Beispiel #3
0
def test_exclude(tmpdir, local):
    """Test with "git rm".

    :param tmpdir: pytest fixture.
    :param local: conftest fixture.
    """
    pytest.run(local, ['git', 'checkout', 'feature'])
    local.join('one.txt').write('one')
    local.join('two.txt').write('two')
    local.ensure('sub', 'three.txt').write('three')
    local.ensure('sub', 'four.txt').write('four')
    pytest.run(local, ['git', 'add', 'one.txt', 'two.txt', 'sub'])
    pytest.run(local, ['git', 'commit', '-m', 'Adding new files.'])
    pytest.run(local, ['git', 'push', 'origin', 'feature'])
    pytest.run(local, ['git', 'checkout', 'master'])

    # Run.
    exclude = [
        '.travis.yml', 'appveyor.yml',  # Ignored (nonexistent), show warnings.
        'README', 'two.txt', join('sub', 'four.txt'),  # Only leave these.
    ]
    new_root = tmpdir.ensure_dir('new_root')
    clone(str(local), str(new_root), 'origin', 'feature', '.', exclude)

    # Verify files.
    assert new_root.join('.git').check(dir=True)
    assert new_root.join('README').check(file=True)
    assert new_root.join('sub', 'four.txt').read() == 'four'
    assert new_root.join('two.txt').read() == 'two'
    paths = sorted(f.relto(new_root) for f in new_root.visit() if new_root.join('.git') not in f.parts())
    assert paths == ['README', 'sub', join('sub', 'four.txt'), 'two.txt']

    # Verify original repo state.
    pytest.run(local, ['git', 'diff-index', '--quiet', 'HEAD', '--'])  # Verify unchanged.
    branch = pytest.run(local, ['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
    assert branch == 'master'

    # Verify new repo state.
    with pytest.raises(CalledProcessError):
        pytest.run(new_root, ['git', 'diff-index', '--quiet', 'HEAD', '--'])
    branch = pytest.run(new_root, ['git', 'rev-parse', '--abbrev-ref', 'HEAD']).strip()
    assert branch == 'feature'
    status = pytest.run(new_root, ['git', 'status', '--porcelain'])
    assert status == 'D  one.txt\nD  sub/three.txt\n'
Beispiel #4
0
def test_exclude_subdir(tmpdir, local):
    """Test with grm_dir set to a subdirectory.

    :param tmpdir: pytest fixture.
    :param local: conftest fixture.
    """
    local.ensure('sub', 'three.txt').write('three')
    local.ensure('sub', 'four.txt').write('four')
    pytest.run(local, ['git', 'add', 'sub'])
    pytest.run(local, ['git', 'commit', '-m', 'Adding new files.'])
    pytest.run(local, ['git', 'push', 'origin', 'master'])

    new_root = tmpdir.ensure_dir('new_root')
    clone(str(local), str(new_root), 'origin', 'master', 'sub', ['three.txt'])
    paths = sorted(f.relto(new_root) for f in new_root.visit() if new_root.join('.git') not in f.parts())
    assert paths == ['README', 'sub', join('sub', 'three.txt')]

    status = pytest.run(new_root, ['git', 'status', '--porcelain'])
    assert status == 'D  sub/four.txt\n'
def push(ctx, config, rel_source, dest_branch, rel_dest, **options):
    """Build locally and then push to remote branch.

    First the build sub command is invoked which takes care of building all versions of your documentation in a
    temporary directory. If that succeeds then all built documents will be pushed to a remote branch.

    REL_SOURCE is the path to the docs directory relative to the git root. If the source directory has moved around
    between git tags you can specify additional directories.

    DEST_BRANCH is the branch name where generated docs will be committed to. The branch will then be pushed to remote.
    If there is a race condition with another job pushing to remote the docs will be re-generated and pushed again.

    REL_DEST is the path to the directory that will hold all generated docs for all versions relative to the git roof of
    DEST_BRANCH.

    To pass options to sphinx-build (run for every branch/tag) use a double hyphen
    (e.g. push docs gh-pages . -- -D setting=value).
    \f

    :param click.core.Context ctx: Click context.
    :param sphinxcontrib.versioning.lib.Config config: Runtime configuration.
    :param tuple rel_source: Possible relative paths (to git root) of Sphinx directory containing conf.py (e.g. docs).
    :param str dest_branch: Branch to clone and push to.
    :param str rel_dest: Relative path (to git root) to write generated docs to.
    :param dict options: Additional Click options.
    """
    if 'pre' in config:
        config.pop('pre')(rel_source)
        config.update({k: v for k, v in options.items() if v})
        if config.local_conf:
            config.update(read_local_conf(config.local_conf), ignore_set=True)
    if NO_EXECUTE:
        raise RuntimeError(config, rel_source, dest_branch, rel_dest)
    log = logging.getLogger(__name__)

    # Clone, build, push.
    for _ in range(PUSH_RETRIES):
        with TempDir() as temp_dir:
            log.info('Cloning %s into temporary directory...', dest_branch)
            try:
                clone(config.git_root, temp_dir, config.push_remote, dest_branch, rel_dest, config.grm_exclude)
            except GitError as exc:
                log.error(exc.message)
                log.error(exc.output)
                raise HandledError

            log.info('Building docs...')
            ctx.invoke(build, rel_source=rel_source, destination=os.path.join(temp_dir, rel_dest))
            versions = config.pop('versions')

            log.info('Attempting to push to branch %s on remote repository.', dest_branch)
            try:
                if commit_and_push(temp_dir, config.push_remote, versions):
                    return
            except GitError as exc:
                log.error(exc.message)
                log.error(exc.output)
                raise HandledError
        log.warning('Failed to push to remote repository. Retrying in %d seconds...', PUSH_SLEEP)
        time.sleep(PUSH_SLEEP)

    # Failed if this is reached.
    log.error('Ran out of retries, giving up.')
    raise HandledError
def push(ctx, config, rel_source, dest_branch, rel_dest, **options):
    """Build locally and then push to remote branch.

    First the build sub command is invoked which takes care of building all versions of your documentation in a
    temporary directory. If that succeeds then all built documents will be pushed to a remote branch.

    REL_SOURCE is the path to the docs directory relative to the git root. If the source directory has moved around
    between git tags you can specify additional directories.

    DEST_BRANCH is the branch name where generated docs will be committed to. The branch will then be pushed to remote.
    If there is a race condition with another job pushing to remote the docs will be re-generated and pushed again.

    REL_DEST is the path to the directory that will hold all generated docs for all versions relative to the git roof of
    DEST_BRANCH.

    To pass options to sphinx-build (run for every branch/tag) use a double hyphen
    (e.g. push docs gh-pages . -- -D setting=value).
    \f

    :param click.core.Context ctx: Click context.
    :param sphinxcontrib.versioning.lib.Config config: Runtime configuration.
    :param tuple rel_source: Possible relative paths (to git root) of Sphinx directory containing conf.py (e.g. docs).
    :param str dest_branch: Branch to clone and push to.
    :param str rel_dest: Relative path (to git root) to write generated docs to.
    :param dict options: Additional Click options.
    """
    if 'pre' in config:
        config.pop('pre')(rel_source)
        config.update({k: v for k, v in options.items() if v})
        if config.local_conf:
            config.update(read_local_conf(config.local_conf), ignore_set=True)
    if NO_EXECUTE:
        raise RuntimeError(config, rel_source, dest_branch, rel_dest)
    log = logging.getLogger(__name__)

    # Clone, build, push.
    for _ in range(PUSH_RETRIES):
        with TempDir() as temp_dir:
            log.info('Cloning %s into temporary directory...', dest_branch)
            try:
                clone(config.git_root, temp_dir, config.push_remote,
                      dest_branch, rel_dest, config.grm_exclude)
            except GitError as exc:
                log.error(exc.message)
                log.error(exc.output)
                raise HandledError

            log.info('Building docs...')
            ctx.invoke(build,
                       rel_source=rel_source,
                       destination=os.path.join(temp_dir, rel_dest))
            versions = config.pop('versions')

            log.info('Attempting to push to branch %s on remote repository.',
                     dest_branch)
            try:
                if commit_and_push(temp_dir, config.push_remote, versions):
                    return
            except GitError as exc:
                log.error(exc.message)
                log.error(exc.output)
                raise HandledError
        log.warning(
            'Failed to push to remote repository. Retrying in %d seconds...',
            PUSH_SLEEP)
        time.sleep(PUSH_SLEEP)

    # Failed if this is reached.
    log.error('Ran out of retries, giving up.')
    raise HandledError
Beispiel #7
0
def test_bad_branch_rel_dest_exclude(tmpdir, local):
    """Test bad data.

    :param tmpdir: pytest fixture.
    :param local: conftest fixture.
    """
    # Unknown branch.
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root')), 'origin', 'unknown_branch', '.', None)
    assert 'Remote branch unknown_branch not found in upstream origin' in exc.value.output

    # Not a branch.
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root')), 'origin', 'light_tag', '.', None)
    assert 'fatal: ref HEAD is not a symbolic ref' in exc.value.output

    # rel_dest outside of repo.
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root2')), 'origin', 'master', '..', ['README'])
    assert "'..' is outside repository" in exc.value.output

    # rel_dest invalid.
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', 'unknown', ['README'])
    assert "pathspec 'unknown' did not match any files" in exc.value.output

    # No origin.
    pytest.run(local, ['git', 'remote', 'rename', 'origin', 'origin2'])
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', '.', None)
    assert 'Git repo missing remote "origin".' in exc.value.message
    assert 'origin2\t' in exc.value.output
    assert 'origin\t' not in exc.value.output

    # No remote.
    pytest.run(local, ['git', 'remote', 'rm', 'origin2'])
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root3')), 'origin', 'master', '.', None)
    assert 'Git repo has no remotes.' in exc.value.message
    assert not exc.value.output

    # Bad remote.
    pytest.run(local, ['git', 'remote', 'add', 'origin', local.join('does_not_exist')])
    with pytest.raises(GitError) as exc:
        clone(str(local), str(tmpdir.ensure_dir('new_root4')), 'origin', 'master', '.', None)
    if IS_WINDOWS:
        assert "'{}' does not appear to be a git repository".format(local.join('does_not_exist')) in exc.value.output
    else:
        assert "repository '{}' does not exist".format(local.join('does_not_exist')) in exc.value.output