Beispiel #1
0
def get_summary(config, definitions):
    common = """<b><blue>Project</blue></b>
    <b>Project Name:</b> ${project_name} - <b>Package Name:</b> ${package_name}
    <b>Description:</b> ${description}
    <b>Author:</b> ${author}
    <b>Version:</b> ${version} - <b>License:</b> ${license}
    <b>Use Github Actions:</b> ${use_github_actions} - <b>Use Asyncio:</b> ${use_asyncio}
<b><blue>Config</blue></b>
    <b>API Key:</b> ${api_key}
    <b>Environment ID:</b> ${environment_id}
    <b>Server Address:</b> ${server_address}
"""

    event_answers = '\n'.join(
        (f'<b><blue>{group}</blue></b>\n'
         f'    <b>{group} types:</b> '
         '${' + f'{category}_' + slugify(group.lower()) + '}')
        for category, category_events in definitions.items()
        for group in category_events.keys()) + '\n'

    examples = """<b><blue>Examples</blue></b>
    <b>Schedulables:</b> ${include_schedules_example} - <b>Variables:</b> ${include_variables_example}
"""
    return common + event_answers + examples
Beispiel #2
0
def test_validate_extension_project_error_exit(mocker, faker, fs, mocked_responses, config_vendor, capsys):
    runner_version = f'{faker.random_number()}.{faker.random_number()}'
    mocker.patch('connect.cli.plugins.project.extension.helpers.click.echo')
    mocker.patch(
        'connect.cli.plugins.project.extension.helpers.get_pypi_runner_version',
        side_effect=runner_version,
    )
    config_vendor.load(config_dir='/tmp')

    mocked_responses.add(
        method='GET',
        url=f'{config_vendor.active.endpoint}/devops/event-definitions',
        headers={
            'Content-Range': 'items 0-0/1',
        },
        json=[
            {
                'type': 'sample_background_event',
                'group': 'Group',
                'name': 'Sample Event',
                'category': 'background',
                'object_statuses': ['status1', 'status2'],
            },
        ],
    )

    data = {
        'project_name': faker.name(),
        'project_slug': slugify(faker.name()),
        'description': 'desc',
        'package_name': slugify(faker.name()),
        'author': 'connect',
        'version': '1.0',
        'license': 'Apache',
        'use_github_actions': 'n',
        'use_asyncio': 'n',
        'include_schedules_example': 'y',
        'include_variables_example': 'y',
        'api_key': faker.pystr(),
        'environment_id': f'ENV-{faker.random_number()}',
        'server_address': faker.domain_name(2),
        'background_group': ['sample_background_event'],
    }

    mocker.patch(
        'connect.cli.plugins.project.extension.helpers.dialogus',
        return_value=data,
    )

    output_dir = f'{fs.root_path}/projects'
    os.mkdir(output_dir)

    bootstrap_extension_project(config_vendor, output_dir, False)

    project_dir = os.path.join(output_dir, data['project_slug'])
    os.unlink(os.path.join(project_dir, 'pyproject.toml'))

    validate_extension_project(config_vendor, project_dir)

    captured = capsys.readouterr()

    assert 'Warning/errors have been found' in captured.out
