Пример #1
0
def test_upload_to_pypi(testing, python2, python3, mocker, library_test_repo):
    """upload_to_pypi should create a dist based on a version and upload to pypi or pypitest"""

    twine_env = {
        'PYPI_USERNAME': '******',
        'PYPI_PASSWORD': '******',
        'PYPITEST_USERNAME': '******',
        'PYPITEST_PASSWORD': '******',
    }
    library_test_repo = RepoInfo(**{
        **library_test_repo._asdict(),
        'python2': python2,
        'python3': python3,
    })

    def check_call_func(*args, **kwargs):
        """Patch check_call to skip twine"""
        command_args = args[0]
        if not command_args[0].endswith("twine"):
            call(*args, **kwargs)

        if command_args[0].endswith("twine"):
            # Need to assert twine here since temp directory is random which makes it assert to assert
            assert kwargs['env']['TWINE_USERNAME'] == (
                twine_env['PYPITEST_USERNAME'] if testing else twine_env['PYPI_USERNAME']
            )
            assert kwargs['env']['TWINE_PASSWORD'] == (
                twine_env['PYPITEST_PASSWORD'] if testing else twine_env['PYPI_PASSWORD']
            )
            assert args[0][1] == 'upload'
            if testing:
                assert args[0][2:4] == ["--repository-url", "https://test.pypi.org/legacy/"]
            dist_files = args[0][-2:]
            assert len([name for name in dist_files if name.endswith(".whl")]) == 1
            assert len([name for name in dist_files if name.endswith(".tar.gz")]) == 1

        if command_args[0].endswith("virtualenv"):
            assert command_args[-1] == ("python3" if python3 else "python2")

        if 'bdist_wheel' in command_args:
            if python2 and python3:
                assert "--universal" in command_args

    mocker.patch('lib.check_call', side_effect=check_call_func)
    call_mock = mocker.patch('lib.call', side_effect=check_call_func)
    check_output_mock = mocker.patch('lib.check_output', return_value=b'x=y=z')
    mocker.patch.dict('os.environ', twine_env, clear=False)
    upload_to_pypi(repo_info=library_test_repo, testing=testing)
    assert check_output_mock.call_count == 1
    assert call_mock.call_args[1] == {'env': {'x': 'y=z'}}
Пример #2
0
def load_repos_info(channel_lookup):
    """
    Load repo information from JSON and looks up channel ids for each repo

    Args:
        channel_lookup (dict): Map of channel names to channel ids

    Returns:
        list of RepoInfo: Information about the repositories
    """
    with open(os.path.join(SCRIPT_DIR, "repos_info.json"), "r", encoding="utf-8") as f:
        repos_info = json.load(f)

    infos = [
        RepoInfo(
            name=repo_info["name"],
            repo_url=repo_info["repo_url"],
            ci_hash_url=(
                repo_info["ci_hash_url"]
                if repo_info.get("project_type") == WEB_APPLICATION_TYPE
                else None
            ),
            rc_hash_url=(
                repo_info["rc_hash_url"]
                if repo_info.get("project_type") == WEB_APPLICATION_TYPE
                else None
            ),
            prod_hash_url=(
                repo_info["prod_hash_url"]
                if repo_info.get("project_type") == WEB_APPLICATION_TYPE
                else None
            ),
            channel_id=channel_lookup[repo_info["channel_name"]],
            project_type=repo_info.get("project_type"),
            web_application_type=repo_info.get("web_application_type"),
            packaging_tool=repo_info.get("packaging_tool"),
            versioning_strategy=repo_info.get("versioning_strategy", FILE_VERSION),
        )
        for repo_info in repos_info["repos"]
        if repo_info.get("repo_url")
    ]

    # some basic validation for sanity checking
    for info in infos:
        if info.project_type == WEB_APPLICATION_TYPE:
            if info.web_application_type not in VALID_WEB_APPLICATION_TYPES:
                raise Exception(
                    f"Unexpected web application type {info.web_application_type} for {info.name}"
                )
        elif info.project_type == LIBRARY_TYPE:
            if info.packaging_tool not in VALID_PACKAGING_TOOL_TYPES:
                raise Exception(
                    f"Unexpected packaging tool {info.packaging_tool} for {info.name}"
                )
        if info.versioning_strategy not in VALID_VERSIONING_STRATEGIES:
            raise Exception(
                f"Unexpected versioning strategy {info.versioning_strategy} for {info.name}"
            )

    return infos
Пример #3
0
def test_load_repos_info(mocker):
    """
    load_repos_info should match channels with repositories
    """
    json_load = mocker.patch('lib.json.load', autospec=True, return_value={
        'repos': [
            {
                "name": "bootcamp-ecommerce",
                "repo_url": "https://github.com/mitodl/bootcamp-ecommerce.git",
                "rc_hash_url": "https://bootcamp-ecommerce-rc.herokuapp.com/static/hash.txt",
                "prod_hash_url": "https://bootcamp-ecommerce.herokuapp.com/static/hash.txt",
                "channel_name": "bootcamp-eng",
                "project_type": "web_application",
                "python2": False,
                "python3": True,
            }
        ]
    })

    assert load_repos_info({
        'bootcamp-eng': 'bootcamp_channel_id'
    }) == [
        RepoInfo(
            name='bootcamp-ecommerce',
            repo_url='https://github.com/mitodl/bootcamp-ecommerce.git',
            rc_hash_url="https://bootcamp-ecommerce-rc.herokuapp.com/static/hash.txt",
            prod_hash_url="https://bootcamp-ecommerce.herokuapp.com/static/hash.txt",
            channel_id='bootcamp_channel_id',
            project_type='web_application',
            python2=False,
            python3=True,
        ),
    ]
    assert json_load.call_count == 1
Пример #4
0
def load_repos_info(channel_lookup):
    """
    Load repo information from JSON and looks up channel ids for each repo

    Args:
        channel_lookup (dict): Map of channel names to channel ids

    Returns:
        list of RepoInfo: Information about the repositories
    """
    with open(os.path.join(SCRIPT_DIR, "repos_info.json")) as f:
        repos_info = json.load(f)
        return [
            RepoInfo(
                name=repo_info['name'],
                repo_url=repo_info.get('repo_url'),
                rc_hash_url=(repo_info['rc_hash_url']
                             if repo_info.get('project_type')
                             == WEB_APPLICATION_TYPE else None),
                prod_hash_url=(repo_info['prod_hash_url']
                               if repo_info.get('project_type')
                               == WEB_APPLICATION_TYPE else None),
                channel_id=channel_lookup[repo_info['channel_name']],
                project_type=repo_info.get('project_type'),
                python2=repo_info.get('python2'),
                python3=repo_info.get('python3'),
                announcements=repo_info.get('announcements'),
            ) for repo_info in repos_info['repos']
        ]
Пример #5
0
async def test_update_version(
    mocker,
    test_repo,
    versioning_strategy,
    expected_python,
    expected_js,
    expected_version_file,
    readonly,
):
    """Call update_version on project"""
    repo_info = RepoInfo(
        **{
            **test_repo._asdict(),
            "versioning_strategy": versioning_strategy,
        })
    new_version = "12.34.56"
    working_dir = "/tmp/a/directory"

    update_py_mock = mocker.patch("version.update_python_version")
    update_js_mock = mocker.async_patch("version.update_npm_version")
    update_version_file_mock = mocker.async_patch(
        "version.update_version_file")

    await update_version(
        repo_info=repo_info,
        new_version=new_version,
        working_dir=working_dir,
        readonly=readonly,
    )

    if expected_python:
        update_py_mock.assert_called_once_with(
            new_version=new_version,
            working_dir=working_dir,
            readonly=readonly,
        )
    else:
        assert update_py_mock.called is False

    if expected_js:
        update_js_mock.assert_called_once_with(
            new_version=new_version,
            working_dir=working_dir,
            readonly=readonly,
        )
    else:
        assert update_js_mock.called is False

    if expected_version_file:
        update_version_file_mock.assert_called_once_with(
            new_version=new_version,
            working_dir=working_dir,
            readonly=readonly,
        )
    else:
        assert update_version_file_mock.called is False
Пример #6
0
async def test_publish(mocker, test_repo_directory, library_test_repo,
                       packaging_tool):
    """publish should call upload_to_pypi or upload_to_npm depending on the packaging_tool"""
    upload_to_pypi_mocked = mocker.async_patch("publish.upload_to_pypi")
    upload_to_npm_mocked = mocker.async_patch("publish.upload_to_npm")

    library_test_repo = RepoInfo(
        **{
            **library_test_repo._asdict(),
            "packaging_tool": packaging_tool,
        })
    github_access_token = "git hub"
    npm_token = "npm token"
    version = "9.8.7"
    working_dir = "/a/working/dir"
    init_mock = mocker.patch(
        "publish.init_working_dir",
        side_effect=async_context_manager_yielder(working_dir),
    )
    await publish(
        repo_info=library_test_repo,
        github_access_token=github_access_token,
        npm_token=npm_token,
        version=version,
    )
    init_mock.assert_called_once_with(github_access_token,
                                      library_test_repo.repo_url,
                                      branch=f"v{version}")

    if packaging_tool == SETUPTOOLS:
        assert upload_to_npm_mocked.called is False
        upload_to_pypi_mocked.assert_called_once_with(project_dir=working_dir)
    elif packaging_tool == NPM:
        assert upload_to_pypi_mocked.called is False
        upload_to_npm_mocked.assert_called_once_with(
            project_dir=working_dir,
            npm_token=npm_token,
        )
Пример #7
0
def load_repos_info(channel_lookup):
    """
    Load repo information from JSON and looks up channel ids for each repo

    Args:
        channel_lookup (dict): Map of channel names to channel ids

    Returns:
        list of RepoInfo: Information about the repositories
    """
    with open(os.path.join(SCRIPT_DIR, "repos_info.json")) as f:
        repos_info = json.load(f)
        return [
            RepoInfo(
                name=repo_info['name'],
                repo_url=repo_info['repo_url'],
                rc_hash_url=repo_info['rc_hash_url'],
                prod_hash_url=repo_info['prod_hash_url'],
                channel_id=channel_lookup[repo_info['channel_name']],
            ) for repo_info in repos_info['repos']
        ]
Пример #8
0
        'Intended Audience :: Developers',
        'Intended Audience :: Education',
        'Programming Language :: Python',
    ],
    include_package_data=True,
    zip_safe=False,
)
"""


WEB_TEST_REPO_INFO = RepoInfo(
    name='doof_repo',
    repo_url='http://github.com/mitodl/doof.git',
    prod_hash_url='http://doof.example.com/hash.txt',
    rc_hash_url='http://doof-rc.example.com/hash.txt',
    channel_id='doof',
    project_type=WEB_APPLICATION_TYPE,
    python2=False,
    python3=True,
    announcements=False,
)


# pylint: disable=redefined-outer-name, unused-argument
@pytest.fixture
def test_repo_directory():
    """Helper function to make a repo for testing"""
    with make_test_repo() as working_dir:
        yield working_dir

Пример #9
0
async def test_upload_to_pypi(testing, python2, python3, mocker, library_test_repo, test_repo_directory):
    """upload_to_pypi should create a dist based on a version and upload to pypi or pypitest"""

    twine_env = {
        'PYPI_USERNAME': '******',
        'PYPI_PASSWORD': '******',
        'PYPITEST_USERNAME': '******',
        'PYPITEST_PASSWORD': '******',
    }
    library_test_repo = RepoInfo(**{
        **library_test_repo._asdict(),
        'python2': python2,
        'python3': python3,
    })

    def check_call_func(*args, env, **kwargs):
        """Patch check_call to skip twine"""
        command_args = args[0]

        env = {
            **os.environ,
            **env
        } if env is not None else os.environ

        if not command_args[0].endswith("twine"):
            call(*args, **kwargs, env=env)

        if command_args[0].endswith("twine"):
            # Need to assert twine here since temp directory is random which makes it assert to assert
            assert env['TWINE_USERNAME'] == (
                twine_env['PYPITEST_USERNAME'] if testing else twine_env['PYPI_USERNAME']
            )
            assert env['TWINE_PASSWORD'] == (
                twine_env['PYPITEST_PASSWORD'] if testing else twine_env['PYPI_PASSWORD']
            )
            assert args[0][1] == 'upload'
            if testing:
                assert args[0][2:4] == ["--repository-url", "https://test.pypi.org/legacy/"]
            dist_files = args[0][-2:]
            assert len([name for name in dist_files if name.endswith(".whl")]) == 1
            assert len([name for name in dist_files if name.endswith(".tar.gz")]) == 1

        if 'bdist_wheel' in command_args:
            if python2 and python3:
                assert "--universal" in command_args

    mocker.async_patch('lib.check_call', side_effect=check_call_func)
    call_mock = mocker.async_patch('lib.call', side_effect=check_call_func)
    mocker.async_patch('lib.check_output', return_value=b'x=y=z')
    mocker.patch.dict('os.environ', twine_env, clear=False)

    init_working_dir_mock = mocker.patch(
        'lib.init_working_dir', side_effect=async_context_manager_yielder(test_repo_directory)
    )

    version = "4.5.6"
    token = "token"
    await upload_to_pypi(
        repo_info=library_test_repo, testing=testing, github_access_token=token, version=version
    )
    assert call_mock.call_args[1] == {'env': {'x': 'y=z'}, 'cwd': test_repo_directory}
    init_working_dir_mock.assert_called_once_with(token, library_test_repo.repo_url, branch=f"v{version}")
Пример #10
0
)
from repo_info import RepoInfo


pytestmark = pytest.mark.asyncio


GITHUB_ACCESS = 'github'
SLACK_ACCESS = 'slack'


TEST_REPOS_INFO = [
    RepoInfo(
        name='doof_repo',
        repo_url='http://github.com/mitodl/doof.git',
        prod_hash_url='http://doof.example.com/hash.txt',
        rc_hash_url='http://doof-rc.example.com/hash.txt',
        channel_id='doof',
    )
]


# pylint: disable=redefined-outer-name
class DoofSpoof(Bot):
    """Testing bot"""
    def __init__(self):
        """Since the testing bot isn't contacting slack or github we don't need these tokens here"""
        super().__init__(
            websocket=Mock(),
            slack_access_token=SLACK_ACCESS,
            github_access_token=GITHUB_ACCESS,
Пример #11
0
        'Development Status :: 2 - Pre-Alpha',
        'Intended Audience :: Developers',
        'Intended Audience :: Education',
        'Programming Language :: Python',
    ],
    include_package_data=True,
    zip_safe=False,
)
"""

