| 59 | 59 | | } |
| 60 | 60 | | if let Some(refs) = advertised { |
| 61 | 61 | | let at = |name: &str| refs.iter().find(|(advertised, _)| advertised == name).map(|(_, hash)| hash.clone()); |
| 62 | | − | return Ok(match at(&pushed.git_ref) { |
| 63 | | − | Some(hash) if hash == pushed.after => Some(at(&format!("{}^{{}}", pushed.git_ref)).unwrap_or(hash)), |
| 64 | | − | // Not there, or left elsewhere: the store refused it. |
| 65 | | − | _ => None, |
| 66 | | − | }); |
| 62 | + | match at(&pushed.git_ref) { |
| 63 | + | Some(hash) if hash == pushed.after => { |
| 64 | + | return Ok(Some(at(&format!("{}^{{}}", pushed.git_ref)).or_else(|| pushed.peeled.clone()).unwrap_or(hash))); |
| 65 | + | } |
| 66 | + | // Left elsewhere: the store refused it. |
| 67 | + | Some(_) => return Ok(None), |
| 68 | + | // Not advertised yet, right after the push (v0.0.0-tagtest2): |
| 69 | + | // the pack's own tag object says where it leads. |
| 70 | + | None => { |
| 71 | + | if let Some(commit) = &pushed.peeled { |
| 72 | + | return Ok(Some(commit.clone())); |
| 73 | + | } |
| 74 | + | } |
| 75 | + | } |
| 76 | + | } else if let Some(commit) = &pushed.peeled { |
| 77 | + | return Ok(Some(commit.clone())); |
| 67 | 78 | | } |
| 68 | 79 | | let Ok(head) = git.log(&pushed.git_ref, 1).await else { |
| 69 | 80 | | return Ok(Some(pushed.after.clone())); |
| ⋯ |
| 332 | 343 | | } |
| 333 | 344 | | |
| 334 | 345 | | fn push(git_ref: &str, before: Option<&str>, after: &str) -> crate::git_http::Pushed { |
| 335 | | − | crate::git_http::Pushed { git_ref: git_ref.into(), before: before.map(str::to_owned), after: after.into() } |
| 346 | + | crate::git_http::Pushed { git_ref: git_ref.into(), before: before.map(str::to_owned), after: after.into(), peeled: None } |
| 336 | 347 | | } |
| 337 | 348 | | |
| 349 | + | #[test] |
| 350 | + | fn an_annotated_tag_not_yet_advertised_is_announced_at_the_commit_its_pack_names() { |
| 351 | + | // `git push origin v0.0.0-tagtest2`: the store neither logs nor |
| 352 | + | // advertises the new tag yet; its object in the pack names main. |
| 353 | + | let git = with_refs(&[("main", "m2")]); |
| 354 | + | let refs = advertised(&[("refs/heads/main", "m2")]); |
| 355 | + | let tag = crate::git_http::Pushed { peeled: Some("m2".into()), ..push("refs/tags/v0.0.0-tagtest2", None, "430024c2") }; |
| 356 | + | assert_eq!(run(pushed_to(&git, &tag, Some(&refs))).unwrap().as_deref(), Some("m2")); |
| 357 | + | assert_eq!(run(pushed_to(&git, &tag, None)).unwrap().as_deref(), Some("m2")); |
| 358 | + | } |
| 359 | + | |
| 338 | 360 | | fn with_refs(refs: &[(&str, &str)]) -> Fake { |
| 339 | 361 | | Fake { refs: refs.iter().map(|&(name, at)| (name.to_owned(), at.to_owned())).collect(), ..Fake::with(history()) } |
| 340 | 362 | | } |
| ⋯ |
| 366 | 388 | | // A lightweight tag has no peeled line: it is its commit. |
| 367 | 389 | | let refs = advertised(&[("refs/tags/v1", "f2")]); |
| 368 | 390 | | assert_eq!(run(pushed_to(&git, &push("refs/tags/v1", None, "f2"), Some(&refs))).unwrap().as_deref(), Some("f2")); |
| 369 | | − | // Left elsewhere, or not there at all: refused. |
| 391 | + | // Left elsewhere: refused. |
| 370 | 392 | | assert_eq!(run(pushed_to(&git, &push("refs/tags/v1", Some("f2"), "m1"), Some(&refs))).unwrap(), None); |
| 371 | | − | assert_eq!(run(pushed_to(&git, &push("refs/tags/v2", None, "m1"), Some(&refs))).unwrap(), None); |
| 393 | + | // Not advertised yet, with nothing peeled: the log decides, as before. |
| 394 | + | assert_eq!(run(pushed_to(&git, &push("refs/tags/v2", None, "m1"), Some(&refs))).unwrap().as_deref(), Some("m1")); |
| 372 | 395 | | } |
| 373 | 396 | | |
| 374 | 397 | | #[test] |