Rewrite rust #38
6
'
Normal file
6
'
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
|
#[serde(tag = "apiVersion")]
|
||||||
|
pub enum Schema {}
|
||||||
|
|
53
Cargo.lock
generated
53
Cargo.lock
generated
@ -124,6 +124,12 @@ dependencies = [
|
|||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hashbrown"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.1.19"
|
version = "0.1.19"
|
||||||
@ -155,6 +161,16 @@ version = "0.3.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indexmap"
|
||||||
|
version = "1.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"hashbrown",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.4"
|
version = "1.0.4"
|
||||||
@ -307,6 +323,7 @@ dependencies = [
|
|||||||
"eyre",
|
"eyre",
|
||||||
"octopush_core",
|
"octopush_core",
|
||||||
"octopush_infra",
|
"octopush_infra",
|
||||||
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -319,7 +336,10 @@ dependencies = [
|
|||||||
"git2",
|
"git2",
|
||||||
"hex",
|
"hex",
|
||||||
"rand",
|
"rand",
|
||||||
|
"serde",
|
||||||
|
"serde_yaml",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -512,6 +532,20 @@ name = "serde"
|
|||||||
version = "1.0.147"
|
version = "1.0.147"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.147"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
@ -524,6 +558,19 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_yaml"
|
||||||
|
version = "0.9.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6d232d893b10de3eb7258ff01974d6ee20663d8e833263c99409d4b13a0209da"
|
||||||
|
dependencies = [
|
||||||
|
"indexmap",
|
||||||
|
"itoa",
|
||||||
|
"ryu",
|
||||||
|
"serde",
|
||||||
|
"unsafe-libyaml",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sharded-slab"
|
name = "sharded-slab"
|
||||||
version = "0.1.4"
|
version = "0.1.4"
|
||||||
@ -736,6 +783,12 @@ dependencies = [
|
|||||||
"tinyvec",
|
"tinyvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unsafe-libyaml"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c1e5fa573d8ac5f1a856f8d7be41d390ee973daf97c806b2c1a465e4e1406e68"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
16
README.md
16
README.md
@ -34,10 +34,10 @@ Refer to [roadmap.md](roadmap.md)
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Octopush comes in two modes. Client or Client -> Server. Octopush can stand alone as
|
Octopush comes in two modes. Client or Client -> Server. Octopush can stand
|
||||||
a client, for smaller and less secure changes. However, for organisations, it
|
alone as a client, for smaller and less secure changes. However, for
|
||||||
may be useful to use Octopush in server mode, which supports more features, and
|
organisations, it may be useful to use Octopush in server mode, which supports
|
||||||
has extra security built in.
|
more features, and has extra security built in.
|
||||||
|
|
||||||
### Client (CLI)
|
### Client (CLI)
|
||||||
|
|
||||||
@ -182,8 +182,8 @@ To run the script use
|
|||||||
octopush process --path "write-a-readme"
|
octopush process --path "write-a-readme"
|
||||||
```
|
```
|
||||||
|
|
||||||
This will cause the octopush process to automatically apply the action on the repo
|
This will cause the octopush process to automatically apply the action on the
|
||||||
and open a pr.
|
repo and open a pr.
|
||||||
|
|
||||||
### Query repositories
|
### Query repositories
|
||||||
|
|
||||||
@ -212,8 +212,8 @@ to help test locally, as well as not cause serious issues. The server
|
|||||||
configuration is pretty much the same, except the command would look like so:
|
configuration is pretty much the same, except the command would look like so:
|
||||||
`octopush server process --path "write-a-readme" --apply`. Octopush will try to
|
`octopush server process --path "write-a-readme" --apply`. Octopush will try to
|
||||||
infer as much as possible, but it may be needed to apply some extra flags to
|
infer as much as possible, but it may be needed to apply some extra flags to
|
||||||
specify upstream repositories and such. Octopush will also help you setup keys and
|
specify upstream repositories and such. Octopush will also help you setup keys
|
||||||
such on the first run, using `octopush setup` or `octopush server setup`.
|
and such on the first run, using `octopush setup` or `octopush server setup`.
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: git.front.kjuulh.io/kjuulh/octopush/blob/main/schema/v1
|
apiVersion: action
|
||||||
name: write-a-readme
|
name: write-a-readme
|
||||||
select:
|
select:
|
||||||
repositories:
|
repositories:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
apiVersion: git.front.kjuulh.io/kjuulh/octopush/blob/main/schema/v1
|
apiVersion: action
|
||||||
name: write-a-readme
|
name: write-a-readme
|
||||||
select:
|
select:
|
||||||
repositories:
|
repositories:
|
||||||
|
@ -11,5 +11,6 @@ octopush_core = { path = "../octopush_core" }
|
|||||||
|
|
||||||
eyre = { workspace = true }
|
eyre = { workspace = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true }
|
||||||
|
tokio = { workspace = true }
|
||||||
|
|
||||||
clap = { version = "4.0.18" }
|
clap = { version = "4.0.18" }
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
|
use std::path::{self, PathBuf};
|
||||||
|
|
||||||
use clap::{Arg, ArgAction, ArgMatches, Command};
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
|
use octopush_core::schema::{self, models::Action};
|
||||||
use octopush_infra::service_register::ServiceRegister;
|
use octopush_infra::service_register::ServiceRegister;
|
||||||
|
|
||||||
pub fn execute_cmd() -> Command {
|
pub fn execute_cmd() -> Command {
|
||||||
@ -16,17 +19,39 @@ pub fn execute_cmd() -> Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> {
|
pub async fn execute_subcommand(args: &ArgMatches) -> eyre::Result<()> {
|
||||||
let _action = args
|
let action = args
|
||||||
.get_one::<String>("action")
|
.get_one::<String>("action")
|
||||||
.ok_or(eyre::anyhow!("--action is required"))?;
|
.ok_or(eyre::anyhow!("--action is required"))?;
|
||||||
|
|
||||||
let service_register = ServiceRegister::new();
|
let service_register = ServiceRegister::new();
|
||||||
|
|
||||||
service_register
|
let action_path: PathBuf = action.into();
|
||||||
.git_provider
|
|
||||||
.clone_from_url("https://git.front.kjuulh.io/kjuulh/cuddle".to_string())
|
let schema = service_register
|
||||||
|
.schema_parser
|
||||||
|
.parse_file(action_path.join("octopush.yml"))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
match schema {
|
||||||
|
schema::models::Schema::Action {
|
||||||
|
name,
|
||||||
|
select,
|
||||||
|
actions,
|
||||||
|
} => {
|
||||||
|
tracing::debug!(name, "running action");
|
||||||
|
|
||||||
|
let mut repo_clones = Vec::with_capacity(select.repositories.len());
|
||||||
|
for repo in select.repositories {
|
||||||
|
let gp = service_register.git_provider.clone();
|
||||||
|
repo_clones.push(tokio::spawn(async move { gp.clone_from_url(repo).await }));
|
||||||
|
}
|
||||||
|
|
||||||
|
for repo_clone in repo_clones {
|
||||||
|
let report = repo_clone.await??;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
service_register.cleanup().await?;
|
service_register.cleanup().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -9,7 +9,10 @@ edition = "2021"
|
|||||||
async-trait = { workspace = true }
|
async-trait = { workspace = true }
|
||||||
eyre = { workspace = true }
|
eyre = { workspace = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
tracing = { workspace = true }
|
||||||
|
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
git2 = "0.15.0"
|
git2 = "0.15.0"
|
||||||
|
serde = { version = "1.0.147", features = ["derive"] }
|
||||||
|
serde_yaml = "0.9.14"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
use git2::{Cred, RemoteCallbacks};
|
||||||
|
|
||||||
use crate::storage::DynStorageEngine;
|
use crate::storage::DynStorageEngine;
|
||||||
|
|
||||||
use super::GitProvider;
|
use super::GitProvider;
|
||||||
@ -15,9 +17,31 @@ impl GitHubGitProvider {
|
|||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl GitProvider for GitHubGitProvider {
|
impl GitProvider for GitHubGitProvider {
|
||||||
async fn clone_from_url(&self, url: String) -> eyre::Result<()> {
|
async fn clone_from_url(&self, url: String) -> eyre::Result<()> {
|
||||||
|
tracing::debug!(url, "allocating dir");
|
||||||
let dir = self.storage_engine.allocate_dir().await?;
|
let dir = self.storage_engine.allocate_dir().await?;
|
||||||
|
|
||||||
tokio::task::spawn_blocking(move || git2::Repository::clone(url.as_str(), dir.path()))
|
tokio::task::spawn_blocking(move || {
|
||||||
|
let mut callbacks = RemoteCallbacks::new();
|
||||||
|
callbacks.credentials(|url, username_from_url, _allowed_types| {
|
||||||
|
tracing::debug!(username_from_url, url, "pulling key from ssh-agent");
|
||||||
|
Cred::ssh_key_from_agent(username_from_url.unwrap())
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut fo = git2::FetchOptions::new();
|
||||||
|
fo.remote_callbacks(callbacks);
|
||||||
|
|
||||||
|
let mut builder = git2::build::RepoBuilder::new();
|
||||||
|
builder.fetch_options(fo);
|
||||||
|
|
||||||
|
let path = dir.path();
|
||||||
|
|
||||||
|
tracing::debug!(
|
||||||
|
url,
|
||||||
|
path = path.as_os_str().to_string_lossy().to_string(),
|
||||||
|
"clone git repo"
|
||||||
|
);
|
||||||
|
builder.clone(url.as_str(), path.as_path())
|
||||||
|
})
|
||||||
.await??;
|
.await??;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,2 +1,3 @@
|
|||||||
pub mod git;
|
pub mod git;
|
||||||
pub mod storage;
|
pub mod storage;
|
||||||
|
pub mod schema;
|
||||||
|
2
crates/octopush_core/src/schema/mod.rs
Normal file
2
crates/octopush_core/src/schema/mod.rs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
pub mod models;
|
||||||
|
pub mod parser;
|
26
crates/octopush_core/src/schema/models.rs
Normal file
26
crates/octopush_core/src/schema/models.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub type Repository = String;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct SelectAction {
|
||||||
|
pub repositories: Vec<Repository>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
|
||||||
|
#[serde(tag = "type")]
|
||||||
|
pub enum Action {
|
||||||
|
#[serde(rename = "go")]
|
||||||
|
Go { entry: String },
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
|
#[serde(tag = "apiVersion")]
|
||||||
|
pub enum Schema {
|
||||||
|
#[serde(rename = "action")]
|
||||||
|
Action {
|
||||||
|
name: String,
|
||||||
|
select: SelectAction,
|
||||||
|
actions: Vec<Action>,
|
||||||
|
},
|
||||||
|
}
|
69
crates/octopush_core/src/schema/parser.rs
Normal file
69
crates/octopush_core/src/schema/parser.rs
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
use std::{path::PathBuf, sync::Arc};
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use super::models::Schema;
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait SchemaParser {
|
||||||
|
async fn parse_file(&self, file: PathBuf) -> eyre::Result<Schema>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type DynSchemaParser = Arc<dyn SchemaParser + Send + Sync>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DefaultSchemaParser {}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl SchemaParser for DefaultSchemaParser {
|
||||||
|
async fn parse_file(&self, file: PathBuf) -> eyre::Result<Schema> {
|
||||||
|
let file = tokio::fs::read(file).await?;
|
||||||
|
|
||||||
|
self.parse(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DefaultSchemaParser {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(&self, contents: Vec<u8>) -> eyre::Result<Schema> {
|
||||||
|
let schema = serde_yaml::from_slice(contents.as_slice())?;
|
||||||
|
|
||||||
|
Ok(schema)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test {
|
||||||
|
use super::DefaultSchemaParser;
|
||||||
|
use crate::schema::models::{Action, Schema, SelectAction};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_parse_action() {
|
||||||
|
let content = r#"apiVersion: action
|
||||||
|
name: write-a-readme
|
||||||
|
select:
|
||||||
|
repositories:
|
||||||
|
- git@git.front.kjuulh.io:kjuulh/octopush-test.git
|
||||||
|
actions:
|
||||||
|
- type: go
|
||||||
|
entry: "main.go"
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let res = DefaultSchemaParser::new().parse(content.trim().into());
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
res.unwrap(),
|
||||||
|
Schema::Action {
|
||||||
|
name: "write-a-readme".into(),
|
||||||
|
select: SelectAction {
|
||||||
|
repositories: vec!["git@git.front.kjuulh.io:kjuulh/octopush-test.git".into()]
|
||||||
|
},
|
||||||
|
actions: vec![Action::Go {
|
||||||
|
entry: "main.go".into()
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ pub trait StorageEngine {
|
|||||||
|
|
||||||
pub type DynStorageEngine = Arc<dyn StorageEngine + Send + Sync>;
|
pub type DynStorageEngine = Arc<dyn StorageEngine + Send + Sync>;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub struct TemporaryDir {
|
pub struct TemporaryDir {
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
}
|
}
|
||||||
|
@ -2,22 +2,26 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use octopush_core::{
|
use octopush_core::{
|
||||||
git::{github::GitHubGitProvider, DynGitProvider},
|
git::{github::GitHubGitProvider, DynGitProvider},
|
||||||
|
schema::parser::{DefaultSchemaParser, DynSchemaParser},
|
||||||
storage::{local::LocalStorageEngine, DynStorageEngine},
|
storage::{local::LocalStorageEngine, DynStorageEngine},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct ServiceRegister {
|
pub struct ServiceRegister {
|
||||||
pub storage_engine: DynStorageEngine,
|
pub storage_engine: DynStorageEngine,
|
||||||
pub git_provider: DynGitProvider,
|
pub git_provider: DynGitProvider,
|
||||||
|
pub schema_parser: DynSchemaParser,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServiceRegister {
|
impl ServiceRegister {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let storage_engine = Arc::new(LocalStorageEngine::new("/tmp/octopush".into()));
|
let storage_engine = Arc::new(LocalStorageEngine::new("/tmp/octopush".into()));
|
||||||
let git_provider = Arc::new(GitHubGitProvider::new(storage_engine.clone()));
|
let git_provider = Arc::new(GitHubGitProvider::new(storage_engine.clone()));
|
||||||
|
let schema_parser = Arc::new(DefaultSchemaParser::new());
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
storage_engine,
|
storage_engine,
|
||||||
git_provider,
|
git_provider,
|
||||||
|
schema_parser,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user