Skip to content

Commit 997a925

Browse files
Add changed files to graphql api (#911)
Change-Id: graphql-changed-files
1 parent b519a2f commit 997a925

File tree

4 files changed

+323
-0
lines changed

4 files changed

+323
-0
lines changed

src/filter/tree.rs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,96 @@ pub fn insert<'a>(
213213
}
214214
}
215215

216+
pub fn diff_paths(
217+
repo: &git2::Repository,
218+
input1: git2::Oid,
219+
input2: git2::Oid,
220+
root: &str,
221+
) -> JoshResult<Vec<(String, i32)>> {
222+
rs_tracing::trace_scoped!("diff_paths");
223+
if input1 == input2 {
224+
return Ok(vec![]);
225+
}
226+
227+
if let (Ok(_), Ok(_)) = (repo.find_blob(input1), repo.find_blob(input2)) {
228+
return Ok(vec![(root.to_string(), 0)]);
229+
}
230+
231+
if let (Ok(_), Err(_)) = (repo.find_blob(input1), repo.find_blob(input2)) {
232+
return Ok(vec![(root.to_string(), -1)]);
233+
}
234+
235+
if let (Err(_), Ok(_)) = (repo.find_blob(input1), repo.find_blob(input2)) {
236+
return Ok(vec![(root.to_string(), 1)]);
237+
}
238+
239+
let mut r = vec![];
240+
241+
if let (Ok(tree1), Ok(tree2)) = (repo.find_tree(input1), repo.find_tree(input2)) {
242+
for entry in tree2.iter() {
243+
let name = entry.name().ok_or_else(|| josh_error("no name"))?;
244+
if let Some(e) = tree1.get_name(entry.name().ok_or_else(|| josh_error("no name"))?) {
245+
r.append(&mut diff_paths(
246+
repo,
247+
e.id(),
248+
entry.id(),
249+
&format!("{}{}{}", root, if root.is_empty() { "" } else { "/" }, name),
250+
)?);
251+
} else {
252+
r.append(&mut diff_paths(
253+
repo,
254+
git2::Oid::zero(),
255+
entry.id(),
256+
&format!("{}{}{}", root, if root.is_empty() { "" } else { "/" }, name),
257+
)?);
258+
}
259+
}
260+
261+
for entry in tree1.iter() {
262+
let name = entry.name().ok_or_else(|| josh_error("no name"))?;
263+
if let Some(_) = tree2.get_name(entry.name().ok_or_else(|| josh_error("no name"))?) {
264+
} else {
265+
r.append(&mut diff_paths(
266+
repo,
267+
entry.id(),
268+
git2::Oid::zero(),
269+
&format!("{}{}{}", root, if root.is_empty() { "" } else { "/" }, name),
270+
)?);
271+
}
272+
}
273+
274+
return Ok(r);
275+
}
276+
277+
if let Ok(tree2) = repo.find_tree(input2) {
278+
for entry in tree2.iter() {
279+
let name = entry.name().ok_or_else(|| josh_error("no name"))?;
280+
r.append(&mut diff_paths(
281+
repo,
282+
git2::Oid::zero(),
283+
entry.id(),
284+
&format!("{}{}{}", root, if root.is_empty() { "" } else { "/" }, name),
285+
)?);
286+
}
287+
return Ok(r);
288+
}
289+
290+
if let Ok(tree1) = repo.find_tree(input2) {
291+
for entry in tree1.iter() {
292+
let name = entry.name().ok_or_else(|| josh_error("no name"))?;
293+
r.append(&mut diff_paths(
294+
repo,
295+
entry.id(),
296+
git2::Oid::zero(),
297+
&format!("{}{}{}", root, if root.is_empty() { "" } else { "/" }, name),
298+
)?);
299+
}
300+
return Ok(r);
301+
}
302+
303+
Ok(r)
304+
}
305+
216306
pub fn overlay(
217307
repo: &git2::Repository,
218308
input1: git2::Oid,

src/graphql.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,22 @@ fn find_paths(
4646
Ok(ws)
4747
}
4848

49+
pub struct DiffPath {
50+
a: Option<Path>,
51+
b: Option<Path>,
52+
}
53+
54+
#[graphql_object(context = Context)]
55+
impl DiffPath {
56+
fn from(&self) -> FieldResult<Option<Path>> {
57+
Ok(self.a.clone())
58+
}
59+
60+
fn to(&self) -> FieldResult<Option<Path>> {
61+
Ok(self.b.clone())
62+
}
63+
}
64+
4965
impl Revision {
5066
fn files_or_dirs(
5167
&self,
@@ -262,6 +278,74 @@ impl Revision {
262278
self.files_or_dirs(at, depth, context, git2::ObjectType::Tree)
263279
}
264280

281+
fn changed_files(
282+
&self,
283+
at: Option<String>,
284+
depth: Option<i32>,
285+
context: &Context,
286+
) -> FieldResult<Option<Vec<DiffPath>>> {
287+
let transaction = context.transaction.lock()?;
288+
let commit = transaction.repo().find_commit(self.commit_id)?;
289+
let filter_commit = transaction.repo().find_commit(filter::apply_to_commit(
290+
self.filter,
291+
&commit,
292+
&transaction,
293+
)?)?;
294+
295+
let (parent_id, parent_tree_id) = filter_commit
296+
.parents()
297+
.next()
298+
.map(|p| (p.id(), p.tree_id()))
299+
.unwrap_or((git2::Oid::zero(), git2::Oid::zero()));
300+
301+
let d = filter::tree::diff_paths(
302+
transaction.repo(),
303+
parent_tree_id,
304+
filter_commit.tree_id(),
305+
"",
306+
)?;
307+
308+
let df = d
309+
.into_iter()
310+
.map(|(path, n)| match n {
311+
1 => DiffPath {
312+
a: None,
313+
b: Some(Path {
314+
path: std::path::Path::new(&path).to_owned(),
315+
commit_id: self.commit_id,
316+
filter: self.filter,
317+
tree: filter_commit.tree_id(),
318+
}),
319+
},
320+
-1 => DiffPath {
321+
a: Some(Path {
322+
path: std::path::Path::new(&path).to_owned(),
323+
commit_id: parent_id,
324+
filter: self.filter,
325+
tree: parent_tree_id,
326+
}),
327+
b: None,
328+
},
329+
_ => DiffPath {
330+
a: Some(Path {
331+
path: std::path::Path::new(&path).to_owned(),
332+
commit_id: parent_id,
333+
filter: self.filter,
334+
tree: parent_tree_id,
335+
}),
336+
b: Some(Path {
337+
path: std::path::Path::new(&path).to_owned(),
338+
commit_id: self.commit_id,
339+
filter: self.filter,
340+
tree: filter_commit.tree_id(),
341+
}),
342+
},
343+
})
344+
.collect();
345+
346+
return Ok(Some(df));
347+
}
348+
265349
fn file(&self, path: String, context: &Context) -> FieldResult<Option<Path>> {
266350
let transaction = context.transaction.lock()?;
267351
let path = std::path::Path::new(&path).to_owned();
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
$ export TESTTMP=${PWD}
2+
3+
$ cd ${TESTTMP}
4+
$ git init -q repo 1> /dev/null
5+
$ cd repo
6+
7+
$ echo contents0 > file1
8+
$ git add .
9+
$ git commit -m "add file1" 1> /dev/null
10+
$ echo contents2 > file2
11+
$ git add .
12+
$ git commit -m "add file2" 1> /dev/null
13+
$ mkdir ws
14+
$ cat > ws/workspace.josh <<EOF
15+
> ::file2
16+
> EOF
17+
$ git add .
18+
$ git commit -m "add ws" 1> /dev/null
19+
20+
$ cat > query <<EOF
21+
> query {
22+
> rev(at: "HEAD") {
23+
> history(limit: 10) {
24+
> summary
25+
> changedFiles {
26+
> from { path }
27+
> to { path }
28+
> }
29+
> }
30+
> }
31+
> }
32+
> EOF
33+
34+
$ josh-filter -g "$(cat query)"
35+
{
36+
"rev": {
37+
"history": [
38+
{
39+
"summary": "add ws",
40+
"changedFiles": [
41+
{
42+
"from": null,
43+
"to": {
44+
"path": "ws/workspace.josh"
45+
}
46+
}
47+
]
48+
},
49+
{
50+
"summary": "add file2",
51+
"changedFiles": [
52+
{
53+
"from": null,
54+
"to": {
55+
"path": "file2"
56+
}
57+
}
58+
]
59+
},
60+
{
61+
"summary": "add file1",
62+
"changedFiles": [
63+
{
64+
"from": null,
65+
"to": {
66+
"path": "file1"
67+
}
68+
}
69+
]
70+
}
71+
]
72+
}
73+
}

tests/proxy/graphql_schema.t

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,41 @@
7575
"name": "Boolean",
7676
"possibleTypes": null
7777
},
78+
{
79+
"description": null,
80+
"enumValues": null,
81+
"fields": [
82+
{
83+
"args": [],
84+
"deprecationReason": null,
85+
"description": null,
86+
"isDeprecated": false,
87+
"name": "from",
88+
"type": {
89+
"kind": "OBJECT",
90+
"name": "Path",
91+
"ofType": null
92+
}
93+
},
94+
{
95+
"args": [],
96+
"deprecationReason": null,
97+
"description": null,
98+
"isDeprecated": false,
99+
"name": "to",
100+
"type": {
101+
"kind": "OBJECT",
102+
"name": "Path",
103+
"ofType": null
104+
}
105+
}
106+
],
107+
"inputFields": null,
108+
"interfaces": [],
109+
"kind": "OBJECT",
110+
"name": "DiffPath",
111+
"possibleTypes": null
112+
},
78113
{
79114
"description": null,
80115
"enumValues": null,
@@ -503,6 +538,47 @@
503538
}
504539
}
505540
},
541+
{
542+
"args": [
543+
{
544+
"defaultValue": null,
545+
"description": null,
546+
"name": "at",
547+
"type": {
548+
"kind": "SCALAR",
549+
"name": "String",
550+
"ofType": null
551+
}
552+
},
553+
{
554+
"defaultValue": null,
555+
"description": null,
556+
"name": "depth",
557+
"type": {
558+
"kind": "SCALAR",
559+
"name": "Int",
560+
"ofType": null
561+
}
562+
}
563+
],
564+
"deprecationReason": null,
565+
"description": null,
566+
"isDeprecated": false,
567+
"name": "changedFiles",
568+
"type": {
569+
"kind": "LIST",
570+
"name": null,
571+
"ofType": {
572+
"kind": "NON_NULL",
573+
"name": null,
574+
"ofType": {
575+
"kind": "OBJECT",
576+
"name": "DiffPath",
577+
"ofType": null
578+
}
579+
}
580+
}
581+
},
506582
{
507583
"args": [
508584
{

0 commit comments

Comments
 (0)