@@ -21,3 +21,5 @@ regex = "1.12.3"
|
||||
toml = "0.9.11"
|
||||
nodrift = "0.3.5"
|
||||
octocrab = "0.49.5"
|
||||
schemars = "1.2.1"
|
||||
serde_json = "1.0.149"
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::{Config, State, cli::serve::ServeCommand};
|
||||
use clap::{Parser, Subcommand};
|
||||
use schemars::schema_for;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
use crate::{Config, State, cli::serve::ServeCommand, forge_config::ForgeConfig};
|
||||
|
||||
mod serve;
|
||||
|
||||
@@ -17,6 +21,10 @@ struct Command {
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Serve(ServeCommand),
|
||||
Schema {
|
||||
#[arg(long, env = "FE_SCHEMA_FILE")]
|
||||
schema_file: PathBuf,
|
||||
},
|
||||
}
|
||||
|
||||
pub async fn execute() -> anyhow::Result<()> {
|
||||
@@ -26,5 +34,17 @@ pub async fn execute() -> anyhow::Result<()> {
|
||||
|
||||
match cli.command.expect("a subcommand") {
|
||||
Commands::Serve(cmd) => cmd.execute(&state).await,
|
||||
Commands::Schema { schema_file } => {
|
||||
let schema = schema_for!(ForgeConfig);
|
||||
|
||||
let output = serde_json::to_string_pretty(&schema)?;
|
||||
|
||||
let mut file = tokio::fs::File::create(&schema_file).await?;
|
||||
|
||||
file.write_all(output.as_bytes()).await?;
|
||||
file.flush().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,67 @@
|
||||
use regex::Regex;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct ForgeConfig {
|
||||
#[serde(flatten)]
|
||||
pub forge_type: ForgeConfigType,
|
||||
|
||||
#[serde(default = "Filter::default")]
|
||||
pub filter: Filter,
|
||||
|
||||
#[serde(default = "ForgeSchedule::default")]
|
||||
pub schedule: ForgeSchedule,
|
||||
|
||||
#[serde(default = "allow_all")]
|
||||
pub allow: Vec<ForgeRegex>,
|
||||
#[serde(default = "Vec::new")]
|
||||
pub deny: Vec<ForgeRegex>,
|
||||
|
||||
#[serde(default)]
|
||||
pub policies: Policies,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
/// # Filter
|
||||
#[derive(Clone, Debug, Deserialize, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Filter {
|
||||
/// # Allow
|
||||
/// Allowed repositories, uses regex patterns
|
||||
///
|
||||
/// ```toml
|
||||
/// allow = [".*", "^something-.*$"]
|
||||
/// ````
|
||||
#[serde(default = "allow_all")]
|
||||
pub allow: Vec<ForgeRegex>,
|
||||
|
||||
/// # Deny
|
||||
/// Denied repositories, uses regex patterns
|
||||
///
|
||||
/// ```toml
|
||||
/// deny = [".*", "^something-.*$"]
|
||||
/// ````
|
||||
#[serde(default = "deny_default")]
|
||||
pub deny: Vec<ForgeRegex>,
|
||||
}
|
||||
|
||||
impl Default for Filter {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
allow: allow_all(),
|
||||
deny: deny_default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn deny_default() -> Vec<ForgeRegex> {
|
||||
vec![]
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Policies {
|
||||
#[serde(default)]
|
||||
pub squash_merge_only: PolicyOption,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Deserialize)]
|
||||
#[derive(Clone, Debug, Default, Deserialize, JsonSchema)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct PolicyOption {
|
||||
#[serde(default)]
|
||||
@@ -39,7 +74,7 @@ fn allow_all() -> Vec<ForgeRegex> {
|
||||
}]
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[derive(Clone, Debug, Deserialize, JsonSchema)]
|
||||
pub enum ForgeSchedule {
|
||||
#[serde(rename = "cron")]
|
||||
Cron(String),
|
||||
@@ -60,6 +95,16 @@ pub struct ForgeRegex {
|
||||
regex: Regex,
|
||||
}
|
||||
|
||||
impl JsonSchema for ForgeRegex {
|
||||
fn schema_name() -> std::borrow::Cow<'static, str> {
|
||||
"regex".into()
|
||||
}
|
||||
|
||||
fn json_schema(_generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
|
||||
schemars::schema_for!(String)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ForgeRegex> for Regex {
|
||||
fn from(value: ForgeRegex) -> Self {
|
||||
value.regex
|
||||
@@ -99,20 +144,28 @@ impl<'de> Deserialize<'de> for ForgeRegex {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
// #[serde(tag = "type")]
|
||||
pub enum ForgeConfigType {
|
||||
/// GitHub forge
|
||||
#[serde(rename = "github")]
|
||||
GitHub {
|
||||
/// Credentials
|
||||
credentials: GitHubCredentials,
|
||||
|
||||
/// Organisation
|
||||
organisation: String,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
/// GitHubCredentials
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)]
|
||||
pub enum GitHubCredentials {
|
||||
/// Token
|
||||
#[serde(rename = "token")]
|
||||
Token(String),
|
||||
|
||||
/// Get token from env key
|
||||
#[serde(rename = "token_env")]
|
||||
TokenEnv(String),
|
||||
}
|
||||
|
||||
@@ -81,8 +81,8 @@ impl nodrift::Drifter for ForgeService {
|
||||
client
|
||||
.get_repositories(
|
||||
organisation,
|
||||
self.config.allow.iter().map(|a| a.into()).collect(),
|
||||
self.config.deny.iter().map(|a| a.into()).collect(),
|
||||
self.config.filter.allow.iter().map(|a| a.into()).collect(),
|
||||
self.config.filter.deny.iter().map(|a| a.into()).collect(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -95,7 +95,7 @@ impl nodrift::Drifter for ForgeService {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn load(path: &Path, state: &State) -> anyhow::Result<Vec<ForgeService>> {
|
||||
pub async fn load(path: &Path, _state: &State) -> anyhow::Result<Vec<ForgeService>> {
|
||||
if !path.exists() {
|
||||
anyhow::bail!("config path does not exist: {}", path.display());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user