Beispiel #3
0
def test_bootstrap_extension_project_background(
    fs,
    faker,
    mocker,
    mocked_responses,
    config_vendor,
    extension_class_declaration,
    extension_imports,
    extension_bg_event,
    extension_schedulable_event,
    test_bg_event,
    test_schedulable_event,
    async_impl,
    with_variables,
    with_schedulable,
    with_github_actions,
):
    runner_version = f'{faker.random_number()}.{faker.random_number()}'
    mocker.patch('connect.cli.plugins.project.extension.helpers.click.echo')
    mocker.patch(
        'connect.cli.plugins.project.extension.helpers.get_pypi_runner_version',
        return_value=runner_version,
    )
    config_vendor.load(config_dir='/tmp')

    mocked_responses.add(
        method='GET',
        url=f'{config_vendor.active.endpoint}/devops/event-definitions',
        headers={
            'Content-Range': 'items 0-0/1',
        },
        json=[
            {
                'type': 'sample_background_event',
                'group': 'Group',
                'name': 'Sample Event',
                'category': 'background',
                'object_statuses': ['status1', 'status2'],
            },
        ],
    )

    data = {
        'project_name': faker.name(),
        'project_slug': slugify(faker.name()),
        'description': 'desc',
        'package_name': slugify(faker.name()),
        'author': 'connect',
        'version': '1.0',
        'license': 'Apache',
        'use_github_actions': 'y' if with_github_actions else 'n',
        'use_asyncio': 'y' if async_impl else 'n',
        'include_schedules_example': 'y' if with_schedulable else 'n',
        'include_variables_example': 'y' if with_variables else 'n',
        'api_key': faker.pystr(),
        'environment_id': f'ENV-{faker.random_number()}',
        'server_address': faker.domain_name(2),
        'background_group': ['sample_background_event'],
    }

    mocker.patch(
        'connect.cli.plugins.project.extension.helpers.dialogus',
        return_value=data,
    )

    output_dir = f'{fs.root_path}/projects'
    os.mkdir(output_dir)

    bootstrap_extension_project(config_vendor, output_dir, False)

    classname_prefix = data['project_slug'].replace('_', ' ').title().replace(' ', '')

    env_file_name = f".{data['project_slug']}_dev.env"

    env_file = open(os.path.join(output_dir, data['project_slug'], env_file_name)).read()
    assert f'export API_KEY="{data["api_key"]}"' in env_file
    assert f'export ENVIRONMENT_ID="{data["environment_id"]}"' in env_file
    assert f'export SERVER_ADDRESS="{data["server_address"]}"' in env_file

    docker_compose_yml = yaml.safe_load(
        open(os.path.join(output_dir, data['project_slug'], 'docker-compose.yml')),
    )

    for service_suffix in ('dev', 'bash', 'test'):
        service = docker_compose_yml['services'][f"{data['project_slug']}_{service_suffix}"]
        assert service['container_name'] == f"{data['project_slug']}_{service_suffix}"
        assert service['image'] == f'cloudblueconnect/connect-extension-runner:{runner_version}'
        assert service['env_file'] == [env_file_name]

    pyproject_toml = toml.load(os.path.join(output_dir, data['project_slug'], 'pyproject.toml'))

    ext_entrypoint = pyproject_toml['tool']['poetry']['plugins']['connect.eaas.ext']
    assert ext_entrypoint == {'extension': f"{data['package_name']}.extension:{classname_prefix}Extension"}

    if with_github_actions:
        assert os.path.exists(
            os.path.join(output_dir, data['project_slug'], '.github', 'workflows', 'build.yml'),
        ) is True

    parser = configparser.ConfigParser()
    parser.read(os.path.join(output_dir, data['project_slug'], '.flake8'))

    assert parser['flake8']['application-import-names'] == data['package_name']

    flake8_style_guide = flake8.get_style_guide(
        show_source=parser['flake8']['show-source'],
        max_line_length=int(parser['flake8']['max-line-length']),
        application_import_names=parser['flake8']['application-import-names'],
        import_order_style=parser['flake8']['import-order-style'],
        max_cognitive_complexity=parser['flake8']['max-cognitive-complexity'],
        ignore=parser['flake8']['ignore'],
        exclude=parser['flake8']['exclude'],
    )

    report = flake8_style_guide.check_files([
        os.path.join(output_dir, data['project_slug'], data['package_name'], 'extension.py'),
        os.path.join(output_dir, data['project_slug'], 'tests', f'test_{data["project_slug"]}.py'),
    ])
    assert report.total_errors == 0

    extension_py = open(
        os.path.join(output_dir, data['project_slug'], data['package_name'], 'extension.py'),
    ).read()

    expected_imports = extension_imports(
        with_schedulable=with_schedulable,
        with_variables=with_variables,
    )

    assert expected_imports in extension_py
    assert extension_class_declaration(
        classname_prefix,
        with_variables=with_variables,
    ) in extension_py

    assert extension_bg_event(async_impl=async_impl) in extension_py

    test_py = open(
        os.path.join(output_dir, data['project_slug'], 'tests', f'test_{data["project_slug"]}.py'),
    ).read()

    assert test_bg_event(classname_prefix, async_impl=async_impl) in test_py

    if with_schedulable:
        assert extension_schedulable_event(async_impl=async_impl) in extension_py
        assert test_schedulable_event(classname_prefix, async_impl=async_impl) in test_py
