1use std::sync::Arc;
4
5use async_trait::async_trait;
6use serde_json::Value;
7
8use khive_runtime::pack::PackRuntime;
9use khive_runtime::{
10 KhiveRuntime, KindHook, NamespaceToken, NoteKindSpec, PackSchemaPlan, RuntimeError, SchemaPlan,
11 VerbRegistry,
12};
13use khive_types::{EdgeEndpointRule, EntityTypeDef, HandlerDef, Pack};
14
15use crate::hook::{CommitHook, IssueLikeHook};
16use crate::vocab::{GIT_ENTITY_TYPES, GIT_NOTE_KIND_SPECS, GIT_SCHEMA_PLAN_STMTS};
17
18pub struct GitPack {
27 runtime: KhiveRuntime,
28}
29
30impl Pack for GitPack {
31 const NAME: &'static str = "git";
32 const NOTE_KINDS: &'static [&'static str] = &["commit", "issue", "pull_request"];
33 const ENTITY_KINDS: &'static [&'static str] = &[];
34 const HANDLERS: &'static [HandlerDef] = &crate::vocab::GIT_HANDLERS;
35 const EDGE_RULES: &'static [EdgeEndpointRule] = &crate::vocab::GIT_EDGE_RULES;
36 const ENTITY_TYPES: &'static [EntityTypeDef] = &GIT_ENTITY_TYPES;
37 const REQUIRES: &'static [&'static str] = &["kg"];
38 const NOTE_KIND_SPECS: &'static [NoteKindSpec] = &GIT_NOTE_KIND_SPECS;
39 const SCHEMA_PLAN: Option<PackSchemaPlan> = Some(PackSchemaPlan {
40 pack: "git",
41 statements: &GIT_SCHEMA_PLAN_STMTS,
42 });
43}
44
45impl GitPack {
46 pub fn new(runtime: KhiveRuntime) -> Self {
48 Self { runtime }
49 }
50
51 pub(crate) fn runtime(&self) -> &KhiveRuntime {
55 &self.runtime
56 }
57}
58
59struct GitPackFactory;
62
63impl khive_runtime::PackFactory for GitPackFactory {
64 fn name(&self) -> &'static str {
65 "git"
66 }
67
68 fn requires(&self) -> &'static [&'static str] {
69 &["kg"]
70 }
71
72 fn create(&self, runtime: KhiveRuntime) -> Box<dyn khive_runtime::PackRuntime> {
73 Box::new(GitPack::new(runtime))
74 }
75}
76
77inventory::submit! { khive_runtime::PackRegistration(&GitPackFactory) }
78
79#[async_trait]
80impl PackRuntime for GitPack {
81 fn name(&self) -> &str {
82 <GitPack as Pack>::NAME
83 }
84
85 fn note_kinds(&self) -> &'static [&'static str] {
86 <GitPack as Pack>::NOTE_KINDS
87 }
88
89 fn entity_kinds(&self) -> &'static [&'static str] {
90 <GitPack as Pack>::ENTITY_KINDS
91 }
92
93 fn handlers(&self) -> &'static [HandlerDef] {
94 <GitPack as Pack>::HANDLERS
95 }
96
97 fn edge_rules(&self) -> &'static [EdgeEndpointRule] {
98 <GitPack as Pack>::EDGE_RULES
99 }
100
101 fn entity_types(&self) -> &'static [EntityTypeDef] {
102 <GitPack as Pack>::ENTITY_TYPES
103 }
104
105 fn requires(&self) -> &'static [&'static str] {
106 <GitPack as Pack>::REQUIRES
107 }
108
109 fn note_kind_specs(&self) -> &'static [NoteKindSpec] {
110 <GitPack as Pack>::NOTE_KIND_SPECS
111 }
112
113 fn schema_plan(&self) -> SchemaPlan {
114 SchemaPlan {
115 pack: "git",
116 statements: &GIT_SCHEMA_PLAN_STMTS,
117 }
118 }
119
120 fn kind_hook(&self, kind: &str) -> Option<Arc<dyn KindHook>> {
121 match kind {
122 "commit" => Some(Arc::new(CommitHook)),
123 "issue" => Some(Arc::new(IssueLikeHook { kind: "issue" })),
124 "pull_request" => Some(Arc::new(IssueLikeHook {
125 kind: "pull_request",
126 })),
127 _ => None,
128 }
129 }
130
131 async fn dispatch(
132 &self,
133 verb: &str,
134 params: Value,
135 registry: &VerbRegistry,
136 token: &NamespaceToken,
137 ) -> Result<Value, RuntimeError> {
138 match verb {
139 "git.digest" => self.handle_digest(token, registry, params).await,
140 "git.commit" => self.handle_commit(token, params).await,
141 "git.branch" => self.handle_branch(token, params).await,
142 "git.push" => self.handle_push(token, params).await,
143 _ => Err(RuntimeError::InvalidInput(format!(
144 "git pack does not handle verb {verb:?}"
145 ))),
146 }
147 }
148}