예제 #1
0
def test_error_if_exclude_and_include_overlap(cmdr, tmp_empty):

    with pytest.raises(ClickException) as excinfo:
        source.copy(cmdr, '.', 'dist', exclude=['file'], include=['file'])

    expected = ("include and exclude must "
                "not have overlapping elements: {'file'}")
    assert expected == str(excinfo.value)
예제 #2
0
def test_no_git_but_exclude(cmdr, tmp_empty):
    Path('file').touch()
    Path('secrets.txt').touch()

    source.copy(cmdr, '.', 'dist', exclude=['secrets.txt'])

    expected = set(Path(p) for p in ('dist/file', ))

    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #3
0
def test_copy_with_gitignore(cmdr, tmp_empty):
    Path('file').touch()
    Path('ignoreme').touch()

    Path('.gitignore').write_text('ignoreme')
    git_init()
    source.copy(cmdr, '.', 'dist')

    expected = set({Path('dist/file')})
    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #4
0
def test_warns_if_fails_to_get_git_tracked_files(tmp_empty, capsys):
    Path('file').touch()
    Path('secrets.txt').touch()

    with Commander() as cmdr:
        source.copy(cmdr, '.', 'dist')

    captured = capsys.readouterr()

    assert 'Unable to get git tracked files' in captured.out
예제 #5
0
def test_no_git_but_exclude_entire_folder(cmdr, tmp_empty):
    Path('file').touch()
    Path('dir').mkdir()
    Path('dir', 'secrets.txt').touch()
    Path('dir', 'more-secrets.txt').touch()

    source.copy(cmdr, '.', 'dist', exclude=['dir'])

    expected = set(Path(p) for p in ('dist/file', ))
    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #6
0
def test_copy(cmdr, tmp_empty):
    Path('file').touch()
    Path('dir').mkdir()
    Path('dir', 'another').touch()
    git_init()
    source.copy(cmdr, '.', 'dist')

    expected = set(Path(p) for p in (
        'dist/file',
        'dist/dir/another',
    ))
    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #7
0
def test_override_git_with_exclude(cmdr, tmp_empty):
    Path('file').touch()
    Path('secrets.txt').touch()

    # let git track everything
    Path('.gitignore').touch()
    git_init()

    # exclude some file
    source.copy(cmdr, '.', 'dist', exclude=['file'])

    expected = set({Path('dist/secrets.txt')})
    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #8
0
def test_warns_on_dirty_git(tmp_empty, capsys):
    Path('file').touch()
    Path('secrets.txt').touch()

    Path('.gitignore').write_text('secrets.txt')
    git_init()

    Path('new-file').touch()

    with Commander() as cmdr:
        source.copy(cmdr, '.', 'dist')

    captured = capsys.readouterr()

    assert 'Your git repository contains untracked' in captured.out
예제 #9
0
def test_ignores_pycache(cmdr, tmp_empty):
    Path('file').touch()
    dir_ = Path('__pycache__')
    dir_.mkdir()
    (dir_ / 'file').touch()
    (dir_ / 'another').touch()
    dir_another = Path('subdir', '__pycache__')
    dir_another.mkdir(parents=True)
    (dir_another / 'file').touch()
    (dir_another / 'another').touch()

    source.copy(cmdr, '.', 'dist')

    expected = set(Path(p) for p in ('dist/file', ))
    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #10
0
def test_copy_override_gitignore_with_include(cmdr, tmp_empty):
    Path('file').touch()
    Path('secrets.txt').touch()

    Path('.gitignore').write_text('secrets.txt')
    git_init()

    source.copy(cmdr, '.', 'dist', include=['secrets.txt'])

    expected = set(Path(p) for p in (
        'dist/file',
        'dist/secrets.txt',
    ))

    assert set(Path(p) for p in source.glob_all('dist')) == expected
예제 #11
0
def build(e, cfg, name, until, skip_tests=False):
    """Build a docker image

    Parameters
    ----------
    e : Commander
        Commander instance

    cfg
        Configuration

    name : str
        Target environment name

    until : str
        Stop after certain starge

    skip_tests : bool, default=False
        Skip image testing (check dag loading and File.client configuration)
    """

    # if this is a pkg, get the name
    try:
        pkg_name = default.find_package_name()
    # if not a package, use the parent folder's name
    except ValueError:
        pkg_name = Path('.').resolve().name
        version = 'latest'
    else:
        # if using versioneer, the version may contain "+"
        version = importlib.import_module(pkg_name).__version__.replace(
            '+', '-plus-')

    if Path('requirements.lock.txt').exists():
        e.cp('requirements.lock.txt')
    elif Path('environment.lock.yml').exists():
        e.cp('environment.lock.yml')
    else:
        raise ClickException('Expected environment.lock.yml or '
                             'requirements.txt.lock at the root '
                             'directory. Add one and try again')

    # generate source distribution

    if Path('setup.py').exists():
        # .egg-info may cause issues if MANIFEST.in was recently updated
        e.rm('dist', 'build', Path('src', pkg_name, f'{pkg_name}.egg-info'))
        e.run('python', '-m', 'build', '--sdist', description='Packaging code')

        # raise error if include is not None? and suggest to use MANIFEST.in
        # instead
    else:
        e.rm('dist')
        target = Path('dist', pkg_name)
        e.info('Packaging code')
        source.copy(cmdr=e,
                    src='.',
                    dst=target,
                    include=cfg.include,
                    exclude=cfg.exclude)
        source.compress_dir(target, Path('dist', f'{pkg_name}.tar.gz'))

    e.cp('dist')

    e.cd(name)

    image_local = f'{pkg_name}:{version}'

    # how to allow passing --no-cache?
    e.run('docker',
          'build',
          '.',
          '--tag',
          image_local,
          description='Building image')

    if not skip_tests:
        # test "ploomber status" in docker image
        e.run('docker',
              'run',
              image_local,
              'ploomber',
              'status',
              description='Testing image',
              error_message='Error while testing your docker image with',
              hint=f'Use "docker run -it {image_local} /bin/bash" to '
              'start an interactive session to debug your image')

        # check that the pipeline in the image has a configured File.client
        test_cmd = ('from ploomber.spec import DAGSpec; '
                    'print("File" in DAGSpec.find().to_dag().clients)')
        e.run('docker',
              'run',
              image_local,
              'python',
              '-c',
              test_cmd,
              description='Testing File client',
              error_message='Missing File client',
              hint=f'Run "docker run -it {image_local} /bin/bash" to '
              'to debug your image. Ensure a File client is configured',
              capture_output=True,
              expected_output='True\n',
              show_cmd=False)

    if until == 'build':
        raise CommanderStop('Done. Run "docker images" to see your image.')

    # TODO: validate format of cfg.repository
    if cfg.repository:
        image_target = f'{cfg.repository}:{version}'
        e.run('docker',
              'tag',
              image_local,
              image_target,
              description='Tagging')
        e.run('docker', 'push', image_target, description='Pushing image')
    else:
        image_target = image_local

    if until == 'push':
        raise CommanderStop('Done. Image pushed to repository.')

    return pkg_name, image_target