trustfall_git_adapter/
lib.rs1use std::sync::LazyLock;
2
3use trustfall::{
4 Schema,
5 provider::{Adapter, resolve_coercion_using_schema},
6};
7
8use crate::{types::Repository, vertex::Vertex};
9
10mod edges;
11mod properties;
12mod types;
13mod vertex;
14
15static SCHEMA: LazyLock<Schema> =
16 LazyLock::new(|| Schema::parse(include_str!("schema.graphql")).expect("schema not valid"));
17
18pub struct GitAdapter<'a> {
19 git2_repo: &'a git2::Repository,
20}
21
22impl<'a> GitAdapter<'a> {
23 pub fn new(git2_repo: &'a git2::Repository) -> Self {
24 GitAdapter { git2_repo }
25 }
26
27 pub fn schema(&self) -> &Schema {
28 &SCHEMA
29 }
30}
31
32impl<'a> Adapter<'a> for &'a GitAdapter<'a> {
33 type Vertex = Vertex<'a>;
34
35 fn resolve_starting_vertices(
36 &self,
37 edge_name: &std::sync::Arc<str>,
38 _parameters: &trustfall_core::ir::EdgeParameters,
39 _resolve_info: &trustfall::provider::ResolveInfo,
40 ) -> trustfall::provider::VertexIterator<'a, Self::Vertex> {
41 match edge_name.as_ref() {
42 "repository" => {
43 let repo_name = match self.git2_repo.find_remote("origin") {
44 Ok(remote) => remote.url().and_then(|url| {
45 url.trim_end_matches(".git")
46 .rsplit('/')
47 .next()
48 .map(|s| s.to_string())
49 }),
50 Err(_) => None,
51 }
52 .unwrap_or_else(|| {
53 self.git2_repo
55 .path()
56 .parent()
57 .and_then(|p| p.file_name())
58 .and_then(|name| name.to_str())
59 .map(|s| s.to_string())
60 .unwrap_or_else(|| "unknown".to_string())
61 });
62
63 Box::new(std::iter::once(Vertex::Repository(Repository::new(
64 repo_name,
65 ))))
66 }
67 _ => unreachable!("resolve_starting_vertices {edge_name}"),
68 }
69 }
70
71 fn resolve_property<V: trustfall::provider::AsVertex<Self::Vertex> + 'a>(
72 &self,
73 contexts: trustfall::provider::ContextIterator<'a, V>,
74 type_name: &std::sync::Arc<str>,
75 property_name: &std::sync::Arc<str>,
76 _resolve_info: &trustfall::provider::ResolveInfo,
77 ) -> trustfall::provider::ContextOutcomeIterator<'a, V, trustfall::FieldValue> {
78 match type_name.as_ref() {
79 "Repository" => properties::resolve_repository_property(contexts, property_name),
80 "Branch" => properties::resolve_branch_property(contexts, property_name),
81 "Commit" => properties::resolve_commit_property(contexts, property_name),
82 "Tag" => properties::resolve_tag_property(contexts, property_name),
83 _ => unreachable!("resolve_property {type_name}"),
84 }
85 }
86
87 fn resolve_neighbors<V: trustfall::provider::AsVertex<Self::Vertex> + 'a>(
88 &self,
89 contexts: trustfall::provider::ContextIterator<'a, V>,
90 type_name: &std::sync::Arc<str>,
91 edge_name: &std::sync::Arc<str>,
92 parameters: &trustfall_core::ir::EdgeParameters,
93 _resolve_info: &trustfall::provider::ResolveEdgeInfo,
94 ) -> trustfall::provider::ContextOutcomeIterator<
95 'a,
96 V,
97 trustfall::provider::VertexIterator<'a, Self::Vertex>,
98 > {
99 match type_name.as_ref() {
100 "Repository" => edges::resolve_repository_edge(self, contexts, edge_name, parameters),
101 "Branch" => edges::resolve_branch_edge(self, contexts, edge_name),
102 "Tag" => edges::resolve_tag_edge(self, contexts, edge_name),
103 _ => unreachable!("resolve_neighbors {type_name}"),
104 }
105 }
106
107 fn resolve_coercion<V: trustfall::provider::AsVertex<Self::Vertex> + 'a>(
108 &self,
109 contexts: trustfall::provider::ContextIterator<'a, V>,
110 _type_name: &std::sync::Arc<str>,
111 coerce_to_type: &std::sync::Arc<str>,
112 _resolve_info: &trustfall::provider::ResolveInfo,
113 ) -> trustfall::provider::ContextOutcomeIterator<'a, V, bool> {
114 resolve_coercion_using_schema(contexts, &SCHEMA, coerce_to_type)
115 }
116}