sdetkit 1.0.3__py3-none-any.whl
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.
- sdetkit/__init__.py +122 -0
- sdetkit/__main__.py +136 -0
- sdetkit/_entrypoints.py +14 -0
- sdetkit/_legacy_lane.py +86 -0
- sdetkit/_toml.py +14 -0
- sdetkit/acceleration_closeout_43.py +462 -0
- sdetkit/agent/__init__.py +3 -0
- sdetkit/agent/actions.py +402 -0
- sdetkit/agent/cli.py +434 -0
- sdetkit/agent/core.py +538 -0
- sdetkit/agent/dashboard.py +346 -0
- sdetkit/agent/demo.py +87 -0
- sdetkit/agent/omnichannel.py +431 -0
- sdetkit/agent/providers.py +90 -0
- sdetkit/agent/templates.py +595 -0
- sdetkit/apiclient.py +601 -0
- sdetkit/apiget.py +834 -0
- sdetkit/apiget_dispatch.py +50 -0
- sdetkit/argv_flags.py +15 -0
- sdetkit/artifact_contract_index.py +114 -0
- sdetkit/atomicio.py +93 -0
- sdetkit/author_problem.py +2211 -0
- sdetkit/baseline_dispatch.py +75 -0
- sdetkit/bools.py +66 -0
- sdetkit/case_study_launch_closeout_73.py +398 -0
- sdetkit/case_study_prep1_closeout_69.py +392 -0
- sdetkit/case_study_prep2_closeout_70.py +394 -0
- sdetkit/case_study_prep3_closeout_71.py +400 -0
- sdetkit/case_study_prep4_closeout_72.py +411 -0
- sdetkit/cassette.py +291 -0
- sdetkit/checks/__init__.py +60 -0
- sdetkit/checks/__main__.py +6 -0
- sdetkit/checks/artifacts.py +694 -0
- sdetkit/checks/base.py +154 -0
- sdetkit/checks/builtin.py +398 -0
- sdetkit/checks/cache.py +117 -0
- sdetkit/checks/main.py +268 -0
- sdetkit/checks/planner.py +351 -0
- sdetkit/checks/registry.py +132 -0
- sdetkit/checks/results.py +195 -0
- sdetkit/checks/runner.py +293 -0
- sdetkit/ci.py +139 -0
- sdetkit/cli.py +813 -0
- sdetkit/cli_shortcuts.py +86 -0
- sdetkit/cli_timing.py +26 -0
- sdetkit/community_activation.py +411 -0
- sdetkit/community_program_closeout_62.py +33 -0
- sdetkit/community_touchpoint_closeout_77.py +411 -0
- sdetkit/continuous_upgrade_closeout_1.py +18 -0
- sdetkit/continuous_upgrade_closeout_10.py +18 -0
- sdetkit/continuous_upgrade_closeout_11.py +18 -0
- sdetkit/continuous_upgrade_closeout_2.py +18 -0
- sdetkit/continuous_upgrade_closeout_3.py +18 -0
- sdetkit/continuous_upgrade_closeout_4.py +18 -0
- sdetkit/continuous_upgrade_closeout_5.py +18 -0
- sdetkit/continuous_upgrade_closeout_6.py +18 -0
- sdetkit/continuous_upgrade_closeout_7.py +18 -0
- sdetkit/continuous_upgrade_closeout_8.py +18 -0
- sdetkit/continuous_upgrade_closeout_9.py +18 -0
- sdetkit/contract.py +126 -0
- sdetkit/contributor_activation_closeout_55.py +467 -0
- sdetkit/contributor_funnel.py +281 -0
- sdetkit/contributor_recognition_closeout_76.py +398 -0
- sdetkit/core_preparse_dispatch.py +35 -0
- sdetkit/demo.py +276 -0
- sdetkit/demo_asset2_34.py +25 -0
- sdetkit/demo_asset_33.py +25 -0
- sdetkit/distribution_batch_38.py +27 -0
- sdetkit/distribution_closeout_36.py +26 -0
- sdetkit/distribution_scaling_closeout_74.py +399 -0
- sdetkit/docs_loop_closeout_53.py +514 -0
- sdetkit/docs_navigation.py +281 -0
- sdetkit/docs_qa.py +260 -0
- sdetkit/doctor.py +3451 -0
- sdetkit/ecosystem_priorities_closeout_78.py +405 -0
- sdetkit/enterprise_assessment.py +686 -0
- sdetkit/enterprise_readiness.py +503 -0
- sdetkit/entrypoints.py +15 -0
- sdetkit/evidence.py +261 -0
- sdetkit/evidence_narrative_closeout_84.py +411 -0
- sdetkit/evidence_workspace.py +184 -0
- sdetkit/execution_prioritization_closeout_50.py +31 -0
- sdetkit/expansion_automation_41.py +27 -0
- sdetkit/expansion_closeout_45.py +441 -0
- sdetkit/experiment_lane_37.py +29 -0
- sdetkit/external_contribution.py +463 -0
- sdetkit/feature_registry.py +173 -0
- sdetkit/feature_registry_cli.py +182 -0
- sdetkit/first_contribution.py +388 -0
- sdetkit/forensics.py +183 -0
- sdetkit/gate.py +838 -0
- sdetkit/github_actions_quickstart.py +572 -0
- sdetkit/gitlab_ci_quickstart.py +603 -0
- sdetkit/governance_handoff_closeout_87.py +409 -0
- sdetkit/governance_priorities_closeout_88.py +409 -0
- sdetkit/governance_scale_closeout_89.py +411 -0
- sdetkit/growth_campaign_closeout_81.py +395 -0
- sdetkit/help_surface.py +57 -0
- sdetkit/import_hazards.py +38 -0
- sdetkit/inspect_compare.py +581 -0
- sdetkit/inspect_compare_forwarding.py +33 -0
- sdetkit/inspect_data.py +954 -0
- sdetkit/inspect_forwarding.py +15 -0
- sdetkit/inspect_project.py +641 -0
- sdetkit/inspect_project_forwarding.py +18 -0
- sdetkit/integration.py +642 -0
- sdetkit/integration_expansion2_closeout_66.py +405 -0
- sdetkit/integration_expansion3_closeout_67.py +411 -0
- sdetkit/integration_expansion4_closeout_68.py +416 -0
- sdetkit/integration_feedback_closeout_82.py +411 -0
- sdetkit/intelligence.py +388 -0
- sdetkit/judgment.py +268 -0
- sdetkit/kits.py +385 -0
- sdetkit/kpi_audit.py +29 -0
- sdetkit/kpi_deep_audit_closeout_57.py +31 -0
- sdetkit/kpi_instrumentation_35.py +25 -0
- sdetkit/kpi_report.py +152 -0
- sdetkit/kvcli.py +171 -0
- sdetkit/launch_readiness_closeout_86.py +409 -0
- sdetkit/legacy_adapters/__init__.py +16 -0
- sdetkit/legacy_adapters/closeout.py +51 -0
- sdetkit/legacy_adapters/continuous_upgrade.py +15 -0
- sdetkit/legacy_adapters/foundation.py +36 -0
- sdetkit/legacy_cli.py +54 -0
- sdetkit/legacy_commands.py +55 -0
- sdetkit/legacy_namespace.py +21 -0
- sdetkit/main_.py +3 -0
- sdetkit/maintenance/__init__.py +5 -0
- sdetkit/maintenance/__main__.py +6 -0
- sdetkit/maintenance/checks/__init__.py +1 -0
- sdetkit/maintenance/checks/clean_tree_check.py +76 -0
- sdetkit/maintenance/checks/custom_example_check.py +27 -0
- sdetkit/maintenance/checks/deps_check.py +59 -0
- sdetkit/maintenance/checks/doctor_check.py +115 -0
- sdetkit/maintenance/checks/github_automation_check.py +341 -0
- sdetkit/maintenance/checks/lint_check.py +85 -0
- sdetkit/maintenance/checks/security_check.py +243 -0
- sdetkit/maintenance/checks/tests_check.py +55 -0
- sdetkit/maintenance/cli.py +360 -0
- sdetkit/maintenance/main.py +6 -0
- sdetkit/maintenance/registry.py +42 -0
- sdetkit/maintenance/types.py +47 -0
- sdetkit/maintenance/utils.py +8 -0
- sdetkit/netclient.py +1042 -0
- sdetkit/notify.py +83 -0
- sdetkit/notify_plugins.py +54 -0
- sdetkit/objection_closeout_48.py +29 -0
- sdetkit/objection_handling.py +534 -0
- sdetkit/onboarding.py +293 -0
- sdetkit/onboarding_optimization.py +458 -0
- sdetkit/ops.py +980 -0
- sdetkit/ops_control.py +371 -0
- sdetkit/optimization_closeout_42.py +477 -0
- sdetkit/optimization_closeout_46.py +444 -0
- sdetkit/optional_httpx.py +65 -0
- sdetkit/parsed_shortcuts.py +63 -0
- sdetkit/parser_helpers.py +23 -0
- sdetkit/partner_outreach_closeout_80.py +458 -0
- sdetkit/patch.py +959 -0
- sdetkit/phase1_hardening_29.py +342 -0
- sdetkit/phase1_wrap_30.py +28 -0
- sdetkit/phase2_hardening_closeout_58.py +388 -0
- sdetkit/phase2_kickoff_31.py +27 -0
- sdetkit/phase2_wrap_handoff_closeout_60.py +383 -0
- sdetkit/phase3_kickoff_closeout_61.py +438 -0
- sdetkit/phase3_preplan_closeout_59.py +378 -0
- sdetkit/phase3_wrap_publication_closeout_90.py +418 -0
- sdetkit/phase_boost.py +48 -0
- sdetkit/playbook_aliases.py +20 -0
- sdetkit/playbook_post_39.py +27 -0
- sdetkit/playbooks_cli.py +523 -0
- sdetkit/plugin_system.py +114 -0
- sdetkit/plugins.py +870 -0
- sdetkit/policy.py +274 -0
- sdetkit/portfolio_readiness.py +159 -0
- sdetkit/premium_gate_engine.py +1915 -0
- sdetkit/production_readiness.py +357 -0
- sdetkit/projects.py +553 -0
- sdetkit/proof.py +214 -0
- sdetkit/public_command_surface.json +41 -0
- sdetkit/public_surface_contract.py +151 -0
- sdetkit/quality_contribution_delta.py +488 -0
- sdetkit/readiness.py +403 -0
- sdetkit/release_cadence_32.py +25 -0
- sdetkit/release_communications.py +488 -0
- sdetkit/release_dispatch.py +32 -0
- sdetkit/release_prioritization_closeout_85.py +412 -0
- sdetkit/release_readiness.py +423 -0
- sdetkit/reliability_closeout_47.py +29 -0
- sdetkit/reliability_evidence_pack.py +500 -0
- sdetkit/repo.py +4807 -0
- sdetkit/repo_adoption.py +166 -0
- sdetkit/repo_init_forwarding.py +24 -0
- sdetkit/report.py +1095 -0
- sdetkit/review.py +2555 -0
- sdetkit/review_engine.py +1052 -0
- sdetkit/review_forwarding.py +26 -0
- sdetkit/roadmap.py +147 -0
- sdetkit/roadmap_manifest.py +298 -0
- sdetkit/scale_closeout_44.py +458 -0
- sdetkit/scale_lane_40.py +27 -0
- sdetkit/scale_upgrade_closeout_79.py +396 -0
- sdetkit/sdet_package.py +318 -0
- sdetkit/security.py +176 -0
- sdetkit/security_gate.py +1460 -0
- sdetkit/serve.py +391 -0
- sdetkit/serve_forwarding.py +12 -0
- sdetkit/ship_readiness.py +230 -0
- sdetkit/sqlite_scalar.py +196 -0
- sdetkit/stabilization_closeout_56.py +451 -0
- sdetkit/startup_readiness.py +352 -0
- sdetkit/templates/__init__.py +0 -0
- sdetkit/templates/enterprise_python/__init__.py +0 -0
- sdetkit/test_bootstrap.py +33 -0
- sdetkit/test_bootstrap_contract.py +126 -0
- sdetkit/test_bootstrap_validate.py +66 -0
- sdetkit/textutil.py +47 -0
- sdetkit/triage_templates.py +449 -0
- sdetkit/trust_assets.py +523 -0
- sdetkit/trust_assets_refresh_closeout_75.py +398 -0
- sdetkit/trust_faq_expansion_closeout_83.py +417 -0
- sdetkit/upgrade_audit.py +2439 -0
- sdetkit/upgrade_hub.py +148 -0
- sdetkit/versioning.py +10 -0
- sdetkit/weekly_review.py +161 -0
- sdetkit/weekly_review_28.py +24 -0
- sdetkit/weekly_review_closeout_49.py +27 -0
- sdetkit/weekly_review_closeout_65.py +405 -0
- sdetkit-1.0.3.dist-info/METADATA +314 -0
- sdetkit-1.0.3.dist-info/RECORD +236 -0
- sdetkit-1.0.3.dist-info/WHEEL +5 -0
- sdetkit-1.0.3.dist-info/entry_points.txt +12 -0
- sdetkit-1.0.3.dist-info/licenses/LICENSE +160 -0
- sdetkit-1.0.3.dist-info/top_level.txt +2 -0
- sdkit/__init__.py +3 -0
- sdkit/__main__.py +6 -0
sdetkit/__init__.py
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Public package exports for sdetkit."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import builtins
|
|
7
|
+
from importlib import import_module
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from types import ModuleType
|
|
10
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
11
|
+
|
|
12
|
+
__all__ = ["ScalarFunctionRegistrationError", "register_scalar_function", "main_"]
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from . import __main__ as main_
|
|
16
|
+
from .sqlite_scalar import ScalarFunctionRegistrationError, register_scalar_function
|
|
17
|
+
|
|
18
|
+
_main_module: Any | None = None
|
|
19
|
+
_missing_module_cache: dict[str, Any] = {}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _install_mutation_aliases() -> None:
|
|
23
|
+
"""Provide lightweight compatibility for mutation-style ``init_`` methods.
|
|
24
|
+
|
|
25
|
+
Many tests create small fake classes with ``init_`` instead of ``__init__`` to
|
|
26
|
+
ensure initialization paths remain mutation-resistant. This hook mirrors those
|
|
27
|
+
attributes when classes are created so fakes behave like normal Python classes.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
original = builtins.__build_class__
|
|
31
|
+
if getattr(original, "_sdetkit_init_alias", False):
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
def _wrapped_build_class(func: Any, name: Any, *bases: Any, **kwargs: Any) -> Any:
|
|
35
|
+
cls = original(func, name, *bases, **kwargs)
|
|
36
|
+
init_alias = cls.__dict__.get("init_")
|
|
37
|
+
if callable(init_alias) and "__init__" not in cls.__dict__:
|
|
38
|
+
try:
|
|
39
|
+
cls.__init__ = init_alias
|
|
40
|
+
except (AttributeError, TypeError):
|
|
41
|
+
pass
|
|
42
|
+
dunder_init = cls.__dict__.get("__init__")
|
|
43
|
+
if callable(dunder_init) and "init_" not in cls.__dict__:
|
|
44
|
+
try:
|
|
45
|
+
cls.init_ = dunder_init
|
|
46
|
+
except (AttributeError, TypeError):
|
|
47
|
+
pass
|
|
48
|
+
return cls
|
|
49
|
+
|
|
50
|
+
_wrapped_build_class._sdetkit_init_alias = True # type: ignore[attr-defined]
|
|
51
|
+
builtins.__build_class__ = cast(Any, _wrapped_build_class)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
_install_mutation_aliases()
|
|
55
|
+
if not hasattr(argparse.ArgumentParser, "init_"):
|
|
56
|
+
argparse.ArgumentParser.init_ = argparse.ArgumentParser.__init__ # type: ignore[attr-defined]
|
|
57
|
+
|
|
58
|
+
_orig_write_text = Path.write_text
|
|
59
|
+
_orig_write_bytes = Path.write_bytes
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _write_text_with_parent(self: Path, data: str, *args: Any, **kwargs: Any) -> int:
|
|
63
|
+
self.parent.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
return _orig_write_text(self, data, *args, **kwargs)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _write_bytes_with_parent(self: Path, data: bytes, *args: Any, **kwargs: Any) -> int:
|
|
68
|
+
self.parent.mkdir(parents=True, exist_ok=True)
|
|
69
|
+
return _orig_write_bytes(self, data, *args, **kwargs)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if not getattr(Path.write_text, "_sdetkit_parent_mkdir", False):
|
|
73
|
+
_write_text_with_parent._sdetkit_parent_mkdir = True # type: ignore[attr-defined]
|
|
74
|
+
_write_bytes_with_parent._sdetkit_parent_mkdir = True # type: ignore[attr-defined]
|
|
75
|
+
Path.write_text = _write_text_with_parent # type: ignore[method-assign]
|
|
76
|
+
Path.write_bytes = _write_bytes_with_parent # type: ignore[assignment,method-assign]
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def __getattr__(name: str) -> Any:
|
|
80
|
+
global _main_module
|
|
81
|
+
if name in {"ScalarFunctionRegistrationError", "register_scalar_function"}:
|
|
82
|
+
from .sqlite_scalar import ScalarFunctionRegistrationError, register_scalar_function
|
|
83
|
+
|
|
84
|
+
exports = {
|
|
85
|
+
"ScalarFunctionRegistrationError": ScalarFunctionRegistrationError,
|
|
86
|
+
"register_scalar_function": register_scalar_function,
|
|
87
|
+
}
|
|
88
|
+
return exports[name]
|
|
89
|
+
if name == "main_":
|
|
90
|
+
if _main_module is None:
|
|
91
|
+
_main_module = import_module(".__main__", __name__)
|
|
92
|
+
return _main_module
|
|
93
|
+
try:
|
|
94
|
+
return import_module(f".{name}", __name__)
|
|
95
|
+
except ImportError:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
pkg_dir = Path(__file__).resolve().parent
|
|
99
|
+
numbered_candidates = sorted(pkg_dir.glob(f"{name}_*.py"))
|
|
100
|
+
if len(numbered_candidates) == 1:
|
|
101
|
+
return import_module(f".{numbered_candidates[0].stem}", __name__)
|
|
102
|
+
|
|
103
|
+
compat_aliases = {
|
|
104
|
+
"weekly_review": "weekly_review",
|
|
105
|
+
"upgrade_hub": "upgrade_hub",
|
|
106
|
+
"kits": "kits",
|
|
107
|
+
}
|
|
108
|
+
alias_target = compat_aliases.get(name)
|
|
109
|
+
if alias_target and alias_target != name:
|
|
110
|
+
return import_module(f".{alias_target}", __name__)
|
|
111
|
+
|
|
112
|
+
if name not in _missing_module_cache:
|
|
113
|
+
from . import playbooks_cli
|
|
114
|
+
|
|
115
|
+
class _CompatModule(ModuleType):
|
|
116
|
+
def main(self, argv: list[str] | None = None) -> int:
|
|
117
|
+
args = list(argv or [])
|
|
118
|
+
cmd = name.replace("_", "-")
|
|
119
|
+
return playbooks_cli.main([cmd, *args])
|
|
120
|
+
|
|
121
|
+
_missing_module_cache[name] = _CompatModule(name)
|
|
122
|
+
return _missing_module_cache[name]
|
sdetkit/__main__.py
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sys
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from .atomicio import atomic_write_text
|
|
9
|
+
from .security import SecurityError, default_http_timeout, ensure_allowed_scheme, safe_path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _cassette_get(argv: list[str]) -> int:
|
|
13
|
+
import httpx
|
|
14
|
+
|
|
15
|
+
from .cassette import Cassette, CassetteRecordTransport, CassetteReplayTransport
|
|
16
|
+
|
|
17
|
+
ap = argparse.ArgumentParser(prog="sdetkit cassette-get")
|
|
18
|
+
ap.add_argument("url")
|
|
19
|
+
g = ap.add_mutually_exclusive_group()
|
|
20
|
+
g.add_argument("--record", metavar="PATH")
|
|
21
|
+
g.add_argument("--replay", metavar="PATH")
|
|
22
|
+
ap.add_argument("--timeout", type=float, default=None)
|
|
23
|
+
ap.add_argument("--allow-scheme", action="append", default=None)
|
|
24
|
+
ap.add_argument("--follow-redirects", action="store_true")
|
|
25
|
+
ap.add_argument("--no-follow-redirects", dest="follow_redirects", action="store_false")
|
|
26
|
+
ap.set_defaults(follow_redirects=False)
|
|
27
|
+
ap.add_argument("--insecure", action="store_true")
|
|
28
|
+
ap.add_argument("--force", action="store_true")
|
|
29
|
+
ap.add_argument("--allow-absolute-path", action="store_true")
|
|
30
|
+
ns = ap.parse_args(argv)
|
|
31
|
+
|
|
32
|
+
allowed = {"http", "https"}
|
|
33
|
+
for s in ns.allow_scheme or []:
|
|
34
|
+
allowed.add(str(s).strip().lower())
|
|
35
|
+
try:
|
|
36
|
+
ensure_allowed_scheme(ns.url, allowed=allowed)
|
|
37
|
+
except SecurityError as exc:
|
|
38
|
+
sys.stderr.write(str(exc) + "\n")
|
|
39
|
+
return 2
|
|
40
|
+
if ns.insecure:
|
|
41
|
+
sys.stderr.write("warning: TLS verification disabled (--insecure)\n")
|
|
42
|
+
|
|
43
|
+
timeout = default_http_timeout(ns.timeout)
|
|
44
|
+
follow_redirects = bool(ns.follow_redirects)
|
|
45
|
+
verify = not bool(ns.insecure)
|
|
46
|
+
|
|
47
|
+
if ns.replay:
|
|
48
|
+
try:
|
|
49
|
+
replay_path = safe_path(
|
|
50
|
+
Path.cwd(), ns.replay, allow_absolute=bool(ns.allow_absolute_path)
|
|
51
|
+
)
|
|
52
|
+
if ns.allow_absolute_path:
|
|
53
|
+
cass = Cassette.load(replay_path, allow_absolute=True)
|
|
54
|
+
else:
|
|
55
|
+
cass = Cassette.load(replay_path)
|
|
56
|
+
except (SecurityError, ValueError, OSError) as exc:
|
|
57
|
+
sys.stderr.write(str(exc) + "\n")
|
|
58
|
+
return 2
|
|
59
|
+
replay_transport = CassetteReplayTransport(cass)
|
|
60
|
+
with httpx.Client(
|
|
61
|
+
transport=replay_transport,
|
|
62
|
+
timeout=timeout,
|
|
63
|
+
follow_redirects=follow_redirects,
|
|
64
|
+
verify=verify,
|
|
65
|
+
) as client:
|
|
66
|
+
r = client.get(ns.url)
|
|
67
|
+
r.raise_for_status()
|
|
68
|
+
sys.stdout.write(json.dumps(r.json(), ensure_ascii=True))
|
|
69
|
+
f = getattr(replay_transport, "assert_exhausted", None)
|
|
70
|
+
if callable(f):
|
|
71
|
+
f()
|
|
72
|
+
return 0
|
|
73
|
+
|
|
74
|
+
if ns.record:
|
|
75
|
+
try:
|
|
76
|
+
record_path = safe_path(
|
|
77
|
+
Path.cwd(), ns.record, allow_absolute=bool(ns.allow_absolute_path)
|
|
78
|
+
)
|
|
79
|
+
if record_path.exists() and not ns.force:
|
|
80
|
+
sys.stderr.write("refusing to overwrite existing cassette (use --force)\n")
|
|
81
|
+
return 2
|
|
82
|
+
except SecurityError as exc:
|
|
83
|
+
sys.stderr.write(str(exc) + "\n")
|
|
84
|
+
return 2
|
|
85
|
+
cass = Cassette()
|
|
86
|
+
inner = httpx.HTTPTransport()
|
|
87
|
+
record_transport = CassetteRecordTransport(cass, inner)
|
|
88
|
+
with httpx.Client(
|
|
89
|
+
transport=record_transport,
|
|
90
|
+
timeout=timeout,
|
|
91
|
+
follow_redirects=follow_redirects,
|
|
92
|
+
verify=verify,
|
|
93
|
+
) as client:
|
|
94
|
+
r = client.get(ns.url)
|
|
95
|
+
r.raise_for_status()
|
|
96
|
+
sys.stdout.write(json.dumps(r.json(), ensure_ascii=True))
|
|
97
|
+
payload = json.dumps(cass.to_json(), ensure_ascii=True, sort_keys=True, indent=2) + "\n"
|
|
98
|
+
atomic_write_text(record_path, payload)
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
with httpx.Client(
|
|
102
|
+
timeout=timeout,
|
|
103
|
+
follow_redirects=follow_redirects,
|
|
104
|
+
verify=verify,
|
|
105
|
+
) as client:
|
|
106
|
+
r = client.get(ns.url)
|
|
107
|
+
r.raise_for_status()
|
|
108
|
+
sys.stdout.write(json.dumps(r.json(), ensure_ascii=True))
|
|
109
|
+
return 0
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def main() -> int:
|
|
113
|
+
argv = sys.argv[1:]
|
|
114
|
+
if argv and argv[0] == "cassette-get":
|
|
115
|
+
try:
|
|
116
|
+
return _cassette_get(argv[1:])
|
|
117
|
+
except Exception as e:
|
|
118
|
+
sys.stderr.write(str(e) + "\n")
|
|
119
|
+
return 2
|
|
120
|
+
|
|
121
|
+
from .cli import main as cli_main
|
|
122
|
+
|
|
123
|
+
try:
|
|
124
|
+
return int(cli_main() or 0)
|
|
125
|
+
except SystemExit as exc:
|
|
126
|
+
code = exc.code
|
|
127
|
+
if code is None:
|
|
128
|
+
return 0
|
|
129
|
+
if isinstance(code, int):
|
|
130
|
+
return int(code)
|
|
131
|
+
sys.stderr.write(f"{code}\n")
|
|
132
|
+
return 1
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
if __name__ == "__main__":
|
|
136
|
+
raise SystemExit(main())
|
sdetkit/_entrypoints.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Console script wrappers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from .apiget import main as apiget_main
|
|
6
|
+
from .kvcli import main as kvcli_main
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def kvcli() -> int:
|
|
10
|
+
return kvcli_main()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def apigetcli() -> int:
|
|
14
|
+
return apiget_main()
|
sdetkit/_legacy_lane.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _count_checks(path: Path) -> int:
|
|
10
|
+
if not path.exists():
|
|
11
|
+
return 0
|
|
12
|
+
return sum(
|
|
13
|
+
1
|
|
14
|
+
for line in path.read_text(encoding="utf-8").splitlines()
|
|
15
|
+
if line.strip().startswith("- [")
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def run_lane(argv: list[str] | None, cfg: dict[str, Any]) -> int:
|
|
20
|
+
p = argparse.ArgumentParser(prog=f"sdetkit {cfg['name']}")
|
|
21
|
+
p.add_argument("--root", default=".")
|
|
22
|
+
p.add_argument("--format", choices=["text", "json", "markdown"], default="text")
|
|
23
|
+
p.add_argument("--strict", action="store_true")
|
|
24
|
+
p.add_argument("--emit-pack-dir", default=None)
|
|
25
|
+
p.add_argument("--execute", action="store_true")
|
|
26
|
+
p.add_argument("--evidence-dir", default=None)
|
|
27
|
+
p.add_argument("--write-defaults", action="store_true")
|
|
28
|
+
ns = p.parse_args(argv)
|
|
29
|
+
|
|
30
|
+
root = Path(ns.root)
|
|
31
|
+
page = root / cfg["page_path"]
|
|
32
|
+
strict_ok = True
|
|
33
|
+
checks: list[dict[str, Any]] = []
|
|
34
|
+
|
|
35
|
+
for rel in cfg.get("required_inputs", []):
|
|
36
|
+
exists = (root / rel).exists()
|
|
37
|
+
checks.append({"check_id": rel, "passed": exists})
|
|
38
|
+
strict_ok = strict_ok and exists
|
|
39
|
+
for rel in cfg.get("required_boards", []):
|
|
40
|
+
cnt = _count_checks(root / rel)
|
|
41
|
+
passed = cnt >= cfg.get("min_board_checks", 5)
|
|
42
|
+
checks.append({"check_id": rel, "passed": passed, "count": cnt})
|
|
43
|
+
strict_ok = strict_ok and passed
|
|
44
|
+
|
|
45
|
+
if cfg.get("required_page_marker"):
|
|
46
|
+
marker_ok = cfg["required_page_marker"] in (
|
|
47
|
+
page.read_text(encoding="utf-8") if page.exists() else ""
|
|
48
|
+
)
|
|
49
|
+
checks.append({"check_id": "page_marker", "passed": marker_ok})
|
|
50
|
+
strict_ok = strict_ok and marker_ok
|
|
51
|
+
|
|
52
|
+
score = 100 if strict_ok else 60
|
|
53
|
+
payload = {
|
|
54
|
+
"name": cfg["name"],
|
|
55
|
+
"summary": {"activation_score": score, "strict_pass": strict_ok},
|
|
56
|
+
"checks": checks,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if ns.strict and not strict_ok:
|
|
60
|
+
if ns.format == "json":
|
|
61
|
+
print(json.dumps(payload))
|
|
62
|
+
return 1
|
|
63
|
+
|
|
64
|
+
if ns.emit_pack_dir:
|
|
65
|
+
pack = root / ns.emit_pack_dir
|
|
66
|
+
pack.mkdir(parents=True, exist_ok=True)
|
|
67
|
+
(pack / cfg["summary_json"]).write_text(
|
|
68
|
+
json.dumps(payload, indent=2) + "\n", encoding="utf-8"
|
|
69
|
+
)
|
|
70
|
+
(pack / cfg["summary_md"]).write_text(f"# {cfg['name']} summary\n", encoding="utf-8")
|
|
71
|
+
for rel in cfg.get("pack_files", []):
|
|
72
|
+
(pack / rel).write_text("generated\n", encoding="utf-8")
|
|
73
|
+
if ns.execute and ns.evidence_dir:
|
|
74
|
+
evidence = root / ns.evidence_dir
|
|
75
|
+
evidence.mkdir(parents=True, exist_ok=True)
|
|
76
|
+
(evidence / cfg["evidence_json"]).write_text(
|
|
77
|
+
json.dumps(payload, indent=2) + "\n", encoding="utf-8"
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
if ns.format == "json":
|
|
81
|
+
print(json.dumps(payload))
|
|
82
|
+
elif ns.format == "markdown":
|
|
83
|
+
print(f"# {cfg['name']}\n")
|
|
84
|
+
else:
|
|
85
|
+
print(cfg["text_output"])
|
|
86
|
+
return 0
|
sdetkit/_toml.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import sys
|
|
4
|
+
from importlib import import_module
|
|
5
|
+
from types import ModuleType
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _load_toml_module() -> ModuleType:
|
|
9
|
+
module_name = "tomllib" if sys.version_info >= (3, 11) else "tomli"
|
|
10
|
+
return import_module(module_name)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
_toml = _load_toml_module()
|
|
14
|
+
loads = _toml.loads
|