From 251d19ea254e40cd71e29c177ea6688cecc537a0 Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Fri, 1 Mar 2024 17:14:24 +0000 Subject: [PATCH 1/7] Add endpoint to run git fetch on outpack root --- Cargo.lock | 107 +++++++++++++++++ Cargo.toml | 4 +- git-utils/.gitignore | 3 + git-utils/Cargo.lock | 273 +++++++++++++++++++++++++++++++++++++++++++ git-utils/Cargo.toml | 10 ++ git-utils/README.md | 14 +++ git-utils/src/lib.rs | 152 ++++++++++++++++++++++++ src/api.rs | 20 +++- src/git.rs | 51 ++++++++ src/lib.rs | 1 + src/responses.rs | 15 ++- tests/test_api.rs | 52 ++++++++- 12 files changed, 688 insertions(+), 14 deletions(-) create mode 100644 git-utils/.gitignore create mode 100644 git-utils/Cargo.lock create mode 100644 git-utils/Cargo.toml create mode 100644 git-utils/README.md create mode 100644 git-utils/src/lib.rs create mode 100644 src/git.rs diff --git a/Cargo.lock b/Cargo.lock index 30d9718..515cb5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -336,6 +336,9 @@ name = "cc" version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] [[package]] name = "cfg-if" @@ -714,6 +717,29 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +[[package]] +name = "git-utils" +version = "0.1.0" +dependencies = [ + "git2", + "tempdir", +] + +[[package]] +name = "git2" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" +dependencies = [ + "bitflags 2.3.3", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + [[package]] name = "h2" version = "0.3.20" @@ -1024,6 +1050,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0aa48fab2893d8a49caa94082ae8488f4e1050d73b367881dcd2198f4199fd8" +[[package]] +name = "jobserver" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.64" @@ -1074,6 +1109,46 @@ version = "0.2.152" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +[[package]] +name = "libgit2-sys" +version = "0.16.2+1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" @@ -1288,6 +1363,24 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "outpack" version = "0.3.0" @@ -1299,6 +1392,8 @@ dependencies = [ "chrono", "clap", "futures", + "git-utils", + "git2", "itertools", "jsonschema", "lazy_static", @@ -1441,6 +1536,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2306,6 +2407,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "version_check" version = "0.9.4" diff --git a/Cargo.toml b/Cargo.toml index 8adf60b..a7652c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ tokio-util = { version = "0.7.10", features = ["io"] } futures = "0.3.30" tower = "0.4.13" mime = "0.3.17" +git2 = "0.18.2" [dev-dependencies] assert_cmd = "2.0.6" @@ -46,6 +47,7 @@ tar = "0.4.38" chrono = "0.4.33" rand = "0.8.5" tracing-capture = "0.1.0" +git-utils = { path = "git-utils" } [features] -python = [ "dep:pyo3" ] +python = ["dep:pyo3"] diff --git a/git-utils/.gitignore b/git-utils/.gitignore new file mode 100644 index 0000000..3db8680 --- /dev/null +++ b/git-utils/.gitignore @@ -0,0 +1,3 @@ +/target +/dist +.idea diff --git a/git-utils/Cargo.lock b/git-utils/Cargo.lock new file mode 100644 index 0000000..48a9d55 --- /dev/null +++ b/git-utils/Cargo.lock @@ -0,0 +1,273 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "cc" +version = "1.0.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" +dependencies = [ + "libc", +] + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "git-utils" +version = "0.1.0" +dependencies = [ + "git2", + "tempdir", +] + +[[package]] +name = "git2" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b3ba52851e73b46a4c3df1d89343741112003f0f6f13beb0dfac9e457c3fdcd" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "idna" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "libgit2-sys" +version = "0.16.2+1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee4126d8b4ee5c9d9ea891dd875cfdc1e9d0950437179104b183d7d8a74d24e8" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "log" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-sys" +version = "0.9.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand", + "remove_dir_all", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "url" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/git-utils/Cargo.toml b/git-utils/Cargo.toml new file mode 100644 index 0000000..7589c23 --- /dev/null +++ b/git-utils/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "git-utils" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +git2 = "0.18.2" +tempdir = "0.3.7" diff --git a/git-utils/README.md b/git-utils/README.md new file mode 100644 index 0000000..34da9cf --- /dev/null +++ b/git-utils/README.md @@ -0,0 +1,14 @@ +# git-utils + +This exists as a separate crate so that we can use it for test setup of both integration and unit tests in the main +outpack crate. + +There are also test utils in `outpack_server/src/test_utils.rs` It would be nice to move all test utils here but some of +the utils reference internals of the outpack crate which we cannot include here. + +Moving forward we should: + +* Put utils for integration and unit tests in this crate +* Put utils only for unit tests in `outpack_server/src/test_utils.rs` +* Put utils only for integration testing either here or in `tests` dir itself + diff --git a/git-utils/src/lib.rs b/git-utils/src/lib.rs new file mode 100644 index 0000000..b02a315 --- /dev/null +++ b/git-utils/src/lib.rs @@ -0,0 +1,152 @@ +use std::fs::File; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +use git2::{Branches, BranchType, Commit, Repository}; +use git2::build::RepoBuilder; +use tempdir::TempDir; + +pub struct TestGit { + pub dir: PathBuf, + pub remote: Repository, + pub local: Repository, +} + +// Initialise a git repo with a remote in the state that +// remote - 3 commits, initial, first commit, second commit +// local - 2 commits, initial, first commit +// So that if we fetch on local then it should know about the second file +pub fn initialise_git_repo(path: Option<&PathBuf>) -> TestGit { + let tmp_dir = TempDir::new("repo").expect("Temp dir created").into_path(); + let remote_path = tmp_dir.join("remote"); + let local_path = tmp_dir.join("local"); + match path { + Some(p) => copy_recursively(p, &remote_path), + None => std::fs::create_dir(&remote_path), + }.unwrap(); + std::fs::create_dir(&local_path).unwrap(); + + let remote = Repository::init(&remote_path).unwrap(); + create_initial_commit(&remote); + create_file(&remote_path, "new_file"); + git_add_all(&remote); + git_commit(&remote, "First commit"); + + let local = git_clone_local(&remote, &local_path); + + create_file(&remote_path, "new_file2"); + git_add_all(&remote); + git_commit(&remote, "Second commit"); + + git_checkout(&remote, "other", true); + create_file(&remote_path, "new_file3"); + git_add_all(&remote); + git_commit(&remote, "Third commit"); + git_checkout(&remote, "main", false); + + TestGit { + dir: tmp_dir, + remote, + local, + } +} + +/// Copy files from source to destination recursively. +/// From https://nick.groenen.me/notes/recursively-copy-files-in-rust/ +pub fn copy_recursively( + source: impl AsRef, + destination: impl AsRef, +) -> std::io::Result<()> { + std::fs::create_dir_all(&destination)?; + for entry in std::fs::read_dir(source)? { + let entry = entry?; + let filetype = entry.file_type()?; + if filetype.is_dir() { + copy_recursively(entry.path(), destination.as_ref().join(entry.file_name()))?; + } else { + std::fs::copy(entry.path(), destination.as_ref().join(entry.file_name()))?; + } + } + Ok(()) +} + +fn create_file(repo_path: &Path, file_name: &str) { + let mut file = File::create(repo_path.join(file_name)).unwrap(); + file.write_all(b"File contents").unwrap(); +} + +fn create_initial_commit(repo: &Repository) { + let signature = repo.signature().unwrap(); + let tree_id = { + let mut index = repo.index().unwrap(); + index.write_tree().unwrap() + }; + let tree = repo.find_tree(tree_id).unwrap(); + repo.commit( + Some("HEAD"), + &signature, + &signature, + "Initial commit", + &tree, + &[], + ) + .unwrap(); +} + +fn git_add_all(repo: &Repository) { + let mut index = repo.index().unwrap(); + index + .add_all(["."], git2::IndexAddOption::DEFAULT, None) + .unwrap(); + index.write().unwrap(); +} + +fn git_commit(repo: &Repository, message: &str) { + let mut index = repo.index().unwrap(); + let oid = index.write_tree().unwrap(); + let signature = repo.signature().unwrap(); + let parent_commit = repo.head().unwrap().peel_to_commit().unwrap(); + let tree = repo.find_tree(oid).unwrap(); + repo.commit( + Some("HEAD"), + &signature, + &signature, + message, + &tree, + &[&parent_commit], + ) + .unwrap(); +} + +fn git_clone_local(from: &Repository, to: &Path) -> Repository { + let mut builder = RepoBuilder::new(); + builder.clone(from.path().to_str().unwrap(), to).unwrap() +} + +pub fn git_get_latest_commit<'a>(repo: &'a Repository, reference: &str) -> Commit<'a> { + repo.find_reference(reference) + .unwrap() + .resolve() + .unwrap() + .peel_to_commit() + .unwrap() +} + +fn git_checkout(repo: &Repository, branch_name: &str, new_branch: bool) { + if new_branch { + let head = repo.head().unwrap(); + let oid = head.target().unwrap(); + let commit = repo.find_commit(oid).unwrap(); + repo.branch(branch_name, &commit, false).unwrap(); + } + + let (object, reference) = repo.revparse_ext(branch_name).expect("Branch not found"); + repo.checkout_tree(&object, None).unwrap(); + // Checkout tree only sets contents of working tree, we need to set HEAD too + // otherwise we leave git ina dirty state + repo.set_head(reference.unwrap().name().unwrap()).unwrap(); +} + +pub fn git_remote_branches(repo: &Repository) -> Branches { + repo.branches(Some(BranchType::Remote)).unwrap() +} diff --git a/src/api.rs b/src/api.rs index 00f1c11..15041d2 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,3 +1,7 @@ +use std::any::Any; +use std::io::ErrorKind; +use std::path::{Path, PathBuf}; + use anyhow::{bail, Context}; use axum::extract::rejection::JsonRejection; use axum::extract::{self, Query, State}; @@ -5,23 +9,19 @@ use axum::response::IntoResponse; use axum::response::Response; use axum::{Json, Router}; use serde::{Deserialize, Serialize}; -use std::any::Any; -use std::io::ErrorKind; -use std::path::{Path, PathBuf}; use tower_http::catch_panic::CatchPanicLayer; use tower_http::request_id::{MakeRequestUuid, PropagateRequestIdLayer, SetRequestIdLayer}; use tower_http::trace::TraceLayer; -use crate::config; use crate::hash; use crate::location; use crate::metadata; use crate::metrics; -use crate::store; - use crate::outpack_file::OutpackFile; use crate::responses::{OutpackError, OutpackSuccess}; +use crate::store; use crate::upload::{Upload, UploadLayer}; +use crate::{config, git}; type OutpackResult = Result, OutpackError>; @@ -68,6 +68,7 @@ async fn list_location_metadata( struct KnownSince { known_since: Option, } + async fn get_metadata_since( root: State, query: Query, @@ -156,6 +157,12 @@ async fn add_packet( .map(OutpackSuccess::from) } +async fn git_fetch(root: State) -> Result, OutpackError> { + git::git_fetch(&root) + .map_err(OutpackError::from) + .map(OutpackSuccess::from) +} + #[derive(Serialize, Deserialize)] struct Ids { ids: Vec, @@ -236,6 +243,7 @@ pub fn api(root: &Path) -> anyhow::Result { .route("/packit/metadata", get(get_metadata_since)) .route("/file/:hash", get(get_file).post(add_file)) .route("/packet/:hash", post(add_packet)) + .route("/git/fetch", post(git_fetch)) .route("/metrics", get(|| async move { metrics::render(registry) })) .fallback(not_found) .with_state(root.to_owned()); diff --git a/src/git.rs b/src/git.rs new file mode 100644 index 0000000..b6caad5 --- /dev/null +++ b/src/git.rs @@ -0,0 +1,51 @@ +use std::path::Path; + +use git2::Repository; + +pub fn git_fetch(root: &Path) -> Result<(), git2::Error> { + let repo = Repository::open(root)?; + let mut remote = repo + .find_remote("origin") + .expect("Failed to find remote 'origin'"); + let ref_specs_iter = remote + .fetch_refspecs() + .expect("Failed to get remotes ref specs"); + let ref_specs: Vec<&str> = ref_specs_iter.iter().map(|spec| spec.unwrap()).collect(); + remote + .fetch(&ref_specs, None, None) + .expect("Failed to fetch"); + Ok(()) +} + +#[cfg(test)] +mod tests { + use git_utils::{git_get_latest_commit, git_remote_branches, initialise_git_repo}; + + use super::*; + + #[test] + fn can_perform_git_fetch() { + let test_git = initialise_git_repo(None); + + let remote_ref = git_get_latest_commit(&test_git.remote, "HEAD"); + let initial_ref = git_get_latest_commit(&test_git.local, "refs/remotes/origin/HEAD"); + assert_ne!( + initial_ref.message().unwrap(), + remote_ref.message().unwrap() + ); + + let initial_branches = git_remote_branches(&test_git.local); + assert_eq!(initial_branches.count(), 2); // HEAD and main + + git_fetch(&test_git.dir.join("local")).unwrap(); + + let post_fetch_ref = git_get_latest_commit(&test_git.local, "refs/remotes/origin/HEAD"); + assert_eq!( + post_fetch_ref.message().unwrap(), + remote_ref.message().unwrap() + ); + + let post_fetch_branches = git_remote_branches(&test_git.local); + assert_eq!(post_fetch_branches.count(), 3); // HEAD, main and other + } +} diff --git a/src/lib.rs b/src/lib.rs index c252f0b..f1f28b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ pub mod index; pub mod init; pub mod query; +mod git; mod hash; mod location; mod metadata; diff --git a/src/responses.rs b/src/responses.rs index 6f9f147..78cee1b 100644 --- a/src/responses.rs +++ b/src/responses.rs @@ -1,8 +1,9 @@ +use std::io; +use std::io::ErrorKind; + use axum::extract::rejection::JsonRejection; use axum::http::StatusCode; use serde::{Deserialize, Serialize}; -use std::io; -use std::io::ErrorKind; use crate::hash; @@ -55,6 +56,16 @@ impl From for OutpackError { } } +impl From for OutpackError { + fn from(e: git2::Error) -> Self { + OutpackError { + error: e.message().to_string(), + detail: format!("{:?}", e.code()), + kind: Some(std::io::ErrorKind::Other), + } + } +} + #[derive(Serialize, Deserialize, Debug)] pub struct SuccessResponse { pub status: String, diff --git a/tests/test_api.rs b/tests/test_api.rs index e76839e..46dd6fc 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -1,17 +1,19 @@ +use std::fs; +use std::fs::File; +use std::path::{Path, PathBuf}; +use std::sync::Arc; +use std::sync::Once; + use axum::body::Body; use axum::extract::Request; use axum::http::header::CONTENT_TYPE; use axum::http::StatusCode; use axum::response::Response; +use git_utils::{git_get_latest_commit, git_remote_branches, initialise_git_repo}; use jsonschema::{Draft, JSONSchema, SchemaResolverError}; use serde::{Deserialize, Serialize}; use serde_json::Value; use sha2::{Digest, Sha256}; -use std::fs; -use std::fs::File; -use std::path::{Path, PathBuf}; -use std::sync::Arc; -use std::sync::Once; use tar::Archive; use tar::Builder; use tempdir::TempDir; @@ -727,6 +729,46 @@ async fn request_id_is_logged() { .single(&message(eq("finished processing request"))); } +#[tokio::test] +async fn can_fetch_git() { + let test_dir = get_test_dir(); + let test_git = initialise_git_repo(Some(&test_dir)); + let mut client = TestClient::new(test_git.dir.join("local")); + + let remote_ref = git_get_latest_commit(&test_git.remote, "HEAD"); + let initial_ref = git_get_latest_commit(&test_git.local, "refs/remotes/origin/HEAD"); + assert_ne!( + initial_ref.message().unwrap(), + remote_ref.message().unwrap() + ); + + let initial_branches = git_remote_branches(&test_git.local); + assert_eq!(initial_branches.count(), 2); // HEAD and main + + let response = client + .post("/git/fetch", mime::APPLICATION_JSON, Body::empty()) + .await; + assert_eq!(response.status(), StatusCode::OK); + assert_eq!(response.content_type(), mime::APPLICATION_JSON); + + let body = response.to_json().await; + validate_success("server", "null-response.json", &body); + + body.get("data") + .expect("Data property present") + .as_null() + .expect("Null data"); + + let post_fetch_ref = git_get_latest_commit(&test_git.local, "refs/remotes/origin/HEAD"); + assert_eq!( + post_fetch_ref.message().unwrap(), + remote_ref.message().unwrap() + ); + + let post_fetch_branches = git_remote_branches(&test_git.local); + assert_eq!(post_fetch_branches.count(), 3); // HEAD, main and other +} + fn validate_success(schema_group: &str, schema_name: &str, instance: &Value) { let compiled_schema = get_schema("server", "response-success.json"); assert_valid(instance, &compiled_schema); From 37e505b813d6e3830968681deeb44708321b7e7b Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Fri, 1 Mar 2024 17:49:05 +0000 Subject: [PATCH 2/7] Set signature manually so works on gh actions --- git-utils/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/git-utils/src/lib.rs b/git-utils/src/lib.rs index b02a315..b7c0457 100644 --- a/git-utils/src/lib.rs +++ b/git-utils/src/lib.rs @@ -2,7 +2,7 @@ use std::fs::File; use std::io::prelude::*; use std::path::{Path, PathBuf}; -use git2::{Branches, BranchType, Commit, Repository}; +use git2::{Branches, BranchType, Commit, Repository, Signature}; use git2::build::RepoBuilder; use tempdir::TempDir; @@ -76,7 +76,7 @@ fn create_file(repo_path: &Path, file_name: &str) { } fn create_initial_commit(repo: &Repository) { - let signature = repo.signature().unwrap(); + let signature = Signature::now("Test User", "test.user@example.com").unwrap(); let tree_id = { let mut index = repo.index().unwrap(); index.write_tree().unwrap() @@ -93,6 +93,7 @@ fn create_initial_commit(repo: &Repository) { .unwrap(); } + fn git_add_all(repo: &Repository) { let mut index = repo.index().unwrap(); index @@ -104,7 +105,7 @@ fn git_add_all(repo: &Repository) { fn git_commit(repo: &Repository, message: &str) { let mut index = repo.index().unwrap(); let oid = index.write_tree().unwrap(); - let signature = repo.signature().unwrap(); + let signature = Signature::now("Test User", "test.user@example.com").unwrap(); let parent_commit = repo.head().unwrap().peel_to_commit().unwrap(); let tree = repo.find_tree(oid).unwrap(); repo.commit( From b7ea8c4c4bc4766efae0d14c29c54ddffd873da4 Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Mon, 4 Mar 2024 10:15:11 +0000 Subject: [PATCH 3/7] Remove reference to main in tests, use existing branch name instead --- git-utils/src/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/git-utils/src/lib.rs b/git-utils/src/lib.rs index b7c0457..9d3ace0 100644 --- a/git-utils/src/lib.rs +++ b/git-utils/src/lib.rs @@ -38,11 +38,12 @@ pub fn initialise_git_repo(path: Option<&PathBuf>) -> TestGit { git_add_all(&remote); git_commit(&remote, "Second commit"); + let default_branch = git_branch(&remote); git_checkout(&remote, "other", true); create_file(&remote_path, "new_file3"); git_add_all(&remote); git_commit(&remote, "Third commit"); - git_checkout(&remote, "main", false); + git_checkout(&remote, &default_branch, false); TestGit { dir: tmp_dir, @@ -133,6 +134,12 @@ pub fn git_get_latest_commit<'a>(repo: &'a Repository, reference: &str) -> Commi .unwrap() } +fn git_branch(repo: &Repository) -> String { + let head = repo.head().unwrap(); + let branch_name = head.shorthand().unwrap(); + branch_name.to_string() +} + fn git_checkout(repo: &Repository, branch_name: &str, new_branch: bool) { if new_branch { let head = repo.head().unwrap(); From 4c0143bc382baf0f33f45a4050fa374a8a521846 Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Mon, 4 Mar 2024 10:54:47 +0000 Subject: [PATCH 4/7] Fix python binding build failures Since adding git2 crate we now have a dependency on OpenSSL which isn't immediately available in the manylinux containers. Fix this by * Using vendored version of OpenSSL * Install perl on RHEL targets --- .github/workflows/python.yaml | 41 ++++++++++++++++++++++------------- Cargo.lock | 10 +++++++++ Cargo.toml | 3 ++- git-utils/Cargo.lock | 10 +++++++++ git-utils/Cargo.toml | 5 ++++- src/query/python.rs | 2 +- 6 files changed, 53 insertions(+), 18 deletions(-) diff --git a/.github/workflows/python.yaml b/.github/workflows/python.yaml index 6983612..24c9d0d 100644 --- a/.github/workflows/python.yaml +++ b/.github/workflows/python.yaml @@ -60,13 +60,13 @@ jobs: fail-fast: false matrix: config: - - {os: ubuntu-latest, target: 'x86_64'} - - {os: ubuntu-latest, target: 'x86'} - - {os: ubuntu-latest, target: 'aarch64'} - - {os: windows-latest, target: 'x64'} - - {os: windows-latest, target: 'x86'} - - {os: macos-latest, target: 'x86_64'} - - {os: macos-latest, target: 'aarch64'} + - { os: ubuntu-latest, target: 'x86_64' } + - { os: ubuntu-latest, target: 'x86' } + - { os: ubuntu-latest, target: 'aarch64' } + - { os: windows-latest, target: 'x64' } + - { os: windows-latest, target: 'x86' } + - { os: macos-latest, target: 'x86_64' } + - { os: macos-latest, target: 'aarch64' } runs-on: ${{ matrix.config.os }} name: Build wheels for ${{ matrix.config.os }} (${{ matrix.config.target }}) @@ -82,8 +82,19 @@ jobs: uses: PyO3/maturin-action@v1 with: target: ${{ matrix.config.target }} - args: --release --out dist + args: --release --out dist --features openssl-vendored manylinux: manylinux2014 + before-script-linux: | + # If we're running on RHEL centos, install needed packages. + if command -v yum &> /dev/null; then + yum update -y && yum install -y perl-core libatomic + + # If we're running on i686 we need to symlink libatomic + # in order to build openssl with -latomic flag. + if [[ ! -d "/usr/lib64" ]]; then + ln -s /usr/lib/libatomic.so.1 /usr/lib/libatomic.so + fi + fi - name: Upload artifacts uses: actions/upload-artifact@v3 with: @@ -107,10 +118,10 @@ jobs: # This permission is needed for the workflow to authenticate against PyPI id-token: write steps: - - name: Download all the dists - uses: actions/download-artifact@v3 - with: - name: python-artifacts - path: dist/ - - name: Publish distribution to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 + - name: Download all the dists + uses: actions/download-artifact@v3 + with: + name: python-artifacts + path: dist/ + - name: Publish distribution to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/Cargo.lock b/Cargo.lock index 515cb5c..b5d875d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1369,6 +1369,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.1.6+3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.101" @@ -1377,6 +1386,7 @@ checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] diff --git a/Cargo.toml b/Cargo.toml index a7652c0..2071f1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ tokio-util = { version = "0.7.10", features = ["io"] } futures = "0.3.30" tower = "0.4.13" mime = "0.3.17" -git2 = "0.18.2" +git2 = { version = "0.18.2" } [dev-dependencies] assert_cmd = "2.0.6" @@ -51,3 +51,4 @@ git-utils = { path = "git-utils" } [features] python = ["dep:pyo3"] +openssl-vendored = ["git2/vendored-openssl"] diff --git a/git-utils/Cargo.lock b/git-utils/Cargo.lock index 48a9d55..90d77c8 100644 --- a/git-utils/Cargo.lock +++ b/git-utils/Cargo.lock @@ -123,6 +123,15 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-src" +version = "300.1.6+3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439fac53e092cd7442a3660c85dde4643ab3b5bd39040912388dcdabf6b88085" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.101" @@ -131,6 +140,7 @@ checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] diff --git a/git-utils/Cargo.toml b/git-utils/Cargo.toml index 7589c23..c16a8fa 100644 --- a/git-utils/Cargo.toml +++ b/git-utils/Cargo.toml @@ -6,5 +6,8 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -git2 = "0.18.2" +git2 = { version = "0.18.2" } tempdir = "0.3.7" + +[features] +openssl-vendored = ["git2/vendored-openssl"] diff --git a/src/query/python.rs b/src/query/python.rs index 33852d4..7f5918a 100644 --- a/src/query/python.rs +++ b/src/query/python.rs @@ -97,7 +97,7 @@ enum TestOperator { } #[pyfunction] -fn parse_query<'a>(py: Python, input: &'a str) -> PyResult { +fn parse_query(py: Python, input: &str) -> PyResult { convert_query(py, crate::query::parse_query(input)?) } From 769ea43ccf7ebdf8de5bfcadefad977c71a28515 Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Wed, 20 Mar 2024 15:20:26 +0000 Subject: [PATCH 5/7] Rename git-utils helper to more general test-utils --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 2 +- src/git.rs | 2 +- {git-utils => test-utils}/.gitignore | 0 {git-utils => test-utils}/Cargo.lock | 16 ++++++++-------- {git-utils => test-utils}/Cargo.toml | 2 +- {git-utils => test-utils}/README.md | 2 +- {git-utils => test-utils}/src/lib.rs | 0 tests/test_api.rs | 7 ++++--- 9 files changed, 25 insertions(+), 24 deletions(-) rename {git-utils => test-utils}/.gitignore (100%) rename {git-utils => test-utils}/Cargo.lock (99%) rename {git-utils => test-utils}/Cargo.toml (92%) rename {git-utils => test-utils}/README.md (97%) rename {git-utils => test-utils}/src/lib.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index b5d875d..ece38a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -717,14 +717,6 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -[[package]] -name = "git-utils" -version = "0.1.0" -dependencies = [ - "git2", - "tempdir", -] - [[package]] name = "git2" version = "0.18.2" @@ -1402,7 +1394,6 @@ dependencies = [ "chrono", "clap", "futures", - "git-utils", "git2", "itertools", "jsonschema", @@ -1423,6 +1414,7 @@ dependencies = [ "tar", "tempdir", "tempfile", + "test-utils", "thiserror", "tokio", "tokio-util", @@ -2098,6 +2090,14 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" +[[package]] +name = "test-utils" +version = "0.1.0" +dependencies = [ + "git2", + "tempdir", +] + [[package]] name = "thiserror" version = "1.0.50" diff --git a/Cargo.toml b/Cargo.toml index 2071f1e..4c87ceb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,7 +47,7 @@ tar = "0.4.38" chrono = "0.4.33" rand = "0.8.5" tracing-capture = "0.1.0" -git-utils = { path = "git-utils" } +test-utils = { path = "test-utils" } [features] python = ["dep:pyo3"] diff --git a/src/git.rs b/src/git.rs index b6caad5..af2fe86 100644 --- a/src/git.rs +++ b/src/git.rs @@ -19,7 +19,7 @@ pub fn git_fetch(root: &Path) -> Result<(), git2::Error> { #[cfg(test)] mod tests { - use git_utils::{git_get_latest_commit, git_remote_branches, initialise_git_repo}; + use test_utils::{git_get_latest_commit, git_remote_branches, initialise_git_repo}; use super::*; diff --git a/git-utils/.gitignore b/test-utils/.gitignore similarity index 100% rename from git-utils/.gitignore rename to test-utils/.gitignore diff --git a/git-utils/Cargo.lock b/test-utils/Cargo.lock similarity index 99% rename from git-utils/Cargo.lock rename to test-utils/Cargo.lock index 90d77c8..66cd010 100644 --- a/git-utils/Cargo.lock +++ b/test-utils/Cargo.lock @@ -32,14 +32,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -[[package]] -name = "git-utils" -version = "0.1.0" -dependencies = [ - "git2", - "tempdir", -] - [[package]] name = "git2" version = "0.18.2" @@ -213,6 +205,14 @@ dependencies = [ "remove_dir_all", ] +[[package]] +name = "test-utils" +version = "0.1.0" +dependencies = [ + "git2", + "tempdir", +] + [[package]] name = "tinyvec" version = "1.6.0" diff --git a/git-utils/Cargo.toml b/test-utils/Cargo.toml similarity index 92% rename from git-utils/Cargo.toml rename to test-utils/Cargo.toml index c16a8fa..4afd7af 100644 --- a/git-utils/Cargo.toml +++ b/test-utils/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "git-utils" +name = "test-utils" version = "0.1.0" edition = "2021" diff --git a/git-utils/README.md b/test-utils/README.md similarity index 97% rename from git-utils/README.md rename to test-utils/README.md index 34da9cf..7b2de79 100644 --- a/git-utils/README.md +++ b/test-utils/README.md @@ -1,4 +1,4 @@ -# git-utils +# test-utils This exists as a separate crate so that we can use it for test setup of both integration and unit tests in the main outpack crate. diff --git a/git-utils/src/lib.rs b/test-utils/src/lib.rs similarity index 100% rename from git-utils/src/lib.rs rename to test-utils/src/lib.rs diff --git a/tests/test_api.rs b/tests/test_api.rs index 46dd6fc..ce5a4ba 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -9,7 +9,6 @@ use axum::extract::Request; use axum::http::header::CONTENT_TYPE; use axum::http::StatusCode; use axum::response::Response; -use git_utils::{git_get_latest_commit, git_remote_branches, initialise_git_repo}; use jsonschema::{Draft, JSONSchema, SchemaResolverError}; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -23,6 +22,8 @@ use tracing_capture::{CaptureLayer, SharedStorage}; use tracing_subscriber::{layer::SubscriberExt, Registry}; use url::Url; +use test_utils::{git_get_latest_commit, git_remote_branches, initialise_git_repo}; + static INIT: Once = Once::new(); pub fn initialize() { @@ -82,7 +83,7 @@ impl TestClient { mime::APPLICATION_JSON, serde_json::to_vec(data).unwrap(), ) - .await + .await } } @@ -344,7 +345,7 @@ async fn can_get_metadata_text() { let expected = fs::File::open(Path::new( "tests/example/.outpack/metadata/20180818-164043-7cdcde4b", )) - .unwrap(); + .unwrap(); let result: Value = response.to_json().await; let expected: Value = serde_json::from_reader(expected).unwrap(); From b311bcd72caafe731567d68bb253f6f8b64cf13e Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Wed, 20 Mar 2024 16:41:06 +0000 Subject: [PATCH 6/7] Avoid using into_path so tempdir is properly cleaned up --- src/git.rs | 2 +- test-utils/src/lib.rs | 13 +++++-------- tests/test_api.rs | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/git.rs b/src/git.rs index af2fe86..4ced179 100644 --- a/src/git.rs +++ b/src/git.rs @@ -37,7 +37,7 @@ mod tests { let initial_branches = git_remote_branches(&test_git.local); assert_eq!(initial_branches.count(), 2); // HEAD and main - git_fetch(&test_git.dir.join("local")).unwrap(); + git_fetch(&test_git.dir.path().join("local")).unwrap(); let post_fetch_ref = git_get_latest_commit(&test_git.local, "refs/remotes/origin/HEAD"); assert_eq!( diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 9d3ace0..cf46cba 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -1,5 +1,3 @@ -use std::fs::File; -use std::io::prelude::*; use std::path::{Path, PathBuf}; use git2::{Branches, BranchType, Commit, Repository, Signature}; @@ -7,7 +5,7 @@ use git2::build::RepoBuilder; use tempdir::TempDir; pub struct TestGit { - pub dir: PathBuf, + pub dir: TempDir, pub remote: Repository, pub local: Repository, } @@ -17,9 +15,9 @@ pub struct TestGit { // local - 2 commits, initial, first commit // So that if we fetch on local then it should know about the second file pub fn initialise_git_repo(path: Option<&PathBuf>) -> TestGit { - let tmp_dir = TempDir::new("repo").expect("Temp dir created").into_path(); - let remote_path = tmp_dir.join("remote"); - let local_path = tmp_dir.join("local"); + let tmp_dir = TempDir::new("repo").expect("Temp dir created"); + let remote_path = tmp_dir.path().join("remote"); + let local_path = tmp_dir.path().join("local"); match path { Some(p) => copy_recursively(p, &remote_path), None => std::fs::create_dir(&remote_path), @@ -72,8 +70,7 @@ pub fn copy_recursively( } fn create_file(repo_path: &Path, file_name: &str) { - let mut file = File::create(repo_path.join(file_name)).unwrap(); - file.write_all(b"File contents").unwrap(); + std::fs::write(repo_path.join(file_name), b"File contents").unwrap(); } fn create_initial_commit(repo: &Repository) { diff --git a/tests/test_api.rs b/tests/test_api.rs index ce5a4ba..6ab44b1 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -734,7 +734,7 @@ async fn request_id_is_logged() { async fn can_fetch_git() { let test_dir = get_test_dir(); let test_git = initialise_git_repo(Some(&test_dir)); - let mut client = TestClient::new(test_git.dir.join("local")); + let mut client = TestClient::new(test_git.dir.path().join("local")); let remote_ref = git_get_latest_commit(&test_git.remote, "HEAD"); let initial_ref = git_get_latest_commit(&test_git.local, "refs/remotes/origin/HEAD"); From b17918d2c65dafae6cf1c77b206f6c2a2b04b571 Mon Sep 17 00:00:00 2001 From: Rob Ashton Date: Wed, 20 Mar 2024 16:46:41 +0000 Subject: [PATCH 7/7] Return errors instead of panic in impl --- src/git.rs | 12 +++--------- tests/test_api.rs | 4 ++-- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/src/git.rs b/src/git.rs index 4ced179..7a45e33 100644 --- a/src/git.rs +++ b/src/git.rs @@ -4,16 +4,10 @@ use git2::Repository; pub fn git_fetch(root: &Path) -> Result<(), git2::Error> { let repo = Repository::open(root)?; - let mut remote = repo - .find_remote("origin") - .expect("Failed to find remote 'origin'"); - let ref_specs_iter = remote - .fetch_refspecs() - .expect("Failed to get remotes ref specs"); + let mut remote = repo.find_remote("origin")?; + let ref_specs_iter = remote.fetch_refspecs()?; let ref_specs: Vec<&str> = ref_specs_iter.iter().map(|spec| spec.unwrap()).collect(); - remote - .fetch(&ref_specs, None, None) - .expect("Failed to fetch"); + remote.fetch(&ref_specs, None, None)?; Ok(()) } diff --git a/tests/test_api.rs b/tests/test_api.rs index 6ab44b1..c68133d 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -83,7 +83,7 @@ impl TestClient { mime::APPLICATION_JSON, serde_json::to_vec(data).unwrap(), ) - .await + .await } } @@ -345,7 +345,7 @@ async fn can_get_metadata_text() { let expected = fs::File::open(Path::new( "tests/example/.outpack/metadata/20180818-164043-7cdcde4b", )) - .unwrap(); + .unwrap(); let result: Value = response.to_json().await; let expected: Value = serde_json::from_reader(expected).unwrap();