Skip to content

Commit

Permalink
Migrate E2E features
Browse files Browse the repository at this point in the history
  • Loading branch information
ofek committed Sep 29, 2023
1 parent 928b634 commit f7cde3d
Show file tree
Hide file tree
Showing 28 changed files with 1,391 additions and 43 deletions.
4 changes: 4 additions & 0 deletions datadog_checks_dev/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

***Added***:

* Migrate E2E features ([#15931](https://github.com/DataDog/integrations-core/pull/15931))

## 25.1.2 / 2023-09-26

***Fixed***:
Expand Down
2 changes: 1 addition & 1 deletion datadog_checks_dev/datadog_checks/dev/_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
E2E_ENV_VAR_PREFIX = '{}_ENV_'.format(E2E_PREFIX)
E2E_SET_UP = '{}_UP'.format(E2E_PREFIX)
E2E_TEAR_DOWN = '{}_DOWN'.format(E2E_PREFIX)
E2E_PARENT_PYTHON = '{}_PYTHON_PATH'.format(E2E_PREFIX)
E2E_PARENT_PYTHON = '{}_PARENT_PYTHON'.format(E2E_PREFIX)
E2E_RESULT_FILE = '{}_RESULT_FILE'.format(E2E_PREFIX)

E2E_FIXTURE_NAME = 'dd_environment'
Expand Down
8 changes: 5 additions & 3 deletions datadog_checks_dev/datadog_checks/dev/plugin/pytest.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,7 @@ def run_check(config=None, **kwargs):
python_path = os.environ[E2E_PARENT_PYTHON]
env = os.environ['HATCH_ENV_ACTIVE']

# TODO: switch to `ddev` when the old CLI is gone
check_command = [python_path, '-m', 'datadog_checks.dev', 'env', 'check', check, env, '--json']
check_command = [python_path, '-m', 'ddev', 'env', 'agent', check, env, 'check', '--json']

if config:
config = format_config(config)
Expand All @@ -197,7 +196,10 @@ def run_check(config=None, **kwargs):
with open(config_file, 'wb') as f:
output = json.dumps(config).encode('utf-8')
f.write(output)
check_command.extend(['--config', config_file])
check_command.extend(['--config-file', config_file])

if 'rate' in kwargs:
kwargs['check_rate'] = kwargs.pop('rate')

for key, value in kwargs.items():
if value is not False:
Expand Down
4 changes: 4 additions & 0 deletions ddev/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

## Unreleased

***Added***:

* Migrate E2E features ([#15931](https://github.com/DataDog/integrations-core/pull/15931))

***Fixed***:

* Trigger tests on JMX metrics.yaml updates ([#15877](https://github.com/DataDog/integrations-core/pull/15877))
Expand Down
2 changes: 1 addition & 1 deletion ddev/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ classifiers = [
dependencies = [
"click~=8.1.6",
"coverage",
"datadog-checks-dev[cli]~=25.0",
"datadog-checks-dev[cli]>=25.1.2,<26",
"hatch>=1.6.3",
"httpx",
"jsonpointer",
Expand Down
11 changes: 9 additions & 2 deletions ddev/src/ddev/cli/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
from __future__ import annotations

import os
from functools import cached_property
from typing import cast

from ddev.cli.terminal import Terminal
from ddev.config.constants import AppEnvVars, VerbosityLevels
from ddev.config.constants import AppEnvVars, ConfigEnvVars, VerbosityLevels
from ddev.config.file import ConfigFile, RootConfig
from ddev.repo.core import Repository
from ddev.utils.fs import Path
Expand All @@ -18,7 +19,7 @@
class Application(Terminal):
def __init__(self, exit_func, *args, **kwargs):
super().__init__(*args, **kwargs)
self.platform = Platform(self.display_raw)
self.platform = Platform(self.output)
self.__exit_func = exit_func

self.config_file = ConfigFile()
Expand All @@ -40,6 +41,12 @@ def config(self) -> RootConfig:
def repo(self) -> Repository:
return self.__repo

@cached_property
def data_dir(self) -> Path:
from platformdirs import user_data_dir

return Path(os.getenv(ConfigEnvVars.DATA) or user_data_dir('ddev', appauthor=False)).expand()

@property
def github(self) -> GitHubManager:
return self.__github
Expand Down
4 changes: 2 additions & 2 deletions ddev/src/ddev/cli/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def show(app, all_keys):
from rich.syntax import Syntax

text = app.config_file.read() if all_keys else app.config_file.read_scrubbed()
app.display_raw(Syntax(text.rstrip(), 'toml', background_color='default'))
app.output(Syntax(text.rstrip(), 'toml', background_color='default'))


@config.command(short_help='Update the config file with any new fields')
Expand Down Expand Up @@ -146,4 +146,4 @@ def set_value(app, key, value):
from rich.syntax import Syntax

app.display_success('New setting:')
app.display_raw(Syntax(rendered_changed, 'toml', background_color='default'))
app.output(Syntax(rendered_changed, 'toml', background_color='default'))
31 changes: 16 additions & 15 deletions ddev/src/ddev/cli/env/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
import click
from datadog_checks.dev.tooling.commands.env.check import check_run
from datadog_checks.dev.tooling.commands.env.edit import edit
from datadog_checks.dev.tooling.commands.env.ls import ls
from datadog_checks.dev.tooling.commands.env.prune import prune
from datadog_checks.dev.tooling.commands.env.reload import reload_env
from datadog_checks.dev.tooling.commands.env.shell import shell
from datadog_checks.dev.tooling.commands.env.start import start
from datadog_checks.dev.tooling.commands.env.stop import stop
from datadog_checks.dev.tooling.commands.env.test import test

from ddev.cli.env.agent import agent
from ddev.cli.env.check import check
from ddev.cli.env.config import config
from ddev.cli.env.reload import reload_command
from ddev.cli.env.shell import shell
from ddev.cli.env.show import show
from ddev.cli.env.start import start
from ddev.cli.env.stop import stop
from ddev.cli.env.test import test_command


@click.group(short_help='Manage environments')
Expand All @@ -20,12 +21,12 @@ def env():
"""


env.add_command(check_run)
env.add_command(edit)
env.add_command(ls)
env.add_command(prune)
env.add_command(reload_env)
env.add_command(agent)
env.add_command(check)
env.add_command(config)
env.add_command(reload_command)
env.add_command(shell)
env.add_command(show)
env.add_command(start)
env.add_command(stop)
env.add_command(test)
env.add_command(test_command)
68 changes: 68 additions & 0 deletions ddev/src/ddev/cli/env/agent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# (C) Datadog, Inc. 2023-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

from typing import TYPE_CHECKING

import click

if TYPE_CHECKING:
from ddev.cli.application import Application


@click.command(short_help='Invoke the Agent', context_settings={'ignore_unknown_options': True})
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.argument('args', required=True, nargs=-1)
@click.option('--config-file', hidden=True)
@click.pass_obj
def agent(app: Application, *, intg_name: str, environment: str, args: tuple[str, ...], config_file: str | None):
"""
Invoke the Agent.
"""
import subprocess

from ddev.e2e.agent import get_agent_interface
from ddev.e2e.config import EnvDataStorage
from ddev.utils.fs import Path

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

metadata = env_data.read_metadata()
agent_type = metadata['env_type']
agent = get_agent_interface(agent_type)(app.platform, integration, environment, metadata, env_data.config_file)

full_args = list(args)
trigger_run = False
if full_args[0] == 'check':
trigger_run = True

# TODO: remove this when all invocations migrate to the actual command
if len(full_args) > 2 and full_args[1] == '--jmx-list':
full_args = ['jmx', 'list', full_args[2]]
# Automatically inject the integration name if not passed
elif len(full_args) == 1 or full_args[1].startswith('-'):
full_args.insert(1, intg_name)

if config_file is None or not trigger_run:
try:
agent.invoke(full_args)
except subprocess.CalledProcessError as e:
app.abort(code=e.returncode)

return

import json

temp_config_file = env_data.config_file.parent / f'{env_data.config_file.name}.bak.example'
env_data.config_file.replace(temp_config_file)
try:
env_data.write_config(json.loads(Path(config_file).read_text()))
agent.invoke(full_args)
finally:
temp_config_file.replace(env_data.config_file)
18 changes: 18 additions & 0 deletions ddev/src/ddev/cli/env/check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# (C) Datadog, Inc. 2023-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

import click


@click.command(context_settings={'ignore_unknown_options': True}, hidden=True)
@click.argument('intg_name')
@click.argument('environment')
@click.argument('args', nargs=-1)
@click.option('--config')
@click.pass_context
def check(ctx: click.Context, *, intg_name: str, environment: str, args: tuple[str, ...], config: str | None):
from ddev.cli.env.agent import agent

ctx.invoke(agent, intg_name=intg_name, environment=environment, args=('check', *args), config_file=config)
95 changes: 95 additions & 0 deletions ddev/src/ddev/cli/env/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# (C) Datadog, Inc. 2023-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

from typing import TYPE_CHECKING

import click

if TYPE_CHECKING:
from ddev.cli.application import Application


@click.group(short_help='Manage the config file')
def config():
pass


@config.command(short_help='Edit the config file with your default editor')
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.pass_obj
def edit(app: Application, *, intg_name: str, environment: str):
"""
Edit the config file with your default editor.
"""
from ddev.e2e.config import EnvDataStorage

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

click.edit(filename=str(env_data.config_file))


@config.command(short_help='Open the config location in your file manager')
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.pass_obj
def explore(app: Application, *, intg_name: str, environment: str):
"""
Open the config location in your file manager.
"""
from ddev.e2e.config import EnvDataStorage

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

click.launch(str(env_data.config_file), locate=True)


@config.command(short_help='Show the location of the config file')
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.pass_obj
def find(app: Application, *, intg_name: str, environment: str):
"""
Show the location of the config file.
"""
from ddev.e2e.config import EnvDataStorage

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

app.output(f'[link={env_data.config_file}]{env_data.config_file}[/]')


@config.command(short_help='Show the contents of the config file')
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.pass_obj
def show(app: Application, *, intg_name: str, environment: str):
"""
Show the contents of the config file.
"""
from ddev.e2e.config import EnvDataStorage

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

from rich.syntax import Syntax

text = env_data.config_file.read_text().rstrip()
app.output(Syntax(text, 'yaml', background_color='default'))
38 changes: 38 additions & 0 deletions ddev/src/ddev/cli/env/reload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# (C) Datadog, Inc. 2023-present
# All rights reserved
# Licensed under a 3-clause BSD style license (see LICENSE)
from __future__ import annotations

from typing import TYPE_CHECKING

import click

if TYPE_CHECKING:
from ddev.cli.application import Application


@click.command('reload', short_help='Restart the Agent to detect environment changes')
@click.argument('intg_name', metavar='INTEGRATION')
@click.argument('environment')
@click.pass_obj
def reload_command(app: Application, *, intg_name: str, environment: str):
"""
Restart the Agent to detect environment changes.
"""
from ddev.e2e.agent import get_agent_interface
from ddev.e2e.config import EnvDataStorage

integration = app.repo.integrations.get(intg_name)
env_data = EnvDataStorage(app.data_dir).get(integration.name, environment)

if not env_data.exists():
app.abort(f'Environment `{environment}` for integration `{integration.name}` is not running')

metadata = env_data.read_metadata()
agent_type = metadata['env_type']
agent = get_agent_interface(agent_type)(app.platform, integration, environment, metadata, env_data.config_file)

try:
agent.restart()
except Exception as e:
app.abort(str(e))
Loading

0 comments on commit f7cde3d

Please sign in to comment.