upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2024-08-06 10:12:26 +0100
committerDanConwayDev <DanConwayDev@protonmail.com>2024-08-06 10:59:24 +0100
commitf1aa1be738af0dc80eb3b5827249bb537de1e0cd (patch)
tree4974673e04f6b05484450bbad44c545ca73bd27b /src
parent5ee6a65d7f095d5ba2d40e47bd97b2e65ed2443f (diff)
feat(remote): `list` includes open proposals
and filters out other branches in `prs/*` namespace
Diffstat (limited to 'src')
-rw-r--r--src/git_remote_helper.rs100
1 files changed, 95 insertions, 5 deletions
diff --git a/src/git_remote_helper.rs b/src/git_remote_helper.rs
index a930617..f851c90 100644
--- a/src/git_remote_helper.rs
+++ b/src/git_remote_helper.rs
@@ -15,17 +15,25 @@ use std::{
15use anyhow::{bail, Context, Result}; 15use anyhow::{bail, Context, Result};
16use auth_git2::GitAuthenticator; 16use auth_git2::GitAuthenticator;
17use client::{ 17use client::{
18 consolidate_fetch_reports, get_repo_ref_from_cache, get_state_from_cache, sign_event, Connect, 18 consolidate_fetch_reports, get_events_from_cache, get_repo_ref_from_cache,
19 STATE_KIND, 19 get_state_from_cache, sign_event, Connect, STATE_KIND,
20}; 20};
21use git::RepoActions; 21use git::RepoActions;
22use git2::{Oid, Repository}; 22use git2::{Oid, Repository};
23use nostr::nips::nip01::Coordinate; 23use nostr::nips::nip01::Coordinate;
24use nostr_sdk::{hashes::sha1::Hash as Sha1Hash, EventBuilder, PublicKey, Tag, Url}; 24use nostr_sdk::{
25 hashes::sha1::Hash as Sha1Hash, Event, EventBuilder, EventId, Kind, PublicKey, Tag, Url,
26};
25use nostr_signer::NostrSigner; 27use nostr_signer::NostrSigner;
26use repo_ref::RepoRef; 28use repo_ref::RepoRef;
27use repo_state::RepoState; 29use repo_state::RepoState;
28use sub_commands::send::send_events; 30use sub_commands::{
31 list::{
32 get_all_proposal_patch_events_from_cache, get_commit_id_from_patch,
33 get_most_recent_patch_with_ancestors, get_proposals_and_revisions_from_cache, status_kinds,
34 },
35 send::{event_is_revision_root, event_to_cover_letter, send_events},
36};
29 37
30#[cfg(not(test))] 38#[cfg(not(test))]
31use crate::client::Client; 39use crate::client::Client;
@@ -231,7 +239,7 @@ async fn list(
231 239
232 let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server)?; 240 let remote_states = list_from_remotes(&term, git_repo, &repo_ref.git_server)?;
233 241
234 let state = if let Some(nostr_state) = nostr_state { 242 let mut state = if let Some(nostr_state) = nostr_state {
235 for (name, value) in &nostr_state.state { 243 for (name, value) in &nostr_state.state {
236 for (url, remote_state) in &remote_states { 244 for (url, remote_state) in &remote_states {
237 let remote_name = get_short_git_server_name(git_repo, url); 245 let remote_name = get_short_git_server_name(git_repo, url);
@@ -272,6 +280,27 @@ async fn list(
272 .clone() 280 .clone()
273 }; 281 };
274 282
283 state.retain(|k, _| !k.starts_with("refs/heads/prs/"));
284
285 let open_proposals = get_open_proposals(git_repo, repo_ref).await?;
286
287 for (_, (proposal, patches)) in open_proposals {
288 if let Ok(cl) = event_to_cover_letter(&proposal) {
289 if let Ok(branch_name) = cl.get_branch_name() {
290 if let Some(patch) = patches.first() {
291 // TODO this isn't resilient because the commit id stated may not be correct
292 // we will need to check whether the commit id exists in the repo or apply the
293 // proposal and each patch to check
294 if let Ok(commit_id) = get_commit_id_from_patch(patch) {
295 state.insert(branch_name, commit_id);
296 }
297 }
298 }
299 }
300 }
301
302 // TODO 'for push' should we check with the git servers to see if any of them
303 // allow push from the user?
275 for (name, value) in state { 304 for (name, value) in state {
276 if value.starts_with("ref: ") { 305 if value.starts_with("ref: ") {
277 if !for_push { 306 if !for_push {
@@ -341,6 +370,67 @@ fn get_ahead_behind(
341 git_repo.get_commits_ahead_behind(&base, &latest) 370 git_repo.get_commits_ahead_behind(&base, &latest)
342} 371}
343 372
373async fn get_open_proposals(
374 git_repo: &Repo,
375 repo_ref: &RepoRef,
376) -> Result<HashMap<EventId, (Event, Vec<Event>)>> {
377 let git_repo_path = git_repo.get_path()?;
378 let proposals: Vec<nostr::Event> =
379 get_proposals_and_revisions_from_cache(git_repo_path, repo_ref.coordinates())
380 .await?
381 .iter()
382 .filter(|e| !event_is_revision_root(e))
383 .cloned()
384 .collect();
385
386 let statuses: Vec<nostr::Event> = {
387 let mut statuses = get_events_from_cache(
388 git_repo_path,
389 vec![
390 nostr::Filter::default()
391 .kinds(status_kinds().clone())
392 .events(proposals.iter().map(nostr::Event::id)),
393 ],
394 )
395 .await?;
396 statuses.sort_by_key(|e| e.created_at);
397 statuses.reverse();
398 statuses
399 };
400 let mut open_proposals = HashMap::new();
401
402 for proposal in proposals {
403 let status = if let Some(e) = statuses
404 .iter()
405 .filter(|e| {
406 status_kinds().contains(&e.kind())
407 && e.iter_tags()
408 .any(|t| t.as_vec()[1].eq(&proposal.id.to_string()))
409 })
410 .collect::<Vec<&nostr::Event>>()
411 .first()
412 {
413 e.kind()
414 } else {
415 Kind::GitStatusOpen
416 };
417 if status.eq(&Kind::GitStatusOpen) {
418 if let Ok(commits_events) =
419 get_all_proposal_patch_events_from_cache(git_repo_path, repo_ref, &proposal.id)
420 .await
421 {
422 if let Ok(most_recent_proposal_patch_chain) =
423 get_most_recent_patch_with_ancestors(commits_events.clone())
424 {
425 open_proposals
426 .insert(proposal.id(), (proposal, most_recent_proposal_patch_chain));
427 }
428 }
429 }
430 }
431 Ok(open_proposals)
432}
433
344fn fetch(git_repo: &Repository, repo_ref: &RepoRef, stdin: &Stdin, oid: &str) -> Result<()> { 434fn fetch(git_repo: &Repository, repo_ref: &RepoRef, stdin: &Stdin, oid: &str) -> Result<()> {
345 let oids = get_oids_from_fetch_batch(stdin, oid)?; 435 let oids = get_oids_from_fetch_batch(stdin, oid)?;
346 436