Skip to content

Commit

Permalink
feat: Initial Re-Write to Rust
Browse files Browse the repository at this point in the history
  • Loading branch information
GeekMasher committed Aug 8, 2024
1 parent 0659b67 commit e175195
Show file tree
Hide file tree
Showing 12 changed files with 562 additions and 0 deletions.
38 changes: 38 additions & 0 deletions src/actions/codescanning.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use super::Action;
use crate::config::Config;
use octoapp::{events::payloads::CodeScanningAlertEvent, OctoAppError};
use octocrab::Octocrab;

pub struct CodeScanningAction {}

impl Action for CodeScanningAction {
type Event = CodeScanningAlertEvent;

fn check(config: &Config, client: &octocrab::Octocrab) -> Result<bool, OctoAppError> {
let config = match config {
Config::V1(config_v1) => config_v1,
};

if !config.code_scanning.is_enabled() {
log::info!("Code Scanning feature is disabled");
return Ok(false);
}

Ok(true)
}

async fn run(
config: &Config,
client: &Octocrab,
event: &Self::Event,
) -> Result<(), OctoAppError> {
let config = match config {
Config::V1(config_v1) => config_v1,
};
log::info!("Running Code Scanning Action");

let team = config.find_team_by_repository(event.repository.full_name)?;

Ok(())
}
}
1 change: 1 addition & 0 deletions src/actions/graphql/CheckProjectBoard.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
query
15 changes: 15 additions & 0 deletions src/actions/graphql/CreateProjectBoard.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
mutation CreateProjectV2($input: CreateProjectV2Input!) {
createProjectV2(input: $input) {
projectV2 {
title
shortDescription
fields {
edges {
node {
name
}
}
}
}
}
}
24 changes: 24 additions & 0 deletions src/actions/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use codescanning::CodeScanningAction;
use octoapp::{events::payloads::CodeScanningAlertEvent, OctoAppError};

use crate::config::Config;

pub mod codescanning;
pub mod projectboard;

pub trait Action {
type Event;
/// Setup the feature if it is needed
async fn setup(config: &Config, client: &octocrab::Octocrab) -> Result<(), OctoAppError> {
Ok(())
}

/// Check if the feature is enabled
fn check(config: &Config, client: &octocrab::Octocrab) -> Result<bool, OctoAppError>;

async fn run(
config: &Config,
client: &octocrab::Octocrab,
event: &Self::Event,
) -> Result<(), OctoAppError>;
}
46 changes: 46 additions & 0 deletions src/actions/projectboard.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use octoapp::OctoAppError;

use crate::config::v1::ConfigV1 as Config;

pub struct ProjectBoardAction {}

impl ProjectBoardAction {
/// Setup the Project Board
pub async fn setup(config: &Config, client: &octocrab::Octocrab) -> Result<(), OctoAppError> {
if !config.project_board.enabled {
log::info!("GHAS Project Board feature is disabled");
return Ok(());
}
todo!("Project Board setup");
}

async fn check(config: &Config, client: &octocrab::Octocrab) -> Result<bool, OctoAppError> {
let query = include_str!("./graphql/CheckProjectBoard.graphql");

let response = client
.graphql(&serde_json::json!({
"query": query,
}))
.await?;

Ok(false)
}

async fn create(config: &Config, client: &octocrab::Octocrab) -> Result<(), OctoAppError> {
let query = include_str!("./graphql/CreateProjectBoard.graphql");

let response = client
.graphql(&serde_json::json!({
"query": query,
"variables": {
"title": &config.project_board.title,
"shortDescription": &config.project_board.description,
}
}))
.await?;

log::info!("Project Board created: {:?}", response);

Ok(())
}
}
93 changes: 93 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use clap::Parser;
use console::style;
use std::path::PathBuf;

pub const VERSION_NUMBER: &str = env!("CARGO_PKG_VERSION");
pub const AUTHOR: &str = env!("CARGO_PKG_AUTHORS");

