Compare commits
2 commits
ad358ad7c2
...
c37bd2c64d
Author | SHA1 | Date | |
---|---|---|---|
c37bd2c64d | |||
8c19680056 |
25 changed files with 291 additions and 57 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -993,6 +993,7 @@ dependencies = [
|
||||||
"secrecy",
|
"secrecy",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"take-until",
|
||||||
"test-log",
|
"test-log",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"time",
|
"time",
|
||||||
|
@ -3635,6 +3636,12 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "take-until"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8bdb6fa0dfa67b38c1e66b7041ba9dcf23b99d8121907cd31c807a332f7a0bbb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.10.1"
|
version = "3.10.1"
|
||||||
|
|
|
@ -84,6 +84,9 @@ anyhow = "1.0"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
pike = "0.1"
|
pike = "0.1"
|
||||||
|
|
||||||
|
# iters
|
||||||
|
take-until = "0.2"
|
||||||
|
|
||||||
# file watcher
|
# file watcher
|
||||||
notify = "6.1"
|
notify = "6.1"
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
//
|
//
|
||||||
use git_next_core::{git::UserNotification, message, server::Shout};
|
use git_next_core::{git::UserNotification, message, server::Shout};
|
||||||
|
|
||||||
message!(UpdateShout: Shout: "Updated Shout configuration");
|
message!(UpdateShout, Shout, "Updated Shout configuration");
|
||||||
|
|
||||||
message!(NotifyUser: UserNotification: "Request to send the message payload to the notification webhook");
|
message!(
|
||||||
|
NotifyUser,
|
||||||
|
UserNotification,
|
||||||
|
"Request to send the message payload to the notification webhook"
|
||||||
|
);
|
||||||
|
|
|
@ -6,22 +6,37 @@ use git_next_core::{
|
||||||
message, newtype, ForgeNotification, RegisteredWebhook, RepoConfig, WebhookAuth, WebhookId,
|
message, newtype, ForgeNotification, RegisteredWebhook, RepoConfig, WebhookAuth, WebhookId,
|
||||||
};
|
};
|
||||||
|
|
||||||
message!(LoadConfigFromRepo: "Request to load the `git-next.toml` from the git repo.");
|
message!(
|
||||||
message!(CloneRepo: "Request to clone (or open) the git repo.");
|
LoadConfigFromRepo,
|
||||||
message!(ReceiveRepoConfig: RepoConfig: r#"Notification that the `git-next.toml` file has been loaded from the repo and parsed.
|
"Request to load the `git-next.toml` from the git repo."
|
||||||
|
);
|
||||||
|
message!(CloneRepo, "Request to clone (or open) the git repo.");
|
||||||
|
message!(
|
||||||
|
ReceiveRepoConfig,
|
||||||
|
RepoConfig,
|
||||||
|
r#"Notification that the `git-next.toml` file has been loaded from the repo and parsed.
|
||||||
|
|
||||||
Contains the parsed contents of the `git-next.toml` file."#);
|
Contains the parsed contents of the `git-next.toml` file."#
|
||||||
message!(ValidateRepo: MessageToken: r#"Request that the state of the branches in the git repo be assessed and generate any followup actions.
|
);
|
||||||
|
message!(
|
||||||
|
ValidateRepo,
|
||||||
|
MessageToken,
|
||||||
|
r#"Request that the state of the branches in the git repo be assessed and generate any followup actions.
|
||||||
|
|
||||||
This is the main function of `git-next` where decisions are made on what branches need to be updated and when.
|
This is the main function of `git-next` where decisions are made on what branches need to be updated and when.
|
||||||
|
|
||||||
Contains a [MessageToken] to reduce duplicate messages being sent. Only messages with the latest [MessageToken] are handled,
|
Contains a [MessageToken] to reduce duplicate messages being sent. Only messages with the latest [MessageToken] are handled,
|
||||||
all others are dropped."#);
|
all others are dropped."#
|
||||||
|
);
|
||||||
|
|
||||||
message!(WebhookRegistered: (WebhookId, WebhookAuth): r#"Notification that a webhook has been registered with a forge.
|
message!(
|
||||||
|
WebhookRegistered,
|
||||||
|
(WebhookId, WebhookAuth),
|
||||||
|
r#"Notification that a webhook has been registered with a forge.
|
||||||
|
|
||||||
Contains a tuple of the ID for the webhook returned from the forge, and the unique authorisation token that
|
Contains a tuple of the ID for the webhook returned from the forge, and the unique authorisation token that
|
||||||
incoming messages from the forge must provide."#);
|
incoming messages from the forge must provide."#
|
||||||
|
);
|
||||||
impl WebhookRegistered {
|
impl WebhookRegistered {
|
||||||
pub const fn webhook_id(&self) -> &WebhookId {
|
pub const fn webhook_id(&self) -> &WebhookId {
|
||||||
&self.0 .0
|
&self.0 .0
|
||||||
|
@ -38,28 +53,51 @@ impl From<RegisteredWebhook> for WebhookRegistered {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message!(UnRegisterWebhook: "Request that the webhook be removed from the forge, so they will stop notifying us.");
|
message!(
|
||||||
|
UnRegisterWebhook,
|
||||||
|
"Request that the webhook be removed from the forge, so they will stop notifying us."
|
||||||
|
);
|
||||||
|
|
||||||
newtype!(MessageToken: u32, Copy, Default, Display, PartialOrd, Ord: r#"An incremental token used to identify the current set of messages.
|
newtype!(
|
||||||
|
MessageToken,
|
||||||
|
u32,
|
||||||
|
Copy,
|
||||||
|
Default,
|
||||||
|
Display,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
r#"An incremental token used to identify the current set of messages.
|
||||||
|
|
||||||
Primarily used by [ValidateRepo] to reduce duplicate messages. The token is incremented when a new Webhook message is
|
Primarily used by [ValidateRepo] to reduce duplicate messages. The token is incremented when a new Webhook message is
|
||||||
received, marking that message the latest, and causing any previous messages still being processed to be dropped when
|
received, marking that message the latest, and causing any previous messages still being processed to be dropped when
|
||||||
they next send a [ValidateRepo] message."#);
|
they next send a [ValidateRepo] message."#
|
||||||
|
);
|
||||||
impl MessageToken {
|
impl MessageToken {
|
||||||
pub const fn next(self) -> Self {
|
pub const fn next(self) -> Self {
|
||||||
Self(self.0 + 1)
|
Self(self.0 + 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message!(RegisterWebhook: "Requests that a Webhook be registered with the forge.");
|
message!(
|
||||||
message!(CheckCIStatus: Commit: r#"Requests that the CI status for the commit be checked.
|
RegisterWebhook,
|
||||||
|
"Requests that a Webhook be registered with the forge."
|
||||||
|
);
|
||||||
|
message!(
|
||||||
|
CheckCIStatus,
|
||||||
|
Commit,
|
||||||
|
r#"Requests that the CI status for the commit be checked.
|
||||||
|
|
||||||
Once the CI Status has been received it will be sent via a [ReceiveCIStatus] message.
|
Once the CI Status has been received it will be sent via a [ReceiveCIStatus] message.
|
||||||
|
|
||||||
Contains the commit from the tip of the `next` branch."#); // next commit
|
Contains the commit from the tip of the `next` branch."#
|
||||||
message!(ReceiveCIStatus: (Commit, Status): r#"Notification of the status of the CI checks for the commit.
|
); // next commit
|
||||||
|
message!(
|
||||||
|
ReceiveCIStatus,
|
||||||
|
(Commit, Status),
|
||||||
|
r#"Notification of the status of the CI checks for the commit.
|
||||||
|
|
||||||
Contains a tuple of the commit that was checked (the tip of the `next` branch) and the status."#); // commit and it's status
|
Contains a tuple of the commit that was checked (the tip of the `next` branch) and the status."#
|
||||||
|
); // commit and it's status
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct AdvanceNextPayload {
|
pub struct AdvanceNextPayload {
|
||||||
|
@ -67,7 +105,23 @@ pub struct AdvanceNextPayload {
|
||||||
pub main: Commit,
|
pub main: Commit,
|
||||||
pub dev_commit_history: Vec<Commit>,
|
pub dev_commit_history: Vec<Commit>,
|
||||||
}
|
}
|
||||||
message!(AdvanceNext: AdvanceNextPayload: "Request to advance the `next` branch on to the next commit on the `dev branch."); // next commit and the dev commit history
|
message!(
|
||||||
message!(AdvanceMain: Commit: "Request to advance the `main` branch on to same commit as the `next` branch."); // next commit
|
AdvanceNext,
|
||||||
message!(WebhookNotification: ForgeNotification: "Notification of a webhook message from the forge.");
|
AdvanceNextPayload,
|
||||||
message!(NotifyUser: UserNotification: "Request to send the message payload to the notification webhook");
|
"Request to advance the `next` branch on to the next commit on the `dev branch."
|
||||||
|
); // next commit and the dev commit history
|
||||||
|
message!(
|
||||||
|
AdvanceMain,
|
||||||
|
Commit,
|
||||||
|
"Request to advance the `main` branch on to same commit as the `next` branch."
|
||||||
|
); // next commit
|
||||||
|
message!(
|
||||||
|
WebhookNotification,
|
||||||
|
ForgeNotification,
|
||||||
|
"Notification of a webhook message from the forge."
|
||||||
|
);
|
||||||
|
message!(
|
||||||
|
NotifyUser,
|
||||||
|
UserNotification,
|
||||||
|
"Request to send the message payload to the notification webhook"
|
||||||
|
);
|
||||||
|
|
|
@ -78,7 +78,7 @@ impl ActorLog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
message!(ExamineActor => RepoActorView: "Request a view of the current state of the [RepoActor].");
|
message!(ExamineActor => RepoActorView, "Request a view of the current state of the [RepoActor].");
|
||||||
impl Handler<ExamineActor> for RepoActor {
|
impl Handler<ExamineActor> for RepoActor {
|
||||||
type Result = RepoActorView;
|
type Result = RepoActorView;
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,15 @@ use git_next_core::{
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
// receive server config
|
// receive server config
|
||||||
message!(ReceiveAppConfig: AppConfig: "Notification of newly loaded server configuration.
|
message!(
|
||||||
|
ReceiveAppConfig,
|
||||||
|
AppConfig,
|
||||||
|
"Notification of newly loaded server configuration.
|
||||||
|
|
||||||
This message will prompt the `git-next` server to stop and restart all repo-actors.
|
This message will prompt the `git-next` server to stop and restart all repo-actors.
|
||||||
|
|
||||||
Contains the new server configuration.");
|
Contains the new server configuration."
|
||||||
|
);
|
||||||
|
|
||||||
// receive valid server config
|
// receive valid server config
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Constructor)]
|
#[derive(Clone, Debug, PartialEq, Eq, Constructor)]
|
||||||
|
@ -22,6 +26,10 @@ pub struct ValidAppConfig {
|
||||||
pub socket_address: SocketAddr,
|
pub socket_address: SocketAddr,
|
||||||
pub storage: Storage,
|
pub storage: Storage,
|
||||||
}
|
}
|
||||||
message!(ReceiveValidAppConfig: ValidAppConfig: "Notification of validated server configuration.");
|
message!(
|
||||||
|
ReceiveValidAppConfig,
|
||||||
|
ValidAppConfig,
|
||||||
|
"Notification of validated server configuration."
|
||||||
|
);
|
||||||
|
|
||||||
message!(Shutdown: "Notification to shutdown the server actor");
|
message!(Shutdown, "Notification to shutdown the server actor");
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//
|
//
|
||||||
use git_next_core::message;
|
use git_next_core::message;
|
||||||
|
|
||||||
message!(ShutdownWebhook: "Request to shutdown the Webhook actor");
|
message!(ShutdownWebhook, "Request to shutdown the Webhook actor");
|
||||||
|
|
|
@ -57,6 +57,9 @@ serde_json = { workspace = true }
|
||||||
|
|
||||||
mockall = { workspace = true }
|
mockall = { workspace = true }
|
||||||
|
|
||||||
|
#iters
|
||||||
|
take-until = { workspace = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Testing
|
# Testing
|
||||||
assert2 = { workspace = true }
|
assert2 = { workspace = true }
|
||||||
|
|
|
@ -3,4 +3,12 @@ use serde::Serialize;
|
||||||
|
|
||||||
use crate::newtype;
|
use crate::newtype;
|
||||||
|
|
||||||
newtype!(BranchName: String, Display, Default, Hash, Serialize: "The name of a Git branch");
|
newtype!(
|
||||||
|
BranchName,
|
||||||
|
String,
|
||||||
|
Display,
|
||||||
|
Default,
|
||||||
|
Hash,
|
||||||
|
Serialize,
|
||||||
|
"The name of a Git branch"
|
||||||
|
);
|
||||||
|
|
|
@ -1,6 +1,18 @@
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
crate::newtype!(ForgeAlias: String, Hash, PartialOrd, Ord, derive_more::Display, Default, Serialize: "The name of a Forge to connect to");
|
use crate::newtype;
|
||||||
|
|
||||||
|
newtype!(
|
||||||
|
ForgeAlias,
|
||||||
|
String,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
derive_more::Display,
|
||||||
|
Default,
|
||||||
|
Serialize,
|
||||||
|
"The name of a Forge to connect to"
|
||||||
|
);
|
||||||
impl From<&ForgeAlias> for std::path::PathBuf {
|
impl From<&ForgeAlias> for std::path::PathBuf {
|
||||||
fn from(value: &ForgeAlias) -> Self {
|
fn from(value: &ForgeAlias) -> Self {
|
||||||
Self::from(&value.0)
|
Self::from(&value.0)
|
||||||
|
|
3
crates/core/src/config/graphs.rs
Normal file
3
crates/core/src/config/graphs.rs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
use crate::newtype;
|
||||||
|
|
||||||
|
newtype!(LogGraph, Vec<String>, "Git log showing branch positions");
|
|
@ -1,2 +1,10 @@
|
||||||
// The hostname of a forge
|
//
|
||||||
crate::newtype!(Hostname: String, derive_more::Display, Default: "The hostname for the forge");
|
use crate::newtype;
|
||||||
|
|
||||||
|
newtype!(
|
||||||
|
Hostname,
|
||||||
|
String,
|
||||||
|
derive_more::Display,
|
||||||
|
Default,
|
||||||
|
"The hostname for the forge"
|
||||||
|
);
|
||||||
|
|
|
@ -7,6 +7,7 @@ mod forge_config;
|
||||||
mod forge_details;
|
mod forge_details;
|
||||||
mod forge_type;
|
mod forge_type;
|
||||||
pub mod git_dir;
|
pub mod git_dir;
|
||||||
|
mod graphs;
|
||||||
mod host_name;
|
mod host_name;
|
||||||
mod registered_webhook;
|
mod registered_webhook;
|
||||||
mod remote_url;
|
mod remote_url;
|
||||||
|
|
|
@ -1,6 +1,14 @@
|
||||||
|
//
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
|
|
||||||
crate::newtype!(RemoteUrl: git_url_parse::GitUrl, derive_more::Display: "The URL of a remote repository");
|
use crate::newtype;
|
||||||
|
|
||||||
|
newtype!(
|
||||||
|
RemoteUrl,
|
||||||
|
git_url_parse::GitUrl,
|
||||||
|
derive_more::Display,
|
||||||
|
"The URL of a remote repository"
|
||||||
|
);
|
||||||
impl RemoteUrl {
|
impl RemoteUrl {
|
||||||
pub fn parse(url: impl Into<String>) -> Option<Self> {
|
pub fn parse(url: impl Into<String>) -> Option<Self> {
|
||||||
Some(Self::new(::git_url_parse::GitUrl::parse(&url.into()).ok()?))
|
Some(Self::new(::git_url_parse::GitUrl::parse(&url.into()).ok()?))
|
||||||
|
|
|
@ -3,6 +3,16 @@ use serde::Serialize;
|
||||||
|
|
||||||
use crate::newtype;
|
use crate::newtype;
|
||||||
|
|
||||||
newtype!(RepoAlias: String, Display, Default, Hash, PartialOrd, Ord, Serialize: r#"The alias of a repo.
|
newtype!(
|
||||||
|
RepoAlias,
|
||||||
|
String,
|
||||||
|
Display,
|
||||||
|
Default,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Serialize,
|
||||||
|
r#"The alias of a repo.
|
||||||
|
|
||||||
This is the alias for the repo within `git-next-server.toml`."#);
|
This is the alias for the repo within `git-next-server.toml`."#
|
||||||
|
);
|
||||||
|
|
|
@ -122,8 +122,13 @@ impl Listen {
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype!(
|
newtype!(
|
||||||
ListenUrl:
|
ListenUrl,
|
||||||
String, Serialize, Deserialize, PartialOrd, Ord, Display:
|
String,
|
||||||
|
Serialize,
|
||||||
|
Deserialize,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Display,
|
||||||
"The base url for receiving all webhooks from all forges"
|
"The base url for receiving all webhooks from all forges"
|
||||||
);
|
);
|
||||||
impl ListenUrl {
|
impl ListenUrl {
|
||||||
|
@ -133,9 +138,13 @@ impl ListenUrl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype!(ForgeWebhookUrl: String: "Raw URL from a forge Webhook");
|
newtype!(ForgeWebhookUrl, String, "Raw URL from a forge Webhook");
|
||||||
|
|
||||||
newtype!(RepoListenUrl: (ListenUrl, ForgeAlias, RepoAlias): "URL to listen for webhook from forges");
|
newtype!(
|
||||||
|
RepoListenUrl,
|
||||||
|
(ListenUrl, ForgeAlias, RepoAlias),
|
||||||
|
"URL to listen for webhook from forges"
|
||||||
|
);
|
||||||
impl Display for RepoListenUrl {
|
impl Display for RepoListenUrl {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
//
|
//
|
||||||
use crate::newtype;
|
use crate::newtype;
|
||||||
|
|
||||||
newtype!(WebhookAuth: ulid::Ulid, derive_more::Display: r#"The unique token authorisation for the webhook.
|
newtype!(
|
||||||
|
WebhookAuth,
|
||||||
|
ulid::Ulid,
|
||||||
|
derive_more::Display,
|
||||||
|
r#"The unique token authorisation for the webhook.
|
||||||
|
|
||||||
Each monitored repository has it's own unique token, and it is different each time `git-next` runs."#);
|
Each monitored repository has it's own unique token, and it is different each time `git-next` runs."#
|
||||||
|
);
|
||||||
impl WebhookAuth {
|
impl WebhookAuth {
|
||||||
/// Parses the authorisation string as a `Ulid` to create a `WebhookAuth`.
|
/// Parses the authorisation string as a `Ulid` to create a `WebhookAuth`.
|
||||||
///
|
///
|
||||||
|
|
|
@ -1,2 +1,9 @@
|
||||||
//
|
//
|
||||||
crate::newtype!(WebhookId: String, derive_more::Display: "The ID of the webhook, as returned by the forge when it is registered.");
|
use crate::newtype;
|
||||||
|
|
||||||
|
newtype!(
|
||||||
|
WebhookId,
|
||||||
|
String,
|
||||||
|
derive_more::Display,
|
||||||
|
"The ID of the webhook, as returned by the forge when it is registered."
|
||||||
|
);
|
||||||
|
|
|
@ -41,8 +41,26 @@ impl From<webhook::Push> for Commit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newtype!(Sha: String, Display, Hash,PartialOrd, Ord, Serialize: "The unique SHA for a git commit.");
|
newtype!(
|
||||||
newtype!(Message: String, Display, Hash, PartialOrd, Ord, Serialize: "The commit message for a git commit.");
|
Sha,
|
||||||
|
String,
|
||||||
|
Display,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Serialize,
|
||||||
|
"The unique SHA for a git commit."
|
||||||
|
);
|
||||||
|
newtype!(
|
||||||
|
Message,
|
||||||
|
String,
|
||||||
|
Display,
|
||||||
|
Hash,
|
||||||
|
PartialOrd,
|
||||||
|
Ord,
|
||||||
|
Serialize,
|
||||||
|
"The commit message for a git commit."
|
||||||
|
);
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Histories {
|
pub struct Histories {
|
||||||
|
|
|
@ -2,9 +2,16 @@ use derive_more::Display;
|
||||||
|
|
||||||
use crate::newtype;
|
use crate::newtype;
|
||||||
|
|
||||||
newtype!(Generation: u32, Display, Default, Copy: r#"A counter for the server generation.
|
newtype!(
|
||||||
|
Generation,
|
||||||
|
u32,
|
||||||
|
Display,
|
||||||
|
Default,
|
||||||
|
Copy,
|
||||||
|
r#"A counter for the server generation.
|
||||||
|
|
||||||
This counter is increased by one each time the server restarts itself when the configuration file is updated."#);
|
This counter is increased by one each time the server restarts itself when the configuration file is updated."#
|
||||||
|
);
|
||||||
impl Generation {
|
impl Generation {
|
||||||
pub fn inc(&mut self) {
|
pub fn inc(&mut self) {
|
||||||
self.0 += 1;
|
self.0 += 1;
|
||||||
|
|
|
@ -5,7 +5,7 @@ use derive_more::Display;
|
||||||
|
|
||||||
use crate::git::{commit::Sha, Commit};
|
use crate::git::{commit::Sha, Commit};
|
||||||
|
|
||||||
newtype!(GitRef: String, Display: "A git reference to a git commit.");
|
newtype!(GitRef, String, Display, "A git reference to a git commit.");
|
||||||
impl From<Commit> for GitRef {
|
impl From<Commit> for GitRef {
|
||||||
fn from(value: Commit) -> Self {
|
fn from(value: Commit) -> Self {
|
||||||
Self(value.sha().to_string())
|
Self(value.sha().to_string())
|
||||||
|
|
58
crates/core/src/git/graph.rs
Normal file
58
crates/core/src/git/graph.rs
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
//
|
||||||
|
|
||||||
|
use std::borrow::ToOwned;
|
||||||
|
|
||||||
|
use take_until::TakeUntilExt;
|
||||||
|
|
||||||
|
use crate::{GitDir, RepoBranches};
|
||||||
|
|
||||||
|
// create a graph to log relative positions
|
||||||
|
//
|
||||||
|
// ANCESTOR=$(git merge-base --octopus origin/main origin/next origin/dev)
|
||||||
|
// SHORT_ANCESTOR=$(echo $ANCESTOR | cut -b -7)
|
||||||
|
fn ancesstor(gitdir: &GitDir, branches: &RepoBranches) -> Option<String> {
|
||||||
|
let result = std::process::Command::new("/usr/bin/git")
|
||||||
|
.current_dir(gitdir.to_path_buf())
|
||||||
|
.args([
|
||||||
|
"merge-base",
|
||||||
|
"--octopus",
|
||||||
|
format!("origin/{}", branches.main()).as_str(),
|
||||||
|
format!("origin/{}", branches.next()).as_str(),
|
||||||
|
format!("origin/{}", branches.dev()).as_str(),
|
||||||
|
])
|
||||||
|
.output();
|
||||||
|
if let Ok(output) = result {
|
||||||
|
return String::from_utf8_lossy(output.stdout.as_slice())
|
||||||
|
.split('\n')
|
||||||
|
.take(1)
|
||||||
|
.map(|line| line.chars().take(7).collect::<String>())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.first()
|
||||||
|
.cloned();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
// git log --oneline --graph --decorate origin/main origin/dev origin/next | awk "1;/$SHORT_ANCESTOR/{exit}"
|
||||||
|
fn log(gitdir: &GitDir, branches: &RepoBranches, ancestor: &str) -> Vec<String> {
|
||||||
|
let result = std::process::Command::new("/usr/bin/git")
|
||||||
|
.current_dir(gitdir.to_path_buf())
|
||||||
|
.args([
|
||||||
|
"log",
|
||||||
|
"--oneline",
|
||||||
|
"--graph",
|
||||||
|
"--decorate",
|
||||||
|
format!("origin/{}", branches.main()).as_str(),
|
||||||
|
format!("origin/{}", branches.next()).as_str(),
|
||||||
|
format!("origin/{}", branches.dev()).as_str(),
|
||||||
|
])
|
||||||
|
.output();
|
||||||
|
if let Ok(output) = result {
|
||||||
|
return String::from_utf8_lossy(output.stdout.as_slice())
|
||||||
|
.split('\n')
|
||||||
|
.take_until(|line| line.starts_with(ancestor))
|
||||||
|
.map(ToOwned::to_owned)
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
vec![]
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ pub mod forge;
|
||||||
mod generation;
|
mod generation;
|
||||||
mod git_ref;
|
mod git_ref;
|
||||||
mod git_remote;
|
mod git_remote;
|
||||||
|
pub mod graph;
|
||||||
pub mod push;
|
pub mod push;
|
||||||
mod repo_details;
|
mod repo_details;
|
||||||
pub mod repository;
|
pub mod repository;
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
#[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);
|
git_next_core::newtype!($name, $value, $docs);
|
||||||
impl actix::prelude::Message for $name {
|
impl actix::prelude::Message for $name {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($name:ident: $docs:literal) => {
|
($name:ident, $docs:literal) => {
|
||||||
git_next_core::newtype!($name: $docs);
|
git_next_core::newtype!($name, $docs);
|
||||||
impl actix::prelude::Message for $name {
|
impl actix::prelude::Message for $name {
|
||||||
type Result = ();
|
type Result = ();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($name:ident: $value:ty => $result:ty: $docs:literal) => {
|
($name:ident, $value:ty => $result:ty, $docs:literal) => {
|
||||||
git_next_core::newtype!($name is a $value: $docs);
|
git_next_core::newtype!($name, $value, $docs);
|
||||||
impl actix::prelude::Message for $name {
|
impl actix::prelude::Message for $name {
|
||||||
type Result = $result;
|
type Result = $result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
($name:ident => $result:ty: $docs:literal) => {
|
($name:ident => $result:ty, $docs:literal) => {
|
||||||
git_next_core::newtype!($name: $docs);
|
git_next_core::newtype!($name, $docs);
|
||||||
impl actix::prelude::Message for $name {
|
impl actix::prelude::Message for $name {
|
||||||
type Result = $result;
|
type Result = $result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
//
|
//
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! newtype {
|
macro_rules! newtype {
|
||||||
($name:ident: $docs:literal) => {
|
($name:ident, $docs:literal) => {
|
||||||
#[doc = $docs]
|
#[doc = $docs]
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
|
@ -20,7 +20,7 @@ macro_rules! newtype {
|
||||||
)]
|
)]
|
||||||
pub struct $name;
|
pub struct $name;
|
||||||
};
|
};
|
||||||
($name:ident: $type:ty $(, $derive:ty)*: $docs:literal) => {
|
($name:ident, $type:ty $(, $derive:ty)*, $docs:literal) => {
|
||||||
#[doc = $docs]
|
#[doc = $docs]
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone,
|
Clone,
|
||||||
|
|
Loading…
Reference in a new issue