WEB_TEST_REPO_INFO = RepoInfo(
    name="doof_repo",
    repo_url="http://github.com/mitodl/doof.git",
    prod_hash_url="http://doof.example.com/hash.txt",
    rc_hash_url="http://doof-rc.example.com/hash.txt",
    ci_hash_url="http://doof-ci.example.com/hash.txt",
    channel_id="doof",
    project_type=WEB_APPLICATION_TYPE,
    web_application_type=DJANGO,
    packaging_tool=None,
    versioning_strategy=PYTHON_VERSION,
)


# pylint: disable=redefined-outer-name, unused-argument
@pytest.fixture
def test_repo_directory():
    """Helper function to make a repo for testing"""
    with make_test_repo() as working_dir:
        yield working_dir

Пример #12
0
async def test_load_repos_info(mocker):
    """
    load_repos_info should match channels with repositories
    """
    json_load = mocker.patch(
        "lib.json.load",
        autospec=True,
        return_value={
            "repos": [
                {
                    "name": "bootcamp-ecommerce",
                    "repo_url":
                    "https://github.com/mitodl/bootcamp-ecommerce.git",
                    "ci_hash_url":
                    "https://bootcamp-ecommerce-ci.herokuapp.com/static/hash.txt",
                    "rc_hash_url":
                    "https://bootcamp-ecommerce-rc.herokuapp.com/static/hash.txt",
                    "prod_hash_url":
                    "https://bootcamp-ecommerce.herokuapp.com/static/hash.txt",
                    "channel_name": "bootcamp-eng",
                    "project_type": WEB_APPLICATION_TYPE,
                    "web_application_type": DJANGO,
                    "versioning_strategy": PYTHON_VERSION,
                },
                {
                    "name": "bootcamp-ecommerce-library",
                    "repo_url":
                    "https://github.com/mitodl/bootcamp-ecommerce-library.git",
                    "channel_name": "bootcamp-library",
                    "project_type": LIBRARY_TYPE,
                    "packaging_tool": NPM,
                    "versioning_strategy": NPM_VERSION,
                },
                {
                    "name": "ocw-hugo-projects",
                    "repo_url":
                    "https://github.com/mitodl/ocw-hugo-projects.git",
                    "channel_name": "ocw-hugo-projects",
                    "project_type": "library",
                    "packaging_tool": "none",
                    "versioning_strategy": FILE_VERSION,
                },
            ]
        },
    )

    expected_web_application = RepoInfo(
        name="bootcamp-ecommerce",
        repo_url="https://github.com/mitodl/bootcamp-ecommerce.git",
        ci_hash_url=
        "https://bootcamp-ecommerce-ci.herokuapp.com/static/hash.txt",
        rc_hash_url=
        "https://bootcamp-ecommerce-rc.herokuapp.com/static/hash.txt",
        prod_hash_url=
        "https://bootcamp-ecommerce.herokuapp.com/static/hash.txt",
        channel_id="bootcamp_channel_id",
        project_type=WEB_APPLICATION_TYPE,
        web_application_type=DJANGO,
        packaging_tool=None,
        versioning_strategy=PYTHON_VERSION,
    )
    expected_npm_library = RepoInfo(
        name="bootcamp-ecommerce-library",
        repo_url="https://github.com/mitodl/bootcamp-ecommerce-library.git",
        ci_hash_url=None,
        rc_hash_url=None,
        prod_hash_url=None,
        channel_id="bootcamp_library_channel_id",
        project_type=LIBRARY_TYPE,
        web_application_type=None,
        packaging_tool=NPM,
        versioning_strategy=NPM_VERSION,
    )
    expected_file_library = RepoInfo(
        name="ocw-hugo-projects",
        repo_url="https://github.com/mitodl/ocw-hugo-projects.git",
        ci_hash_url=None,
        rc_hash_url=None,
        prod_hash_url=None,
        channel_id="ocw_hugo_channel_id",
        project_type=LIBRARY_TYPE,
        web_application_type=None,
        packaging_tool=NONE,
        versioning_strategy=FILE_VERSION,
    )

    assert load_repos_info({
        "bootcamp-eng": "bootcamp_channel_id",
        "bootcamp-library": "bootcamp_library_channel_id",
        "ocw-hugo-projects": "ocw_hugo_channel_id",
    }) == [
        expected_web_application, expected_npm_library, expected_file_library
    ]
    assert json_load.call_count == 1