ta_changeset/output_adapters/
json.rs1use crate::error::ChangeSetError;
4use crate::output_adapters::{OutputAdapter, RenderContext};
5
6#[derive(Default)]
7pub struct JsonAdapter {}
8
9impl JsonAdapter {
10 pub fn new() -> Self {
11 Self {}
12 }
13}
14
15impl OutputAdapter for JsonAdapter {
16 fn render(&self, ctx: &RenderContext) -> Result<String, ChangeSetError> {
17 let json = serde_json::to_string_pretty(ctx.package).map_err(|e| {
21 ChangeSetError::InvalidData(format!("JSON serialization failed: {}", e))
22 })?;
23
24 Ok(json)
25 }
26
27 fn name(&self) -> &str {
28 "json"
29 }
30}
31
32#[cfg(test)]
33mod tests {
34 use super::*;
35 use crate::output_adapters::DetailLevel;
36 use crate::pr_package::*;
37 use chrono::Utc;
38 use uuid::Uuid;
39
40 #[test]
41 fn renders_valid_json() {
42 let package = PRPackage {
43 package_version: "1.0.0".to_string(),
44 package_id: Uuid::new_v4(),
45 created_at: Utc::now(),
46 goal: Goal {
47 goal_id: "goal-1".to_string(),
48 title: "Test".to_string(),
49 objective: "Test".to_string(),
50 success_criteria: vec![],
51 constraints: vec![],
52 parent_goal_title: None,
53 },
54 iteration: Iteration {
55 iteration_id: "iter-1".to_string(),
56 sequence: 1,
57 workspace_ref: WorkspaceRef {
58 ref_type: "staging".to_string(),
59 ref_name: "staging/1".to_string(),
60 base_ref: None,
61 },
62 },
63 agent_identity: AgentIdentity {
64 agent_id: "agent-1".to_string(),
65 agent_type: "coder".to_string(),
66 constitution_id: "default".to_string(),
67 capability_manifest_hash: "hash".to_string(),
68 orchestrator_run_id: None,
69 },
70 summary: Summary {
71 what_changed: "Test".to_string(),
72 why: "Test".to_string(),
73 impact: "None".to_string(),
74 rollback_plan: "Revert".to_string(),
75 open_questions: vec![],
76 alternatives_considered: vec![],
77 },
78 plan: Plan {
79 completed_steps: vec![],
80 next_steps: vec![],
81 decision_log: vec![],
82 },
83 changes: Changes {
84 artifacts: vec![],
85 patch_sets: vec![],
86 pending_actions: vec![],
87 },
88 risk: Risk {
89 risk_score: 0,
90 findings: vec![],
91 policy_decisions: vec![],
92 },
93 provenance: Provenance {
94 inputs: vec![],
95 tool_trace_hash: "hash".to_string(),
96 },
97 review_requests: ReviewRequests {
98 requested_actions: vec![],
99 reviewers: vec![],
100 required_approvals: 1,
101 notes_to_reviewer: None,
102 },
103 signatures: Signatures {
104 package_hash: "hash".to_string(),
105 agent_signature: "sig".to_string(),
106 gateway_attestation: None,
107 },
108 status: PRStatus::Draft,
109 verification_warnings: vec![],
110 validation_log: vec![],
111 display_id: None,
112 tag: None,
113 vcs_status: None,
114 parent_draft_id: None,
115 pending_approvals: vec![],
116 supervisor_review: None,
117 ignored_artifacts: vec![],
118 baseline_artifacts: vec![],
119 agent_decision_log: vec![],
120 goal_shortref: None,
121 draft_seq: 0,
122 plan_phase: None,
123 };
124
125 let adapter = JsonAdapter::new();
126 let ctx = RenderContext {
127 package: &package,
128 detail_level: DetailLevel::Full,
129 file_filters: vec![],
130 diff_provider: None,
131 section_filter: None,
132 };
133
134 let output = adapter.render(&ctx).unwrap();
135 assert!(serde_json::from_str::<serde_json::Value>(&output).is_ok());
136 assert!(output.contains("package_version"));
137 assert!(output.contains("package_id"));
138 }
139}