Beispiel #4
0
     'My Awesome Project',
     'validators':
     (RequiredValidator(message='Please, provide a project name.'), ),
 },
 {
     'name':
     'project_slug',
     'label':
     'Project: root',
     'type':
     'input',
     'description':
     ('Choose a name for the root folder of your Reports module.'
      ' This must be a valid python\nidentifier:'),
     'default':
     lambda x: slugify(x['project_name']),
     'validators': (
         RequiredValidator(
             message='Please, provide a project root folder.'),
         PythonIdentifierValidator(),
     ),
 },
 {
     'name':
     'author',
     'label':
     'Project: author',
     'type':
     'input',
     'description':
     'Please enter the author for this project:',
Beispiel #5
0
def get_questions(config, definitions):
    project = [
        {
            'name':
            'project_name',
            'label':
            'Project: name',
            'type':
            'input',
            'description':
            'Enter a friendly name for your Extension:',
            'default':
            'My Awesome Project',
            'validators':
            (RequiredValidator(message='Please, provide a project name.'), ),
        },
        {
            'name':
            'project_slug',
            'label':
            'Project: root',
            'type':
            'input',
            'description':
            'Choose a name for the root folder of your Extension module.',
            'default':
            lambda ctx: slugify(ctx['project_name']),
            'validators': (RequiredValidator(
                message='Please, provide a project root folder.'), ),
        },
        {
            'name':
            'description',
            'label':
            'Project: description',
            'type':
            'input',
            'description':
            'Briefly describe your Extension:',
            'default':
            'Project description',
            'validators':
            (RequiredValidator(message='Please, provide a description.'), ),
        },
        {
            'name':
            'package_name',
            'label':
            'Project: package',
            'type':
            'input',
            'description':
            ('Choose a name for the root python package of your extension module.'
             ' This must be a valid python\nidentifier:'),
            'default':
            'connect_ext',
            'validators': (
                RequiredValidator(message='Please, provide a package name.'),
                PythonIdentifierValidator(),
            ),
        },
        {
            'name': 'use_asyncio',
            'label': 'Project: asyncio',
            'type': 'selectone',
            'description':
            'Do you want to develop your Extension using the Python asyncio library ?',
            'values': [
                ('n', 'No'),
                ('y', 'Yes'),
            ],
            'formatting_template': '${label}',
        },
        {
            'name':
            'author',
            'label':
            'Project: author',
            'type':
            'input',
            'description':
            'Enter the name of the Extension author:',
            'default':
            'Globex Corporation',
            'validators':
            (RequiredValidator(message='Please, provide an author name.'), ),
        },
        {
            'name':
            'version',
            'label':
            'Project: version',
            'type':
            'input',
            'description':
            'Introduce a version identifier for your Extension:',
            'default':
            '0.1.0',
            'validators':
            (RequiredValidator(message='Please, provide a version.'), ),
        },
        {
            'name':
            'license',
            'label':
            'Project: license',
            'type':
            'selectone',
            'description':
            'Choose an Open Source license for your Extension:',
            'values': [
                ('Apache Software License 2.0', 'Apache Software License 2.0'),
                ('MIT', 'MIT'),
                ('BSD', 'BSD'),
            ],
            'formatting_template':
            '${label}',
        },
        {
            'name':
            'use_github_actions',
            'label':
            'Project: CI',
            'type':
            'selectone',
            'description':
            ('If you plan to host the Extension code on GitHub, are you also planning\n'
             'to use GitHub actions as your continuous integration system ?'),
            'values': [
                ('n', 'No'),
                ('y', 'Yes'),
            ],
            'formatting_template':
            '${label}',
        },
    ]

    environment = [
        {
            'name':
            'api_key',
            'label':
            'Config: API key',
            'type':
            'input',
            'description':
            ('Enter the API key that will be used to authenticate API calls to Connect:\n'
             'The API key can be created within the integration module of Connect.\n'
             'It defaults to the current active CLI account.'),
            'default':
            config.active.api_key,
            'validators':
            (RequiredValidator(message='Please, provide an API Key.'), ),
        },
        {
            'name':
            'environment_id',
            'label':
            'Config: environment ID',
            'type':
            'input',
            'description':
            ('Enter the DevOps environment identifier to which your Extension will connect:\n'
             'It can be found in the DevOps module of Connect within the Local Access widget.\n'
             'See: https://connect.cloudblue.com/community/modules/devops/user-interface/#Service_Details'
             ),
            'validators': (RequiredValidator(
                message='Please, provide a DevOps environment ID.'), ),
        },
        {
            'name':
            'server_address',
            'label':
            'Config: API hostname',
            'type':
            'input',
            'description':
            'Connect API hostname: ',
            'default':
            urlparse(config.active.endpoint).netloc,
            'validators':
            (RequiredValidator(message='Please, provide the API hostname.'), ),
        },
    ]

    event_questions = []

    for category, cagegory_events in definitions.items():
        for group, events in cagegory_events.items():
            event_questions.append(
                {
                    'name':
                    f'{category}_{slugify(group.lower())}',
                    'label':
                    f'{category.title()}: {group.lower()}',
                    'type':
                    'selectmany',
                    'description':
                    (f'What types of {group.title()} {category} '
                     'events do you want your Extension to process ?'),
                    'values': [(event['type'], event['name'])
                               for event in events],
                    'formatting_template':
                    '${label}',
                }, )

    examples = [
        {
            'name': 'include_schedules_example',
            'label': 'Examples: schedulables',
            'type': 'selectone',
            'description':
            'Do you want to include an example of schedulable method ? ',
            'values': [
                ('n', 'No'),
                ('y', 'Yes'),
            ],
            'formatting_template': '${label}',
        },
        {
            'name': 'include_variables_example',
            'label': 'Examples: variables',
            'type': 'selectone',
            'description':
            'Do you want to include an example of environment variables ? ',
            'values': [
                ('n', 'No'),
                ('y', 'Yes'),
            ],
            'formatting_template': '${label}',
        },
    ]

    return project + environment + event_questions + examples