refactor: merge core crate into cli crate
This commit is contained in:
parent
c8cc45ca7f
commit
e5a5e508ff
160 changed files with 888 additions and 1113 deletions
32
Cargo.lock
generated
32
Cargo.lock
generated
|
@ -1070,7 +1070,8 @@ dependencies = [
|
||||||
"derive_more",
|
"derive_more",
|
||||||
"directories",
|
"directories",
|
||||||
"git-conventional",
|
"git-conventional",
|
||||||
"git-next-core",
|
"git-url-parse",
|
||||||
|
"gix",
|
||||||
"hex",
|
"hex",
|
||||||
"hmac",
|
"hmac",
|
||||||
"kameo",
|
"kameo",
|
||||||
|
@ -1080,6 +1081,7 @@ dependencies = [
|
||||||
"mockall",
|
"mockall",
|
||||||
"notifica",
|
"notifica",
|
||||||
"notify",
|
"notify",
|
||||||
|
"pike",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"rand",
|
"rand",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
@ -1091,6 +1093,7 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sha2",
|
"sha2",
|
||||||
"standardwebhooks",
|
"standardwebhooks",
|
||||||
|
"take-until",
|
||||||
"test-log",
|
"test-log",
|
||||||
"thiserror 2.0.11",
|
"thiserror 2.0.11",
|
||||||
"time",
|
"time",
|
||||||
|
@ -1104,33 +1107,6 @@ dependencies = [
|
||||||
"warp",
|
"warp",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "git-next-core"
|
|
||||||
version = "0.14.1"
|
|
||||||
dependencies = [
|
|
||||||
"assert2",
|
|
||||||
"async-trait",
|
|
||||||
"derive-with",
|
|
||||||
"derive_more",
|
|
||||||
"git-url-parse",
|
|
||||||
"gix",
|
|
||||||
"kxio",
|
|
||||||
"mockall",
|
|
||||||
"pike",
|
|
||||||
"pretty_assertions",
|
|
||||||
"rand",
|
|
||||||
"secrecy",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"take-until",
|
|
||||||
"test-log",
|
|
||||||
"thiserror 2.0.11",
|
|
||||||
"time",
|
|
||||||
"toml",
|
|
||||||
"tracing",
|
|
||||||
"ulid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "git-url-parse"
|
name = "git-url-parse"
|
||||||
version = "0.4.5"
|
version = "0.4.5"
|
||||||
|
|
|
@ -22,7 +22,6 @@ categories = ["development-tools"]
|
||||||
# expect_used = "warn"
|
# expect_used = "warn"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
git-next-core = { path = "crates/core", version = "0.14" }
|
|
||||||
|
|
||||||
# TUI
|
# TUI
|
||||||
ratatui = "0.29"
|
ratatui = "0.29"
|
||||||
|
@ -59,6 +58,7 @@ git-url-parse = "0.4"
|
||||||
|
|
||||||
# fs/network
|
# fs/network
|
||||||
kxio = "5.1"
|
kxio = "5.1"
|
||||||
|
# kxio = { path = "../kxio/" }
|
||||||
|
|
||||||
# TOML parsing
|
# TOML parsing
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
|
|
@ -26,7 +26,6 @@ tui = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
git-next-core = { workspace = true }
|
|
||||||
|
|
||||||
# TUI
|
# TUI
|
||||||
ratatui = { workspace = true, optional = true }
|
ratatui = { workspace = true, optional = true }
|
||||||
|
@ -93,6 +92,19 @@ hmac = { workspace = true }
|
||||||
sha2 = { workspace = true }
|
sha2 = { workspace = true }
|
||||||
hex = { workspace = true }
|
hex = { workspace = true }
|
||||||
|
|
||||||
|
# Git
|
||||||
|
gix = { workspace = true }
|
||||||
|
git-url-parse = { workspace = true }
|
||||||
|
|
||||||
|
# boilerplate
|
||||||
|
pike = { workspace = true }
|
||||||
|
|
||||||
|
|
||||||
|
mockall = { workspace = true }
|
||||||
|
|
||||||
|
#iters
|
||||||
|
take-until = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Testing
|
# Testing
|
||||||
assert2 = { workspace = true }
|
assert2 = { workspace = true }
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
use crate::alerts::short_message;
|
use crate::alerts::short_message;
|
||||||
use git_next_core::git::UserNotification;
|
use crate::core::git::UserNotification;
|
||||||
|
|
||||||
pub(super) fn send_desktop_notification(user_notification: &UserNotification) {
|
pub(super) fn send_desktop_notification(user_notification: &UserNotification) {
|
||||||
let message = short_message(user_notification);
|
let message = short_message(user_notification);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{
|
use crate::core::{
|
||||||
git::UserNotification,
|
git::UserNotification,
|
||||||
server::{EmailConfig, SmtpConfig},
|
server::{EmailConfig, SmtpConfig},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::git::UserNotification;
|
use crate::core::git::UserNotification;
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git::UserNotification, message, server::Shout};
|
use crate::core::{git::UserNotification, server::Shout};
|
||||||
|
use crate::message;
|
||||||
|
|
||||||
message!(UpdateShout, Shout, "Updated Shout configuration");
|
message!(UpdateShout, Shout, "Updated Shout configuration");
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use derive_more::derive::Constructor;
|
use derive_more::derive::Constructor;
|
||||||
|
|
||||||
use git_next_core::{git::UserNotification, server::Shout};
|
use crate::core::{git::UserNotification, server::Shout};
|
||||||
|
|
||||||
pub use history::History;
|
pub use history::History;
|
||||||
use kameo::{mailbox::unbounded::UnboundedMailbox, Actor};
|
use kameo::{mailbox::unbounded::UnboundedMailbox, Actor};
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::core::git::UserNotification;
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
use git_next_core::git::UserNotification;
|
|
||||||
|
|
||||||
use crate::{alerts::History, repo::tests::given};
|
use crate::{alerts::History, repo::tests::given};
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git::UserNotification, server::OutboundWebhook};
|
use crate::core::{git::UserNotification, server::OutboundWebhook};
|
||||||
use secrecy::ExposeSecret as _;
|
use secrecy::ExposeSecret as _;
|
||||||
use standardwebhooks::Webhook;
|
use standardwebhooks::Webhook;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::{
|
use crate::core::config::{
|
||||||
ApiToken, BranchName, ForgeAlias, ForgeDetails, ForgeType, Hostname, RepoAlias, RepoBranches,
|
ApiToken, BranchName, ForgeAlias, ForgeDetails, ForgeType, Hostname, RepoAlias, RepoBranches,
|
||||||
RepoConfig, RepoConfigSource, RepoPath, User,
|
RepoConfig, RepoConfigSource, RepoPath, User,
|
||||||
};
|
};
|
||||||
|
@ -15,31 +15,31 @@ pub fn forge_details(n: u32, forge_type: ForgeType) -> ForgeDetails {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn api_token(n: u32) -> ApiToken {
|
pub fn api_token(n: u32) -> ApiToken {
|
||||||
ApiToken::new(format!("api-{n}").into())
|
ApiToken::new(format!("api-{n}").into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn user(n: u32) -> User {
|
pub fn user(n: u32) -> User {
|
||||||
User::new(format!("user-{n}"))
|
User::new(format!("user-{n}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn hostname(n: u32) -> Hostname {
|
pub fn hostname(n: u32) -> Hostname {
|
||||||
Hostname::new(format!("hostname-{n}"))
|
Hostname::new(format!("hostname-{n}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn forge_name(n: u32) -> ForgeAlias {
|
pub fn forge_name(n: u32) -> ForgeAlias {
|
||||||
ForgeAlias::new(format!("forge-name-{n}"))
|
ForgeAlias::new(format!("forge-name-{n}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn branch_name(n: u32) -> BranchName {
|
pub fn branch_name(n: u32) -> BranchName {
|
||||||
BranchName::new(format!("branch-name-{n}"))
|
BranchName::new(format!("branch-name-{n}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn repo_path(n: u32) -> RepoPath {
|
pub fn repo_path(n: u32) -> RepoPath {
|
||||||
RepoPath::new(format!("repo-path-{n}"))
|
RepoPath::new(format!("repo-path-{n}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn repo_alias(n: u32) -> RepoAlias {
|
pub fn repo_alias(n: u32) -> RepoAlias {
|
||||||
RepoAlias::new(format!("repo-alias-{n}"))
|
RepoAlias::new(format!("repo-alias-{n}"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::core::config::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User};
|
||||||
config::{ApiToken, ForgeType, Hostname, RepoAlias, ServerRepoConfig, User},
|
use crate::s;
|
||||||
s,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::CommitCount;
|
use super::CommitCount;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::{ApiToken, ForgeAlias, ForgeConfig, ForgeType, Hostname, User};
|
use crate::core::config::{ApiToken, ForgeAlias, ForgeConfig, ForgeType, Hostname, User};
|
||||||
|
|
||||||
use super::CommitCount;
|
use super::CommitCount;
|
||||||
|
|
|
@ -2,7 +2,10 @@
|
||||||
mod api_token;
|
mod api_token;
|
||||||
mod branch_name;
|
mod branch_name;
|
||||||
mod commit_count;
|
mod commit_count;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
|
||||||
mod forge_alias;
|
mod forge_alias;
|
||||||
mod forge_config;
|
mod forge_config;
|
||||||
mod forge_details;
|
mod forge_details;
|
||||||
|
@ -53,4 +56,4 @@ pub use webhook::forge_notification::ForgeNotification;
|
||||||
pub use webhook::id::WebhookId;
|
pub use webhook::id::WebhookId;
|
||||||
|
|
||||||
// re-export
|
// re-export
|
||||||
pub use pike::{pike, pike_opt, pike_res};
|
pub use pike::pike;
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use crate::config::{WebhookAuth, WebhookId};
|
use crate::core::config::{WebhookAuth, WebhookId};
|
||||||
|
|
||||||
#[derive(Debug, derive_more::Constructor)]
|
#[derive(Debug, derive_more::Constructor)]
|
||||||
pub struct RegisteredWebhook {
|
pub struct RegisteredWebhook {
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::BranchName;
|
use crate::core::config::BranchName;
|
||||||
|
|
||||||
/// Mapped from `.git-next.toml` file at `branches`
|
/// Mapped from `.git-next.toml` file at `branches`
|
||||||
#[derive(
|
#[derive(
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::config::{RepoBranches, RepoConfigSource};
|
use crate::core::config::{RepoBranches, RepoConfigSource};
|
||||||
|
|
||||||
/// Mapped from `.git-next.toml` file in target repo
|
/// Mapped from `.git-next.toml` file in target repo
|
||||||
/// Is also derived from the optional parameters in `git-next-server.toml` at
|
/// Is also derived from the optional parameters in `git-next-server.toml` at
|
|
@ -15,24 +15,10 @@ use serde::{Deserialize, Serialize};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{ForgeAlias, ForgeConfig, RepoAlias},
|
core::config::{ForgeAlias, ForgeConfig, RepoAlias},
|
||||||
newtype, s,
|
newtype, s, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("fs: {0}")]
|
|
||||||
KxioFs(#[from] kxio::fs::Error),
|
|
||||||
|
|
||||||
#[error("deserialise toml: {0}")]
|
|
||||||
TomlDe(#[from] toml::de::Error),
|
|
||||||
|
|
||||||
#[error("parse IP addres/port: {0}")]
|
|
||||||
AddressParse(#[from] std::net::AddrParseError),
|
|
||||||
}
|
|
||||||
|
|
||||||
type Result<T> = core::result::Result<T, Error>;
|
|
||||||
|
|
||||||
/// Mapped from the `git-next-server.toml` file
|
/// Mapped from the `git-next-server.toml` file
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
|
@ -2,7 +2,7 @@
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
config::{
|
core::config::{
|
||||||
git_dir::StoragePathType, BranchName, GitDir, RepoBranches, RepoConfig, RepoConfigSource,
|
git_dir::StoragePathType, BranchName, GitDir, RepoBranches, RepoConfig, RepoConfigSource,
|
||||||
RepoPath,
|
RepoPath,
|
||||||
},
|
},
|
|
@ -7,16 +7,15 @@ use std::collections::BTreeMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{
|
||||||
|
server::{AppConfig, Http, Storage},
|
||||||
|
webhook::push::Branch,
|
||||||
|
},
|
||||||
s,
|
s,
|
||||||
server::{AppConfig, Http, Storage},
|
|
||||||
webhook::push::Branch,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
mod url;
|
mod url;
|
||||||
|
|
||||||
type Result<T> = core::result::Result<T, Box<dyn std::error::Error>>;
|
|
||||||
type TestResult = Result<()>;
|
|
||||||
|
|
||||||
mod server_repo_config {
|
mod server_repo_config {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -100,10 +99,12 @@ mod server_repo_config {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod repo_config {
|
mod repo_config {
|
||||||
|
use crate::Result;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn should_parse_toml() -> TestResult {
|
fn should_parse_toml() -> Result<()> {
|
||||||
let main = given::a_name();
|
let main = given::a_name();
|
||||||
let next = given::a_name();
|
let next = given::a_name();
|
||||||
let dev = given::a_name();
|
let dev = given::a_name();
|
||||||
|
@ -517,10 +518,12 @@ mod server {
|
||||||
use super::*;
|
use super::*;
|
||||||
mod load {
|
mod load {
|
||||||
|
|
||||||
|
use crate::{err, Result};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_should_parse_app_config() -> TestResult {
|
fn load_should_parse_app_config() -> Result<()> {
|
||||||
let app_config = given::an_app_config();
|
let app_config = given::an_app_config();
|
||||||
let fs = kxio::fs::temp()?;
|
let fs = kxio::fs::temp()?;
|
||||||
let_assert!(Ok(()) = write_app_config(&app_config, &fs), "write");
|
let_assert!(Ok(()) = write_app_config(&app_config, &fs), "write");
|
||||||
|
@ -530,7 +533,7 @@ mod server {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_app_config(app_config: &AppConfig, fs: &kxio::fs::FileSystem) -> TestResult {
|
fn write_app_config(app_config: &AppConfig, fs: &kxio::fs::FileSystem) -> Result<()> {
|
||||||
let http = &app_config.listen_socket_addr()?;
|
let http = &app_config.listen_socket_addr()?;
|
||||||
let http_addr = http.ip();
|
let http_addr = http.ip();
|
||||||
let http_port = app_config.listen_socket_addr()?.port();
|
let http_port = app_config.listen_socket_addr()?.port();
|
||||||
|
@ -553,11 +556,11 @@ mod server {
|
||||||
.forges()
|
.forges()
|
||||||
.next()
|
.next()
|
||||||
.map(|(fa, _)| fa)
|
.map(|(fa, _)| fa)
|
||||||
.ok_or("forge missing")?;
|
.ok_or_else(|| err!("forge missing"))?;
|
||||||
let forge_default = app_config
|
let forge_default = app_config
|
||||||
.forge
|
.forge
|
||||||
.get(forge_alias.as_ref())
|
.get(forge_alias.as_ref())
|
||||||
.ok_or("forge missing")?;
|
.ok_or_else(|| err!("forge missing"))?;
|
||||||
let forge_type = forge_default.forge_type();
|
let forge_type = forge_default.forge_type();
|
||||||
let forge_hostname = forge_default.hostname();
|
let forge_hostname = forge_default.hostname();
|
||||||
let forge_user = forge_default.user();
|
let forge_user = forge_default.user();
|
||||||
|
@ -716,7 +719,7 @@ mod push {
|
||||||
let message = given::a_name();
|
let message = given::a_name();
|
||||||
let push_event = {
|
let push_event = {
|
||||||
let branch_name = repo_branches.main();
|
let branch_name = repo_branches.main();
|
||||||
crate::webhook::Push::new(branch_name, sha, message)
|
crate::core::webhook::Push::new(branch_name, sha, message)
|
||||||
};
|
};
|
||||||
assert_eq!(push_event.branch(&repo_branches), Some(Branch::Main));
|
assert_eq!(push_event.branch(&repo_branches), Some(Branch::Main));
|
||||||
}
|
}
|
||||||
|
@ -727,7 +730,7 @@ mod push {
|
||||||
let message = given::a_name();
|
let message = given::a_name();
|
||||||
let push_event = {
|
let push_event = {
|
||||||
let branch_name = repo_branches.next();
|
let branch_name = repo_branches.next();
|
||||||
crate::webhook::Push::new(branch_name, sha, message)
|
crate::core::webhook::Push::new(branch_name, sha, message)
|
||||||
};
|
};
|
||||||
assert_eq!(push_event.branch(&repo_branches), Some(Branch::Next));
|
assert_eq!(push_event.branch(&repo_branches), Some(Branch::Next));
|
||||||
}
|
}
|
||||||
|
@ -738,7 +741,7 @@ mod push {
|
||||||
let message = given::a_name();
|
let message = given::a_name();
|
||||||
let push_event = {
|
let push_event = {
|
||||||
let branch_name = repo_branches.dev();
|
let branch_name = repo_branches.dev();
|
||||||
crate::webhook::Push::new(branch_name, sha, message)
|
crate::core::webhook::Push::new(branch_name, sha, message)
|
||||||
};
|
};
|
||||||
assert_eq!(push_event.branch(&repo_branches), Some(Branch::Dev));
|
assert_eq!(push_event.branch(&repo_branches), Some(Branch::Dev));
|
||||||
}
|
}
|
||||||
|
@ -749,7 +752,7 @@ mod push {
|
||||||
let message = given::a_name();
|
let message = given::a_name();
|
||||||
let push_event = {
|
let push_event = {
|
||||||
let branch_name = BranchName::new(given::a_name());
|
let branch_name = BranchName::new(given::a_name());
|
||||||
crate::webhook::Push::new(branch_name, sha, message)
|
crate::core::webhook::Push::new(branch_name, sha, message)
|
||||||
};
|
};
|
||||||
assert_eq!(push_event.branch(&repo_branches), None);
|
assert_eq!(push_event.branch(&repo_branches), None);
|
||||||
}
|
}
|
||||||
|
@ -761,7 +764,7 @@ mod push {
|
||||||
let push_event = {
|
let push_event = {
|
||||||
let branch_name = repo_branches.main();
|
let branch_name = repo_branches.main();
|
||||||
let sha = sha.clone();
|
let sha = sha.clone();
|
||||||
crate::webhook::Push::new(branch_name, sha, message)
|
crate::core::webhook::Push::new(branch_name, sha, message)
|
||||||
};
|
};
|
||||||
assert_eq!(push_event.sha(), sha);
|
assert_eq!(push_event.sha(), sha);
|
||||||
}
|
}
|
||||||
|
@ -773,14 +776,14 @@ mod push {
|
||||||
let push_event = {
|
let push_event = {
|
||||||
let branch_name = repo_branches.main();
|
let branch_name = repo_branches.main();
|
||||||
let message = message.clone();
|
let message = message.clone();
|
||||||
crate::webhook::Push::new(branch_name, sha, message)
|
crate::core::webhook::Push::new(branch_name, sha, message)
|
||||||
};
|
};
|
||||||
assert_eq!(push_event.message(), message);
|
assert_eq!(push_event.message(), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod given {
|
mod given {
|
||||||
|
|
||||||
use crate::server::{EmailConfig, Listen, ListenUrl, OutboundWebhook, Shout, SmtpConfig};
|
use crate::core::server::{EmailConfig, Listen, ListenUrl, OutboundWebhook, Shout, SmtpConfig};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use rand::Rng as _;
|
use rand::Rng as _;
|
||||||
|
@ -911,8 +914,8 @@ mod given {
|
||||||
RepoAlias::new(a_name())
|
RepoAlias::new(a_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a_webhook_message_body() -> crate::webhook::forge_notification::Body {
|
pub fn a_webhook_message_body() -> crate::core::webhook::forge_notification::Body {
|
||||||
crate::webhook::forge_notification::Body::new(a_name())
|
crate::core::webhook::forge_notification::Body::new(a_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn some_repo_branches() -> RepoBranches {
|
pub fn some_repo_branches() -> RepoBranches {
|
|
@ -3,7 +3,7 @@ use std::collections::BTreeMap;
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
|
|
||||||
use crate::config::{ForgeAlias, RepoAlias};
|
use crate::core::config::{ForgeAlias, RepoAlias};
|
||||||
|
|
||||||
/// A notification receive from a Forge, typically via a Webhook.
|
/// A notification receive from a Forge, typically via a Webhook.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, derive_more::Constructor)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, derive_more::Constructor)]
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use crate::config::{BranchName, RepoBranches};
|
use crate::core::config::{BranchName, RepoBranches};
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Constructor, PartialEq, Eq, derive_with::With)]
|
#[derive(Clone, Debug, Constructor, PartialEq, Eq, derive_with::With)]
|
|
@ -1,5 +1,6 @@
|
||||||
mod auth {
|
mod auth {
|
||||||
use crate::{s, WebhookAuth};
|
use crate::core::WebhookAuth;
|
||||||
|
use crate::s;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bytes() -> Result<(), Box<dyn std::error::Error>> {
|
fn bytes() -> Result<(), Box<dyn std::error::Error>> {
|
|
@ -1,5 +1,6 @@
|
||||||
//
|
//
|
||||||
use crate::{newtype, webhook};
|
use crate::core::webhook;
|
||||||
|
use crate::newtype;
|
||||||
|
|
||||||
use derive_more::Display;
|
use derive_more::Display;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
@ -68,18 +69,3 @@ pub struct Histories {
|
||||||
pub next: Vec<Commit>,
|
pub next: Vec<Commit>,
|
||||||
pub dev: Vec<Commit>,
|
pub dev: Vec<Commit>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod log {
|
|
||||||
use crate::BranchName;
|
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("branch: {branch}, error: {error}")]
|
|
||||||
Gix { branch: BranchName, error: String },
|
|
||||||
|
|
||||||
#[error("lock")]
|
|
||||||
Lock,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,38 +1,36 @@
|
||||||
//
|
//
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("lock")]
|
// #[error("lock")]
|
||||||
Lock,
|
// Lock,
|
||||||
|
|
||||||
#[error("File not found: {}", 0)]
|
// #[error("File not found: {}", 0)]
|
||||||
NotFound(String),
|
// NotFound(String),
|
||||||
|
|
||||||
#[error("Unable to parse file contents")]
|
// #[error("Unable to parse file contents")]
|
||||||
ParseContent,
|
// ParseContent,
|
||||||
|
|
||||||
#[error("Unable to decode from base64")]
|
// #[error("Unable to decode from base64")]
|
||||||
DecodeFromBase64,
|
// DecodeFromBase64,
|
||||||
|
|
||||||
#[error("Unable to decode from UTF-8")]
|
// #[error("Unable to decode from UTF-8")]
|
||||||
DecodeFromUtf8,
|
// DecodeFromUtf8,
|
||||||
|
|
||||||
#[error("Unknown file encoding: {}", 0)]
|
// #[error("Unknown file encoding: {}", 0)]
|
||||||
UnknownEncoding(String),
|
// UnknownEncoding(String),
|
||||||
|
|
||||||
#[error("Not a file: {}", 0)]
|
// #[error("Not a file: {}", 0)]
|
||||||
NotFile(String),
|
// NotFile(String),
|
||||||
|
|
||||||
#[error("Unknown error (status: {})", 0)]
|
// #[error("Unknown error (status: {})", 0)]
|
||||||
Unknown(String),
|
// Unknown(String),
|
||||||
|
|
||||||
#[error("commit log: {0}")]
|
// #[error("commit log: {0}")]
|
||||||
CommitLog(#[from] crate::git::commit::log::Error),
|
// CommitLog(#[from] crate::git::commit::log::Error),
|
||||||
|
|
||||||
#[error("commit not found")]
|
|
||||||
CommitNotFound,
|
|
||||||
|
|
||||||
|
// #[error("commit not found")]
|
||||||
|
// CommitNotFound,
|
||||||
#[error("no tree in commit")]
|
#[error("no tree in commit")]
|
||||||
NoTreeInCommit(String),
|
NoTreeInCommit(String),
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
pub mod commit;
|
pub mod commit;
|
||||||
pub(super) mod r#trait;
|
pub mod r#trait;
|
||||||
pub mod webhook;
|
pub mod webhook;
|
||||||
|
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
pub use r#trait::ForgeLike;
|
pub use r#trait::ForgeLike;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
pub use r#trait::MockForgeLike;
|
pub use r#trait::MockForgeLike;
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::core::{
|
||||||
git, server::RepoListenUrl, webhook, ForgeNotification, RegisteredWebhook, WebhookAuth,
|
git, server::RepoListenUrl, webhook, ForgeNotification, RegisteredWebhook, WebhookAuth,
|
||||||
WebhookId,
|
WebhookId,
|
||||||
};
|
};
|
||||||
|
@ -8,6 +8,8 @@ use crate::{
|
||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
pub trait ForgeLike: std::fmt::Debug + Send + Sync {
|
pub trait ForgeLike: std::fmt::Debug + Send + Sync {
|
||||||
fn duplicate(&self) -> Box<dyn ForgeLike>;
|
fn duplicate(&self) -> Box<dyn ForgeLike>;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn name(&self) -> String;
|
fn name(&self) -> String;
|
||||||
|
|
||||||
/// Checks that the message has a valid authorisation.
|
/// Checks that the message has a valid authorisation.
|
||||||
|
@ -38,6 +40,7 @@ pub trait ForgeLike: std::fmt::Debug + Send + Sync {
|
||||||
) -> git::forge::webhook::Result<git::forge::commit::Status>;
|
) -> git::forge::webhook::Result<git::forge::commit::Status>;
|
||||||
|
|
||||||
// Lists all the webhooks
|
// Lists all the webhooks
|
||||||
|
#[cfg(test)]
|
||||||
async fn list_webhooks(
|
async fn list_webhooks(
|
||||||
&self,
|
&self,
|
||||||
repo_listen_url: &RepoListenUrl,
|
repo_listen_url: &RepoListenUrl,
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use derive_more::{Constructor, Display};
|
use derive_more::{Constructor, Display};
|
||||||
|
|
||||||
use crate::{Hostname, RepoPath};
|
use crate::core::{Hostname, RepoPath};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Constructor, Display)]
|
#[derive(Clone, Debug, PartialEq, Eq, Constructor, Display)]
|
||||||
#[display("{}:{}", host, repo_path)]
|
#[display("{}:{}", host, repo_path)]
|
|
@ -3,7 +3,8 @@ use std::borrow::ToOwned;
|
||||||
|
|
||||||
use take_until::TakeUntilExt;
|
use take_until::TakeUntilExt;
|
||||||
|
|
||||||
use crate::{newtype, GitDir, RepoBranches};
|
use crate::core::{GitDir, RepoBranches};
|
||||||
|
use crate::newtype;
|
||||||
|
|
||||||
use super::RepoDetails;
|
use super::RepoDetails;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
//
|
//
|
||||||
pub mod commit;
|
pub mod commit;
|
||||||
pub mod fetch;
|
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod forge;
|
pub mod forge;
|
||||||
mod generation;
|
mod generation;
|
||||||
|
@ -18,38 +17,30 @@ mod tests;
|
||||||
|
|
||||||
pub use commit::Commit;
|
pub use commit::Commit;
|
||||||
pub use forge::ForgeLike;
|
pub use forge::ForgeLike;
|
||||||
pub use forge::MockForgeLike;
|
|
||||||
pub use generation::Generation;
|
pub use generation::Generation;
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
pub use git_ref::GitRef;
|
pub use git_ref::GitRef;
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
pub use git_remote::GitRemote;
|
pub use git_remote::GitRemote;
|
||||||
pub use repo_details::RepoDetails;
|
pub use repo_details::RepoDetails;
|
||||||
pub use repository::Repository;
|
|
||||||
pub use repository::RepositoryFactory;
|
pub use repository::RepositoryFactory;
|
||||||
pub use user_notification::UserNotification;
|
pub use user_notification::UserNotification;
|
||||||
|
|
||||||
use crate::common::branch_name;
|
#[cfg(test)]
|
||||||
use crate::common::repo_alias;
|
|
||||||
use crate::common::repo_path;
|
|
||||||
use crate::ForgeDetails;
|
|
||||||
use crate::GitDir;
|
|
||||||
use crate::RepoConfig;
|
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn repo_details(
|
pub fn repo_details(
|
||||||
n: u32,
|
n: u32,
|
||||||
generation: Generation,
|
generation: Generation,
|
||||||
forge: ForgeDetails,
|
forge: super::ForgeDetails,
|
||||||
repo_config: Option<RepoConfig>,
|
repo_config: Option<super::RepoConfig>,
|
||||||
gitdir: GitDir,
|
gitdir: super::GitDir,
|
||||||
) -> RepoDetails {
|
) -> RepoDetails {
|
||||||
RepoDetails {
|
RepoDetails {
|
||||||
generation,
|
generation,
|
||||||
repo_alias: repo_alias(n),
|
repo_alias: super::common::repo_alias(n),
|
||||||
repo_path: repo_path(n),
|
repo_path: super::common::repo_path(n),
|
||||||
gitdir,
|
gitdir,
|
||||||
branch: branch_name(n),
|
branch: super::common::branch_name(n),
|
||||||
forge,
|
forge,
|
||||||
repo_config,
|
repo_config,
|
||||||
}
|
}
|
|
@ -1,5 +1,9 @@
|
||||||
//
|
//
|
||||||
use crate::{git, git::repository::open::OpenRepositoryLike, BranchName};
|
use crate::{
|
||||||
|
core::BranchName,
|
||||||
|
git::{self, repository::open::OpenRepositoryLike},
|
||||||
|
Result,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub enum Force {
|
pub enum Force {
|
||||||
|
@ -15,36 +19,6 @@ impl std::fmt::Display for Force {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
#[error("io")]
|
|
||||||
Io(#[from] std::io::Error),
|
|
||||||
|
|
||||||
#[error("network: {0}")]
|
|
||||||
Network(#[from] kxio::net::Error),
|
|
||||||
|
|
||||||
#[error("fetch: {0}")]
|
|
||||||
Fetch(#[from] git::fetch::Error),
|
|
||||||
|
|
||||||
#[error("lock")]
|
|
||||||
Lock,
|
|
||||||
|
|
||||||
#[error("gix open: {0}")]
|
|
||||||
Open(#[from] Box<gix::open::Error>),
|
|
||||||
|
|
||||||
#[error("gix iter: {0}")]
|
|
||||||
GixIter(#[from] gix::reference::iter::Error),
|
|
||||||
|
|
||||||
#[error("gix iter init: {0}")]
|
|
||||||
GixIterInit(#[from] gix::reference::iter::init::Error),
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
#[error("test")]
|
|
||||||
TestResult(#[from] Box<dyn std::error::Error>),
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets the position of a branch in the remote repo
|
/// Resets the position of a branch in the remote repo
|
||||||
///
|
///
|
||||||
/// Performs a 'git fetch' first to ensure we have up-to-date branch positions before
|
/// Performs a 'git fetch' first to ensure we have up-to-date branch positions before
|
|
@ -1,12 +1,16 @@
|
||||||
//
|
//
|
||||||
|
use crate::core::pike;
|
||||||
|
use crate::s;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{
|
||||||
|
BranchName, ForgeAlias, ForgeConfig, ForgeDetails, GitDir, RemoteUrl, RepoAlias,
|
||||||
|
RepoConfig, RepoPath, ServerRepoConfig, StoragePathType,
|
||||||
|
},
|
||||||
git::{
|
git::{
|
||||||
self,
|
self,
|
||||||
repository::open::{oreal::RealOpenRepository, OpenRepositoryLike},
|
repository::open::{oreal::RealOpenRepository, OpenRepositoryLike},
|
||||||
Generation,
|
Generation,
|
||||||
},
|
},
|
||||||
pike, s, BranchName, ForgeAlias, ForgeConfig, ForgeDetails, GitDir, Hostname, RemoteUrl,
|
|
||||||
RepoAlias, RepoConfig, RepoPath, ServerRepoConfig, StoragePathType,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
|
@ -70,8 +74,9 @@ impl RepoDetails {
|
||||||
&self.gitdir
|
&self.gitdir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn with_hostname(mut self, hostname: Hostname) -> Self {
|
pub fn with_hostname(mut self, hostname: crate::core::Hostname) -> Self {
|
||||||
let forge = self.forge;
|
let forge = self.forge;
|
||||||
self.forge = forge.with_hostname(hostname);
|
self.forge = forge.with_hostname(hostname);
|
||||||
self
|
self
|
|
@ -41,9 +41,10 @@ pub fn real() -> Box<dyn RepositoryFactory> {
|
||||||
Box::new(RealRepositoryFactory)
|
Box::new(RealRepositoryFactory)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn mock() -> Box<MockRepositoryFactory> {
|
pub fn mock() -> MockRepositoryFactory {
|
||||||
Box::new(MockRepositoryFactory::new())
|
MockRepositoryFactory::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
|
@ -1,21 +1,18 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::RemoteUrl,
|
||||||
git::{
|
git::{
|
||||||
self,
|
repository::open::OpenRepositoryLike, validation::remotes::validate_default_remotes,
|
||||||
repository::{
|
|
||||||
open::{OpenRepository, OpenRepositoryLike},
|
|
||||||
test::TestRepository,
|
|
||||||
},
|
|
||||||
validation::remotes::validate_default_remotes,
|
|
||||||
RepoDetails,
|
RepoDetails,
|
||||||
},
|
},
|
||||||
GitDir, RemoteUrl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
pub mod factory;
|
pub mod factory;
|
||||||
pub mod open;
|
pub mod open;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
|
@ -24,19 +21,20 @@ pub use factory::RepositoryFactory;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
// #[cfg(test)]
|
||||||
#[allow(clippy::large_enum_variant)]
|
// #[derive(Clone, Debug)]
|
||||||
pub enum Repository {
|
// #[allow(clippy::large_enum_variant)]
|
||||||
Real,
|
// pub enum Repository {
|
||||||
Test(TestRepository),
|
// Real,
|
||||||
}
|
// Test(test::TestRepository),
|
||||||
|
// }
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) const fn test(
|
pub const fn test(
|
||||||
fs: kxio::fs::FileSystem,
|
fs: kxio::fs::FileSystem,
|
||||||
forge_details: crate::ForgeDetails,
|
forge_details: crate::core::ForgeDetails,
|
||||||
) -> TestRepository {
|
) -> test::TestRepository {
|
||||||
TestRepository::new(fs, vec![], vec![], forge_details)
|
test::TestRepository::new(fs, vec![], vec![], forge_details)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Opens a repository, cloning if necessary
|
/// Opens a repository, cloning if necessary
|
||||||
|
@ -60,6 +58,7 @@ pub fn open(
|
||||||
Ok(open_repository)
|
Ok(open_repository)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
pub trait RepositoryLike {
|
pub trait RepositoryLike {
|
||||||
/// Opens the repository.
|
/// Opens the repository.
|
||||||
|
@ -67,15 +66,16 @@ pub trait RepositoryLike {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return an `Err` if the repository can't be opened.
|
/// Will return an `Err` if the repository can't be opened.
|
||||||
fn open(&self, gitdir: &GitDir) -> Result<OpenRepository>;
|
fn open(&self, gitdir: &crate::core::GitDir) -> Result<open::OpenRepository>;
|
||||||
|
|
||||||
/// Clones the git repository from the remote server.
|
// /// Clones the git repository from the remote server.
|
||||||
///
|
// ///
|
||||||
/// # Errors
|
// /// # Errors
|
||||||
///
|
// ///
|
||||||
/// Will return an `Err` if there are any network connectivity issues
|
// /// Will return an `Err` if there are any network connectivity issues
|
||||||
/// connecting with the server.
|
// /// connecting with the server.
|
||||||
fn git_clone(&self, repo_details: &RepoDetails) -> Result<OpenRepository>;
|
// #[cfg(test)]
|
||||||
|
// fn git_clone(&self, repo_details: &RepoDetails) -> Result<open::OpenRepository>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
|
||||||
|
@ -98,39 +98,35 @@ pub type Result<T> = core::result::Result<T, Error>;
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("invalid git dir: {0}")]
|
// #[error("invalid git dir: {0}")]
|
||||||
InvalidGitDir(GitDir),
|
// InvalidGitDir(GitDir),
|
||||||
|
|
||||||
#[error("kxiofs: {0}")]
|
#[error("kxiofs: {0}")]
|
||||||
KxioFs(#[from] kxio::fs::Error),
|
KxioFs(#[from] kxio::fs::Error),
|
||||||
|
|
||||||
#[error("io: {0}")]
|
// #[error("io: {0}")]
|
||||||
Io(std::io::Error),
|
// Io(std::io::Error),
|
||||||
|
|
||||||
#[error("git exec wait: {0}")]
|
// #[error("git exec wait: {0}")]
|
||||||
Wait(std::io::Error),
|
// Wait(std::io::Error),
|
||||||
|
|
||||||
#[error("git exec spawn: {0}")]
|
|
||||||
Spawn(std::io::Error),
|
|
||||||
|
|
||||||
|
// #[error("git exec spawn: {0}")]
|
||||||
|
// Spawn(std::io::Error),
|
||||||
#[error("validation: {0}")]
|
#[error("validation: {0}")]
|
||||||
Validation(String),
|
Validation(String),
|
||||||
|
|
||||||
#[error("git clone: {0}")]
|
#[error("git clone: {0}")]
|
||||||
Clone(String),
|
Clone(String),
|
||||||
|
|
||||||
#[error("git fetch: {0}")]
|
// #[error("git fetch: {0}")]
|
||||||
FetchError(#[from] git::fetch::Error),
|
// FetchError(#[from] git::fetch::Error),
|
||||||
|
|
||||||
#[error("open: {0}")]
|
#[error("open: {0}")]
|
||||||
Open(String),
|
Open(String),
|
||||||
|
|
||||||
#[error("git fetch: {0}")]
|
#[error("git fetch: {0}")]
|
||||||
Fetch(String),
|
Fetch(String),
|
||||||
|
|
||||||
#[error("fake repository lock")]
|
// #[error("fake repository lock")]
|
||||||
FakeLock,
|
// FakeLock,
|
||||||
|
|
||||||
#[error("MismatchDefaultFetchRemote(found: {found:?}, expected: {expected:?})")]
|
#[error("MismatchDefaultFetchRemote(found: {found:?}, expected: {expected:?})")]
|
||||||
MismatchDefaultFetchRemote {
|
MismatchDefaultFetchRemote {
|
||||||
found: Box<RemoteUrl>,
|
found: Box<RemoteUrl>,
|
|
@ -3,56 +3,55 @@
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
pub mod oreal;
|
pub mod oreal;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
pub mod otest;
|
pub mod otest;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
git,
|
core::{BranchName, RemoteUrl},
|
||||||
git::repository::{
|
git::{self, repository::Direction},
|
||||||
open::{oreal::RealOpenRepository, otest::TestOpenRepository},
|
Result,
|
||||||
Direction,
|
|
||||||
},
|
|
||||||
BranchName, GitDir, RemoteUrl,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::{
|
use std::path::Path;
|
||||||
path::Path,
|
|
||||||
sync::{Arc, RwLock},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum OpenRepository {
|
pub enum OpenRepository {
|
||||||
/// A real git repository.
|
// /// A real git repository.
|
||||||
///
|
// ///
|
||||||
/// This variant is the normal implementation for use in production code.
|
// /// This variant is the normal implementation for use in production code.
|
||||||
Real(RealOpenRepository),
|
// #[cfg(test)]
|
||||||
|
// Real(oreal::RealOpenRepository),
|
||||||
/// A real git repository, but with preprogrammed responses to network access.
|
/// A real git repository, but with preprogrammed responses to network access.
|
||||||
///
|
///
|
||||||
/// This variant is for use only in testing. Requests to methods
|
/// This variant is for use only in testing. Requests to methods
|
||||||
/// that would require network access, such as to the git remote
|
/// that would require network access, such as to the git remote
|
||||||
/// server will result in an error, unless a predefined change
|
/// server will result in an error, unless a predefined change
|
||||||
/// has been scheduled for that request.
|
/// has been scheduled for that request.
|
||||||
Test(TestOpenRepository),
|
Test(otest::TestOpenRepository),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(tarpaulin_include))]
|
// #[cfg(test)]
|
||||||
pub fn real(gix_repo: gix::Repository, forge_details: crate::ForgeDetails) -> OpenRepository {
|
// #[cfg(not(tarpaulin_include))]
|
||||||
OpenRepository::Real(oreal::RealOpenRepository::new(
|
// pub fn real(gix_repo: gix::Repository, forge_details: crate::core::ForgeDetails) -> OpenRepository {
|
||||||
Arc::new(RwLock::new(gix_repo.into())),
|
// OpenRepository::Real(oreal::RealOpenRepository::new(
|
||||||
forge_details,
|
// std::sync::Arc::new(std::sync::RwLock::new(gix_repo.into())),
|
||||||
))
|
// forge_details,
|
||||||
}
|
// ))
|
||||||
|
// }
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
#[cfg(not(tarpaulin_include))] // don't test mocks
|
#[cfg(not(tarpaulin_include))] // don't test mocks
|
||||||
pub(crate) fn test(
|
pub fn test(
|
||||||
gitdir: &GitDir,
|
gitdir: &crate::core::GitDir,
|
||||||
fs: &kxio::fs::FileSystem,
|
fs: &kxio::fs::FileSystem,
|
||||||
on_fetch: Vec<otest::OnFetch>,
|
on_fetch: Vec<otest::OnFetch>,
|
||||||
on_push: Vec<otest::OnPush>,
|
on_push: Vec<otest::OnPush>,
|
||||||
forge_details: crate::ForgeDetails,
|
forge_details: crate::core::ForgeDetails,
|
||||||
) -> OpenRepository {
|
) -> OpenRepository {
|
||||||
OpenRepository::Test(TestOpenRepository::new(
|
OpenRepository::Test(otest::TestOpenRepository::new(
|
||||||
gitdir,
|
gitdir,
|
||||||
fs,
|
fs,
|
||||||
on_fetch,
|
on_fetch,
|
||||||
|
@ -64,8 +63,9 @@ pub(crate) fn test(
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
#[mockall::automock]
|
#[mockall::automock]
|
||||||
pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
||||||
/// Creates a clone of the `OpenRepositoryLike`.
|
// /// Creates a clone of the `OpenRepositoryLike`.
|
||||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike>;
|
// #[cfg(test)]
|
||||||
|
// fn duplicate(&self) -> Box<dyn OpenRepositoryLike>;
|
||||||
|
|
||||||
/// Returns a `Vec` of all the branches in the remote repo.
|
/// Returns a `Vec` of all the branches in the remote repo.
|
||||||
///
|
///
|
||||||
|
@ -73,7 +73,7 @@ pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
||||||
///
|
///
|
||||||
/// Will return `Err` if there are any network connectivity issues with
|
/// Will return `Err` if there are any network connectivity issues with
|
||||||
/// the remote server.
|
/// the remote server.
|
||||||
fn remote_branches(&self) -> git::push::Result<Vec<BranchName>>;
|
fn remote_branches(&self) -> Result<Vec<BranchName>>;
|
||||||
fn find_default_remote(&self, direction: Direction) -> Option<RemoteUrl>;
|
fn find_default_remote(&self, direction: Direction) -> Option<RemoteUrl>;
|
||||||
|
|
||||||
/// Performs a `git fetch`
|
/// Performs a `git fetch`
|
||||||
|
@ -82,7 +82,7 @@ pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
||||||
///
|
///
|
||||||
/// Will return an `Err` if their is no remote fetch defined in .git/config, or
|
/// Will return an `Err` if their is no remote fetch defined in .git/config, or
|
||||||
/// if there are any network connectivity issues with the remote server.
|
/// if there are any network connectivity issues with the remote server.
|
||||||
fn fetch(&self) -> Result<(), git::fetch::Error>;
|
fn fetch(&self) -> Result<()>;
|
||||||
|
|
||||||
/// Performs a `git push`
|
/// Performs a `git push`
|
||||||
///
|
///
|
||||||
|
@ -96,7 +96,7 @@ pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
to_commit: &git::GitRef,
|
to_commit: &git::GitRef,
|
||||||
force: &git::push::Force,
|
force: &git::push::Force,
|
||||||
) -> git::push::Result<()>;
|
) -> Result<()>;
|
||||||
|
|
||||||
/// List of commits in a branch, optionally up-to any specified commit.
|
/// List of commits in a branch, optionally up-to any specified commit.
|
||||||
///
|
///
|
||||||
|
@ -108,7 +108,7 @@ pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
||||||
&self,
|
&self,
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
find_commits: &[git::Commit],
|
find_commits: &[git::Commit],
|
||||||
) -> git::commit::log::Result<Vec<git::Commit>>;
|
) -> Result<Vec<git::Commit>>;
|
||||||
|
|
||||||
/// Read the contents of a file as a string.
|
/// Read the contents of a file as a string.
|
||||||
///
|
///
|
||||||
|
@ -117,20 +117,21 @@ pub trait OpenRepositoryLike: std::fmt::Debug + Sync + Send {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `Err` if the file does not exists on the specified branch.
|
/// Will return `Err` if the file does not exists on the specified branch.
|
||||||
fn read_file(&self, branch_name: &BranchName, file_name: &Path) -> git::file::Result<String>;
|
fn read_file(&self, branch_name: &BranchName, file_name: &Path) -> Result<String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub(crate) fn mock() -> Box<MockOpenRepositoryLike> {
|
pub fn mock() -> Box<MockOpenRepositoryLike> {
|
||||||
Box::new(MockOpenRepositoryLike::new())
|
Box::new(MockOpenRepositoryLike::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
impl std::ops::Deref for OpenRepository {
|
impl std::ops::Deref for OpenRepository {
|
||||||
type Target = dyn OpenRepositoryLike;
|
type Target = dyn OpenRepositoryLike;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
match self {
|
match self {
|
||||||
Self::Real(real) => real,
|
// Self::Real(real) => real,
|
||||||
Self::Test(test) => test,
|
Self::Test(test) => test,
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
git::{self, repository::OpenRepositoryLike},
|
core::{BranchName, ForgeDetails, Hostname, RemoteUrl, RepoPath},
|
||||||
s, BranchName, ForgeDetails, Hostname, RemoteUrl, RepoPath,
|
err, git,
|
||||||
};
|
};
|
||||||
|
use crate::{s, Result};
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
use gix::bstr::BStr;
|
use gix::bstr::BStr;
|
||||||
|
@ -11,7 +12,6 @@ use tracing::{info, warn};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::ToOwned,
|
borrow::ToOwned,
|
||||||
path::Path,
|
path::Path,
|
||||||
result::Result,
|
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -21,26 +21,29 @@ pub struct RealOpenRepository {
|
||||||
forge_details: ForgeDetails,
|
forge_details: ForgeDetails,
|
||||||
}
|
}
|
||||||
impl super::OpenRepositoryLike for RealOpenRepository {
|
impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
fn remote_branches(&self) -> git::push::Result<Vec<BranchName>> {
|
fn remote_branches(&self) -> Result<Vec<BranchName>> {
|
||||||
let refs = self
|
let refs = self
|
||||||
.inner
|
.inner
|
||||||
.read()
|
.read()
|
||||||
.map_err(|_| git::push::Error::Lock)
|
.map_err(|_| err!("read"))
|
||||||
.and_then(|repo| {
|
.and_then(|repo| {
|
||||||
Ok(repo.to_thread_local().references()?).and_then(|refs| {
|
repo.to_thread_local()
|
||||||
Ok(refs.remote_branches().map(|rb| {
|
.references()
|
||||||
rb.filter_map(Result::ok)
|
.map_err(|_| err!("thread local references"))
|
||||||
.map(|r| r.name().to_owned())
|
.and_then(|refs| {
|
||||||
.map(|n| s!(n))
|
Ok(refs.remote_branches().map(|rb| {
|
||||||
.filter_map(|p| {
|
rb.filter_map(Result::ok)
|
||||||
p.strip_prefix("refs/remotes/origin/")
|
.map(|r| r.name().to_owned())
|
||||||
.map(ToOwned::to_owned)
|
.map(|n| s!(n))
|
||||||
})
|
.filter_map(|p| {
|
||||||
.filter(|b| b.as_str() != "HEAD")
|
p.strip_prefix("refs/remotes/origin/")
|
||||||
.map(BranchName::new)
|
.map(ToOwned::to_owned)
|
||||||
.collect::<Vec<_>>()
|
})
|
||||||
})?)
|
.filter(|b| b.as_str() != "HEAD")
|
||||||
})
|
.map(BranchName::new)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})?)
|
||||||
|
})
|
||||||
})?;
|
})?;
|
||||||
Ok(refs)
|
Ok(refs)
|
||||||
}
|
}
|
||||||
|
@ -66,12 +69,12 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
#[cfg(not(tarpaulin_include))] // would require writing to external service
|
#[cfg(not(tarpaulin_include))] // would require writing to external service
|
||||||
fn fetch(&self) -> Result<(), git::fetch::Error> {
|
fn fetch(&self) -> Result<()> {
|
||||||
if self
|
if self
|
||||||
.find_default_remote(git::repository::Direction::Fetch)
|
.find_default_remote(git::repository::Direction::Fetch)
|
||||||
.is_none()
|
.is_none()
|
||||||
{
|
{
|
||||||
return Err(git::fetch::Error::NoFetchRemoteFound);
|
return Err(err!("No Fetch Remote Found"));
|
||||||
}
|
}
|
||||||
info!("Fetching");
|
info!("Fetching");
|
||||||
gix::command::prepare("/usr/bin/git fetch --prune")
|
gix::command::prepare("/usr/bin/git fetch --prune")
|
||||||
|
@ -79,7 +82,7 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
git_dir: Some(
|
git_dir: Some(
|
||||||
self.inner
|
self.inner
|
||||||
.read()
|
.read()
|
||||||
.map_err(|_| git::fetch::Error::Lock)
|
.map_err(|_| err!("Lock"))
|
||||||
.map(|r| r.git_dir().to_path_buf())?,
|
.map(|r| r.git_dir().to_path_buf())?,
|
||||||
),
|
),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -101,7 +104,7 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
to_commit: &git::GitRef,
|
to_commit: &git::GitRef,
|
||||||
force: &git::push::Force,
|
force: &git::push::Force,
|
||||||
) -> Result<(), git::push::Error> {
|
) -> Result<()> {
|
||||||
use secrecy::ExposeSecret as _;
|
use secrecy::ExposeSecret as _;
|
||||||
|
|
||||||
let origin = repo_details.origin();
|
let origin = repo_details.origin();
|
||||||
|
@ -120,7 +123,7 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
let git_dir = self
|
let git_dir = self
|
||||||
.inner
|
.inner
|
||||||
.read()
|
.read()
|
||||||
.map_err(|_| git::push::Error::Lock)
|
.map_err(|_| err!("Lock"))
|
||||||
.map(|r| r.git_dir().to_path_buf())?;
|
.map(|r| r.git_dir().to_path_buf())?;
|
||||||
let ctx = gix::diff::command::Context {
|
let ctx = gix::diff::command::Context {
|
||||||
git_dir: Some(git_dir),
|
git_dir: Some(git_dir),
|
||||||
|
@ -140,7 +143,7 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
&self,
|
&self,
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
find_commits: &[git::Commit],
|
find_commits: &[git::Commit],
|
||||||
) -> Result<Vec<git::Commit>, git::commit::log::Error> {
|
) -> Result<Vec<git::Commit>> {
|
||||||
let limit: usize = if find_commits.is_empty() {
|
let limit: usize = if find_commits.is_empty() {
|
||||||
1
|
1
|
||||||
} else {
|
} else {
|
||||||
|
@ -148,63 +151,60 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
.max_dev_commits()
|
.max_dev_commits()
|
||||||
.map_or(25, |commit_count| commit_count.clone().peel() as usize)
|
.map_or(25, |commit_count| commit_count.clone().peel() as usize)
|
||||||
};
|
};
|
||||||
self.inner
|
self.inner.read().map_err(|_| err!("Lock")).map(|repo| {
|
||||||
.read()
|
let branch = format!("remotes/origin/{branch_name}");
|
||||||
.map_err(|_| git::commit::log::Error::Lock)
|
let branch = BStr::new(&branch);
|
||||||
.map(|repo| {
|
let thread_local = repo.to_thread_local();
|
||||||
let branch = format!("remotes/origin/{branch_name}");
|
let branch_head = thread_local
|
||||||
let branch = BStr::new(&branch);
|
.rev_parse_single(branch)
|
||||||
let thread_local = repo.to_thread_local();
|
.map_err(|e| s!(e))
|
||||||
let branch_head = thread_local
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
.rev_parse_single(branch)
|
let object = branch_head
|
||||||
|
.object()
|
||||||
|
.map_err(|e| s!(e))
|
||||||
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
|
let commit = object
|
||||||
|
.try_into_commit()
|
||||||
|
.map_err(|e| s!(e))
|
||||||
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
|
let walk = thread_local
|
||||||
|
.rev_walk([commit.id])
|
||||||
|
.all()
|
||||||
|
.map_err(|e| s!(e))
|
||||||
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
|
let mut commits = vec![];
|
||||||
|
for item in walk.take(limit) {
|
||||||
|
let item = item
|
||||||
.map_err(|e| s!(e))
|
.map_err(|e| s!(e))
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
let object = branch_head
|
let commit = item
|
||||||
.object()
|
.object()
|
||||||
.map_err(|e| s!(e))
|
.map_err(|e| s!(e))
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
let commit = object
|
let id = commit.id();
|
||||||
.try_into_commit()
|
let message = commit
|
||||||
|
.message_raw()
|
||||||
.map_err(|e| s!(e))
|
.map_err(|e| s!(e))
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
.map_err(as_gix_error(branch_name.clone()))?;
|
||||||
let walk = thread_local
|
let commit = git::Commit::new(
|
||||||
.rev_walk([commit.id])
|
git::commit::Sha::new(s!(id)),
|
||||||
.all()
|
git::commit::Message::new(s!(message)),
|
||||||
.map_err(|e| s!(e))
|
);
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
if find_commits.contains(&commit) {
|
||||||
let mut commits = vec![];
|
|
||||||
for item in walk.take(limit) {
|
|
||||||
let item = item
|
|
||||||
.map_err(|e| s!(e))
|
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
|
||||||
let commit = item
|
|
||||||
.object()
|
|
||||||
.map_err(|e| s!(e))
|
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
|
||||||
let id = commit.id();
|
|
||||||
let message = commit
|
|
||||||
.message_raw()
|
|
||||||
.map_err(|e| s!(e))
|
|
||||||
.map_err(as_gix_error(branch_name.clone()))?;
|
|
||||||
let commit = git::Commit::new(
|
|
||||||
git::commit::Sha::new(s!(id)),
|
|
||||||
git::commit::Message::new(s!(message)),
|
|
||||||
);
|
|
||||||
if find_commits.contains(&commit) {
|
|
||||||
commits.push(commit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
commits.push(commit);
|
commits.push(commit);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
Ok(commits)
|
commits.push(commit);
|
||||||
})?
|
}
|
||||||
|
Ok(commits)
|
||||||
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all, fields(%branch_name, ?file_name))]
|
#[tracing::instrument(skip_all, fields(%branch_name, ?file_name))]
|
||||||
fn read_file(&self, branch_name: &BranchName, file_name: &Path) -> git::file::Result<String> {
|
fn read_file(&self, branch_name: &BranchName, file_name: &Path) -> Result<String> {
|
||||||
self.inner
|
self.inner
|
||||||
.read()
|
.read()
|
||||||
.map_err(|_| git::file::Error::Lock)
|
.map_err(|_| err!("Lock"))
|
||||||
.and_then(|repo| {
|
.and_then(|repo| {
|
||||||
let thread_local = repo.to_thread_local();
|
let thread_local = repo.to_thread_local();
|
||||||
let fref = thread_local.find_reference(format!("origin/{branch_name}").as_str())?;
|
let fref = thread_local.find_reference(format!("origin/{branch_name}").as_str())?;
|
||||||
|
@ -223,13 +223,14 @@ impl super::OpenRepositoryLike for RealOpenRepository {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike> {
|
// #[cfg(test)]
|
||||||
Box::new(self.clone())
|
// fn duplicate(&self) -> Box<dyn super::OpenRepositoryLike> {
|
||||||
}
|
// Box::new(self.clone())
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_gix_error(branch: BranchName) -> impl FnOnce(String) -> git::commit::log::Error {
|
fn as_gix_error(branch: BranchName) -> impl FnOnce(String) -> color_eyre::eyre::Error {
|
||||||
|error| git::commit::log::Error::Gix { branch, error }
|
move |error| err!("gix: branch: {branch}: {error}")
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&RemoteUrl> for git::GitRemote {
|
impl From<&RemoteUrl> for git::GitRemote {
|
|
@ -1,10 +1,11 @@
|
||||||
//
|
//
|
||||||
|
use crate::s;
|
||||||
use crate::{
|
use crate::{
|
||||||
git::{
|
core::{
|
||||||
self,
|
git::{self, repository::open::oreal::RealOpenRepository},
|
||||||
repository::open::{OpenRepositoryLike, RealOpenRepository},
|
BranchName, ForgeDetails, GitDir, RemoteUrl, RepoBranches,
|
||||||
},
|
},
|
||||||
s, BranchName, ForgeDetails, GitDir, RemoteUrl, RepoBranches,
|
err, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
|
@ -14,7 +15,7 @@ use std::{
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub type OnFetchFn = fn(&RepoBranches, &GitDir, &kxio::fs::FileSystem) -> git::fetch::Result<()>;
|
pub type OnFetchFn = fn(&RepoBranches, &GitDir, &kxio::fs::FileSystem) -> Result<()>;
|
||||||
#[derive(Clone, Debug, Constructor)]
|
#[derive(Clone, Debug, Constructor)]
|
||||||
pub struct OnFetch {
|
pub struct OnFetch {
|
||||||
repo_branches: RepoBranches,
|
repo_branches: RepoBranches,
|
||||||
|
@ -29,7 +30,7 @@ impl OnFetch {
|
||||||
///
|
///
|
||||||
/// Will return any `Err` if there is no fetch remote defined in .git/config
|
/// Will return any `Err` if there is no fetch remote defined in .git/config
|
||||||
/// of if there are any network connectivity issues with the remote server.
|
/// of if there are any network connectivity issues with the remote server.
|
||||||
pub fn invoke(&self) -> git::fetch::Result<()> {
|
pub fn invoke(&self) -> Result<()> {
|
||||||
(self.action)(&self.repo_branches, &self.gitdir, &self.fs)
|
(self.action)(&self.repo_branches, &self.gitdir, &self.fs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +43,7 @@ pub type OnPushFn = fn(
|
||||||
&RepoBranches,
|
&RepoBranches,
|
||||||
&GitDir,
|
&GitDir,
|
||||||
&kxio::fs::FileSystem,
|
&kxio::fs::FileSystem,
|
||||||
) -> git::push::Result<()>;
|
) -> Result<()>;
|
||||||
#[derive(Clone, Debug, Constructor)]
|
#[derive(Clone, Debug, Constructor)]
|
||||||
pub struct OnPush {
|
pub struct OnPush {
|
||||||
repo_branches: RepoBranches,
|
repo_branches: RepoBranches,
|
||||||
|
@ -63,7 +64,7 @@ impl OnPush {
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
to_commit: &git::GitRef,
|
to_commit: &git::GitRef,
|
||||||
force: &git::push::Force,
|
force: &git::push::Force,
|
||||||
) -> git::push::Result<()> {
|
) -> Result<()> {
|
||||||
(self.action)(
|
(self.action)(
|
||||||
repo_details,
|
repo_details,
|
||||||
branch_name,
|
branch_name,
|
||||||
|
@ -86,7 +87,7 @@ pub struct TestOpenRepository {
|
||||||
}
|
}
|
||||||
#[cfg(not(tarpaulin_include))]
|
#[cfg(not(tarpaulin_include))]
|
||||||
impl git::repository::OpenRepositoryLike for TestOpenRepository {
|
impl git::repository::OpenRepositoryLike for TestOpenRepository {
|
||||||
fn remote_branches(&self) -> git::push::Result<Vec<BranchName>> {
|
fn remote_branches(&self) -> Result<Vec<BranchName>> {
|
||||||
self.real.remote_branches()
|
self.real.remote_branches()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,14 +95,11 @@ impl git::repository::OpenRepositoryLike for TestOpenRepository {
|
||||||
self.real.find_default_remote(direction)
|
self.real.find_default_remote(direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(&self) -> Result<(), git::fetch::Error> {
|
fn fetch(&self) -> Result<()> {
|
||||||
let i: usize = *self
|
let i: usize = *self.fetch_counter.read().map_err(|_| err!("Lock"))?;
|
||||||
.fetch_counter
|
|
||||||
.read()
|
|
||||||
.map_err(|_| git::fetch::Error::Lock)?;
|
|
||||||
self.fetch_counter
|
self.fetch_counter
|
||||||
.write()
|
.write()
|
||||||
.map_err(|_| git::fetch::Error::Lock)
|
.map_err(|_| err!("Lock"))
|
||||||
.map(|mut c| *c += 1)?;
|
.map(|mut c| *c += 1)?;
|
||||||
#[allow(clippy::expect_used)]
|
#[allow(clippy::expect_used)]
|
||||||
self.on_fetch
|
self.on_fetch
|
||||||
|
@ -116,15 +114,12 @@ impl git::repository::OpenRepositoryLike for TestOpenRepository {
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
to_commit: &git::GitRef,
|
to_commit: &git::GitRef,
|
||||||
force: &git::push::Force,
|
force: &git::push::Force,
|
||||||
) -> git::push::Result<()> {
|
) -> Result<()> {
|
||||||
let i: usize = *self
|
let i: usize = *self.push_counter.read().map_err(|_| err!("Lock"))?;
|
||||||
.push_counter
|
|
||||||
.read()
|
|
||||||
.map_err(|_| git::fetch::Error::Lock)?;
|
|
||||||
println!("Push: {i}");
|
println!("Push: {i}");
|
||||||
self.push_counter
|
self.push_counter
|
||||||
.write()
|
.write()
|
||||||
.map_err(|_| git::fetch::Error::Lock)
|
.map_err(|_| err!("Lock"))
|
||||||
.map(|mut c| *c += 1)?;
|
.map(|mut c| *c += 1)?;
|
||||||
#[allow(clippy::expect_used)]
|
#[allow(clippy::expect_used)]
|
||||||
self.on_push
|
self.on_push
|
||||||
|
@ -137,17 +132,17 @@ impl git::repository::OpenRepositoryLike for TestOpenRepository {
|
||||||
&self,
|
&self,
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
find_commits: &[git::Commit],
|
find_commits: &[git::Commit],
|
||||||
) -> git::commit::log::Result<Vec<git::Commit>> {
|
) -> Result<Vec<git::Commit>> {
|
||||||
self.real.commit_log(branch_name, find_commits)
|
self.real.commit_log(branch_name, find_commits)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file(&self, branch_name: &BranchName, file_name: &Path) -> git::file::Result<String> {
|
fn read_file(&self, branch_name: &BranchName, file_name: &Path) -> Result<String> {
|
||||||
self.real.read_file(branch_name, file_name)
|
self.real.read_file(branch_name, file_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn duplicate(&self) -> Box<dyn OpenRepositoryLike> {
|
// fn duplicate(&self) -> Box<dyn super::OpenRepositoryLike> {
|
||||||
Box::new(self.clone())
|
// Box::new(self.clone())
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
impl TestOpenRepository {
|
impl TestOpenRepository {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
|
@ -1,6 +1,6 @@
|
||||||
use std::ops::Deref as _;
|
use std::ops::Deref as _;
|
||||||
|
|
||||||
use crate::CommitCount;
|
use crate::core::CommitCount;
|
||||||
|
|
||||||
//
|
//
|
||||||
use super::*;
|
use super::*;
|
|
@ -1,12 +1,14 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{
|
||||||
|
BranchName, ForgeConfig, ForgeType, GitDir, Hostname, RepoAlias, RepoBranches, RepoConfig,
|
||||||
|
RepoConfigSource, RepoPath, ServerRepoConfig, StoragePathType, User,
|
||||||
|
},
|
||||||
git::{
|
git::{
|
||||||
self,
|
self,
|
||||||
repository::RepositoryLike as _,
|
repository::RepositoryLike as _,
|
||||||
tests::{given, then},
|
tests::{given, then},
|
||||||
},
|
},
|
||||||
BranchName, ForgeConfig, ForgeType, GitDir, Hostname, RepoAlias, RepoBranches, RepoConfig,
|
|
||||||
RepoConfigSource, RepoPath, ServerRepoConfig, StoragePathType, User,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
|
@ -14,7 +16,8 @@ use secrecy::ExposeSecret;
|
||||||
|
|
||||||
use std::{collections::BTreeMap, path::PathBuf};
|
use std::{collections::BTreeMap, path::PathBuf};
|
||||||
|
|
||||||
type TestResult = Result<(), Box<dyn std::error::Error>>;
|
// type TestResult = Result<(), Box<dyn std::error::Error>>;
|
||||||
|
type TestResult = color_eyre::Result<()>;
|
||||||
|
|
||||||
mod commit_log;
|
mod commit_log;
|
||||||
mod fetch;
|
mod fetch;
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{ForgeDetails, GitDir},
|
||||||
git::{
|
git::{
|
||||||
self,
|
self,
|
||||||
repository::{
|
repository::{
|
||||||
|
@ -11,9 +12,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
RepositoryLike, Result,
|
RepositoryLike, Result,
|
||||||
},
|
},
|
||||||
RepoDetails,
|
|
||||||
},
|
},
|
||||||
ForgeDetails, GitDir,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[allow(clippy::module_name_repetitions)]
|
#[allow(clippy::module_name_repetitions)]
|
||||||
|
@ -43,8 +42,4 @@ impl RepositoryLike for TestRepository {
|
||||||
self.forge_details.clone(),
|
self.forge_details.clone(),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn git_clone(&self, _repo_details: &RepoDetails) -> Result<OpenRepository> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{ApiToken, GitDir, StoragePathType},
|
||||||
git::{self, tests::given},
|
git::{self, tests::given},
|
||||||
ApiToken, GitDir, StoragePathType,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
|
@ -1,9 +1,12 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{
|
||||||
|
git_dir::StoragePathType, BranchName, ForgeAlias, ForgeConfig, ForgeType, GitDir, Hostname,
|
||||||
|
RemoteUrl, RepoAlias, RepoBranches, RepoConfig, RepoConfigSource, RepoPath,
|
||||||
|
ServerRepoConfig,
|
||||||
|
},
|
||||||
git::{self, Generation, GitRef, GitRemote, RepoDetails},
|
git::{self, Generation, GitRef, GitRemote, RepoDetails},
|
||||||
git_dir::StoragePathType,
|
s, Result,
|
||||||
s, webhook, BranchName, ForgeAlias, ForgeConfig, ForgeType, GitDir, Hostname, RemoteUrl,
|
|
||||||
RepoAlias, RepoBranches, RepoConfig, RepoConfigSource, RepoPath, ServerRepoConfig,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
|
@ -14,8 +17,6 @@ use std::{
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
type TestResult = Result<(), Box<dyn std::error::Error>>;
|
|
||||||
|
|
||||||
mod commit {
|
mod commit {
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -180,7 +181,7 @@ mod repo_details {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub mod given {
|
pub mod given {
|
||||||
use crate::ForgeDetails;
|
use crate::core::ForgeDetails;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -200,9 +201,9 @@ pub mod given {
|
||||||
RepoAlias::new(a_name())
|
RepoAlias::new(a_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a_pathbuf() -> PathBuf {
|
// pub fn a_pathbuf() -> PathBuf {
|
||||||
PathBuf::from(given::a_name())
|
// PathBuf::from(given::a_name())
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn a_name() -> String {
|
pub fn a_name() -> String {
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
@ -296,9 +297,12 @@ pub mod given {
|
||||||
git::commit::Sha::new(a_name())
|
git::commit::Sha::new(a_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a_webhook_push(sha: &git::commit::Sha, message: &git::commit::Message) -> webhook::Push {
|
pub fn a_webhook_push(
|
||||||
|
sha: &git::commit::Sha,
|
||||||
|
message: &git::commit::Message,
|
||||||
|
) -> crate::core::webhook::Push {
|
||||||
let branch = a_branch_name();
|
let branch = a_branch_name();
|
||||||
webhook::Push::new(branch, s!(sha), s!(message))
|
crate::core::webhook::Push::new(branch, s!(sha), s!(message))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a_filesystem() -> kxio::fs::TempFileSystem {
|
pub fn a_filesystem() -> kxio::fs::TempFileSystem {
|
||||||
|
@ -354,37 +358,39 @@ pub mod given {
|
||||||
}
|
}
|
||||||
pub mod then {
|
pub mod then {
|
||||||
|
|
||||||
|
use crate::err;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn commit_named_file_to_branch(
|
// pub fn commit_named_file_to_branch(
|
||||||
file_name: &Path,
|
// file_name: &Path,
|
||||||
contents: &str,
|
// contents: &str,
|
||||||
fs: &kxio::fs::FileSystem,
|
// fs: &kxio::fs::FileSystem,
|
||||||
gitdir: &GitDir,
|
// gitdir: &GitDir,
|
||||||
branch_name: &BranchName,
|
// branch_name: &BranchName,
|
||||||
) -> TestResult {
|
// ) -> Result<()> {
|
||||||
// git checkout ${branch_name}
|
// // git checkout ${branch_name}
|
||||||
git_checkout_new_branch(branch_name, gitdir)?;
|
// git_checkout_new_branch(branch_name, gitdir)?;
|
||||||
// echo ${word} > file-${word}
|
// // echo ${word} > file-${word}
|
||||||
let pathbuf = PathBuf::from(gitdir);
|
// let pathbuf = PathBuf::from(gitdir);
|
||||||
let file = fs.base().join(pathbuf).join(file_name);
|
// let file = fs.base().join(pathbuf).join(file_name);
|
||||||
#[allow(clippy::expect_used)]
|
// #[allow(clippy::expect_used)]
|
||||||
fs.file(&file).write(contents)?;
|
// fs.file(&file).write(contents)?;
|
||||||
// git add ${file}
|
// // git add ${file}
|
||||||
git_add_file(gitdir, &file)?;
|
// git_add_file(gitdir, &file)?;
|
||||||
// git commit -m"Added ${file}"
|
// // git commit -m"Added ${file}"
|
||||||
git_commit(gitdir, &file)?;
|
// git_commit(gitdir, &file)?;
|
||||||
|
//
|
||||||
then::push_branch(fs, gitdir, branch_name)?;
|
// then::push_branch(fs, gitdir, branch_name)?;
|
||||||
|
//
|
||||||
Ok(())
|
// Ok(())
|
||||||
}
|
// }
|
||||||
|
|
||||||
pub fn create_a_commit_on_branch(
|
pub fn create_a_commit_on_branch(
|
||||||
fs: &kxio::fs::FileSystem,
|
fs: &kxio::fs::FileSystem,
|
||||||
gitdir: &GitDir,
|
gitdir: &GitDir,
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
) -> TestResult {
|
) -> Result<()> {
|
||||||
// git checkout ${branch_name}
|
// git checkout ${branch_name}
|
||||||
git_checkout_new_branch(branch_name, gitdir)?;
|
git_checkout_new_branch(branch_name, gitdir)?;
|
||||||
// echo ${word} > file-${word}
|
// echo ${word} > file-${word}
|
||||||
|
@ -406,7 +412,7 @@ pub mod then {
|
||||||
fs: &kxio::fs::FileSystem,
|
fs: &kxio::fs::FileSystem,
|
||||||
gitdir: &GitDir,
|
gitdir: &GitDir,
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
) -> TestResult {
|
) -> Result<()> {
|
||||||
let gitrefs = fs
|
let gitrefs = fs
|
||||||
.base()
|
.base()
|
||||||
.join(gitdir.to_path_buf())
|
.join(gitdir.to_path_buf())
|
||||||
|
@ -421,7 +427,7 @@ pub mod then {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn git_checkout_new_branch(branch_name: &BranchName, gitdir: &GitDir) -> TestResult {
|
pub fn git_checkout_new_branch(branch_name: &BranchName, gitdir: &GitDir) -> Result<()> {
|
||||||
exec(
|
exec(
|
||||||
&format!("git checkout -b {branch_name}"),
|
&format!("git checkout -b {branch_name}"),
|
||||||
std::process::Command::new("/usr/bin/git")
|
std::process::Command::new("/usr/bin/git")
|
||||||
|
@ -432,7 +438,7 @@ pub mod then {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn git_switch(branch_name: &BranchName, gitdir: &GitDir) -> TestResult {
|
pub fn git_switch(branch_name: &BranchName, gitdir: &GitDir) -> Result<()> {
|
||||||
exec(
|
exec(
|
||||||
&format!("git switch {branch_name}"),
|
&format!("git switch {branch_name}"),
|
||||||
std::process::Command::new("/usr/bin/git")
|
std::process::Command::new("/usr/bin/git")
|
||||||
|
@ -442,7 +448,7 @@ pub mod then {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(label: &str, output: Result<std::process::Output, std::io::Error>) -> TestResult {
|
fn exec(label: &str, output: Result<std::process::Output, std::io::Error>) -> Result<()> {
|
||||||
println!("== {label}");
|
println!("== {label}");
|
||||||
match output {
|
match output {
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
|
@ -459,12 +465,12 @@ pub mod then {
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
println!("ERROR: {err:#?}");
|
println!("ERROR: {err:#?}");
|
||||||
Ok(Err(err)?)
|
Err(err!(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn git_add_file(gitdir: &GitDir, file: &Path) -> TestResult {
|
fn git_add_file(gitdir: &GitDir, file: &Path) -> Result<()> {
|
||||||
exec(
|
exec(
|
||||||
&format!("git add {file:?}"),
|
&format!("git add {file:?}"),
|
||||||
std::process::Command::new("/usr/bin/git")
|
std::process::Command::new("/usr/bin/git")
|
||||||
|
@ -474,7 +480,7 @@ pub mod then {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn git_commit(gitdir: &GitDir, file: &Path) -> TestResult {
|
fn git_commit(gitdir: &GitDir, file: &Path) -> Result<()> {
|
||||||
exec(
|
exec(
|
||||||
&format!(r#"git commit -m"Added {file:?}""#),
|
&format!(r#"git commit -m"Added {file:?}""#),
|
||||||
std::process::Command::new("/usr/bin/git")
|
std::process::Command::new("/usr/bin/git")
|
||||||
|
@ -484,7 +490,7 @@ pub mod then {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn git_log_all(gitdir: &GitDir) -> TestResult {
|
pub fn git_log_all(gitdir: &GitDir) -> Result<()> {
|
||||||
exec(
|
exec(
|
||||||
"git log --all --oneline --decorate --graph",
|
"git log --all --oneline --decorate --graph",
|
||||||
std::process::Command::new("/usr/bin/git")
|
std::process::Command::new("/usr/bin/git")
|
||||||
|
@ -498,7 +504,7 @@ pub mod then {
|
||||||
fs: &kxio::fs::FileSystem,
|
fs: &kxio::fs::FileSystem,
|
||||||
gitdir: &GitDir,
|
gitdir: &GitDir,
|
||||||
branch_name: &BranchName,
|
branch_name: &BranchName,
|
||||||
) -> Result<git::commit::Sha, Box<dyn std::error::Error>> {
|
) -> color_eyre::Result<git::commit::Sha> {
|
||||||
let main_ref = fs
|
let main_ref = fs
|
||||||
.base()
|
.base()
|
||||||
.join(gitdir.to_path_buf())
|
.join(gitdir.to_path_buf())
|
|
@ -1,7 +1,8 @@
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
//
|
//
|
||||||
use crate::{git::Commit, BranchName, ForgeAlias, RepoAlias};
|
use crate::core::{BranchName, ForgeAlias, RepoAlias};
|
||||||
|
use crate::git::Commit;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use super::graph::Log;
|
use super::graph::Log;
|
|
@ -1,12 +1,11 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
git::{self, repository::open::OpenRepositoryLike, RepoDetails, UserNotification},
|
core::{git::RepoDetails, BranchName, RepoConfig},
|
||||||
s, BranchName, RepoConfig,
|
git::{self, repository::open::OpenRepositoryLike, UserNotification},
|
||||||
|
Result,
|
||||||
};
|
};
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
pub type Result<T> = core::result::Result<T, Error>;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Positions {
|
pub struct Positions {
|
||||||
pub main: git::Commit,
|
pub main: git::Commit,
|
||||||
|
@ -28,35 +27,32 @@ pub fn validate(
|
||||||
open_repository: &dyn OpenRepositoryLike,
|
open_repository: &dyn OpenRepositoryLike,
|
||||||
repo_details: &git::RepoDetails,
|
repo_details: &git::RepoDetails,
|
||||||
repo_config: &RepoConfig,
|
repo_config: &RepoConfig,
|
||||||
) -> Result<(Positions, git::graph::Log)> {
|
) -> PositionsResult<(Positions, git::graph::Log)> {
|
||||||
let main_branch = repo_config.branches().main();
|
let main_branch = repo_config.branches().main();
|
||||||
let next_branch = repo_config.branches().next();
|
let next_branch = repo_config.branches().next();
|
||||||
let dev_branch = repo_config.branches().dev();
|
let dev_branch = repo_config.branches().dev();
|
||||||
// Collect Commit Histories for `main`, `next` and `dev` branches
|
// Collect Commit Histories for `main`, `next` and `dev` branches
|
||||||
open_repository.fetch()?;
|
open_repository
|
||||||
|
.fetch()
|
||||||
|
.map_err(|e| PositionsError::Retryable(e.to_string()))?;
|
||||||
let git_log = git::graph::log(repo_details);
|
let git_log = git::graph::log(repo_details);
|
||||||
|
|
||||||
let commit_histories = get_commit_histories(open_repository, repo_config)?;
|
let commit_histories = get_commit_histories(open_repository, repo_config)
|
||||||
|
.map_err(|e| PositionsError::Retryable(e.to_string()))?;
|
||||||
// branch tips
|
// branch tips
|
||||||
let main = commit_histories
|
let main = commit_histories.main.first().cloned().ok_or_else(|| {
|
||||||
.main
|
PositionsError::NonRetryable(format!("Branch has no commits: {main_branch}"))
|
||||||
.first()
|
})?;
|
||||||
.cloned()
|
let next = commit_histories.next.first().cloned().ok_or_else(|| {
|
||||||
.ok_or_else(|| Error::NonRetryable(format!("Branch has no commits: {main_branch}")))?;
|
PositionsError::NonRetryable(format!("Branch has no commits: {next_branch}"))
|
||||||
let next = commit_histories
|
})?;
|
||||||
.next
|
let dev = commit_histories.dev.first().cloned().ok_or_else(|| {
|
||||||
.first()
|
PositionsError::NonRetryable(format!("Branch has no commits: {dev_branch}"))
|
||||||
.cloned()
|
})?;
|
||||||
.ok_or_else(|| Error::NonRetryable(format!("Branch has no commits: {next_branch}")))?;
|
|
||||||
let dev = commit_histories
|
|
||||||
.dev
|
|
||||||
.first()
|
|
||||||
.cloned()
|
|
||||||
.ok_or_else(|| Error::NonRetryable(format!("Branch has no commits: {dev_branch}")))?;
|
|
||||||
// Validations:
|
// Validations:
|
||||||
// Dev must be on main branch, else the USER must rebase it
|
// Dev must be on main branch, else the USER must rebase it
|
||||||
if is_not_based_on(&commit_histories.dev, &main) {
|
if is_not_based_on(&commit_histories.dev, &main) {
|
||||||
return Err(Error::UserIntervention(
|
return Err(PositionsError::UserIntervention(
|
||||||
UserNotification::DevNotBasedOnMain {
|
UserNotification::DevNotBasedOnMain {
|
||||||
forge_alias: repo_details.forge.forge_alias().clone(),
|
forge_alias: repo_details.forge.forge_alias().clone(),
|
||||||
repo_alias: repo_details.repo_alias.clone(),
|
repo_alias: repo_details.repo_alias.clone(),
|
||||||
|
@ -121,7 +117,7 @@ fn reset_next_to_main(
|
||||||
main: &git::Commit,
|
main: &git::Commit,
|
||||||
next: &git::Commit,
|
next: &git::Commit,
|
||||||
next_branch: &BranchName,
|
next_branch: &BranchName,
|
||||||
) -> Error {
|
) -> PositionsError {
|
||||||
match git::push::reset(
|
match git::push::reset(
|
||||||
open_repository,
|
open_repository,
|
||||||
repo_details,
|
repo_details,
|
||||||
|
@ -129,8 +125,8 @@ fn reset_next_to_main(
|
||||||
&main.clone().into(),
|
&main.clone().into(),
|
||||||
&git::push::Force::From(next.clone().into()),
|
&git::push::Force::From(next.clone().into()),
|
||||||
) {
|
) {
|
||||||
Ok(()) => Error::Retryable(format!("Branch {next_branch} has been reset")),
|
Ok(()) => PositionsError::Retryable(format!("Branch {next_branch} has been reset")),
|
||||||
Err(err) => Error::NonRetryable(format!(
|
Err(err) => PositionsError::NonRetryable(format!(
|
||||||
"Failed to reset branch '{next_branch}' to commit '{next}': {err}"
|
"Failed to reset branch '{next_branch}' to commit '{next}': {err}"
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
|
@ -154,7 +150,7 @@ fn is_based_on(commits: &[git::commit::Commit], needle: &git::Commit) -> bool {
|
||||||
pub fn get_commit_histories(
|
pub fn get_commit_histories(
|
||||||
open_repository: &dyn OpenRepositoryLike,
|
open_repository: &dyn OpenRepositoryLike,
|
||||||
repo_config: &RepoConfig,
|
repo_config: &RepoConfig,
|
||||||
) -> git::commit::log::Result<git::commit::Histories> {
|
) -> Result<git::commit::Histories> {
|
||||||
debug!("main...");
|
debug!("main...");
|
||||||
let main = (open_repository.commit_log(&repo_config.branches().main(), &[]))?;
|
let main = (open_repository.commit_log(&repo_config.branches().main(), &[]))?;
|
||||||
let main_head = [main[0].clone()];
|
let main_head = [main[0].clone()];
|
||||||
|
@ -166,8 +162,9 @@ pub fn get_commit_histories(
|
||||||
Ok(histories)
|
Ok(histories)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type PositionsResult<T> = std::result::Result<T, PositionsError>;
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum Error {
|
pub enum PositionsError {
|
||||||
#[error("{0} - will retry")]
|
#[error("{0} - will retry")]
|
||||||
Retryable(String),
|
Retryable(String),
|
||||||
|
|
||||||
|
@ -177,13 +174,3 @@ pub enum Error {
|
||||||
#[error("user intervention required")]
|
#[error("user intervention required")]
|
||||||
UserIntervention(UserNotification),
|
UserIntervention(UserNotification),
|
||||||
}
|
}
|
||||||
impl From<git::fetch::Error> for Error {
|
|
||||||
fn from(value: git::fetch::Error) -> Self {
|
|
||||||
Self::Retryable(s!(value))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl From<git::commit::log::Error> for Error {
|
|
||||||
fn from(value: git::commit::log::Error) -> Self {
|
|
||||||
Self::Retryable(s!(value))
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,8 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::RemoteUrl,
|
||||||
git::{self, repository::open::OpenRepositoryLike},
|
git::{self, repository::open::OpenRepositoryLike},
|
||||||
s, RemoteUrl,
|
s,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
|
@ -44,12 +45,11 @@ pub enum Error {
|
||||||
#[error("no default fetch remote")]
|
#[error("no default fetch remote")]
|
||||||
NoDefaultFetchRemote,
|
NoDefaultFetchRemote,
|
||||||
|
|
||||||
#[error("no url for default push remote")]
|
// #[error("no url for default push remote")]
|
||||||
NoUrlForDefaultPushRemote,
|
// NoUrlForDefaultPushRemote,
|
||||||
|
|
||||||
#[error("no hostname for default push remote")]
|
|
||||||
NoHostnameForDefaultPushRemote,
|
|
||||||
|
|
||||||
|
// #[error("no hostname for default push remote")]
|
||||||
|
// NoHostnameForDefaultPushRemote,
|
||||||
#[error("unable to open repo: {0}")]
|
#[error("unable to open repo: {0}")]
|
||||||
UnableToOpenRepo(String),
|
UnableToOpenRepo(String),
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//
|
//
|
||||||
use crate::{
|
use crate::{
|
||||||
|
core::{GitDir, StoragePathType},
|
||||||
git::{
|
git::{
|
||||||
self,
|
self,
|
||||||
repository::{
|
repository::{
|
||||||
|
@ -10,7 +11,6 @@ use crate::{
|
||||||
tests::{given, then},
|
tests::{given, then},
|
||||||
validation::positions::validate,
|
validation::positions::validate,
|
||||||
},
|
},
|
||||||
s, GitDir, StoragePathType,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
|
@ -56,6 +56,10 @@ mod positions {
|
||||||
|
|
||||||
mod validate {
|
mod validate {
|
||||||
|
|
||||||
|
use git::validation::positions::PositionsError;
|
||||||
|
|
||||||
|
use crate::err;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -66,7 +70,7 @@ mod positions {
|
||||||
let mut mock_open_repository = git::repository::open::mock();
|
let mut mock_open_repository = git::repository::open::mock();
|
||||||
mock_open_repository
|
mock_open_repository
|
||||||
.expect_fetch()
|
.expect_fetch()
|
||||||
.return_once(|| Err(git::fetch::Error::TestFailureExpected));
|
.return_once(|| Err(err!("expected failure")));
|
||||||
let mut repository_factory = git::repository::factory::mock();
|
let mut repository_factory = git::repository::factory::mock();
|
||||||
repository_factory
|
repository_factory
|
||||||
.expect_open()
|
.expect_open()
|
||||||
|
@ -81,10 +85,7 @@ mod positions {
|
||||||
println!("{result:?}");
|
println!("{result:?}");
|
||||||
let_assert!(Err(err) = result, "validate");
|
let_assert!(Err(err) = result, "validate");
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(err, PositionsError::Retryable(_)));
|
||||||
err,
|
|
||||||
git::validation::positions::Error::Retryable(_)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -100,10 +101,7 @@ mod positions {
|
||||||
.expect_commit_log()
|
.expect_commit_log()
|
||||||
.returning(move |branch_name, _| {
|
.returning(move |branch_name, _| {
|
||||||
if branch_name == &main_branch {
|
if branch_name == &main_branch {
|
||||||
Err(git::commit::log::Error::Gix {
|
Err(err!("{branch_name}: foo"))
|
||||||
branch: branch_name.clone(),
|
|
||||||
error: s!("foo"),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
@ -120,10 +118,7 @@ mod positions {
|
||||||
let result = validate(&*open_repository, &repo_details, &repo_config);
|
let result = validate(&*open_repository, &repo_details, &repo_config);
|
||||||
println!("{result:?}");
|
println!("{result:?}");
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(result, Err(PositionsError::Retryable(_))));
|
||||||
result,
|
|
||||||
Err(git::validation::positions::Error::Retryable(_))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -139,10 +134,7 @@ mod positions {
|
||||||
.expect_commit_log()
|
.expect_commit_log()
|
||||||
.returning(move |branch_name, _| {
|
.returning(move |branch_name, _| {
|
||||||
if branch_name == &next_branch {
|
if branch_name == &next_branch {
|
||||||
Err(git::commit::log::Error::Gix {
|
Err(err!("{branch_name} foo"))
|
||||||
branch: branch_name.clone(),
|
|
||||||
error: s!("foo"),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![given::a_commit()])
|
Ok(vec![given::a_commit()])
|
||||||
}
|
}
|
||||||
|
@ -159,10 +151,7 @@ mod positions {
|
||||||
let result = validate(&*open_repository, &repo_details, &repo_config);
|
let result = validate(&*open_repository, &repo_details, &repo_config);
|
||||||
println!("{result:?}");
|
println!("{result:?}");
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(result, Err(PositionsError::Retryable(_))));
|
||||||
result,
|
|
||||||
Err(git::validation::positions::Error::Retryable(_))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -178,10 +167,7 @@ mod positions {
|
||||||
.expect_commit_log()
|
.expect_commit_log()
|
||||||
.returning(move |branch_name, _| {
|
.returning(move |branch_name, _| {
|
||||||
if branch_name == &dev_branch {
|
if branch_name == &dev_branch {
|
||||||
Err(git::commit::log::Error::Gix {
|
Err(err!("{branch_name} foo"))
|
||||||
branch: branch_name.clone(),
|
|
||||||
error: s!("foo"),
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
Ok(vec![given::a_commit()])
|
Ok(vec![given::a_commit()])
|
||||||
}
|
}
|
||||||
|
@ -198,10 +184,7 @@ mod positions {
|
||||||
let result = validate(&*open_repository, &repo_details, &repo_config);
|
let result = validate(&*open_repository, &repo_details, &repo_config);
|
||||||
println!("{result:?}");
|
println!("{result:?}");
|
||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(result, Err(PositionsError::Retryable(_))));
|
||||||
result,
|
|
||||||
Err(git::validation::positions::Error::Retryable(_))
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -232,7 +215,7 @@ mod positions {
|
||||||
// add a commit to next 1 -> 4
|
// add a commit to next 1 -> 4
|
||||||
then::create_a_commit_on_branch(fs, gitdir, &branches.next())?;
|
then::create_a_commit_on_branch(fs, gitdir, &branches.next())?;
|
||||||
then::git_log_all(gitdir)?;
|
then::git_log_all(gitdir)?;
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let_assert!(
|
let_assert!(
|
||||||
|
@ -250,7 +233,7 @@ mod positions {
|
||||||
//then
|
//then
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
err,
|
err,
|
||||||
git::validation::positions::Error::UserIntervention(_)
|
git::validation::positions::PositionsError::UserIntervention(_)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +266,7 @@ mod positions {
|
||||||
then::create_a_commit_on_branch(fs, gitdir, &branches.dev())?;
|
then::create_a_commit_on_branch(fs, gitdir, &branches.dev())?;
|
||||||
|
|
||||||
then::git_log_all(gitdir)?;
|
then::git_log_all(gitdir)?;
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
// second fetch as prep to push
|
// second fetch as prep to push
|
||||||
|
@ -293,7 +276,7 @@ mod positions {
|
||||||
fs.deref().clone(),
|
fs.deref().clone(),
|
||||||
|_branches, _gitdir, _fs| {
|
|_branches, _gitdir, _fs| {
|
||||||
// don't change anything
|
// don't change anything
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
test_repository.on_push(OnPush::new(
|
test_repository.on_push(OnPush::new(
|
||||||
|
@ -318,7 +301,7 @@ mod positions {
|
||||||
&git::push::Force::From(sha_next.into()),
|
&git::push::Force::From(sha_next.into()),
|
||||||
"should force push only if next is on expected sha"
|
"should force push only if next is on expected sha"
|
||||||
);
|
);
|
||||||
git::push::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let_assert!(
|
let_assert!(
|
||||||
|
@ -336,10 +319,7 @@ mod positions {
|
||||||
//then
|
//then
|
||||||
println!("Got: {err:?}");
|
println!("Got: {err:?}");
|
||||||
// NOTE: assertions for correct push are in on_push above
|
// NOTE: assertions for correct push are in on_push above
|
||||||
assert!(matches!(
|
assert!(matches!(err, PositionsError::Retryable(_)));
|
||||||
err,
|
|
||||||
git::validation::positions::Error::Retryable(_)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -370,7 +350,7 @@ mod positions {
|
||||||
then::create_a_commit_on_branch(fs, gitdir, &branches.dev())?;
|
then::create_a_commit_on_branch(fs, gitdir, &branches.dev())?;
|
||||||
|
|
||||||
then::git_log_all(gitdir)?;
|
then::git_log_all(gitdir)?;
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
// second fetch as prep to push
|
// second fetch as prep to push
|
||||||
|
@ -380,7 +360,7 @@ mod positions {
|
||||||
fs.deref().clone(),
|
fs.deref().clone(),
|
||||||
|_branches, _gitdir, _fs| {
|
|_branches, _gitdir, _fs| {
|
||||||
// don't change anything
|
// don't change anything
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
test_repository.on_push(OnPush::new(
|
test_repository.on_push(OnPush::new(
|
||||||
|
@ -388,7 +368,7 @@ mod positions {
|
||||||
gitdir.clone(),
|
gitdir.clone(),
|
||||||
fs.deref().clone(),
|
fs.deref().clone(),
|
||||||
|_repo_details, _branch_name, _gitref, _force, _repo_branches, _gitdir, _fs| {
|
|_repo_details, _branch_name, _gitref, _force, _repo_branches, _gitdir, _fs| {
|
||||||
git::push::Result::Err(git::push::Error::Lock)
|
Err(err!("Lock"))
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let_assert!(
|
let_assert!(
|
||||||
|
@ -409,10 +389,7 @@ mod positions {
|
||||||
Ok(_) = then::get_sha_for_branch(&fs, &gitdir, &repo_config.branches().next()),
|
Ok(_) = then::get_sha_for_branch(&fs, &gitdir, &repo_config.branches().next()),
|
||||||
"load next branch sha"
|
"load next branch sha"
|
||||||
);
|
);
|
||||||
assert!(matches!(
|
assert!(matches!(err, PositionsError::NonRetryable(_)));
|
||||||
err,
|
|
||||||
git::validation::positions::Error::NonRetryable(_)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
#[test]
|
#[test]
|
||||||
#[allow(clippy::expect_used)]
|
#[allow(clippy::expect_used)]
|
||||||
|
@ -441,7 +418,7 @@ mod positions {
|
||||||
then::create_a_commit_on_branch(fs, gitdir, &branches.next())?;
|
then::create_a_commit_on_branch(fs, gitdir, &branches.next())?;
|
||||||
|
|
||||||
then::git_log_all(gitdir)?;
|
then::git_log_all(gitdir)?;
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
// second fetch as prep to push
|
// second fetch as prep to push
|
||||||
|
@ -451,7 +428,7 @@ mod positions {
|
||||||
fs.deref().clone(),
|
fs.deref().clone(),
|
||||||
|_branches, _gitdir, _fs| {
|
|_branches, _gitdir, _fs| {
|
||||||
// don't change anything
|
// don't change anything
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
test_repository.on_push(OnPush::new(
|
test_repository.on_push(OnPush::new(
|
||||||
|
@ -476,7 +453,7 @@ mod positions {
|
||||||
&git::push::Force::From(sha_next.into()),
|
&git::push::Force::From(sha_next.into()),
|
||||||
"should force push only if next is on expected sha"
|
"should force push only if next is on expected sha"
|
||||||
);
|
);
|
||||||
git::push::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let_assert!(
|
let_assert!(
|
||||||
|
@ -494,10 +471,7 @@ mod positions {
|
||||||
//then
|
//then
|
||||||
println!("Got: {err:?}");
|
println!("Got: {err:?}");
|
||||||
// NOTE: assertions for correct push are in on_push above
|
// NOTE: assertions for correct push are in on_push above
|
||||||
assert!(matches!(
|
assert!(matches!(err, PositionsError::Retryable(_)));
|
||||||
err,
|
|
||||||
git::validation::positions::Error::Retryable(_)
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -528,7 +502,7 @@ mod positions {
|
||||||
then::create_a_commit_on_branch(fs, gitdir, &branches.next())?;
|
then::create_a_commit_on_branch(fs, gitdir, &branches.next())?;
|
||||||
|
|
||||||
then::git_log_all(gitdir)?;
|
then::git_log_all(gitdir)?;
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
// second fetch as prep to push
|
// second fetch as prep to push
|
||||||
|
@ -538,7 +512,7 @@ mod positions {
|
||||||
fs.deref().clone(),
|
fs.deref().clone(),
|
||||||
|_branches, _gitdir, _fs| {
|
|_branches, _gitdir, _fs| {
|
||||||
// don't change anything
|
// don't change anything
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
test_repository.on_push(OnPush::new(
|
test_repository.on_push(OnPush::new(
|
||||||
|
@ -563,7 +537,7 @@ mod positions {
|
||||||
&git::push::Force::From(sha_next.into()),
|
&git::push::Force::From(sha_next.into()),
|
||||||
"should force push only if next is on expected sha"
|
"should force push only if next is on expected sha"
|
||||||
);
|
);
|
||||||
git::push::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let_assert!(
|
let_assert!(
|
||||||
|
@ -624,7 +598,7 @@ mod positions {
|
||||||
then::create_a_commit_on_branch(fs, gitdir, &branches.dev())?;
|
then::create_a_commit_on_branch(fs, gitdir, &branches.dev())?;
|
||||||
|
|
||||||
then::git_log_all(gitdir)?;
|
then::git_log_all(gitdir)?;
|
||||||
git::fetch::Result::Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
let_assert!(
|
let_assert!(
|
|
@ -1,15 +1,15 @@
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! message {
|
macro_rules! message {
|
||||||
($name:ident, $value:ty, $docs:literal) => {
|
($name:ident, $value:ty, $docs:literal) => {
|
||||||
git_next_core::newtype!($name, $value, $docs);
|
$crate::newtype!($name, $value, $docs);
|
||||||
};
|
};
|
||||||
($name:ident, $docs:literal) => {
|
($name:ident, $docs:literal) => {
|
||||||
git_next_core::newtype!($name, $docs);
|
$crate::newtype!($name, $docs);
|
||||||
};
|
};
|
||||||
($name:ident, $value:ty => $result:ty, $docs:literal) => {
|
($name:ident, $value:ty => $result:ty, $docs:literal) => {
|
||||||
git_next_core::newtype!($name, $value, $docs);
|
$crate::newtype!($name, $value, $docs);
|
||||||
};
|
};
|
||||||
($name:ident => $result:ty, $docs:literal) => {
|
($name:ident => $result:ty, $docs:literal) => {
|
||||||
git_next_core::newtype!($name, $docs);
|
$crate::newtype!($name, $docs);
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -34,6 +34,7 @@ macro_rules! newtype {
|
||||||
)]
|
)]
|
||||||
pub struct $name($type);
|
pub struct $name($type);
|
||||||
impl $name {
|
impl $name {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn new(value: impl Into<$type>) -> Self {
|
pub fn new(value: impl Into<$type>) -> Self {
|
||||||
Self(value.into())
|
Self(value.into())
|
||||||
}
|
}
|
|
@ -6,7 +6,7 @@ use kameo::{mailbox::unbounded::UnboundedMailbox, message::Message, Actor};
|
||||||
use notify::{event::ModifyKind, RecommendedWatcher, Watcher};
|
use notify::{event::ModifyKind, RecommendedWatcher, Watcher};
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
use git_next_core::message;
|
use crate::message;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
default_on_actor_link_died, default_on_actor_panic, default_on_actor_stop, on_actor_start,
|
default_on_actor_link_died, default_on_actor_panic, default_on_actor_stop, on_actor_start,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::git::{ForgeLike, RepoDetails};
|
use crate::core::git::{ForgeLike, RepoDetails};
|
||||||
|
|
||||||
#[cfg(feature = "forgejo")]
|
#[cfg(feature = "forgejo")]
|
||||||
use crate::forges::forgejo::ForgeJo;
|
use crate::forges::forgejo::ForgeJo;
|
||||||
|
@ -16,9 +16,9 @@ impl Forge {
|
||||||
pub fn create(repo_details: RepoDetails, net: Net) -> Box<dyn ForgeLike> {
|
pub fn create(repo_details: RepoDetails, net: Net) -> Box<dyn ForgeLike> {
|
||||||
match repo_details.forge.forge_type() {
|
match repo_details.forge.forge_type() {
|
||||||
#[cfg(feature = "forgejo")]
|
#[cfg(feature = "forgejo")]
|
||||||
git_next_core::ForgeType::ForgeJo => Box::new(ForgeJo::new(repo_details, net)),
|
crate::core::ForgeType::ForgeJo => Box::new(ForgeJo::new(repo_details, net)),
|
||||||
#[cfg(feature = "github")]
|
#[cfg(feature = "github")]
|
||||||
git_next_core::ForgeType::GitHub => Box::new(Github::new(repo_details, net)),
|
crate::core::ForgeType::GitHub => Box::new(Github::new(repo_details, net)),
|
||||||
_ => {
|
_ => {
|
||||||
drop(repo_details);
|
drop(repo_details);
|
||||||
drop(net);
|
drop(net);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#[cfg(any(feature = "forgejo", feature = "github"))]
|
#[cfg(any(feature = "forgejo", feature = "github"))]
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use git_next_core::{
|
use crate::core::{
|
||||||
self as core,
|
self as core,
|
||||||
git::{self, RepoDetails},
|
git::{self, RepoDetails},
|
||||||
GitDir, RepoConfigSource, StoragePathType,
|
GitDir, RepoConfigSource, StoragePathType,
|
||||||
|
@ -12,7 +12,7 @@ use git_next_core::{
|
||||||
#[test]
|
#[test]
|
||||||
fn test_forgejo_name() {
|
fn test_forgejo_name() {
|
||||||
let mock_net = kxio::net::mock();
|
let mock_net = kxio::net::mock();
|
||||||
let repo_details = given_repo_details(git_next_core::ForgeType::ForgeJo);
|
let repo_details = given_repo_details(crate::core::ForgeType::ForgeJo);
|
||||||
let forge = Forge::create(repo_details, mock_net.clone().into());
|
let forge = Forge::create(repo_details, mock_net.clone().into());
|
||||||
assert_eq!(forge.name(), "forgejo");
|
assert_eq!(forge.name(), "forgejo");
|
||||||
mock_net.assert_no_unused_plans();
|
mock_net.assert_no_unused_plans();
|
||||||
|
@ -22,14 +22,14 @@ fn test_forgejo_name() {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_github_name() {
|
fn test_github_name() {
|
||||||
let mock_net = kxio::net::mock();
|
let mock_net = kxio::net::mock();
|
||||||
let repo_details = given_repo_details(git_next_core::ForgeType::GitHub);
|
let repo_details = given_repo_details(crate::core::ForgeType::GitHub);
|
||||||
let forge = Forge::create(repo_details, mock_net.clone().into());
|
let forge = Forge::create(repo_details, mock_net.clone().into());
|
||||||
assert_eq!(forge.name(), "github");
|
assert_eq!(forge.name(), "github");
|
||||||
mock_net.assert_no_unused_plans();
|
mock_net.assert_no_unused_plans();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn given_repo_details(forge_type: git_next_core::ForgeType) -> RepoDetails {
|
fn given_repo_details(forge_type: crate::core::ForgeType) -> RepoDetails {
|
||||||
let fs = kxio::fs::temp().unwrap_or_else(|e| {
|
let fs = kxio::fs::temp().unwrap_or_else(|e| {
|
||||||
println!("{e}");
|
println!("{e}");
|
||||||
panic!("fs")
|
panic!("fs")
|
||||||
|
|
|
@ -6,7 +6,7 @@ mod webhook;
|
||||||
|
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
|
||||||
use git_next_core::{
|
use crate::core::{
|
||||||
self as core,
|
self as core,
|
||||||
git::{self, forge::commit::Status},
|
git::{self, forge::commit::Status},
|
||||||
server::RepoListenUrl,
|
server::RepoListenUrl,
|
||||||
|
@ -31,6 +31,8 @@ impl git::ForgeLike for ForgeJo {
|
||||||
fn duplicate(&self) -> Box<dyn git::ForgeLike> {
|
fn duplicate(&self) -> Box<dyn git::ForgeLike> {
|
||||||
Box::new(self.clone())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
"forgejo".to_string()
|
"forgejo".to_string()
|
||||||
}
|
}
|
||||||
|
@ -74,6 +76,7 @@ impl git::ForgeLike for ForgeJo {
|
||||||
Ok(status)
|
Ok(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
async fn list_webhooks(
|
async fn list_webhooks(
|
||||||
&self,
|
&self,
|
||||||
repo_listen_url: &RepoListenUrl,
|
repo_listen_url: &RepoListenUrl,
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
use crate::forges::forgejo::ForgeJo;
|
use crate::forges::forgejo::ForgeJo;
|
||||||
|
|
||||||
use git_next_core::{
|
use crate::core::{
|
||||||
git::{self, forge::commit::Status, ForgeLike as _},
|
git::{self, forge::commit::Status, ForgeLike as _},
|
||||||
server::{ListenUrl, RepoListenUrl},
|
server::{ListenUrl, RepoListenUrl},
|
||||||
BranchName, ForgeAlias, ForgeConfig, ForgeNotification, ForgeType, GitDir, Hostname, RepoAlias,
|
BranchName, ForgeAlias, ForgeConfig, ForgeNotification, ForgeType, GitDir, Hostname, RepoAlias,
|
||||||
|
@ -99,7 +99,7 @@ mod forgejo {
|
||||||
let next = repo_branches.next();
|
let next = repo_branches.next();
|
||||||
let sha = given::a_name();
|
let sha = given::a_name();
|
||||||
let message = given::a_name();
|
let message = given::a_name();
|
||||||
let body = git_next_core::webhook::forge_notification::Body::new(
|
let body = crate::core::webhook::forge_notification::Body::new(
|
||||||
json!({"ref":format!("refs/heads/{next}"),"after":sha,"head_commit":{"message":message}})
|
json!({"ref":format!("refs/heads/{next}"),"after":sha,"head_commit":{"message":message}})
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
@ -108,7 +108,7 @@ mod forgejo {
|
||||||
assert_eq!(push.message(), message);
|
assert_eq!(push.message(), message);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
push.branch(&repo_branches),
|
push.branch(&repo_branches),
|
||||||
Some(git_next_core::webhook::push::Branch::Next)
|
Some(crate::core::webhook::push::Branch::Next)
|
||||||
);
|
);
|
||||||
mock_net.assert_no_unused_plans();
|
mock_net.assert_no_unused_plans();
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ mod forgejo {
|
||||||
let fs = given::a_filesystem();
|
let fs = given::a_filesystem();
|
||||||
let mock_net = given::a_network();
|
let mock_net = given::a_network();
|
||||||
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
|
let forge = given::a_forgejo_forge(&given::repo_details(&fs), mock_net.clone());
|
||||||
let body = git_next_core::webhook::forge_notification::Body::new(
|
let body = crate::core::webhook::forge_notification::Body::new(
|
||||||
r#"{"type":"invalid"}"#.to_string(),
|
r#"{"type":"invalid"}"#.to_string(),
|
||||||
);
|
);
|
||||||
let_assert!(Err(_) = forge.parse_webhook_body(&body));
|
let_assert!(Err(_) = forge.parse_webhook_body(&body));
|
||||||
|
@ -651,8 +651,8 @@ mod forgejo {
|
||||||
}
|
}
|
||||||
mod given {
|
mod given {
|
||||||
|
|
||||||
|
use crate::core::server::RepoListenUrl;
|
||||||
use git::RepoDetails;
|
use git::RepoDetails;
|
||||||
use git_next_core::server::RepoListenUrl;
|
|
||||||
use kxio::net::{MockNet, StatusCode};
|
use kxio::net::{MockNet, StatusCode};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -739,8 +739,8 @@ mod forgejo {
|
||||||
WebhookAuth::generate()
|
WebhookAuth::generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn a_webhook_message_body() -> git_next_core::webhook::forge_notification::Body {
|
pub fn a_webhook_message_body() -> crate::core::webhook::forge_notification::Body {
|
||||||
git_next_core::webhook::forge_notification::Body::new(a_name())
|
crate::core::webhook::forge_notification::Body::new(a_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn repo_branches() -> RepoBranches {
|
pub fn repo_branches() -> RepoBranches {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git, server::RepoListenUrl, WebhookId};
|
use crate::core::{git, server::RepoListenUrl, WebhookId};
|
||||||
use kxio::net::Net;
|
use kxio::net::Net;
|
||||||
|
|
||||||
use crate::forges::forgejo::webhook::Hook;
|
use crate::forges::forgejo::webhook::Hook;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git, webhook, BranchName, WebhookId};
|
use crate::core::{git, webhook, BranchName, WebhookId};
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use crate::forges::forgejo;
|
use crate::forges::forgejo;
|
||||||
|
|
||||||
use git_next_core::{git, webhook};
|
use crate::core::{git, webhook};
|
||||||
|
|
||||||
pub fn parse_body(
|
pub fn parse_body(
|
||||||
body: &webhook::forge_notification::Body,
|
body: &webhook::forge_notification::Body,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{
|
use crate::core::{
|
||||||
git::{self, forge::webhook::Error},
|
git::{self, forge::webhook::Error},
|
||||||
server::RepoListenUrl,
|
server::RepoListenUrl,
|
||||||
RegisteredWebhook, WebhookAuth, WebhookId,
|
RegisteredWebhook, WebhookAuth, WebhookId,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git, WebhookId};
|
use crate::core::{git, WebhookId};
|
||||||
|
|
||||||
use kxio::net::Net;
|
use kxio::net::Net;
|
||||||
use secrecy::ExposeSecret as _;
|
use secrecy::ExposeSecret as _;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
|
use crate::core::git::{self, forge::commit::Status};
|
||||||
use crate::forges::github::{self as github, GithubState};
|
use crate::forges::github::{self as github, GithubState};
|
||||||
use git_next_core::git::{self, forge::commit::Status};
|
|
||||||
use github::GithubStatus;
|
use github::GithubStatus;
|
||||||
|
|
||||||
/// Checks the results of any (e.g. CI) status checks for the commit.
|
/// Checks the results of any (e.g. CI) status checks for the commit.
|
||||||
|
|
|
@ -5,12 +5,12 @@ mod tests;
|
||||||
mod commit;
|
mod commit;
|
||||||
pub mod webhook;
|
pub mod webhook;
|
||||||
|
|
||||||
use crate::forges::github;
|
use crate::core::{
|
||||||
use git_next_core::{
|
|
||||||
self as core, git,
|
self as core, git,
|
||||||
server::{self, RepoListenUrl},
|
server::{self, RepoListenUrl},
|
||||||
ForgeNotification, RegisteredWebhook, WebhookAuth, WebhookId,
|
ForgeNotification, RegisteredWebhook, WebhookAuth, WebhookId,
|
||||||
};
|
};
|
||||||
|
use crate::forges::github;
|
||||||
|
|
||||||
use derive_more::Constructor;
|
use derive_more::Constructor;
|
||||||
|
|
||||||
|
@ -24,6 +24,8 @@ impl git::ForgeLike for Github {
|
||||||
fn duplicate(&self) -> Box<dyn git::ForgeLike> {
|
fn duplicate(&self) -> Box<dyn git::ForgeLike> {
|
||||||
Box::new(self.clone())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
fn name(&self) -> String {
|
fn name(&self) -> String {
|
||||||
"github".to_string()
|
"github".to_string()
|
||||||
}
|
}
|
||||||
|
@ -58,6 +60,7 @@ impl git::ForgeLike for Github {
|
||||||
github::commit::status(self, commit).await
|
github::commit::status(self, commit).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
async fn list_webhooks(
|
async fn list_webhooks(
|
||||||
&self,
|
&self,
|
||||||
repo_listen_url: &RepoListenUrl,
|
repo_listen_url: &RepoListenUrl,
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
//
|
//
|
||||||
#![allow(clippy::expect_used)]
|
#![allow(clippy::expect_used)]
|
||||||
|
|
||||||
use crate::forges::github::{Github, GithubState, GithubStatus};
|
use crate::core::{
|
||||||
use git_next_core::{
|
|
||||||
git::{self, forge::commit::Status, ForgeLike},
|
git::{self, forge::commit::Status, ForgeLike},
|
||||||
server::ListenUrl,
|
server::ListenUrl,
|
||||||
webhook::{self, forge_notification::Body},
|
webhook::{self, forge_notification::Body},
|
||||||
ForgeAlias, ForgeConfig, ForgeNotification, ForgeType, GitDir, Hostname, RepoAlias,
|
ForgeAlias, ForgeConfig, ForgeNotification, ForgeType, GitDir, Hostname, RepoAlias,
|
||||||
RepoBranches, RepoPath, ServerRepoConfig, StoragePathType, WebhookAuth, WebhookId,
|
RepoBranches, RepoPath, ServerRepoConfig, StoragePathType, WebhookAuth, WebhookId,
|
||||||
};
|
};
|
||||||
|
use crate::forges::github::{Github, GithubState, GithubStatus};
|
||||||
|
|
||||||
use assert2::let_assert;
|
use assert2::let_assert;
|
||||||
use kxio::net::{MockNet, StatusCode};
|
use kxio::net::{MockNet, StatusCode};
|
||||||
|
@ -488,7 +488,7 @@ mod github {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod with {
|
pub mod with {
|
||||||
use git_next_core::server::RepoListenUrl;
|
use crate::core::server::RepoListenUrl;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -546,8 +546,8 @@ mod github {
|
||||||
|
|
||||||
mod given {
|
mod given {
|
||||||
|
|
||||||
|
use crate::core::server::RepoListenUrl;
|
||||||
use git::RepoDetails;
|
use git::RepoDetails;
|
||||||
use git_next_core::server::RepoListenUrl;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
@ -657,7 +657,7 @@ mod github {
|
||||||
),
|
),
|
||||||
&a_forge_alias(),
|
&a_forge_alias(),
|
||||||
&ForgeConfig::new(
|
&ForgeConfig::new(
|
||||||
ForgeType::ForgeJo,
|
ForgeType::GitHub,
|
||||||
a_name(),
|
a_name(),
|
||||||
a_name(),
|
a_name(),
|
||||||
a_name(),
|
a_name(),
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use std::string::ToString;
|
use std::string::ToString;
|
||||||
|
|
||||||
use git_next_core::{ForgeNotification, WebhookAuth};
|
use crate::core::{ForgeNotification, WebhookAuth};
|
||||||
|
|
||||||
use hmac::Mac;
|
use hmac::Mac;
|
||||||
type HmacSha256 = hmac::Hmac<sha2::Sha256>;
|
type HmacSha256 = hmac::Hmac<sha2::Sha256>;
|
||||||
|
@ -25,7 +25,7 @@ pub fn is_authorised(msg: &ForgeNotification, webhook_auth: &WebhookAuth) -> boo
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub fn sign_body(
|
pub fn sign_body(
|
||||||
webhook_auth: &WebhookAuth,
|
webhook_auth: &WebhookAuth,
|
||||||
body: &git_next_core::webhook::forge_notification::Body,
|
body: &crate::core::webhook::forge_notification::Body,
|
||||||
) -> Option<String> {
|
) -> Option<String> {
|
||||||
let payload = body.as_str();
|
let payload = body.as_str();
|
||||||
let mut hmac = HmacSha256::new_from_slice(webhook_auth.to_string().as_bytes()).ok()?;
|
let mut hmac = HmacSha256::new_from_slice(webhook_auth.to_string().as_bytes()).ok()?;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
|
use crate::core::{git, server::RepoListenUrl, WebhookId};
|
||||||
use crate::forges::github;
|
use crate::forges::github;
|
||||||
use git_next_core::{git, server::RepoListenUrl, WebhookId};
|
|
||||||
|
|
||||||
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#list-repository-webhooks
|
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#list-repository-webhooks
|
||||||
pub async fn list(
|
pub async fn list(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
//
|
//
|
||||||
use git_next_core::{git, webhook, ApiToken, BranchName};
|
use crate::core::{git, webhook, ApiToken, BranchName};
|
||||||
|
|
||||||
pub mod authorisation;
|
pub mod authorisation;
|
||||||
mod list;
|
mod list;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
use crate::forges::github;
|
use crate::forges::github;
|
||||||
|
|
||||||
use git_next_core::{git, webhook};
|
use crate::core::{git, webhook};
|
||||||
|
|
||||||
pub fn parse_body(
|
pub fn parse_body(
|
||||||
body: &webhook::forge_notification::Body,
|
body: &webhook::forge_notification::Body,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
|
use crate::core::{git, server::RepoListenUrl, RegisteredWebhook, WebhookAuth, WebhookId};
|
||||||
use crate::forges::github::{self as github, webhook};
|
use crate::forges::github::{self as github, webhook};
|
||||||
use git_next_core::{git, server::RepoListenUrl, RegisteredWebhook, WebhookAuth, WebhookId};
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#create-a-repository-webhook
|
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#create-a-repository-webhook
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//
|
//
|
||||||
|
use crate::core::{git, WebhookId};
|
||||||
use crate::forges::github;
|
use crate::forges::github;
|
||||||
use git_next_core::{git, WebhookId};
|
|
||||||
|
|
||||||
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#delete-a-repository-webhook
|
// https://docs.github.com/en/rest/repos/webhooks?apiVersion=2022-11-28#delete-a-repository-webhook
|
||||||
pub async fn unregister(
|
pub async fn unregister(
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue