nthlayer-generate 2.0.2__tar.gz → 2.0.3__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.
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/PKG-INFO +1 -1
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/pyproject.toml +1 -1
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/__init__.py +1 -1
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/init.py +202 -30
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/manifest.py +55 -2
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/validator.py +6 -5
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate.egg-info/PKG-INFO +1 -1
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate.egg-info/SOURCES.txt +1 -0
- nthlayer_generate-2.0.3/tests/test_init.py +1805 -0
- nthlayer_generate-2.0.3/tests/test_source_citations.py +117 -0
- nthlayer_generate-2.0.2/tests/test_init.py +0 -621
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/README.md +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/setup.cfg +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/alertmanager/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/alertmanager/config.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/alerts/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/alerts/loader.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/alerts/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/alerts/validator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/apply.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/backstage.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/dashboard.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/dashboard_validate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/dependencies.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/docs.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/environments.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/formatters/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/formatters/json_fmt.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/formatters/junit.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/formatters/markdown.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/formatters/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/formatters/sarif.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/generate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/generate_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/generate_loki.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/identity.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/lint.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/migrate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/migrate_manifest.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/ownership.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/plan.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/recommend_metrics.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/recording_rules.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/setup.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/simulate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/slo.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/topology.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/ux.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/validate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/validate_metadata.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/validate_slo.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/cli/validate_spec.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/clients/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/clients/base.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/clients/cortex.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/clients/pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/clients/slack.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/cli.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/integrations.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/loader.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/secrets/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/secrets/backends.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/config/settings.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/core/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/core/errors.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/core/tiers.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/builder_sdk.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/intents.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/manifest_builder.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/panel_spec.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/resolver.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/sdk_adapter.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/base.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/base_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/consul_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/elasticsearch_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/etcd_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/haproxy_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/http_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/kafka_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/kubernetes.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/mongodb_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/mysql_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/nats_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/nginx_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/postgresql_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/pulsar_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/rabbitmq_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/redis_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/stream_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/traefik_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/templates/worker_intent.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dashboards/validator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/demo.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/discovery.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/backstage.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/base.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/consul.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/etcd.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/kubernetes.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/prometheus.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/dependencies/providers/zookeeper.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/discovery/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/discovery/classifier.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/discovery/client.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/discovery/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/domain/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/domain/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/generators/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/generators/alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/generators/backstage.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/generators/docs.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/generators/sloth.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/normalizer.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/backstage.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/base.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/codeowners.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/declared.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/kubernetes.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/ownership_providers/pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/identity/resolver.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/integrations/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/integrations/pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/logging.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/loki/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/loki/generator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/loki/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/loki/templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/discovery.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/recommender.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/runtime/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/runtime/go.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/runtime/jvm.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/runtime/nodejs.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/runtime/python.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/standards/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/standards/aliases.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/standards/otel_semconv.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/api.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/cache.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/database_client.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/gateway.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/grpc.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/queue_consumer.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/registry.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/metrics/templates/worker.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestration/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestration/engine.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestration/handlers.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestration/plan_builder.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestration/registry.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestration/results.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/orchestrator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/pagerduty/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/pagerduty/defaults.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/pagerduty/naming.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/pagerduty/orchestration.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/pagerduty/resources.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/policies/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/policies/engine.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/policies/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/policies/rules.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/__main__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/base.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/cli.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/grafana.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/lock.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/mimir.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/prometheus.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/providers/registry.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/recording_rules/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/recording_rules/builder.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/recording_rules/manifest_builder.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/recording_rules/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/simulate/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/simulate/engine.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/simulate/graph.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/simulate/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/simulate/output.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/simulate/what_if.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/calculator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/ceiling.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/dependencies.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/parser.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/slos/pipeline.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/alerting.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/builtin_templates/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/contracts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/custom_templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/environment_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/environment_detection.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/environment_gates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/environment_merger.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/environments.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/helpers.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/loader.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/opensrm_parser.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/parser.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/template.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/template_loader.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/variable_substitution.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/topology/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/topology/enrichment.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/topology/models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/topology/serializers.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/user_config.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/validation/__init__.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/validation/conftest.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/validation/metadata.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/validation/promql.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/validation/promruval.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate.egg-info/dependency_links.txt +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate.egg-info/entry_points.txt +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate.egg-info/requires.txt +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate.egg-info/top_level.txt +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_alert_pipeline.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_alerting_config.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_alertmanager.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_backstage_generator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_budget_policy.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_apply.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_dashboard.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_dashboard_validate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_environments.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_formatters.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_generate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_generate_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_generate_loki.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_identity.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_lint.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_migrate_manifest.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_plan.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_setup.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_slo.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_ux.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_validate.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_validate_metadata.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_validate_slo.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_cli_validate_spec.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_clients.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_config_cli.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_config_loader.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_config_secrets_backends.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_config_secrets_init.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_conftest_validation.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_contract_validation.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_core_errors.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_core_tiers.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_critical_models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_custom_templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dashboard_generation.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dashboard_templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dashboards_builder_sdk.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dashboards_models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dashboards_resolver.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dashboards_validator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_demo.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_demo_app_auth.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dependencies.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_dependency_declarations.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_deps_discovery.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_deps_provider_backstage.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_deps_provider_consul.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_deps_provider_etcd.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_deps_provider_kubernetes.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_deps_provider_zookeeper.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_discovery_client.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_docs_generator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_domain_models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_env_flag.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_environment_commands.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_generators_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_generators_backstage.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_generators_docs.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_generators_sloth.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_hybrid_dashboard_builder.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_identity.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_init_documented_flags.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_integrations_pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_intent_templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_loki.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_metadata_validation.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_metrics_discovery.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_metrics_recommender.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_mimir_provider.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_multi_environment_integration.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_opensrm.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_orchestrator.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_ownership.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_pagerduty_module.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_pagerduty_orchestration.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_pagerduty_resources.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_policy_engine.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_policy_handler.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_policy_models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_policy_rules.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_prometheus_provider.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_provider_grafana.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_provider_pagerduty.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_providers_lock.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_recording_rules.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_sdk_adapter.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_service_type_agreement.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_simulate_cli.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_simulate_engine.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_simulate_graph.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_simulate_models.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_simulate_what_if.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_slo_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_slo_ceiling.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_slo_cli.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_slos.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_specs.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_sync_awesome_alerts.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_templates.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_topology.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_user_config.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_validation.py +0 -0
- {nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/tests/test_validation_promruval.py +0 -0
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"""CLI command for initializing new NthLayer services."""
|
|
2
2
|
|
|
3
|
+
import re
|
|
3
4
|
from pathlib import Path
|
|
4
5
|
|
|
6
|
+
import yaml
|
|
5
7
|
from nthlayer_common.manifest.models import resolve_service_type
|
|
6
8
|
|
|
7
9
|
from nthlayer_generate.cli.ux import (
|
|
@@ -17,6 +19,7 @@ from nthlayer_generate.cli.ux import (
|
|
|
17
19
|
)
|
|
18
20
|
from nthlayer_generate.core.tiers import TIER_CONFIGS
|
|
19
21
|
from nthlayer_generate.specs.custom_templates import CustomTemplateLoader
|
|
22
|
+
from nthlayer_generate.specs.manifest import is_valid_service_name
|
|
20
23
|
|
|
21
24
|
# The service-type menu. INVARIANT: every key is a value a manifest can
|
|
22
25
|
# store verbatim — nothing here is translated on the way out (opensrm-8qpd).
|
|
@@ -115,12 +118,22 @@ def init_command(
|
|
|
115
118
|
if not team and interactive:
|
|
116
119
|
team = text_input("Team name", placeholder="e.g., platform, payments")
|
|
117
120
|
|
|
118
|
-
|
|
121
|
+
# `not team` first: team is `str | None` here, so `.strip()` alone would
|
|
122
|
+
# raise on None and also lose the narrowing the calls below rely on. The
|
|
123
|
+
# `.strip()` half is what catches a whitespace-only --team here, where the
|
|
124
|
+
# message fits it, rather than at the _is_valid_team branch below, whose
|
|
125
|
+
# message would be false for it.
|
|
126
|
+
if not team or not team.strip():
|
|
119
127
|
error("Team name is required")
|
|
120
128
|
if not interactive:
|
|
121
129
|
console.print(" [muted]Pass it with --team <team>[/muted]")
|
|
122
130
|
return 1
|
|
123
131
|
|
|
132
|
+
if not _is_valid_team(team):
|
|
133
|
+
error("Invalid team name")
|
|
134
|
+
console.print(" [muted]Team name must not contain line breaks, tabs or NUL[/muted]")
|
|
135
|
+
return 1
|
|
136
|
+
|
|
124
137
|
# Select service tier using interactive menu
|
|
125
138
|
tier = None
|
|
126
139
|
if interactive:
|
|
@@ -196,10 +209,25 @@ def init_command(
|
|
|
196
209
|
service_name, team, tier, service_type, dependencies, template_obj
|
|
197
210
|
)
|
|
198
211
|
|
|
212
|
+
# encoding="utf-8" explicitly, and UnicodeError caught alongside OSError
|
|
213
|
+
# (opensrm-t4rd edge-case pass). Without the encoding, `write_text` uses the
|
|
214
|
+
# locale's, so on a non-UTF-8 system an ordinary accented team name raised
|
|
215
|
+
# UnicodeEncodeError -- which is a ValueError, NOT an OSError, so the handler
|
|
216
|
+
# below missed it and init died by traceback. Worse, `write_text` had already
|
|
217
|
+
# created the file, so a ZERO-BYTE manifest was left behind and every later
|
|
218
|
+
# run then hit the `exists()` guard above and refused, permanently, until
|
|
219
|
+
# someone deleted it by hand.
|
|
220
|
+
#
|
|
221
|
+
# The unlink is the rollback half of this bead's defect 3: a run that fails
|
|
222
|
+
# must not leave a partial artifact that blocks the next one.
|
|
199
223
|
try:
|
|
200
|
-
service_file.write_text(service_content)
|
|
201
|
-
except OSError as e:
|
|
224
|
+
service_file.write_text(service_content, encoding="utf-8")
|
|
225
|
+
except (OSError, UnicodeError) as e:
|
|
202
226
|
error(f"Error creating service file: {e}")
|
|
227
|
+
try:
|
|
228
|
+
service_file.unlink(missing_ok=True)
|
|
229
|
+
except OSError:
|
|
230
|
+
pass
|
|
203
231
|
return 1
|
|
204
232
|
|
|
205
233
|
# Create .nthlayer directory
|
|
@@ -209,20 +237,40 @@ def init_command(
|
|
|
209
237
|
except OSError as e:
|
|
210
238
|
warning(f"Could not create .nthlayer directory: {e}")
|
|
211
239
|
|
|
212
|
-
# Create config file if it doesn't exist
|
|
240
|
+
# Create config file if it doesn't exist.
|
|
241
|
+
#
|
|
242
|
+
# `is_file()`, NOT `exists()` -- the same confusion this bead fixed for
|
|
243
|
+
# `nthlayer_dir` below. With `.nthlayer/config.yaml` present as a DIRECTORY,
|
|
244
|
+
# `exists()` is True because it is a directory, so the write was skipped and
|
|
245
|
+
# init reported success for a config it had never written, with no warning.
|
|
213
246
|
config_file = nthlayer_dir / "config.yaml"
|
|
214
|
-
if not config_file.
|
|
247
|
+
if not config_file.is_file():
|
|
215
248
|
config_content = _generate_config_yaml()
|
|
216
249
|
try:
|
|
217
|
-
config_file.write_text(config_content)
|
|
218
|
-
except OSError as e:
|
|
250
|
+
config_file.write_text(config_content, encoding="utf-8")
|
|
251
|
+
except (OSError, UnicodeError) as e:
|
|
219
252
|
warning(f"Could not create config file: {e}")
|
|
220
253
|
|
|
221
254
|
# Success message
|
|
222
255
|
console.print()
|
|
223
256
|
success(f"Created {service_file}")
|
|
224
|
-
|
|
257
|
+
# is_dir(), NOT exists() (opensrm-t4rd): with .nthlayer a regular FILE,
|
|
258
|
+
# exists() is True *because it is a file*, so init claimed to have created
|
|
259
|
+
# a directory it had not.
|
|
260
|
+
if nthlayer_dir.is_dir():
|
|
225
261
|
success(f"Created {nthlayer_dir}/")
|
|
262
|
+
else:
|
|
263
|
+
# NOT fatal, including under --no-interactive. Decided deliberately
|
|
264
|
+
# (opensrm-t4rd acceptance): the manifest is the primary artifact and it
|
|
265
|
+
# was written correctly, so a CI gate keying on the exit code is right to
|
|
266
|
+
# pass. What was wrong before was claiming the directory had been created;
|
|
267
|
+
# the warning below states plainly that it was not, and names the fix.
|
|
268
|
+
# Making it fatal would fail runs whose manifest is perfectly good merely
|
|
269
|
+
# because .nthlayer could not be created (read-only parent, a stray file).
|
|
270
|
+
warning(
|
|
271
|
+
f"{nthlayer_dir}/ was not created — config was not written. "
|
|
272
|
+
f"It already exists as a file, or the parent is not writable."
|
|
273
|
+
)
|
|
226
274
|
|
|
227
275
|
console.print()
|
|
228
276
|
console.print("[bold]Next steps:[/bold]")
|
|
@@ -241,28 +289,147 @@ def init_command(
|
|
|
241
289
|
return 0
|
|
242
290
|
|
|
243
291
|
|
|
244
|
-
|
|
245
|
-
|
|
292
|
+
# WHY THE SCALAR HELPERS BELOW EXIST (opensrm-t4rd).
|
|
293
|
+
#
|
|
294
|
+
# generate's hard rule 5 — no raw string construction for generated output —
|
|
295
|
+
# applied at the one input that is scriptable and unvalidated. `--team` was
|
|
296
|
+
# interpolated raw with only a truthiness check. Measured before the fix, all
|
|
297
|
+
# exiting 0:
|
|
298
|
+
#
|
|
299
|
+
# --team 'Platform: Core' -> the manifest failed to parse
|
|
300
|
+
# --team $'ops\nname: hijacked' -> injected a second service.name
|
|
301
|
+
# --team $'ops\ntier: critical' -> manifest VALIDATED CLEAN carrying a
|
|
302
|
+
# bogus tier shadowed by the real one
|
|
303
|
+
#
|
|
304
|
+
# A colon in a team name is ordinary, so quoting has to be available. It is
|
|
305
|
+
# applied conditionally, for the reason in `_yaml_scalar`, and done with
|
|
306
|
+
# pyyaml rather than `json.dumps`, for the reason in `_quoted_yaml_scalar`.
|
|
307
|
+
#
|
|
308
|
+
# The allowlist is deliberately narrow: anything outside it is quoted rather
|
|
309
|
+
# than reasoned about. It excludes every YAML indicator character (`:` `#`
|
|
310
|
+
# `-` at the start, `{` `[` `&` `*` `!` `|` `>` `%` `@` and a backtick),
|
|
311
|
+
# leading whitespace, and anything non-ASCII. Matching it is necessary but NOT
|
|
312
|
+
# sufficient — see `_emits_as_same_string`.
|
|
313
|
+
_PLAIN_SCALAR_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9 ._-]*")
|
|
246
314
|
|
|
247
|
-
Args:
|
|
248
|
-
name: Service name to validate
|
|
249
315
|
|
|
250
|
-
|
|
251
|
-
|
|
316
|
+
def _yaml_scalar(value: object) -> str:
|
|
317
|
+
"""Render *value* as a YAML scalar that cannot alter the document.
|
|
318
|
+
|
|
319
|
+
Plain when it provably round-trips, quoted otherwise. Quoting is
|
|
320
|
+
conditional so the documented example output stays byte-identical to what
|
|
321
|
+
init writes (``test_block_is_byte_identical_to_real_output``, the
|
|
322
|
+
docs-vs-reality guard from opensrm-noc6).
|
|
323
|
+
|
|
324
|
+
A non-str is quoted rather than rejected: values arrive straight from a
|
|
325
|
+
YAML loader, so a template declaring ``name: on`` makes this a bool and
|
|
326
|
+
``re.fullmatch`` would raise on it.
|
|
252
327
|
"""
|
|
253
|
-
if not
|
|
328
|
+
if not isinstance(value, str):
|
|
329
|
+
return _quoted_yaml_scalar(str(value))
|
|
330
|
+
if _PLAIN_SCALAR_RE.fullmatch(value) and _emits_as_same_string(value):
|
|
331
|
+
return value
|
|
332
|
+
return _quoted_yaml_scalar(value)
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
# pyyaml wraps long scalars by default, which would emit a second line into a
|
|
336
|
+
# document built by string interpolation. Large enough to never wrap.
|
|
337
|
+
_NO_WRAP = 10**9
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
def _quoted_yaml_scalar(value: str) -> str:
|
|
341
|
+
"""Render *value* as a double-quoted YAML scalar on exactly one line.
|
|
342
|
+
|
|
343
|
+
``default_style='"'`` forces the quoted form for every input, so the result
|
|
344
|
+
is always a single line and never a block scalar.
|
|
345
|
+
|
|
346
|
+
``json.dumps`` was used here first, on the reasoning that a JSON string is
|
|
347
|
+
also a valid YAML double-quoted scalar. True for the BMP, false above it:
|
|
348
|
+
with ``ensure_ascii=True`` json escapes a non-BMP character as a UTF-16
|
|
349
|
+
surrogate PAIR, and pyyaml resolves each 16-bit escape separately without
|
|
350
|
+
recombining them, so an emoji team name read back as two lone surrogates,
|
|
351
|
+
validated clean, and could not be re-encoded to UTF-8 at all.
|
|
352
|
+
``ensure_ascii=False`` is no better: it mismatches on U+0085 and makes
|
|
353
|
+
pyyaml raise on U+007F.
|
|
354
|
+
|
|
355
|
+
``allow_unicode=True`` is readability only, not correctness: it emits BMP
|
|
356
|
+
non-ASCII literally (``cafe`` with its accent, rather than an escape).
|
|
357
|
+
Above the BMP pyyaml escapes regardless of the flag -- but as ONE 32-bit
|
|
358
|
+
escape, which its own reader resolves back to one character. That single
|
|
359
|
+
escape, not the flag, is what json's surrogate pair got wrong. Measured:
|
|
360
|
+
both settings round-trip every value in the corpus.
|
|
361
|
+
|
|
362
|
+
The trailing newline pyyaml adds is stripped. No document-end marker is
|
|
363
|
+
stripped, because ``default_style='"'`` means only pyyaml's
|
|
364
|
+
double-quoted writer ever runs, and that writer never emits one.
|
|
365
|
+
"""
|
|
366
|
+
return yaml.safe_dump(value, default_style='"', allow_unicode=True, width=_NO_WRAP).rstrip("\n")
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def _emits_as_same_string(value: str) -> bool:
|
|
370
|
+
"""True if *value* written as a plain YAML scalar reads back identically.
|
|
371
|
+
|
|
372
|
+
The allowlist excludes every YAML *indicator*, but says nothing about
|
|
373
|
+
implicit *type resolution*, which is the half that was missing. Measured,
|
|
374
|
+
every one of these matched the allowlist, was emitted unquoted, and loaded
|
|
375
|
+
back as something other than the string written -- all at exit 0:
|
|
376
|
+
|
|
377
|
+
--team null -> None -> validate FAILS, "team is required"
|
|
378
|
+
--team yes/on/true -> True -> validates CLEAN, bool in a str field
|
|
379
|
+
--team no/off/false -> False -> validate FAILS
|
|
380
|
+
--team 123 -> 123 -> int
|
|
381
|
+
--team 1_000 -> 1000 -> int
|
|
382
|
+
--team 1.5 -> 1.5 -> float
|
|
383
|
+
--team 0x1f -> 31 -> int
|
|
384
|
+
--team 2026-01-01 -> date(...) -> datetime.date, validates CLEAN
|
|
385
|
+
--team 'ops ' -> 'ops' -> trailing space silently stripped
|
|
386
|
+
|
|
387
|
+
Case variants resolve too (``NULL``, ``Yes``), which is why this asks the
|
|
388
|
+
loader instead of carrying a deny list that would have to track the YAML 1.1
|
|
389
|
+
type schema -- and stay correct as pyyaml changes. Both shapes above are the
|
|
390
|
+
bead's own defects one field over: the first writes a manifest generate's
|
|
391
|
+
validator rejects, the second a clean manifest carrying a wrong value.
|
|
392
|
+
|
|
393
|
+
Checking the bare scalar is faithful to the mapping-value position it is
|
|
394
|
+
emitted into, because the allowlist already excludes every character whose
|
|
395
|
+
resolution differs between those two contexts.
|
|
396
|
+
|
|
397
|
+
``ValueError`` is caught alongside ``YAMLError`` because pyyaml's integer
|
|
398
|
+
constructor raises it rather than a YAML error on an allowlist-matching
|
|
399
|
+
input: ``0b_`` reaches ``int("", 2)``. Uncaught, that crashed ``nthlayer
|
|
400
|
+
init`` with a traceback and wrote nothing. Fuzzing every
|
|
401
|
+
allowlist-matching string up to length 4 (10248 of them) reaches exactly
|
|
402
|
+
these two types, ``ValueError`` on 3 inputs -- ``0b_``, ``0x_``, ``0b__``.
|
|
403
|
+
|
|
404
|
+
Either way the answer is the same: a value that will not load is not
|
|
405
|
+
provably a plain string, so it gets quoted.
|
|
406
|
+
"""
|
|
407
|
+
try:
|
|
408
|
+
loaded = yaml.safe_load(value)
|
|
409
|
+
except (yaml.YAMLError, ValueError):
|
|
254
410
|
return False
|
|
411
|
+
return isinstance(loaded, str) and loaded == value
|
|
255
412
|
|
|
256
|
-
# Must be lowercase, numbers, and hyphens only
|
|
257
|
-
# Must not start or end with hyphen
|
|
258
|
-
if name[0] == "-" or name[-1] == "-":
|
|
259
|
-
return False
|
|
260
413
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
414
|
+
def _is_valid_team(team: str) -> bool:
|
|
415
|
+
r"""True if *team* contains no line break, tab or NUL.
|
|
416
|
+
|
|
417
|
+
Those four only, not every control character: the rest are quoted correctly
|
|
418
|
+
by ``_yaml_scalar`` and are merely odd, not dangerous. Blankness is not
|
|
419
|
+
checked here either — the caller rejects it first, with a message that
|
|
420
|
+
actually fits it.
|
|
421
|
+
|
|
422
|
+
Quoting alone already makes the document safe, so this is not what prevents
|
|
423
|
+
injection. It is what turns a newline in --team into a clear error rather
|
|
424
|
+
than a silently escaped ``\n`` in the output, because a team name spanning
|
|
425
|
+
lines is a mistake every time.
|
|
426
|
+
"""
|
|
427
|
+
return not any(ch in team for ch in "\n\r\t\x00")
|
|
428
|
+
|
|
264
429
|
|
|
265
|
-
|
|
430
|
+
def _is_valid_service_name(name: str) -> bool:
|
|
431
|
+
"""Delegates to the one service-name rule; see specs/manifest for why."""
|
|
432
|
+
return is_valid_service_name(name)
|
|
266
433
|
|
|
267
434
|
|
|
268
435
|
def _generate_service_yaml_v2(
|
|
@@ -293,14 +460,14 @@ def _generate_service_yaml_v2(
|
|
|
293
460
|
resources_yaml = _build_resources_yaml(service_name, tier, service_type, dependencies)
|
|
294
461
|
|
|
295
462
|
# Template line if using a template
|
|
296
|
-
template_line = f" template: {template.name}\n" if template else ""
|
|
463
|
+
template_line = f" template: {_yaml_scalar(template.name)}\n" if template else ""
|
|
297
464
|
|
|
298
465
|
return f"""# {service_name} Service Definition
|
|
299
466
|
# Generated by NthLayer
|
|
300
467
|
|
|
301
468
|
service:
|
|
302
|
-
name: {service_name}
|
|
303
|
-
team: {team}
|
|
469
|
+
name: {_yaml_scalar(service_name)}
|
|
470
|
+
team: {_yaml_scalar(team)}
|
|
304
471
|
tier: {tier}
|
|
305
472
|
type: {service_type}
|
|
306
473
|
{template_line}
|
|
@@ -457,11 +624,11 @@ def _generate_service_yaml(service_name: str, team: str, template) -> str:
|
|
|
457
624
|
# Generated by NthLayer
|
|
458
625
|
|
|
459
626
|
service:
|
|
460
|
-
name: {service_name}
|
|
461
|
-
team: {team}
|
|
627
|
+
name: {_yaml_scalar(service_name)}
|
|
628
|
+
team: {_yaml_scalar(team)}
|
|
462
629
|
tier: {template.tier} # critical | standard | low
|
|
463
630
|
type: {template.type} # api | worker | stream | batch | database | ai-gate | x-web
|
|
464
|
-
template: {template.name}
|
|
631
|
+
template: {_yaml_scalar(template.name)}
|
|
465
632
|
|
|
466
633
|
# Template provides:
|
|
467
634
|
{_format_template_resources(template)}
|
|
@@ -493,7 +660,12 @@ def _format_template_resources(template) -> str:
|
|
|
493
660
|
"""
|
|
494
661
|
lines = []
|
|
495
662
|
for resource in template.resources:
|
|
496
|
-
|
|
663
|
+
# A comment, but still a line in the document: `resource.kind` and
|
|
664
|
+
# `resource.name` come from a template file on disk with no
|
|
665
|
+
# validation, so a newline in either would escape the `#` and land
|
|
666
|
+
# at top level. `_yaml_scalar` escapes it instead, and leaves the
|
|
667
|
+
# ordinary values (`SLO`, `availability`) unquoted.
|
|
668
|
+
lines.append(f"# - {_yaml_scalar(resource.kind)}: {_yaml_scalar(resource.name)}")
|
|
497
669
|
return "\n".join(lines) if lines else "# (no resources)"
|
|
498
670
|
|
|
499
671
|
|
|
@@ -11,6 +11,7 @@ this unified model, ensuring format-agnostic processing.
|
|
|
11
11
|
|
|
12
12
|
from __future__ import annotations
|
|
13
13
|
|
|
14
|
+
import re
|
|
14
15
|
from dataclasses import dataclass, field
|
|
15
16
|
from enum import Enum
|
|
16
17
|
from typing import TYPE_CHECKING, Any
|
|
@@ -45,6 +46,59 @@ VALID_TIERS = {
|
|
|
45
46
|
"low",
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
# THE service-name rule for the init path (opensrm-t4rd). Two copies of it
|
|
50
|
+
# disagreed:
|
|
51
|
+
# cli/init.py's guard looped over `char.islower() or char.isdigit()`, which are
|
|
52
|
+
# UNICODE predicates, and rejected only a leading or trailing hyphen — so
|
|
53
|
+
# `1-svc`, `café` and fullwidth `abc` all passed the CLI and were then rejected
|
|
54
|
+
# by specs/validator.py, which applies the pattern below. `nthlayer init` exited
|
|
55
|
+
# 0 having written a manifest its own validator refuses, and an exit code is
|
|
56
|
+
# what a CI gate keys on.
|
|
57
|
+
#
|
|
58
|
+
# NOT exhaustive: cli/setup.py has a third, still-divergent copy that accepts
|
|
59
|
+
# `123`, `café` and `1-svc` (it does reject both hyphen ends). Tracked in
|
|
60
|
+
# opensrm-h9fq, and asserted by
|
|
61
|
+
# test_init.py::TestSetupGuardStillDiverges so this note cannot rot quietly.
|
|
62
|
+
#
|
|
63
|
+
# Same shape as the service-type divergence recorded below under opensrm-z3ab,
|
|
64
|
+
# which is why the rule lives here with it rather than in either caller.
|
|
65
|
+
#
|
|
66
|
+
# AUTHORITY: this pattern is generate's own, and is deliberately STRICTER than
|
|
67
|
+
# the opensrm schema, so schema-valid documents exist that `init` refuses to
|
|
68
|
+
# write. That gap is a spec decision, tracked in opensrm-fwnp — which is also
|
|
69
|
+
# where the schema's actual patterns are recorded, rather than quoted here
|
|
70
|
+
# where they would rot. A test cannot hold them: generate's CI installs
|
|
71
|
+
# nthlayer-common from PyPI and has no `opensrm/` checkout, so a schema.json
|
|
72
|
+
# assertion would `pytest.skip` in exactly the environment meant to gate the
|
|
73
|
+
# merge (the reasoning is spelled out in test_service_type_agreement.py).
|
|
74
|
+
#
|
|
75
|
+
# The rule is the union of what the two old guards each enforced:
|
|
76
|
+
# - must start with a lowercase letter (validator.py had this; the CLI did not)
|
|
77
|
+
# - must not end with a hyphen (the CLI had this; validator.py did not)
|
|
78
|
+
# Neither was right alone, so aligning to either one would have loosened the
|
|
79
|
+
# other. Checked before tightening: no leading- or trailing-hyphen service name
|
|
80
|
+
# was in use anywhere in this repo.
|
|
81
|
+
SERVICE_NAME_PATTERN = r"[a-z]([a-z0-9-]*[a-z0-9])?"
|
|
82
|
+
_SERVICE_NAME_RE = re.compile(SERVICE_NAME_PATTERN)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def is_valid_service_name(name: str) -> bool:
|
|
86
|
+
"""True if *name* is a legal service name for generated manifests.
|
|
87
|
+
|
|
88
|
+
Uses ``fullmatch``, not ``match`` with a trailing ``$``. In Python ``$``
|
|
89
|
+
also matches just before a final newline, so ``re.match(r"...$", "svc\n")``
|
|
90
|
+
SUCCEEDS — and a trailing newline is an ordinary authoring accident from a
|
|
91
|
+
YAML block scalar.
|
|
92
|
+
|
|
93
|
+
``isinstance`` is checked first because the loader hands this whatever YAML
|
|
94
|
+
resolved: a manifest with ``name: yes`` yields ``True``, which passes
|
|
95
|
+
``bool(name)`` and then makes ``fullmatch`` raise ``TypeError``, so
|
|
96
|
+
``nthlayer validate`` died with a traceback instead of reporting the error.
|
|
97
|
+
A non-str name is never valid, so returning False is both safe and correct.
|
|
98
|
+
"""
|
|
99
|
+
return isinstance(name, str) and bool(name) and _SERVICE_NAME_RE.fullmatch(name) is not None
|
|
100
|
+
|
|
101
|
+
|
|
48
102
|
# Service types come from nthlayer-common, which is the single source of
|
|
49
103
|
# truth for the rule (opensrm-z3ab). generate kept its own copy until the
|
|
50
104
|
# two silently disagreed: it accepted `web`, which schema.json rejects,
|
|
@@ -539,8 +593,7 @@ class ReliabilityManifest:
|
|
|
539
593
|
resolved_type = resolve_service_type(self.type)
|
|
540
594
|
if resolved_type is None:
|
|
541
595
|
raise ValueError(
|
|
542
|
-
f"Invalid type '{self.type}'. "
|
|
543
|
-
f"Must be one of: {valid_service_types_phrase()}."
|
|
596
|
+
f"Invalid type '{self.type}'. Must be one of: {valid_service_types_phrase()}."
|
|
544
597
|
)
|
|
545
598
|
self.type = resolved_type
|
|
546
599
|
|
{nthlayer_generate-2.0.2 → nthlayer_generate-2.0.3}/src/nthlayer_generate/specs/validator.py
RENAMED
|
@@ -6,7 +6,6 @@ Supports both OpenSRM format (apiVersion: srm/v1) and legacy NthLayer format.
|
|
|
6
6
|
|
|
7
7
|
from __future__ import annotations
|
|
8
8
|
|
|
9
|
-
import re
|
|
10
9
|
import warnings as stdlib_warnings
|
|
11
10
|
from dataclasses import dataclass, field
|
|
12
11
|
from pathlib import Path
|
|
@@ -27,7 +26,7 @@ from nthlayer_generate.specs.loader import (
|
|
|
27
26
|
ManifestLoadError,
|
|
28
27
|
load_manifest,
|
|
29
28
|
)
|
|
30
|
-
from nthlayer_generate.specs.manifest import VALID_TIERS
|
|
29
|
+
from nthlayer_generate.specs.manifest import VALID_TIERS, is_valid_service_name
|
|
31
30
|
from nthlayer_generate.specs.models import VALID_RESOURCE_KINDS
|
|
32
31
|
from nthlayer_generate.specs.parser import ServiceParseError, parse_service_file
|
|
33
32
|
from nthlayer_generate.specs.template import validate_template_variables
|
|
@@ -199,11 +198,13 @@ def validate_service_file(
|
|
|
199
198
|
)
|
|
200
199
|
|
|
201
200
|
# Validate service name format
|
|
202
|
-
|
|
201
|
+
# Shared with cli/init.py's guard via specs/manifest (opensrm-t4rd). Two
|
|
202
|
+
# copies disagreed, so init exited 0 writing names this rejected.
|
|
203
|
+
if not is_valid_service_name(service_context.name):
|
|
203
204
|
errors.append(
|
|
204
205
|
f"Invalid service name: '{service_context.name}'. "
|
|
205
|
-
"Must start with lowercase letter
|
|
206
|
-
"numbers, and
|
|
206
|
+
"Must start with a lowercase letter, contain only lowercase letters, "
|
|
207
|
+
"numbers and hyphens, and not end with a hyphen."
|
|
207
208
|
)
|
|
208
209
|
|
|
209
210
|
# Validate tier
|