@shundoo-ai/dsh-cosmic 1.0.19 → 1.0.21
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.
- package/cordis.patch.yml +5 -5
- package/package.json +1 -1
- package/skills/cosmic-build/CHANGELOG.md +4 -0
- package/skills/cosmic-build/LOCAL-PATCHES.md +91 -40
- package/skills/cosmic-build/SKILL.md +46 -13
- package/skills/cosmic-build/assets/platform-report-filters/TypedReportFilterFields.java +169 -0
- package/skills/cosmic-build/assets/platform-report-filters/platform.patch +98 -0
- package/skills/cosmic-build/assets/report-algo-benchmark/ReportAlgoBenchmark.java +48 -0
- package/skills/cosmic-build/assets/report-algo-benchmark/ReportBenchmarkLogFactory.java +7 -0
- package/skills/cosmic-build/examples/java-rules/CosmicEntryQuery.java +26 -0
- package/skills/cosmic-build/examples/java-rules/CosmicReportAggregation.java +35 -0
- package/skills/cosmic-build/examples/java-rules/CosmicReportFilters.java +77 -0
- package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapter.java +25 -0
- package/skills/cosmic-build/examples/java-rules/CosmicTimeAdapterCheck.java +26 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/api/algo/GroupbyDataSet.md +47 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterInfo.md +12 -12
- package/skills/cosmic-build/knowledge/cosmic/platform/api/entity/report/FilterItemInfo.md +2 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/form-plugin.md +2 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/java-type-contracts.md +11 -2
- package/skills/cosmic-build/knowledge/cosmic/platform/list-plugin.md +18 -14
- package/skills/cosmic-build/knowledge/cosmic/platform/operation-plugin.md +4 -4
- package/skills/cosmic-build/knowledge/cosmic/platform/reportlistdata-plugin.md +17 -9
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/cross-entity-aggregate-writeback.md +2 -0
- package/skills/cosmic-build/knowledge/cosmic/platform/scenes/operation/pre-post-operation.md +15 -7
- package/skills/cosmic-build/knowledge/cosmic/platform/sdk/sdk-algo.md +24 -68
- package/skills/cosmic-build/knowledge/cosmic/platform/workflow-plugin.md +2 -7
- package/skills/cosmic-build/references/application-context.md +35 -1
- package/skills/cosmic-build/references/common-reference.md +1 -1
- package/skills/cosmic-build/references/compile-guide.md +55 -68
- package/skills/cosmic-build/references/delivery.md +59 -7
- package/skills/cosmic-build/references/execution-contract.md +38 -0
- package/skills/cosmic-build/references/form-discovery.md +7 -1
- package/skills/cosmic-build/references/java-plugin-delivery.md +32 -162
- package/skills/cosmic-build/references/operation-dispatch.md +17 -0
- package/skills/cosmic-build/references/plugin-handoff-input.md +131 -0
- package/skills/cosmic-build/references/plugin-runtime-routing.md +1 -1
- package/skills/cosmic-build/references/report-filter-contract.md +78 -0
- package/skills/cosmic-build/references/sdk-inspection.md +23 -0
- package/skills/cosmic-build/schemas/data-model-authoring.schema.json +2 -3
- package/skills/cosmic-build/scripts/_http_client.py +55 -55
- package/skills/cosmic-build/scripts/appconfig_load.py +2 -2
- package/skills/cosmic-build/scripts/apply_report_filter_extension.py +39 -0
- package/skills/cosmic-build/scripts/bootstrap_cosmic_context.py +37 -2
- package/skills/cosmic-build/scripts/compile_plugin_source.py +279 -156
- package/skills/cosmic-build/scripts/execution_binding.py +40 -0
- package/skills/cosmic-build/scripts/inspect_platform_sdk.py +169 -0
- package/skills/cosmic-build/scripts/kd_api.py +23 -22
- package/skills/cosmic-build/scripts/kd_auth.py +1 -1
- package/skills/cosmic-build/scripts/kd_env_loader.py +19 -10
- package/skills/cosmic-build/scripts/kd_token_cache.py +2 -2
- package/skills/cosmic-build/scripts/kingscript_sdk_sync.py +350 -0
- package/skills/cosmic-build/scripts/kingscript_source_gate.py +11 -8
- package/skills/cosmic-build/scripts/platform_api_contract.py +246 -11
- package/skills/cosmic-build/scripts/plugin_corpus/build_index.py +403 -0
- package/skills/cosmic-build/scripts/plugin_corpus/jvm_classfile.py +281 -0
- package/skills/cosmic-build/scripts/plugin_corpus/measure_api_usage.py +446 -0
- package/skills/cosmic-build/scripts/plugin_source_gate.py +48 -7
- package/skills/cosmic-build/scripts/plugin_target_sdk.py +45 -0
- package/skills/cosmic-build/scripts/prepare_plugin_handoff.py +493 -47
- package/skills/cosmic-build/scripts/preview_url.py +35 -6
- package/skills/cosmic-build/scripts/query_plugin_handoff.py +250 -0
- package/skills/cosmic-build/scripts/register_plugins.py +28 -2
- package/skills/cosmic-build/scripts/render_output_cards.py +42 -9
- package/skills/cosmic-build/scripts/report_algo_benchmark.py +46 -0
- package/skills/cosmic-build/scripts/run.py +2 -2
- package/skills/cosmic-build/scripts/sync_generated_locale_assets.py +43 -0
- package/skills/cosmic-build/scripts/test/fixtures/ReportSdkCheck.java +64 -0
- package/skills/cosmic-build/scripts/test/fixtures/java_context_booking_native.json +541 -0
- package/skills/cosmic-build/scripts/test/test_add_rule_business_contract.py +85 -14
- package/skills/cosmic-build/scripts/test/test_batch5_drift_governance.py +12 -3
- package/skills/cosmic-build/scripts/test/test_build_meta_order.py +0 -16
- package/skills/cosmic-build/scripts/test/test_cli_continuation.py +87 -0
- package/skills/cosmic-build/scripts/test/test_compile_plugin_source.py +224 -3
- package/skills/cosmic-build/scripts/test/test_control_authoring.py +123 -4
- package/skills/cosmic-build/scripts/test/test_cosmic_sdk_examples.py +141 -0
- package/skills/cosmic-build/scripts/test/test_data_model_contract.py +30 -5
- package/skills/cosmic-build/scripts/test/test_delivery_stage_boundary.py +2 -10
- package/skills/cosmic-build/scripts/test/test_dym_sync_background.py +11 -0
- package/skills/cosmic-build/scripts/test/test_dynamic_form_metadata_only_contract.py +59 -1
- package/skills/cosmic-build/scripts/test/test_guide_skeleton_contract.py +87 -43
- package/skills/cosmic-build/scripts/test/test_inspect_platform_sdk.py +71 -0
- package/skills/cosmic-build/scripts/test/test_kd_api.py +67 -19
- package/skills/cosmic-build/scripts/test/test_kingscript_sdk_sync.py +221 -0
- package/skills/cosmic-build/scripts/test/test_kingscript_source_gate.py +10 -0
- package/skills/cosmic-build/scripts/test/test_list_configuration_closure.py +18 -0
- package/skills/cosmic-build/scripts/test/test_long_session_regressions.py +116 -0
- package/skills/cosmic-build/scripts/test/test_mcp_cli.py +524 -0
- package/skills/cosmic-build/scripts/test/test_modeling_input_recovery.py +141 -0
- package/skills/cosmic-build/scripts/test/test_open_world_cli_catalog.py +36 -2
- package/skills/cosmic-build/scripts/test/test_platform_api_contract.py +161 -1
- package/skills/cosmic-build/scripts/test/test_plugin_business_contract.py +91 -0
- package/skills/cosmic-build/scripts/test/test_plugin_corpus.py +195 -0
- package/skills/cosmic-build/scripts/test/test_plugin_handoff.py +346 -1
- package/skills/cosmic-build/scripts/test/test_plugin_target_sdk.py +70 -0
- package/skills/cosmic-build/scripts/test/test_preview_url.py +44 -1
- package/skills/cosmic-build/scripts/test/test_property_batch.py +22 -0
- package/skills/cosmic-build/scripts/test/test_property_input_discovery.py +13 -11
- package/skills/cosmic-build/scripts/test/test_query_plugin_handoff.py +160 -0
- package/skills/cosmic-build/scripts/test/test_register_plugins.py +31 -1
- package/skills/cosmic-build/scripts/test/test_render_output_cards.py +50 -4
- package/skills/cosmic-build/scripts/test/test_report_business_contract.py +27 -0
- package/skills/cosmic-build/scripts/test/test_report_doc_contract_sync.py +5 -4
- package/skills/cosmic-build/scripts/test/test_report_sdk_optimization.py +36 -0
- package/skills/cosmic-build/scripts/test/test_rule_batch_evidence.py +1 -1
- package/skills/cosmic-build/scripts/test/test_rule_domain_contract.py +20 -0
- package/skills/cosmic-build/scripts/test/test_rule_function_formula.py +16 -6
- package/skills/cosmic-build/scripts/test/test_skill_entry_contract.py +1 -0
- package/skills/cosmic-build/scripts/test/test_test_environment.py +45 -0
- package/skills/cosmic-build/scripts/test/test_verify_plugin_loading.py +79 -0
- package/skills/cosmic-build/scripts/test_environment.py +49 -0
- package/skills/cosmic-build/scripts/verify_plugin_loading.py +71 -0
- package/skills/cosmic-build/skills/cosmic-coding-impl/SKILL.md +86 -162
- package/skills/cosmic-build/skills/cosmic-coding-script/ATTRIBUTION.md +1 -1
- package/skills/cosmic-build/skills/cosmic-coding-script/SKILL.md +45 -14
- package/skills/cosmic-build/skills/cosmic-coding-script/references/kwc-controller-authoring.md +6 -0
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/README.md +29 -19
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/docs//350/204/232/346/234/254SDK.md +3 -4
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/indexes/package-index.md +1 -1
- package/skills/cosmic-build/skills/cosmic-coding-script/references/sdk/strategy.md +27 -18
- package/skills/cosmic-build/skills/cosmic-meta-api/SKILL.md +11 -17
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/ai_meta.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/app_menu.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/apis/meta_log.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/control-authoring.json +45 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/form-control-traits.json +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/layout-ui.json +18 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/menu-publish.json +8 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-batch.json +7 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/property-input-index.json +3 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/report-write-contracts.json +1 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-domain.json +37 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/rule-event-contract.json +24 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/cli/run-build-meta.json +61 -12
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/dropdown-menu.schema.json +69 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/report-write.schema.json +2 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-set.schema.json +1 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/contracts/schema/rule-write.schema.json +14 -7
- package/skills/cosmic-build/skills/cosmic-meta-api/docs/api-summary.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/app-action/SKILL.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/develop/SKILL.md +1 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/export/SKILL.md +5 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/init/SKILL.md +13 -36
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/SKILL.md +8 -9
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/pdm/scripts/config.json.example +5 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/reset/SKILL.md +6 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/usage/SKILL.md +20 -148
- package/skills/cosmic-build/skills/cosmic-meta-api/modules/verify/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/build_receipts.py +171 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_apps.py +25 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_controls.py +55 -21
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_fields.py +10 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_formactions.py +63 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_forms.py +59 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_listui.py +8 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_metaops.py +36 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_plugins.py +115 -90
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_properties.py +666 -4
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/cmd_rules.py +1415 -87
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/commands.py +6 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/config.py +28 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/execution_errors.py +40 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/formatters.py +32 -5
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/property_policy_contract.py +6 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/report_ops.py +113 -17
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/reset.py +3 -3
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/_core/rule_contract.py +107 -26
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/build_meta_order.py +50 -49
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/cosmic_api.py +856 -150
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/field_decorator.py +47 -14
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_build_receipt_resume.py +374 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_cli_failure_contract.py +24 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_creation_identity_boundary.py +4 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_dropdown_menu_contract.py +382 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_existing_form_ui.py +0 -25
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_field_decorator.py +50 -6
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_functional_group_resolution.py +83 -16
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_identity_template_resolution.py +103 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_plugin_contract.py +28 -2
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_readback_derivation.py +22 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_report_typed_filters.py +65 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_rule_write_closure.py +1041 -15
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_post_build_recovery.py +65 -0
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/test/test_run_batch_verification_evidence.py +17 -0
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/api-param-checklist.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-knowledge/generation/rule-modeling-guide.md +7 -4
- package/skills/cosmic-build/skills/cosmic-meta-modeling/SKILL.md +61 -13
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/app-menu/SKILL.md +8 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/SKILL.md +5 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/formtemplate/dynamic-form-artifact-schema.md +5 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/modules/report/SKILL.md +21 -9
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-entity-graphs.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-storage-constraints.md +5 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/authoring-ui-composition.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/creation-recovery.md +13 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/references/parse-core.md +3 -0
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_contract.py +6 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/data_model_emit.py +135 -87
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/field_type_registry.py +11 -1
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/isv_resolver.py +1 -3
- package/skills/cosmic-build/skills/cosmic-meta-modeling/scripts/report_validator.py +29 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/SKILL.md +4 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/context/SKILL.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/execute/SKILL.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/SKILL.md +5 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/operation-write.md +6 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/operation/validation.md +2 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/SKILL.md +20 -5
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/complex-apis.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/property/policy-grammar.md +4 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/report-op/SKILL.md +9 -0
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/SKILL.md +61 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/raw-rule-authoring.md +3 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-actions.md +2 -2
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/rule-reference.md +6 -6
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/rule/state.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/unit/SKILL.md +6 -3
- package/skills/cosmic-build/skills/cosmic-meta-modifier/modules/verify/usage-guide.md +4 -4
- package/skills/cosmic-build/skills/cosmic-meta-modifier/references/list-filter-modification.md +4 -1
- package/skills/cosmic-build/skills/cosmic-meta-ui/SKILL.md +9 -1
- package/skills/cosmic-build/skills/cosmic-meta-ui/modules/button/SKILL.md +3 -0
- package/skills/cosmic-build/skills/mcp-server/SKILL.md +210 -0
- package/skills/cosmic-build/skills/mcp-server/scripts/mcp_cli.py +431 -0
- package/skills/cosmic-build/skills/openapi-gen/SKILL.md +3 -3
- package/skills/cosmic-build/skills/openapi-gen/scripts/api/gen_runner.py +2 -2
- package/skills/cosmic-dev-best-practices/references/bill-dev-convention.md +19 -9
- package/skills/cosmic-dev-best-practices/references/cosmic-meta-api.md +14 -11
- package/skills/cosmic-dev-best-practices/references/design-examples/basedata-design-example.md +1 -1
- package/skills/cosmic-dev-best-practices/references/design-examples/bill-design-example.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/AssistantField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/BasedataField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/BasedataPropField.md +3 -3
- package/skills/cosmic-dev-best-practices/references/elements/CreaterField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/CurrencyField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/CustomerField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/FlexField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/MaterielField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/OrgField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/SupplierField.md +2 -2
- package/skills/cosmic-dev-best-practices/references/elements/UnitField.md +1 -1
- package/skills/cosmic-dev-best-practices/references/elements/UserField.md +3 -3
- package/skills/cosmic-dev-best-practices/references/elements/common-field-property-conventions.md +16 -11
- package/skills/cosmic-dev-best-practices/references/layout-control-convention.md +5 -4
- package/skills/erp-analysis/references/delivery-contract.md +4 -2
- package/skills/erp-analysis/templates/AGENTS.template.md +1 -1
- package/skills/cosmic-build/skills/cosmic-meta-api/scripts/.dsh/cosmic/.kd/config.json +0 -21
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import argparse
|
|
3
4
|
import importlib
|
|
4
5
|
import json
|
|
5
6
|
import sys
|
|
@@ -225,7 +226,7 @@ class AddRuleBusinessContractTest(unittest.TestCase):
|
|
|
225
226
|
mismatches = cosmic_api._rule_readback_mismatches(expected, observed, metadata)
|
|
226
227
|
self.assertTrue(any(item["path"].endswith(".Fields") for item in mismatches))
|
|
227
228
|
|
|
228
|
-
def
|
|
229
|
+
def test_rule_ret_accepts_designer_after_copy_and_rejects_unknown_bits(self) -> None:
|
|
229
230
|
with self.assertRaisesRegex(ValueError, "RULE_RET_UNKNOWN_EVENT_BIT"):
|
|
230
231
|
rule_contract.normalize_rule_config(
|
|
231
232
|
{
|
|
@@ -239,19 +240,89 @@ class AddRuleBusinessContractTest(unittest.TestCase):
|
|
|
239
240
|
],
|
|
240
241
|
}
|
|
241
242
|
)
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
],
|
|
253
|
-
|
|
254
|
-
|
|
243
|
+
for action_type, original in rule_contract._EVENT_CONTRACT["actionMasks"].items():
|
|
244
|
+
with self.subTest(action=action_type):
|
|
245
|
+
for bit in rule_contract._EVENT_CONTRACT["eventBits"]:
|
|
246
|
+
rule_contract.validate_action_ret(action_type, int(bit))
|
|
247
|
+
rule_contract.validate_action_ret(action_type, 2047)
|
|
248
|
+
merged = rule_contract.merge_action_events(
|
|
249
|
+
action_type, original, ["复制后"],
|
|
250
|
+
)
|
|
251
|
+
self.assertEqual(original | 1024, merged)
|
|
252
|
+
self.assertEqual(merged, rule_contract.merge_action_events(
|
|
253
|
+
action_type, merged, ["AfterCopy"],
|
|
254
|
+
))
|
|
255
|
+
for action_type, rule_type, target_args, ret in (
|
|
256
|
+
("HideFieldAction", "formRule", {"fields": ["field_b"]}, 1275),
|
|
257
|
+
("CallFieldChangeAction", "bizRule", {"expression": "field_b"}, 1797),
|
|
258
|
+
):
|
|
259
|
+
result = rule_contract.normalize_rule_config({
|
|
260
|
+
"ruleType": rule_type,
|
|
261
|
+
"trueActions": [{"actionType": action_type, "ret": ret, **target_args}],
|
|
262
|
+
})
|
|
263
|
+
self.assertEqual(ret, result["trueActions"][0]["RET"])
|
|
264
|
+
with self.assertRaisesRegex(ValueError, "RULE_ACTION_CONTRACT_BLOCKED"):
|
|
265
|
+
rule_contract.validate_action_ret("SetVisibleAction", 1024)
|
|
266
|
+
for invalid in (True, "1024", 0, -1):
|
|
267
|
+
with self.subTest(invalid=invalid):
|
|
268
|
+
with self.assertRaisesRegex(ValueError, "RULE_RET_INVALID"):
|
|
269
|
+
rule_contract.validate_action_ret("ClearValueAction", invalid)
|
|
270
|
+
business = rule_contract.normalize_rule_config({
|
|
271
|
+
"ruleType": "bizRule",
|
|
272
|
+
"trueActions": [{
|
|
273
|
+
"actionType": "ClearValueAction", "expression": "field_b",
|
|
274
|
+
"RET": 1021 | 1024,
|
|
275
|
+
}],
|
|
276
|
+
})
|
|
277
|
+
self.assertEqual(2045, business["trueActions"][0]["RET"])
|
|
278
|
+
self.assertEqual(2045, rule_contract.merge_action_events(
|
|
279
|
+
"ClearValueAction", 1021, ["复制后", "AfterCopy"],
|
|
280
|
+
))
|
|
281
|
+
self.assertEqual(1025, rule_contract.select_action_events(
|
|
282
|
+
"CallFieldChangeAction", ["字段值变化", "复制后"],
|
|
283
|
+
))
|
|
284
|
+
self.assertEqual(1027, rule_contract.select_action_events(
|
|
285
|
+
"HideFieldAction", ["加载", "字段值变化", "复制后"],
|
|
286
|
+
))
|
|
287
|
+
self.assertEqual(1021, rule_contract.merge_action_events(
|
|
288
|
+
"ClearValueAction", 253,
|
|
289
|
+
["新建", "字段值变化", "创建后", "字段值变化后"],
|
|
290
|
+
))
|
|
291
|
+
self.assertEqual(1021, rule_contract.merge_action_events(
|
|
292
|
+
"ClearValueAction", 253,
|
|
293
|
+
["Create", "FieldChange", "AfterCreate", "AfterFieldChange"],
|
|
294
|
+
))
|
|
295
|
+
with self.assertRaisesRegex(ValueError, "RULE_EVENT_UNKNOWN"):
|
|
296
|
+
rule_contract.merge_action_events("ClearValueAction", 253, ["typo"])
|
|
297
|
+
with self.assertRaisesRegex(ValueError, "RULE_EVENTS_INVALID"):
|
|
298
|
+
rule_contract.merge_action_events("ClearValueAction", 253, "AfterCopy")
|
|
299
|
+
|
|
300
|
+
def test_clear_fields_cli_retains_every_repeated_target(self) -> None:
|
|
301
|
+
class Parsed(Exception):
|
|
302
|
+
def __init__(self, value):
|
|
303
|
+
self.value = value
|
|
304
|
+
|
|
305
|
+
original = argparse.ArgumentParser.parse_args
|
|
306
|
+
|
|
307
|
+
def capture(parser, _args=None, namespace=None):
|
|
308
|
+
return_value = original(parser, arguments, namespace)
|
|
309
|
+
raise Parsed(return_value)
|
|
310
|
+
|
|
311
|
+
prefix = [
|
|
312
|
+
"ensureConditionalClearFields", "--formNumber", "demo",
|
|
313
|
+
"--condition-field", "数量", "--operator", "greater-than", "--value", "10",
|
|
314
|
+
]
|
|
315
|
+
for suffix in (
|
|
316
|
+
["--target", "单价", "--target", "备注"],
|
|
317
|
+
["--target", "单价", "备注"],
|
|
318
|
+
):
|
|
319
|
+
arguments = prefix + suffix + ["--add-event", "新建"]
|
|
320
|
+
with self.subTest(suffix=suffix):
|
|
321
|
+
with mock.patch.object(cosmic_api._CliArgumentParser, "parse_args", capture):
|
|
322
|
+
with self.assertRaises(Parsed) as result:
|
|
323
|
+
cosmic_api._main_impl()
|
|
324
|
+
self.assertEqual(["单价", "备注"], result.exception.value.targets)
|
|
325
|
+
self.assertEqual(["新建"], result.exception.value.add_events)
|
|
255
326
|
|
|
256
327
|
def test_direct_rule_enables_trigger_field_event_before_write(self) -> None:
|
|
257
328
|
rule = {"triggerField": "字段A(uhyl_field_a);uhyl_field_c"}
|
|
@@ -34,14 +34,23 @@ class GeneratedLocaleAssetsTest(unittest.TestCase):
|
|
|
34
34
|
result = module.inspect()
|
|
35
35
|
self.assertTrue(result["ok"], result)
|
|
36
36
|
self.assertEqual(
|
|
37
|
-
{"control-authoring-v1", "data-model-compiler-v1", "
|
|
37
|
+
{"control-authoring-v1", "data-model-compiler-v1", "dym-sync-contract-v2",
|
|
38
|
+
"entry-write-v1", "existing-form-ui-v1",
|
|
39
|
+
"kingscript-gate-v1", "mcp-server-v1", "metalog-v1",
|
|
38
40
|
"operation-contract-harvest-v1", "operation-write-v1",
|
|
39
|
-
"plugin-handoff-v1", "
|
|
40
|
-
"report-tests-v1", "report-write-v1", "rule-write-v1"},
|
|
41
|
+
"plugin-handoff-v1", "property-policy-contract-v1", "python-runtime-v1",
|
|
42
|
+
"report-tests-v1", "report-write-v1", "rule-write-v1", "execution-recovery-v1", "plugin-handoff-query-v1"},
|
|
41
43
|
set(result["families"]),
|
|
42
44
|
)
|
|
43
45
|
self.assertEqual(len(result["files"]), result["counts"]["in_sync"])
|
|
44
46
|
|
|
47
|
+
def test_execution_recovery_mirrors_are_machine_synced(self) -> None:
|
|
48
|
+
module = _load_sync_module()
|
|
49
|
+
result = module.inspect(["execution-recovery-v1"])
|
|
50
|
+
self.assertTrue(result["ok"], result)
|
|
51
|
+
self.assertIn("skills/cosmic-meta-api/scripts/_core/build_receipts.py",
|
|
52
|
+
module.GENERATED_FAMILIES["execution-recovery-v1"])
|
|
53
|
+
|
|
45
54
|
def test_report_test_mirrors_are_machine_synced_not_hand_maintained(self) -> None:
|
|
46
55
|
"""Of the 37 test mirrors that predate this family, 32 had drifted.
|
|
47
56
|
|
|
@@ -23,7 +23,6 @@ from build_meta_order import ( # noqa: E402
|
|
|
23
23
|
BuildDependencyError,
|
|
24
24
|
bind_ref_bill_ids,
|
|
25
25
|
collect_ref_bill_targets,
|
|
26
|
-
dependency_blocked_results,
|
|
27
26
|
plan_build_waves,
|
|
28
27
|
split_deferred_ref_bill_writes,
|
|
29
28
|
split_deferred_property_fields,
|
|
@@ -461,21 +460,6 @@ class TestBuildMetaOrder(unittest.TestCase):
|
|
|
461
460
|
set(map(os.path.abspath, paths)),
|
|
462
461
|
)
|
|
463
462
|
|
|
464
|
-
def test_failed_wave_blocks_all_later_writes(self):
|
|
465
|
-
waves = [
|
|
466
|
-
["/tmp/product.json", "/tmp/member.json"],
|
|
467
|
-
["/tmp/order.json"],
|
|
468
|
-
["/tmp/order_rules.json"],
|
|
469
|
-
]
|
|
470
|
-
blocked = dependency_blocked_results(waves, failed_wave_index=1)
|
|
471
|
-
self.assertEqual(
|
|
472
|
-
[item["artifact"] for item in blocked],
|
|
473
|
-
["order.json", "order_rules.json"],
|
|
474
|
-
)
|
|
475
|
-
self.assertTrue(
|
|
476
|
-
all(item["errorCode"] == "DEPENDENCY_WAVE_FAILED" for item in blocked)
|
|
477
|
-
)
|
|
478
|
-
self.assertTrue(all(item["phase"] == "dependency" for item in blocked))
|
|
479
463
|
|
|
480
464
|
|
|
481
465
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import subprocess
|
|
3
|
+
import sys
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
ROOT = Path(__file__).resolve().parents[2]
|
|
7
|
+
MODELING = ROOT / "skills/cosmic-meta-modeling/scripts"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def run(script, *args):
|
|
11
|
+
return subprocess.run([sys.executable, str(script), *args], capture_output=True, text=True)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def test_compiler_describes_the_existing_schema_without_workspace_or_platform(tmp_path):
|
|
15
|
+
result = run(MODELING / "data_model_emit.py", "--describe")
|
|
16
|
+
assert result.returncode == 0, result.stderr
|
|
17
|
+
contract = json.loads(result.stdout)
|
|
18
|
+
assert contract["inputSchema"] == json.loads((ROOT / "schemas/data-model-authoring.schema.json").read_text())
|
|
19
|
+
assert {arg["flags"][0] for arg in contract["arguments"] if arg["required"]} == {"--app-root", "--authoring-file"}
|
|
20
|
+
assert contract["execution"]["argvPrefix"][1] == str(MODELING / "data_model_emit.py")
|
|
21
|
+
localized = run(ROOT / ".locales/zh/skills/cosmic-meta-modeling/scripts/data_model_emit.py", "--describe")
|
|
22
|
+
assert localized.returncode == 0, localized.stderr
|
|
23
|
+
assert json.loads(localized.stdout)["inputSchema"] == contract["inputSchema"]
|
|
24
|
+
authoring = contract["authoringContract"]
|
|
25
|
+
assert json.loads(localized.stdout)["authoringContract"] == {
|
|
26
|
+
**authoring,
|
|
27
|
+
"templateFieldInspection": {
|
|
28
|
+
**authoring["templateFieldInspection"],
|
|
29
|
+
"argv": [sys.executable, str(ROOT / ".locales/zh/skills/cosmic-meta-api/scripts/cosmic_api.py"),
|
|
30
|
+
*authoring["templateFieldInspection"]["argv"][2:]],
|
|
31
|
+
},
|
|
32
|
+
}
|
|
33
|
+
assert authoring["callerFieldInputs"] == contract["inputSchema"]["definitions"]["field"]["required"]
|
|
34
|
+
sys.path.insert(0, str(MODELING))
|
|
35
|
+
from data_model_emit import _apply_direct_authoring_constraints
|
|
36
|
+
for kind, template in authoring["defaultTemplates"].items():
|
|
37
|
+
section = {"artifact": {"entities": [{"type": kind, "fields": []}]}}
|
|
38
|
+
_apply_direct_authoring_constraints(section)
|
|
39
|
+
assert section["artifact"]["entities"][0]["templateKey"] == template
|
|
40
|
+
selected = {"artifact": {"entities": [{"type": kind, "templateKey": "explicit_template", "fields": []}]}}
|
|
41
|
+
_apply_direct_authoring_constraints(selected)
|
|
42
|
+
assert selected["artifact"]["entities"][0]["templateKey"] == "explicit_template"
|
|
43
|
+
inspection = authoring["templateFieldInspection"]["argv"]
|
|
44
|
+
help_result = run(Path(inspection[1]), "--stdout", "getEntityFields", "--help")
|
|
45
|
+
assert help_result.returncode == 0, help_result.stderr
|
|
46
|
+
assert all(flag in help_result.stdout for flag in ("--app-root", "--formNumber"))
|
|
47
|
+
assert not list(tmp_path.iterdir())
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def test_catalog_queries_reuse_source_and_unknown_types_fail():
|
|
51
|
+
script = MODELING / "field_type_registry.py"
|
|
52
|
+
full = json.loads(run(script, "--catalog").stdout)
|
|
53
|
+
selected = json.loads(run(script, "--catalog", "--types", "DateField", "BasedataField", "TextField").stdout)
|
|
54
|
+
assert selected["fieldTypes"] == [x for x in full["fieldTypes"] if x["name"] in {"DateField", "BasedataField", "TextField"}]
|
|
55
|
+
compact = json.loads(run(script, "--catalog", "--compact").stdout)
|
|
56
|
+
assert [(x["name"], x["semantics"]) for x in compact["fieldTypes"]] == [(x["name"], x["semantics"]) for x in full["fieldTypes"]]
|
|
57
|
+
assert len(json.dumps(compact)) < len(json.dumps(full))
|
|
58
|
+
assert run(script, "--catalog", "--types", "InventedField").returncode != 0
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def test_saved_receipt_exposes_next_command_without_inventing_verification(tmp_path, capsys):
|
|
62
|
+
api_scripts = ROOT / "skills/cosmic-meta-api/scripts"
|
|
63
|
+
sys.path.insert(0, str(api_scripts))
|
|
64
|
+
from _core import formatters
|
|
65
|
+
|
|
66
|
+
output = tmp_path / "receipt.json"
|
|
67
|
+
receipt = {"success": 1, "failed": 1, "results": [
|
|
68
|
+
{"ok": True, "phase": "buildMeta", "verification": {"status": "pass"}},
|
|
69
|
+
{"ok": False, "phase": "unknown", "error": "response lost"},
|
|
70
|
+
], "delivery": {"command": ["python", "render.py", "--form-number", "verified-target"]},
|
|
71
|
+
"doNotRetryBuildMeta": True, "reconcile": {"ready": True}}
|
|
72
|
+
formatters.set_output_file(str(output))
|
|
73
|
+
formatters.set_stdout_mode(False)
|
|
74
|
+
try:
|
|
75
|
+
formatters.pjson(receipt)
|
|
76
|
+
summary = json.loads(capsys.readouterr().out.split("RESULT_SUMMARY=", 1)[1])
|
|
77
|
+
assert json.loads(output.read_text()) == receipt
|
|
78
|
+
assert summary["delivery"] == receipt["delivery"]
|
|
79
|
+
assert summary["doNotRetryBuildMeta"] is True
|
|
80
|
+
assert summary["results"][0]["verification"] == {"status": "pass"}
|
|
81
|
+
assert "verification" not in summary["results"][1]
|
|
82
|
+
formatters.set_stdout_mode(True)
|
|
83
|
+
formatters.pjson(receipt)
|
|
84
|
+
assert json.loads(capsys.readouterr().out) == receipt
|
|
85
|
+
finally:
|
|
86
|
+
formatters.set_stdout_mode(False)
|
|
87
|
+
formatters.set_output_file(None)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import os
|
|
3
|
+
import subprocess
|
|
2
4
|
import sys
|
|
3
5
|
from pathlib import Path
|
|
4
6
|
from types import SimpleNamespace
|
|
@@ -23,6 +25,29 @@ def test_resolve_module_uses_project_dir_mapping(tmp_path):
|
|
|
23
25
|
assert resolve_module(gradle_root, module_root) == ":demo"
|
|
24
26
|
|
|
25
27
|
|
|
28
|
+
def test_compile_environment_reports_only_configured_sdk_libraries(tmp_path, monkeypatch):
|
|
29
|
+
gradle = tmp_path / "gradle"
|
|
30
|
+
project = gradle / "code" / "demo"
|
|
31
|
+
project.mkdir(parents=True)
|
|
32
|
+
(gradle / "settings.gradle").write_text("include(':demo')\nproject(':demo').projectDir = new File('code/demo')\n")
|
|
33
|
+
sdk = tmp_path / "target-sdk"
|
|
34
|
+
bos = sdk / "mservice-cosmic" / "lib" / "bos"
|
|
35
|
+
bos.mkdir(parents=True)
|
|
36
|
+
(bos / "target.jar").write_bytes(b"")
|
|
37
|
+
(sdk / "mservice" / "lib" / "bos").mkdir(parents=True)
|
|
38
|
+
(sdk / "mservice" / "lib" / "bos" / "other.jar").write_bytes(b"")
|
|
39
|
+
(gradle / "gradle.properties").write_text(f"systemProp.cosmic_home={sdk}\nsecret.password=not-read\n")
|
|
40
|
+
(gradle / "config.gradle").write_text('cosmic_libs_path = "${cosmic_home}/mservice-cosmic/lib"\npath = [bos : "${cosmic_libs_path}/bos"]\n')
|
|
41
|
+
monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda write_derived: {
|
|
42
|
+
"status": "ready", "GRADLE_ROOT": str(gradle), "JAVA_HOME": str(tmp_path / "jdk")})
|
|
43
|
+
result = compile_plugin_source.inspect_compile_environment(str(project))
|
|
44
|
+
assert result["status"] == "ready" and result["module"] == ":demo"
|
|
45
|
+
assert [item["path"] for item in result["sdkDirectories"]] == [str(bos.resolve())]
|
|
46
|
+
assert "not-read" not in str(result)
|
|
47
|
+
assert result["sdkDirectories"][0]["source"] == [str((gradle / "gradle.properties").resolve()),
|
|
48
|
+
str((gradle / "config.gradle").resolve())]
|
|
49
|
+
|
|
50
|
+
|
|
26
51
|
def test_validate_source_blocks_unresolved_dependency_markers(tmp_path):
|
|
27
52
|
project_root = tmp_path / "module"
|
|
28
53
|
source = project_root / "src" / "main" / "java" / "demo" / "Task.java"
|
|
@@ -39,9 +64,76 @@ def test_validate_source_blocks_unresolved_dependency_markers(tmp_path):
|
|
|
39
64
|
assert issues == [{"line": 1, "message": "unresolved L3 dependency"}]
|
|
40
65
|
|
|
41
66
|
|
|
67
|
+
def test_timeprop_hints_survive_single_and_batch_handoff_without_false_blocking(tmp_path):
|
|
68
|
+
project_root = tmp_path / "module"
|
|
69
|
+
source = project_root / "src" / "main" / "java" / "demo" / "Booking.java"
|
|
70
|
+
source.parent.mkdir(parents=True)
|
|
71
|
+
source.write_text(
|
|
72
|
+
'class Booking {\n'
|
|
73
|
+
' private static final String START = "start_time";\n'
|
|
74
|
+
' void check(DynamicObject row) { row.getDate(START); }\n'
|
|
75
|
+
'}\n', encoding="utf-8",
|
|
76
|
+
)
|
|
77
|
+
handoff = project_root / "app" / "_runtime" / "Booking.json"
|
|
78
|
+
handoff.parent.mkdir(parents=True)
|
|
79
|
+
handoff.write_text(json.dumps({"status": True, "handoff": {
|
|
80
|
+
"projectRoot": str(project_root), "appRoot": str(project_root / "app"),
|
|
81
|
+
"sourcePath": str(source), "className": "Booking", "type": "operation",
|
|
82
|
+
"formNumber": "booking", "description": "时段检查", "operationKeys": ["save"],
|
|
83
|
+
"formGraph": {"entities": [{"fields": [{"fieldKey": "start_time", "fieldType": "TimeProp"}]}]},
|
|
84
|
+
}}), encoding="utf-8")
|
|
85
|
+
config = tmp_path / "appconfig.json"
|
|
86
|
+
config.write_text('{"compile": false}')
|
|
87
|
+
env = {**os.environ, "KD_APPCONFIG": str(config)}
|
|
88
|
+
run = subprocess.run([sys.executable, str(SCRIPTS / "compile_plugin_source.py"),
|
|
89
|
+
"--handoff", str(handoff)], capture_output=True, text=True, env=env)
|
|
90
|
+
outcome = json.loads(run.stdout)
|
|
91
|
+
assert run.returncode == 0
|
|
92
|
+
assert outcome["compileSkipped"] is True
|
|
93
|
+
assert outcome["compiledArtifact"] is None
|
|
94
|
+
assert outcome["loadingVerification"]["runtimeVerified"] is False
|
|
95
|
+
assert outcome["fieldAccessorCheck"] == "metadata-hints"
|
|
96
|
+
assert outcome["sourceWarnings"][0]["fieldKeys"] == ["start_time"]
|
|
97
|
+
batch = tmp_path / "sources.json"
|
|
98
|
+
batch.write_text(json.dumps([{"handoffPath": str(handoff)}]))
|
|
99
|
+
run = subprocess.run([sys.executable, str(SCRIPTS / "compile_plugin_source.py"),
|
|
100
|
+
"--project-root", str(project_root), "--app-root", str(project_root / "app"),
|
|
101
|
+
"--sources-file", str(batch)], capture_output=True, text=True, env=env)
|
|
102
|
+
result = json.loads(run.stdout)
|
|
103
|
+
assert run.returncode == 0
|
|
104
|
+
assert result["results"][0]["sourceWarnings"] == outcome["sourceWarnings"]
|
|
105
|
+
run = subprocess.run([sys.executable, str(SCRIPTS / "compile_plugin_source.py"),
|
|
106
|
+
"--project-root", str(project_root), "--app-root", str(tmp_path / "another-app"),
|
|
107
|
+
"--sources-file", str(batch)], capture_output=True, text=True, env=env)
|
|
108
|
+
assert run.returncode == 2
|
|
109
|
+
assert json.loads(run.stdout)["results"][0]["errorCode"] == "PLUGIN_BATCH_INPUT_INVALID"
|
|
110
|
+
|
|
111
|
+
assert compile_plugin_source.time_accessor_issues(
|
|
112
|
+
'// row.getDate(START)\nrow.getInt(START); row.getDate("booking_date");', {"start_time"}
|
|
113
|
+
) == []
|
|
114
|
+
assert len(compile_plugin_source.time_accessor_issues('row.getDate("start_time");', {"start_time"})) == 1
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_timeprop_scan_ignores_literals_and_known_other_receivers_and_preserves_ambiguous_constants():
|
|
118
|
+
assert compile_plugin_source.time_accessor_issues(
|
|
119
|
+
'class P { static final String START = "start_time"; String note = "Do not use row.getDate(START)"; }',
|
|
120
|
+
{"start_time"},
|
|
121
|
+
) == []
|
|
122
|
+
assert compile_plugin_source.time_accessor_issues(
|
|
123
|
+
'class P { void run(java.sql.ResultSet rs) { rs.getDate("start_time"); } }', {"start_time"},
|
|
124
|
+
) == []
|
|
125
|
+
issues = compile_plugin_source.time_accessor_issues(
|
|
126
|
+
'class P { static final String FIELD = "start_time"; void run(DynamicObject row) { row.getDate(FIELD); } '
|
|
127
|
+
'static class Other { static final String FIELD = "booking_date"; } }', {"start_time"},
|
|
128
|
+
)
|
|
129
|
+
assert len(issues) == 1
|
|
130
|
+
assert issues[0]["severity"] == "warning"
|
|
131
|
+
assert issues[0]["fieldKeys"] == ["start_time"]
|
|
132
|
+
|
|
133
|
+
|
|
42
134
|
def test_a_chinese_placeholder_word_in_a_comment_is_not_an_unresolved_dependency(tmp_path):
|
|
43
135
|
"""The word is ordinary business vocabulary. Scanning comments for it stopped delivery as
|
|
44
|
-
L3-BLOCK on a correct Chinese comment
|
|
136
|
+
L3-BLOCK on a correct Chinese comment or a legitimate state/message string."""
|
|
45
137
|
project_root = tmp_path / "module"
|
|
46
138
|
source = project_root / "src" / "main" / "java" / "demo" / "Task.java"
|
|
47
139
|
source.parent.mkdir(parents=True)
|
|
@@ -62,8 +154,11 @@ def test_a_chinese_placeholder_word_in_a_comment_is_not_an_unresolved_dependency
|
|
|
62
154
|
encoding="utf-8",
|
|
63
155
|
)
|
|
64
156
|
|
|
157
|
+
assert validate_source(source, project_root, "Task") == []
|
|
158
|
+
|
|
159
|
+
source.write_text('class Task { String reason = "待替换"; }', encoding="utf-8")
|
|
65
160
|
assert validate_source(source, project_root, "Task") == [
|
|
66
|
-
{"line":
|
|
161
|
+
{"line": 1, "message": "unresolved placeholder text"},
|
|
67
162
|
]
|
|
68
163
|
|
|
69
164
|
|
|
@@ -173,10 +268,29 @@ def test_compile_success_archives_before_marking_source_ready(tmp_path, monkeypa
|
|
|
173
268
|
|
|
174
269
|
archive = json.loads((app_root / "archive.json").read_text(encoding="utf-8"))
|
|
175
270
|
assert result["status"] is True
|
|
271
|
+
assert result["buildContext"]["gradleRoot"] == str(gradle_root.resolve())
|
|
272
|
+
assert result["buildContext"]["testTaskCandidate"] == ":demo:test"
|
|
273
|
+
assert result["sourceReview"]["businessCoverage"] == "not-established-by-compilation"
|
|
176
274
|
assert archive["javas"][0]["className"] == "Task"
|
|
177
275
|
assert (project_root / ".temp" / ".Task-gate").read_text() == "source_ready"
|
|
178
276
|
|
|
179
277
|
|
|
278
|
+
def test_operation_dispatch_preflight_flags_unverified_map_keys_and_unselected_shared_effects():
|
|
279
|
+
source = '''class Plugin {
|
|
280
|
+
String operation() { return (String) this.operateMeta.get("operationKey"); }
|
|
281
|
+
void beginOperationTransaction(Event event) { updateRelatedObject(); }
|
|
282
|
+
}'''
|
|
283
|
+
warnings = compile_plugin_source.operation_dispatch_warnings(source, ["save", "confirm"])
|
|
284
|
+
assert {warning["errorCode"] for warning in warnings} == {
|
|
285
|
+
"PLUGIN_OPERATION_MAP_KEY_UNVERIFIED", "PLUGIN_OPERATION_SCOPE_UNVERIFIED"}
|
|
286
|
+
assert all(warning["severity"] == "warning" for warning in warnings)
|
|
287
|
+
assert compile_plugin_source.operation_dispatch_warnings(
|
|
288
|
+
'class P { String example="operateMeta.get(\\"operationKey\\")"; '
|
|
289
|
+
'void beginOperationTransaction(Event event) { if (expected.equals(event.getOperationKey())) updateRelatedObject(); } }',
|
|
290
|
+
["save", "confirm"],
|
|
291
|
+
) == []
|
|
292
|
+
|
|
293
|
+
|
|
180
294
|
def test_compile_refuses_a_method_declared_twice_even_when_compilation_is_disabled(tmp_path, monkeypatch):
|
|
181
295
|
project_root = tmp_path / "module"
|
|
182
296
|
source = project_root / "src" / "main" / "java" / "demo" / "Bill.java"
|
|
@@ -563,7 +677,7 @@ def test_a_comment_placeholder_after_a_form_feed_is_still_located(tmp_path):
|
|
|
563
677
|
source.write_text(
|
|
564
678
|
"class Task {\n"
|
|
565
679
|
" /* page\x0cbreak */\n"
|
|
566
|
-
' void run() { String s = "
|
|
680
|
+
' void run() { String s = "占位实现"; }\n'
|
|
567
681
|
"}\n",
|
|
568
682
|
encoding="utf-8",
|
|
569
683
|
)
|
|
@@ -649,3 +763,110 @@ def test_compile_refuses_a_drifted_override_even_when_compilation_is_disabled(tm
|
|
|
649
763
|
assert result["issues"][0]["registeredSignatures"] == ["propertyChanged(PropertyChangedArgs)"]
|
|
650
764
|
assert not (app_root / "archive.json").exists()
|
|
651
765
|
assert not (project_root / ".temp").exists()
|
|
766
|
+
|
|
767
|
+
|
|
768
|
+
def test_batch_builds_one_module_once_and_keeps_full_diagnostics_in_one_log(tmp_path, monkeypatch, capsys):
|
|
769
|
+
project = tmp_path / "module"
|
|
770
|
+
java = project / "src/main/java/demo"
|
|
771
|
+
java.mkdir(parents=True)
|
|
772
|
+
(project / "settings.gradle").write_text("")
|
|
773
|
+
entries = []
|
|
774
|
+
for i in range(6):
|
|
775
|
+
source = java / f"Task{i}.java"
|
|
776
|
+
source.write_text(f"package demo; public class Task{i} {{}}")
|
|
777
|
+
entries.append({"sourcePath": str(source), "className": f"Task{i}", "type": "task",
|
|
778
|
+
"formNumber": "example", "operationKeys": [], "description": "scheduled task"})
|
|
779
|
+
batch = tmp_path / "sources.json"
|
|
780
|
+
batch.write_text(json.dumps(entries))
|
|
781
|
+
calls = []
|
|
782
|
+
diagnostics = "\n".join(f"{java / f'Task{i % 6}.java'}:{i+1}: error: missing symbol {i}" for i in range(60))
|
|
783
|
+
monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda **_: {
|
|
784
|
+
"status": "ready", "GRADLE_ROOT": str(project), "JAVA_HOME": str(tmp_path / "jdk"),
|
|
785
|
+
})
|
|
786
|
+
def build(argv, **kwargs):
|
|
787
|
+
calls.append(argv)
|
|
788
|
+
return SimpleNamespace(returncode=1, stdout=diagnostics)
|
|
789
|
+
monkeypatch.setattr(compile_plugin_source.subprocess, "run", build)
|
|
790
|
+
monkeypatch.setattr(sys, "argv", ["compile_plugin_source.py", "--project-root", str(project),
|
|
791
|
+
"--app-root", str(tmp_path / "app"), "--sources-file", str(batch)])
|
|
792
|
+
assert compile_plugin_source.main() == 2
|
|
793
|
+
result = json.loads(capsys.readouterr().out)
|
|
794
|
+
assert len(calls) == 1
|
|
795
|
+
assert "--rerun-tasks" not in calls[0]
|
|
796
|
+
assert len(result["results"]) == 6
|
|
797
|
+
assert all(item["status"] is False for item in result["results"])
|
|
798
|
+
assert sum(len(item.get("diagnostics", [])) for item in result["results"]) == 5
|
|
799
|
+
paths = {item["logPath"] for item in result["results"]}
|
|
800
|
+
assert len(paths) == 1
|
|
801
|
+
assert Path(next(iter(paths))).read_text() == diagnostics
|
|
802
|
+
assert not (tmp_path / "app/archive.json").exists()
|
|
803
|
+
# Failures are not cached across invocations, so a recovered environment can be retried.
|
|
804
|
+
assert compile_plugin_source.main() == 2
|
|
805
|
+
capsys.readouterr()
|
|
806
|
+
assert len(calls) == 2
|
|
807
|
+
monkeypatch.setattr(compile_plugin_source.subprocess, "run",
|
|
808
|
+
lambda *a, **k: SimpleNamespace(returncode=0, stdout="BUILD SUCCESSFUL"))
|
|
809
|
+
assert compile_plugin_source.main() == 0
|
|
810
|
+
result = json.loads(capsys.readouterr().out)
|
|
811
|
+
assert all(item["status"] is True for item in result["results"])
|
|
812
|
+
archive = json.loads((tmp_path / "app/archive.json").read_text())
|
|
813
|
+
assert len(archive["javas"]) == 6
|
|
814
|
+
assert all(item["compileStatus"] == "passed" and len(item["sourceHash"]) == 64 for item in archive["javas"])
|
|
815
|
+
|
|
816
|
+
|
|
817
|
+
def test_failed_recompile_invalidates_prior_archive_readiness(tmp_path, monkeypatch):
|
|
818
|
+
project = tmp_path / "module"
|
|
819
|
+
source = project / "src/main/java/demo/Task.java"
|
|
820
|
+
source.parent.mkdir(parents=True)
|
|
821
|
+
source.write_text("package demo; public class Task {}")
|
|
822
|
+
(project / "settings.gradle").write_text("")
|
|
823
|
+
app = tmp_path / "app"
|
|
824
|
+
monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda **_: {"status": "disabled"})
|
|
825
|
+
args = dict(app_root=app, plugin_type="task", form_number="example", operation_keys=[], description="scheduled task")
|
|
826
|
+
assert compile_plugin_source.compile_source(project, source, "Task", 30, **args)["status"]
|
|
827
|
+
assert json.loads((app / "archive.json").read_text())["javas"][0]["compileStatus"] == "skipped-by-config"
|
|
828
|
+
monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda **_: {
|
|
829
|
+
"status": "ready", "GRADLE_ROOT": str(project), "JAVA_HOME": str(tmp_path / "jdk"),
|
|
830
|
+
})
|
|
831
|
+
monkeypatch.setattr(compile_plugin_source.subprocess, "run", lambda *a, **k: SimpleNamespace(returncode=1, stdout="dependency resolution failed"))
|
|
832
|
+
assert compile_plugin_source.compile_source(project, source, "Task", 30, **args)["status"] is False
|
|
833
|
+
assert json.loads((app / "archive.json").read_text())["javas"][0]["compileStatus"] == "pending"
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
def test_compile_reports_independent_source_issues_together(tmp_path):
|
|
837
|
+
source = tmp_path / "src" / "main" / "java" / "sample" / "Example.java"
|
|
838
|
+
source.parent.mkdir(parents=True)
|
|
839
|
+
source.write_text('''package sample;
|
|
840
|
+
import kd.bos.servicehelper.QueryServiceHelper;
|
|
841
|
+
import kd.bos.dataentity.entity.DynamicObject;
|
|
842
|
+
import kd.bos.orm.query.QFilter;
|
|
843
|
+
class Example {
|
|
844
|
+
void run() {
|
|
845
|
+
DynamicObject[] values = QueryServiceHelper.query("sample", "id", null);
|
|
846
|
+
QFilter filter = new QFilter("id", "not in", null);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
''')
|
|
850
|
+
result = compile_plugin_source.compile_source(tmp_path, source, "Example", 10, app_root=tmp_path / "app",
|
|
851
|
+
plugin_type="operation", form_number="sample", operation_keys=["process"], description="check")
|
|
852
|
+
assert set(result["errorCodes"]) >= {"PLUGIN_SOURCE_RETURN_TYPE_MISMATCH", "PLUGIN_SOURCE_QFILTER_STRING_OPERATOR"}
|
|
853
|
+
assert all(issue["errorCode"] in result["errorCodes"] for issue in result["issues"])
|
|
854
|
+
assert not (tmp_path / "app" / "archive.json").exists()
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
def test_compile_consumes_handoff_without_retyped_identity(tmp_path, monkeypatch, capsys):
|
|
858
|
+
source = tmp_path / "src" / "main" / "java" / "sample" / "Example.java"
|
|
859
|
+
source.parent.mkdir(parents=True)
|
|
860
|
+
source.write_text("package sample; public class Example {}")
|
|
861
|
+
prepared = tmp_path / "handoff.json"
|
|
862
|
+
prepared.write_text(json.dumps({"status": True, "handoff": {"projectRoot": str(tmp_path),
|
|
863
|
+
"appRoot": str(tmp_path / "app"), "sourcePath": str(source), "className": "Example", "type": "task",
|
|
864
|
+
"formNumber": "sample", "operationKeys": [], "description": "check"}}))
|
|
865
|
+
monkeypatch.setattr(compile_plugin_source, "inspect_config", lambda write_derived: {"status": "disabled", "compile": False})
|
|
866
|
+
monkeypatch.setattr(sys, "argv", ["compile_plugin_source.py", "--handoff", str(prepared)])
|
|
867
|
+
assert compile_plugin_source.main() == 0
|
|
868
|
+
result = json.loads(capsys.readouterr().out)
|
|
869
|
+
assert result["compileSkipped"] is True
|
|
870
|
+
archive = json.loads((tmp_path / "app" / "archive.json").read_text())
|
|
871
|
+
assert archive["javas"][0]["className"] == "Example"
|
|
872
|
+
assert archive["javas"][0]["filePath"] == str(source.resolve())
|