atlas-init 0.8.1__tar.gz → 0.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {atlas_init-0.8.1 → atlas_init-0.9.0}/PKG-INFO +1 -1
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/__init__.py +1 -1
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_root/trigger.py +1 -1
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/rich_utils.py +22 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/gen_examples.py +4 -2
- atlas_init-0.8.1/atlas_init/tf_ext/gen_module_readme.py → atlas_init-0.9.0/atlas_init/tf_ext/gen_readme.py +46 -26
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/models.py +27 -1
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/models_module.py +7 -3
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_dep.py +69 -22
- atlas_init-0.9.0/atlas_init/tf_ext/tf_example_readme.py +392 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_mod_gen.py +4 -6
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_modules.py +3 -1
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/typer_app.py +2 -1
- {atlas_init-0.8.1 → atlas_init-0.9.0}/.gitignore +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/LICENSE +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/__main__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/atlas_init.yaml +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_args.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/app.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/aws.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/cfn_parameter_finder.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/contract.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/example.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_cfn/files.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/go.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/run.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/run_manager.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/sdk.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/sdk_auto_changes.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_helper/tf_runner.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_root/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_root/go_test.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_root/mms_released.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/app.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/changelog.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/ci_tests.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/codegen/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/codegen/models.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/codegen/openapi_minimal.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/debug_logs.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/debug_logs_test_data.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/debug_logs_test_data_package_config.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/example_update.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/github_logs.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/go_test_run.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/go_test_summary.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/go_test_tf_error.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/hcl/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/hcl/cli.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/hcl/cluster_mig.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/hcl/modifier.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/hcl/modifier2.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/hcl/parser.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/log_clean.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/mock_tf_log.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/openapi.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_go_parser.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_inspection.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_table.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_table_models.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_v2.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_v2_sdk.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_v3.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_v3_sdk.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_v3_sdk_base.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cli_tf/schema_v3_sdk_create.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cloud/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/cloud/aws.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/crud/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/crud/mongo_client.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/crud/mongo_dao.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/crud/mongo_utils.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/html_out/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/html_out/md_export.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/humps.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/repos/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/repos/cfn.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/repos/go_sdk.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/repos/path.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/sdk_ext/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/sdk_ext/go.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/sdk_ext/typer_app.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/config.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/env_vars.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/env_vars_generated.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/env_vars_modules.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/interactive.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/interactive2.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/settings/path.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/terraform.yaml +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/.terraform.lock.hcl +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/always.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/main.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_kms/aws_kms.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_kms/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_s3/aws_s3.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_s3/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_vars/aws_vars.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_vpc/aws_vpc.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/aws_vpc/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cfn/assume_role_services.yaml +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cfn/cfn.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cfn/kms.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cfn/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cfn/resource_actions.yaml +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cfn/variables.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cloud_provider/cloud_provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cloud_provider/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cluster/cluster.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/cluster/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/encryption_at_rest/main.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/encryption_at_rest/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/federated_vars/federated_vars.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/federated_vars/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/project_extra/project_extra.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/project_extra/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/stream_instance/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/stream_instance/stream_instance.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/vpc_peering/provider.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/vpc_peering/vpc_peering.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/vpc_privatelink/atlas-privatelink.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/vpc_privatelink/variables.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/modules/vpc_privatelink/versions.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/outputs.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/providers.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf/variables.tf +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/__init__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/__main__.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/api_call.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/args.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/constants.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/gen_resource_main.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/gen_resource_output.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/gen_resource_variables.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/gen_versions.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/newres.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/paths.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/plan_diffs.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/provider_schema.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/py_gen.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/schema_to_dataclass.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/settings.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_desc_gen.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_desc_update.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_mod_gen_provider.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/tf_ext/tf_vars.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/atlas_init/typer_app.py +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/pyproject.toml +0 -0
- {atlas_init-0.8.1 → atlas_init-0.9.0}/readme.md +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: atlas-init
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.9.0
|
4
4
|
Project-URL: Documentation, https://github.com/EspenAlbert/atlas-init#readme
|
5
5
|
Project-URL: Issues, https://github.com/EspenAlbert/atlas-init/issues
|
6
6
|
Project-URL: Source, https://github.com/EspenAlbert/atlas-init
|
@@ -30,7 +30,7 @@ def create_realm_app():
|
|
30
30
|
project_id = atlas_settings.MONGODB_ATLAS_PROJECT_ID
|
31
31
|
base_url = atlas_settings.realm_url
|
32
32
|
cluster_name = cluster_settings.MONGODB_ATLAS_CLUSTER_NAME
|
33
|
-
auth_headers = login_to_realm(
|
33
|
+
auth_headers = login_to_realm(atlas_settings, base_url)
|
34
34
|
realm_settings = env_vars_cls_or_none(RealmSettings, dotenv_path=settings.env_vars_trigger)
|
35
35
|
if realm_settings and function_exists(
|
36
36
|
base_url,
|
@@ -1,6 +1,8 @@
|
|
1
1
|
import logging
|
2
2
|
from typing import Literal
|
3
3
|
|
4
|
+
from rich.console import Console
|
5
|
+
from rich.tree import Tree
|
4
6
|
import typer
|
5
7
|
from pydantic import BaseModel
|
6
8
|
from rich.logging import RichHandler
|
@@ -62,3 +64,23 @@ def configure_logging(
|
|
62
64
|
app.pretty_exceptions_show_locals = False
|
63
65
|
|
64
66
|
return handler
|
67
|
+
|
68
|
+
|
69
|
+
# https://github.com/Textualize/rich/blob/8c4d3d1d50047e3aaa4140d0ffc1e0c9f1df5af4/tests/test_live.py#L11
|
70
|
+
def create_capture_console(*, width: int = 60, height: int = 80, force_terminal: bool = True) -> Console:
|
71
|
+
return Console(
|
72
|
+
width=width,
|
73
|
+
height=height,
|
74
|
+
force_terminal=force_terminal,
|
75
|
+
legacy_windows=False,
|
76
|
+
color_system=None, # use no color system to reduce complexity of output,
|
77
|
+
_environ={},
|
78
|
+
)
|
79
|
+
|
80
|
+
|
81
|
+
def tree_text(tree: Tree) -> str:
|
82
|
+
console = create_capture_console()
|
83
|
+
console.width = 10_000
|
84
|
+
console.begin_capture()
|
85
|
+
console.print(tree)
|
86
|
+
return "\n".join(line.rstrip() for line in console.end_capture().splitlines())
|
@@ -19,10 +19,12 @@ def _examples_casted(examples: dict) -> dict[str, ResourceAbs]:
|
|
19
19
|
return examples
|
20
20
|
|
21
21
|
|
22
|
-
def read_example_dirs(
|
22
|
+
def read_example_dirs(examples_dir: Path) -> list[Path]:
|
23
|
+
if not examples_dir.exists():
|
24
|
+
return []
|
23
25
|
return sorted(
|
24
26
|
example_dir
|
25
|
-
for example_dir in
|
27
|
+
for example_dir in examples_dir.glob("*")
|
26
28
|
if example_dir.is_dir()
|
27
29
|
and len(example_dir.name) > 2
|
28
30
|
and example_dir.name[:2].isdigit()
|
@@ -1,11 +1,14 @@
|
|
1
|
+
from __future__ import annotations
|
1
2
|
import logging
|
2
3
|
from enum import StrEnum
|
4
|
+
from pathlib import Path
|
5
|
+
from typing import Callable, TypeAlias
|
3
6
|
|
4
7
|
from ask_shell import run_and_wait
|
5
8
|
from zero_3rdparty.file_utils import ensure_parents_write_text, update_between_markers
|
6
9
|
|
7
10
|
from atlas_init.tf_ext.gen_examples import read_example_dirs
|
8
|
-
from atlas_init.tf_ext.models_module import
|
11
|
+
from atlas_init.tf_ext.models_module import EXAMPLES_DIRNAME, README_FILENAME, TERRAFORM_DOCS_CONFIG_FILENAME
|
9
12
|
|
10
13
|
logger = logging.getLogger(__name__)
|
11
14
|
_readme_disclaimer = """\
|
@@ -13,12 +16,13 @@ _readme_disclaimer = """\
|
|
13
16
|
This Module is not meant for external consumption.
|
14
17
|
It is part of a development PoC.
|
15
18
|
Any usage problems will not be supported.
|
16
|
-
However, if you have any ideas or feedback feel free to open a Github Issue!
|
19
|
+
However, if you have any ideas or feedback, feel free to open a Github Issue!
|
17
20
|
"""
|
18
21
|
|
19
22
|
|
20
23
|
class ReadmeMarkers(StrEnum):
|
21
24
|
DISCLAIMER = "DISCLAIMER"
|
25
|
+
MODULES = "MODULES"
|
22
26
|
EXAMPLE = "TF_EXAMPLES"
|
23
27
|
TF_DOCS = "TF_DOCS"
|
24
28
|
|
@@ -42,9 +46,23 @@ class ReadmeMarkers(StrEnum):
|
|
42
46
|
def example_boilerplate(cls) -> str:
|
43
47
|
return "\n".join(cls.marker_lines(marker_name) for marker_name in list(cls))
|
44
48
|
|
49
|
+
@classmethod
|
50
|
+
def readme_generators(cls) -> ReadmeGenerators:
|
51
|
+
return [
|
52
|
+
(cls.DISCLAIMER, lambda _: _readme_disclaimer),
|
53
|
+
(cls.EXAMPLE, lambda workspace: read_examples(workspace / EXAMPLES_DIRNAME)),
|
54
|
+
]
|
55
|
+
|
56
|
+
|
57
|
+
ReadmeGenerators: TypeAlias = list[tuple[ReadmeMarkers, Callable[[Path], str]]]
|
45
58
|
|
46
|
-
|
47
|
-
|
59
|
+
|
60
|
+
def read_examples(examples_dir: Path) -> str:
|
61
|
+
example_dirs = read_example_dirs(examples_dir)
|
62
|
+
if not example_dirs:
|
63
|
+
return ""
|
64
|
+
# ensure the examples are formatted first
|
65
|
+
run_and_wait("terraform fmt -recursive .", cwd=examples_dir.parent, allow_non_zero_exit=True, ansi_content=False)
|
48
66
|
content = ["# Examples"]
|
49
67
|
for example_dir in example_dirs:
|
50
68
|
example_name = example_dir.name
|
@@ -80,10 +98,10 @@ sort:
|
|
80
98
|
"""
|
81
99
|
|
82
100
|
|
83
|
-
def terraform_docs_config_content(
|
101
|
+
def terraform_docs_config_content(readme_path: Path) -> str:
|
84
102
|
config = _static_terraform_config
|
85
103
|
for replacement_in, replacement_out in [
|
86
|
-
("FILENAME",
|
104
|
+
("FILENAME", readme_path.name),
|
87
105
|
("START_MARKER", ReadmeMarkers.as_start(ReadmeMarkers.TF_DOCS)),
|
88
106
|
("END_MARKER", ReadmeMarkers.as_end(ReadmeMarkers.TF_DOCS)),
|
89
107
|
]:
|
@@ -91,36 +109,38 @@ def terraform_docs_config_content(module: ModuleGenConfig) -> str:
|
|
91
109
|
return config
|
92
110
|
|
93
111
|
|
94
|
-
def
|
95
|
-
|
112
|
+
def generate_and_write_readme(terraform_workdir: Path, *, generators: ReadmeGenerators | None = None) -> str:
|
113
|
+
generators = generators or ReadmeMarkers.readme_generators()
|
114
|
+
readme_path = terraform_workdir / README_FILENAME
|
96
115
|
assert readme_path.exists(), (
|
97
116
|
f"{readme_path} does not exist, currently a boilerplate is expected, consider adding to {readme_path}\n{ReadmeMarkers.example_boilerplate()}"
|
98
117
|
)
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
118
|
+
for marker, generator in generators:
|
119
|
+
content = generator(terraform_workdir)
|
120
|
+
if not content:
|
121
|
+
continue
|
122
|
+
update_between_markers(
|
123
|
+
readme_path,
|
124
|
+
content,
|
125
|
+
ReadmeMarkers.as_start(marker),
|
126
|
+
ReadmeMarkers.as_end(marker),
|
127
|
+
)
|
128
|
+
generate_terraform_docs(readme_path)
|
129
|
+
logger.info(f"updated {readme_path}")
|
130
|
+
return readme_path.read_text()
|
131
|
+
|
132
|
+
|
133
|
+
def generate_terraform_docs(readme_path: Path) -> None:
|
134
|
+
docs_config_path = readme_path.parent / TERRAFORM_DOCS_CONFIG_FILENAME
|
114
135
|
if docs_config_path.exists():
|
115
136
|
logger.warning(f"{docs_config_path} already exists, skipping generation")
|
116
137
|
else:
|
117
|
-
config_content = terraform_docs_config_content(
|
138
|
+
config_content = terraform_docs_config_content(readme_path)
|
118
139
|
ensure_parents_write_text(docs_config_path, config_content)
|
119
140
|
logger.info(f"generated {docs_config_path}")
|
120
|
-
run_and_wait(f"terraform-docs -c {docs_config_path} .", cwd=
|
141
|
+
run_and_wait(f"terraform-docs -c {docs_config_path} .", cwd=readme_path.parent)
|
121
142
|
readme_content = _default_link_updater(readme_path.read_text())
|
122
143
|
ensure_parents_write_text(readme_path, readme_content)
|
123
|
-
return readme_path.read_text()
|
124
144
|
|
125
145
|
|
126
146
|
def _default_link_updater(readme_content: str) -> str: # can be a global replacer for now
|
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
|
-
from
|
2
|
+
from dataclasses import dataclass, field
|
3
|
+
from typing import Iterable, Self
|
3
4
|
|
4
5
|
from model_lib import Entity
|
5
6
|
from pydantic import Field, RootModel, model_validator
|
@@ -30,6 +31,31 @@ def choose_next_emoji() -> str:
|
|
30
31
|
return emoji
|
31
32
|
|
32
33
|
|
34
|
+
@dataclass
|
35
|
+
class EmojiCounter:
|
36
|
+
counter: int = 0
|
37
|
+
existing_emojis: dict[str, str] = field(default_factory=dict)
|
38
|
+
|
39
|
+
@property
|
40
|
+
def emoji_to_names(self) -> dict[str, str]:
|
41
|
+
return dict(zip(self.existing_emojis.values(), self.existing_emojis.keys()))
|
42
|
+
|
43
|
+
def emoji_name(self) -> Iterable[tuple[str, str]]:
|
44
|
+
src = self.emoji_to_names
|
45
|
+
for emoji in _emojii_list:
|
46
|
+
if emoji in src:
|
47
|
+
yield emoji, src[emoji]
|
48
|
+
else:
|
49
|
+
break
|
50
|
+
|
51
|
+
def get_emoji(self, name: str) -> str:
|
52
|
+
if existing := self.existing_emojis.get(name):
|
53
|
+
return existing
|
54
|
+
emoji = self.existing_emojis[name] = _emojii_list[self.counter]
|
55
|
+
self.counter += 1
|
56
|
+
return emoji
|
57
|
+
|
58
|
+
|
33
59
|
class ModuleState(Entity):
|
34
60
|
resource_types: set[str] = Field(default_factory=set, description="Set of resource types in the module.")
|
35
61
|
|
@@ -24,6 +24,9 @@ from atlas_init.tf_ext.py_gen import (
|
|
24
24
|
from atlas_init.tf_ext.settings import RepoOut, TfExtSettings
|
25
25
|
|
26
26
|
ResourceTypeT: TypeAlias = str
|
27
|
+
TERRAFORM_DOCS_CONFIG_FILENAME: str = ".terraform-docs.yml"
|
28
|
+
README_FILENAME: str = "README.md"
|
29
|
+
EXAMPLES_DIRNAME: str = "examples"
|
27
30
|
|
28
31
|
|
29
32
|
@dataclass
|
@@ -253,12 +256,13 @@ class ModuleGenConfig(Entity):
|
|
253
256
|
return resource_type
|
254
257
|
raise ValueError(f"Could not resolve resource type for path {path}")
|
255
258
|
|
259
|
+
@property
|
256
260
|
def readme_path(self) -> Path:
|
257
|
-
return self.module_out_path /
|
261
|
+
return self.module_out_path / README_FILENAME
|
258
262
|
|
259
263
|
@property
|
260
264
|
def examples_path(self) -> Path:
|
261
|
-
return self.module_out_path /
|
265
|
+
return self.module_out_path / EXAMPLES_DIRNAME
|
262
266
|
|
263
267
|
def example_name(self, name: str, example_nr: int) -> str:
|
264
268
|
return f"{example_nr:02d}_{name}"
|
@@ -267,7 +271,7 @@ class ModuleGenConfig(Entity):
|
|
267
271
|
return self.examples_path / name
|
268
272
|
|
269
273
|
def terraform_docs_config_path(self) -> Path:
|
270
|
-
return self.module_out_path /
|
274
|
+
return self.module_out_path / TERRAFORM_DOCS_CONFIG_FILENAME
|
271
275
|
|
272
276
|
|
273
277
|
@dataclass
|
@@ -1,16 +1,18 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from functools import total_ordering
|
3
4
|
import logging
|
4
5
|
from collections import defaultdict
|
5
6
|
from pathlib import Path
|
6
|
-
from
|
7
|
+
from threading import RLock
|
8
|
+
from typing import Callable, Iterable, NamedTuple
|
7
9
|
|
8
10
|
import pydot
|
9
11
|
from ask_shell import ShellError, new_task, run_and_wait
|
10
12
|
from ask_shell._run import stop_runs_and_pool
|
11
13
|
from ask_shell.run_pool import run_pool
|
12
14
|
from model_lib import Entity, dump
|
13
|
-
from pydantic import BaseModel, Field
|
15
|
+
from pydantic import BaseModel, Field, model_validator
|
14
16
|
from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_fixed
|
15
17
|
from typer import Typer
|
16
18
|
from zero_3rdparty.file_utils import ensure_parents_write_text
|
@@ -57,13 +59,25 @@ def tf_dep_graph(
|
|
57
59
|
example_dirs = get_example_directories(repo_path, skip_names)
|
58
60
|
logger.info(f"example_dirs: \n{'\n'.join(str(d) for d in sorted(example_dirs))}")
|
59
61
|
with new_task("Find terraform graphs", total=len(example_dirs)) as task:
|
60
|
-
atlas_graph =
|
62
|
+
atlas_graph = create_atlas_graph(example_dirs, task)
|
61
63
|
with new_task("Dump graph"):
|
62
64
|
graph_yaml = atlas_graph.dump_yaml()
|
63
65
|
ensure_parents_write_text(settings.atlas_graph_path, graph_yaml)
|
64
66
|
logger.info(f"Atlas graph dumped to {settings.atlas_graph_path}")
|
65
67
|
|
66
68
|
|
69
|
+
def create_atlas_graph(example_dirs: list[Path], task: new_task) -> AtlasGraph:
|
70
|
+
atlas_graph = AtlasGraph()
|
71
|
+
|
72
|
+
def on_graph(example_dir: Path, graph: pydot.Dot):
|
73
|
+
atlas_graph.add_edges(graph.get_edges())
|
74
|
+
atlas_graph.add_variable_edges(example_dir)
|
75
|
+
|
76
|
+
parse_graphs(on_graph, example_dirs, task)
|
77
|
+
|
78
|
+
return atlas_graph
|
79
|
+
|
80
|
+
|
67
81
|
def print_edges(graph: pydot.Dot):
|
68
82
|
edges = graph.get_edges()
|
69
83
|
for edge in edges:
|
@@ -79,9 +93,15 @@ class ResourceParts(NamedTuple):
|
|
79
93
|
return self.resource_type.split("_")[0]
|
80
94
|
|
81
95
|
|
96
|
+
@total_ordering
|
82
97
|
class ResourceRef(BaseModel):
|
83
98
|
full_ref: str
|
84
99
|
|
100
|
+
@model_validator(mode="after")
|
101
|
+
def ensure_plain(self):
|
102
|
+
self.full_ref = plain_name(self.full_ref)
|
103
|
+
return self
|
104
|
+
|
85
105
|
def _resource_parts(self) -> ResourceParts:
|
86
106
|
match self.full_ref.split("."):
|
87
107
|
case [resource_type, resource_name] if "_" in resource_type:
|
@@ -106,6 +126,11 @@ class ResourceRef(BaseModel):
|
|
106
126
|
def is_module(self) -> bool:
|
107
127
|
return self.full_ref.startswith(MODULE_PREFIX)
|
108
128
|
|
129
|
+
@property
|
130
|
+
def module_name(self) -> str:
|
131
|
+
assert self.is_module, f"ResourceRef {self.full_ref} is not a module"
|
132
|
+
return self.full_ref.removeprefix(MODULE_PREFIX).split(".")[0]
|
133
|
+
|
109
134
|
@property
|
110
135
|
def is_data(self) -> bool:
|
111
136
|
return self.full_ref.startswith(DATA_PREFIX)
|
@@ -114,6 +139,22 @@ class ResourceRef(BaseModel):
|
|
114
139
|
def resource_type(self) -> str:
|
115
140
|
return self._resource_parts().resource_type
|
116
141
|
|
142
|
+
def __lt__(self, other: object) -> bool:
|
143
|
+
if not isinstance(other, ResourceRef):
|
144
|
+
raise TypeError(f"cannot compare {type(self)} with {type(other)}")
|
145
|
+
return self.full_ref < other.full_ref
|
146
|
+
|
147
|
+
def __hash__(self) -> int:
|
148
|
+
return hash(self.full_ref)
|
149
|
+
|
150
|
+
def __eq__(self, other: object) -> bool:
|
151
|
+
if not isinstance(other, ResourceRef):
|
152
|
+
return NotImplemented
|
153
|
+
return self.full_ref == other.full_ref
|
154
|
+
|
155
|
+
def __str__(self) -> str:
|
156
|
+
return self.full_ref
|
157
|
+
|
117
158
|
|
118
159
|
class EdgeParsed(BaseModel):
|
119
160
|
parent: ResourceRef
|
@@ -149,7 +190,15 @@ class EdgeParsed(BaseModel):
|
|
149
190
|
|
150
191
|
|
151
192
|
def edge_plain(edge_endpoint: pydot.EdgeEndpoint) -> str:
|
152
|
-
return str(edge_endpoint)
|
193
|
+
return plain_name(str(edge_endpoint))
|
194
|
+
|
195
|
+
|
196
|
+
def node_plain(node: pydot.Node) -> str:
|
197
|
+
return plain_name(node.get_name())
|
198
|
+
|
199
|
+
|
200
|
+
def plain_name(name: str) -> str:
|
201
|
+
return name.strip('"').strip()
|
153
202
|
|
154
203
|
|
155
204
|
def edge_src_dest(edge: pydot.Edge) -> tuple[str, str]:
|
@@ -235,34 +284,27 @@ class AtlasGraph(Entity):
|
|
235
284
|
self.parent_child_edges[parent_type].add(child_type)
|
236
285
|
|
237
286
|
|
238
|
-
def parse_graphs(
|
239
|
-
|
287
|
+
def parse_graphs(
|
288
|
+
on_graph: Callable[[Path, pydot.Dot], None], example_dirs: list[Path], task: new_task, max_dirs: int = 1_000
|
289
|
+
) -> None:
|
240
290
|
with run_pool("parse example graphs", total=len(example_dirs)) as executor:
|
241
291
|
futures = {
|
242
292
|
executor.submit(parse_graph, example_dir): example_dir
|
243
293
|
for i, example_dir in enumerate(example_dirs)
|
244
294
|
if i < max_dirs
|
245
295
|
}
|
246
|
-
|
247
|
-
for future in futures:
|
296
|
+
for future, example_dir in futures.items():
|
248
297
|
try:
|
249
|
-
|
298
|
+
_, graph = future.result()
|
250
299
|
except ShellError as e:
|
251
|
-
logger.error(f"Error parsing graph for {
|
300
|
+
logger.error(f"Error parsing graph for {example_dir}: {e}")
|
252
301
|
continue
|
253
302
|
except KeyboardInterrupt:
|
254
303
|
logger.error("KeyboardInterrupt received, stopping graph parsing.")
|
255
304
|
stop_runs_and_pool("KeyboardInterrupt", immediate=True)
|
256
305
|
break
|
257
|
-
|
258
|
-
graph = graphs[example_dir] = parse_graph_output(example_dir, graph_output)
|
259
|
-
except GraphParseError as e:
|
260
|
-
logger.error(e)
|
261
|
-
continue
|
262
|
-
atlas_graph.add_edges(graph.get_edges())
|
263
|
-
atlas_graph.add_variable_edges(example_dir)
|
306
|
+
on_graph(example_dir, graph)
|
264
307
|
task.update(advance=1)
|
265
|
-
return atlas_graph
|
266
308
|
|
267
309
|
|
268
310
|
class GraphParseError(Exception):
|
@@ -271,9 +313,13 @@ class GraphParseError(Exception):
|
|
271
313
|
super().__init__(f"Failed to parse graph for {example_dir}: {message}")
|
272
314
|
|
273
315
|
|
316
|
+
_lock = RLock()
|
317
|
+
|
318
|
+
|
274
319
|
def parse_graph_output(example_dir: Path, graph_output: str, verbose: bool = False) -> pydot.Dot:
|
275
320
|
assert graph_output, f"Graph output is empty for {example_dir}"
|
276
|
-
|
321
|
+
with _lock:
|
322
|
+
dots = pydot.graph_from_dot_data(graph_output)
|
277
323
|
if not dots:
|
278
324
|
raise GraphParseError(example_dir, f"No graphs found in the output:\n{graph_output}")
|
279
325
|
assert len(dots) == 1, f"Expected one graph for {example_dir}, got {len(dots)}"
|
@@ -297,10 +343,10 @@ class EmptyGraphOutputError(Exception):
|
|
297
343
|
@retry(
|
298
344
|
stop=stop_after_attempt(3),
|
299
345
|
wait=wait_fixed(1),
|
300
|
-
retry=retry_if_exception_type(EmptyGraphOutputError),
|
346
|
+
retry=retry_if_exception_type((EmptyGraphOutputError, GraphParseError)),
|
301
347
|
reraise=True,
|
302
348
|
)
|
303
|
-
def parse_graph(example_dir: Path) -> tuple[Path,
|
349
|
+
def parse_graph(example_dir: Path) -> tuple[Path, pydot.Dot]:
|
304
350
|
env_vars = {
|
305
351
|
"MONGODB_ATLAS_PREVIEW_PROVIDER_V2_ADVANCED_CLUSTER": "true" if is_v2_example_dir(example_dir) else "false",
|
306
352
|
}
|
@@ -309,7 +355,8 @@ def parse_graph(example_dir: Path) -> tuple[Path, str]:
|
|
309
355
|
run_and_wait("terraform init", cwd=example_dir, env=env_vars)
|
310
356
|
run = run_and_wait("terraform graph", cwd=example_dir, env=env_vars)
|
311
357
|
if graph_output := run.stdout_one_line:
|
312
|
-
|
358
|
+
graph = parse_graph_output(example_dir, graph_output) # just to make sure we get no errors
|
359
|
+
return example_dir, graph
|
313
360
|
raise EmptyGraphOutputError(example_dir)
|
314
361
|
|
315
362
|
|