pub const BANNER: &str = r#" ________ ___ ___ _____ _________ __________ .__ _____
/ _____/ / | \ / _ \ / _____/ \______ \ _______ _|__| ______ _ __ ___________ / _ \ ______ ______
/ \ ___/ ~ \/ /_\ \ \_____ \ | _// __ \ \/ / |/ __ \ \/ \/ // __ \_ __ \ / /_\ \\____ \\____ \
\ \_\ \ Y / | \/ \ | | \ ___/\ /| \ ___/\ /\ ___/| | \/ / | \ |_> > |_> >
\______ /\___|_ /\____|__ /_______ / |____|_ /\___ >\_/ |__|\___ >\/\_/ \___ >__| \____|__ / __/| __/
\/ \/ \/ \/ \/ \/ \/ \/ \/|__| |__|
"#;

#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Arguments {
/// Enable Debugging
#[clap(long, env, default_value_t = false)]
pub debug: bool,

/// Disable Banner
#[clap(long, default_value_t = false)]
pub disable_banner: bool,

/// Test Mode
#[clap(long, default_value_t = false)]
pub test_mode: bool,

/// Configuration file path
#[clap(short, long, env, default_value = "./config.yml")]
pub config: PathBuf,

/// GitHub Review App Team Name
#[clap(long)]
pub ghas_team_name: Option<String>,

/// GitHub Review App Tool Name
#[clap(long)]
pub ghas_tool_name: Option<String>,

/// GitHub App Endpoint
#[clap(long, env, default_value = "/github")]
pub github_app_endpoint: String,

/// GitHub App ID
#[clap(long, env = "APP_ID")]
pub github_app_id: Option<u32>,

/// GitHub App Private Key
#[clap(long, env = "PRIVATE_KEY")]
pub github_app_private_key: Option<String>,

/// GitHub App Key Path
#[clap(long, env = "PRIVATE_KEY_PATH")]
pub github_app_key_path: Option<PathBuf>,

/// GitHub App Client Secret
#[clap(long, env = "CLIENT_SECRET")]
pub github_app_client_secret: Option<String>,

/// GitHub App Webhook Secret
#[clap(long, env = "WEBHOOK_SECRET")]
pub github_app_webhook_secret: Option<String>,
}

pub fn init() -> Arguments {
dotenvy::dotenv().ok();

let arguments = Arguments::parse();

let log_level = match &arguments.debug {
false => log::LevelFilter::Info,
true => log::LevelFilter::Debug,
};

env_logger::builder()
.parse_default_env()
.filter_level(log_level)
.init();

if !arguments.disable_banner {
println!(
"{}\n {} - v{}",
style(BANNER).green(),
style(AUTHOR).red(),
style(VERSION_NUMBER).blue()
);
}

arguments
}
60 changes: 60 additions & 0 deletions src/config/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use anyhow::Result;
use std::path::PathBuf;

pub mod v1;

#[derive(Debug, Clone, serde::Deserialize)]
#[serde(untagged)]
pub enum Config {
V1(v1::ConfigV1),
}

impl Config {
pub fn new() -> Self {
Self::default()
}

/// Load the configuration from a file
pub fn load(path: impl Into<PathBuf>) -> Result<Self> {
let path = path.into();
log::info!("Loading configuration from {:?}", path);

let data = std::fs::read_to_string(&path)?;
Self::load_str(&data)
}
/// Load the configuration from a string
pub fn load_str(data: &str) -> Result<Self> {
let mut config: Self = serde_yaml::from_str(data)?;

Self::load_defaults(&mut config);

Ok(config)
}
/// Load the configuration from the command line arguments
pub fn load_arguments(arguments: &crate::cli::Arguments) -> Self {
let mut config = Self::default();
Self::load_defaults(&mut config);
config
}

fn load_defaults(config: &mut Self) {
match config {
Self::V1(ref mut config) => {
// Defaults for V1
if config.teams.is_empty() {
config.teams.push(v1::Team {
name: "ghas-reviewers".to_string(),
default: Some(true),
..Default::default()
});
}
}
}
}
}

impl Default for Config {
fn default() -> Self {
Self::V1(v1::ConfigV1::default())
}
}
Loading

0 comments on commit e175195

Please sign in to comment.