Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion devprofiler/src/bitbucket/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ pub mod auth;
pub mod workspace;
pub mod repo;
mod config;
pub mod webhook;
pub mod webhook;
pub mod user;
32 changes: 32 additions & 0 deletions devprofiler/src/bitbucket/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::db::auth::auth_info;
use crate::db::user::save_user_to_db;
use crate::utils::auth::AuthInfo;
use crate::utils::user::{User, Provider, ProviderEnum};
use super::config::{bitbucket_base_url, get_api};

pub async fn get_and_save_workspace_users(workspace_id: &str, access_token: &str) {
let base_url = bitbucket_base_url();
let members_url = format!("{}/workspaces/{}/members", &base_url, workspace_id);
let response_json = get_api(&members_url, access_token, None).await;
for user_json in response_json {
let provider_id = user_json["user"]["uuid"].to_string().replace('"', "");
let user = User::new(
Provider::new(
provider_id,
ProviderEnum::Bitbucket),
user_json["user"]["display_name"].to_string().replace('"', ""),
user_json["workspace"]["slug"].to_string().replace('"', ""),
None);
save_user_to_db(&user);
}
}

pub async fn get_commit_bb(commit: &str, repo_name: &str, repo_owner: &str) {
let base_url = bitbucket_base_url();
let commits_url = format!("{}/repositories/{repo_owner}/{repo_name}/commit/{commit}", &base_url);
println!("commits url = {}", &commits_url);
let authinfo: AuthInfo = auth_info();
let access_token = authinfo.access_token();
let response_json = get_api(&commits_url, access_token, None).await;
println!("response json for commits url = {:?}", &response_json);
}
98 changes: 46 additions & 52 deletions devprofiler/src/core/review.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,55 @@ use std::env;

use serde_json::Value;

use crate::{utils::{hunk::{HunkMap, PrHunkItem}, review::Review, gitops::{commit_exists, git_pull, get_excluded_files, generate_diff, process_diff, generate_blame}}, db::{hunk::{get_hunk_from_db, store_hunkmap_to_db}, repo::get_clone_url_clone_dir, review::save_review_to_db}, core::coverage::process_coverage};
use crate::{utils::{hunk::{HunkMap, PrHunkItem}, review::Review, gitops::{commit_exists, git_pull, get_excluded_files, generate_diff, process_diff, generate_blame}}, db::{hunk::{get_hunk_from_db, store_hunkmap_to_db}, repo::get_clone_url_clone_dir, review::{save_review_to_db, self}}, core::coverage::process_coverage};

pub async fn process_review(message_data: &Vec<u8>) {
let review_opt = get_tasks(message_data);
match review_opt {
Some(review) => {
let hunk = get_hunk_from_db(&review);
match hunk {
Some(hunkval) => {
publish_hunkmap(&hunkval);
return;},
None => {}
}
let mut prvec = Vec::<PrHunkItem>::new();
println!("Processing PR : {}", review.id());
if !commit_exists(&review.base_head_commit()) || !commit_exists(&review.pr_head_commit()) {
println!("Pulling repository {} for commit history", review.repo_name());
git_pull(&review).await;
}
let fileopt = get_excluded_files(&review);
println!("fileopt = {:?}", &fileopt);
match fileopt {
Some((_, smallfiles)) => {
let diffmap = generate_diff(&review, &smallfiles);
println!("diffmap = {:?}", &diffmap);
let diffres = process_diff(&diffmap);
match diffres {
Ok(linemap) => {
let blamevec = generate_blame(&review, &linemap);
let hmapitem = PrHunkItem::new(
review.id().to_string(),
review.author().to_string(),
blamevec,
);
prvec.push(hmapitem);
}
Err(e) => {
eprint!("Unable to process diff : {e}");
}
}
let hunkmap = HunkMap::new(review.provider().to_string(),
review.repo_owner().to_string(),
review.repo_name().to_string(),
prvec,
format!("{}/hunkmap", review.db_key()),
);
store_hunkmap_to_db(&hunkmap, &review);
publish_hunkmap(&hunkmap);
process_coverage(&hunkmap).await;
},
None => {eprintln!("No files to review for PR {}", review.id());}
};
},
None => { eprintln!("No review tasks found!" ); }
};
if review_opt.is_none() {
eprintln!("No review tasks found!");
return;
}
let review = review_opt.expect("review_opt is empty");
let hunk = get_hunk_from_db(&review);
if hunk.is_some() {
let hunkval = hunk.expect("hunk is empty");
publish_hunkmap(&hunkval);
eprintln!("Hunk already in db!");
return;
}
let mut prvec = Vec::<PrHunkItem>::new();
println!("Processing PR : {}", review.id());
if !commit_exists(&review.base_head_commit()) || !commit_exists(&review.pr_head_commit()) {
println!("Pulling repository {} for commit history", review.repo_name());
git_pull(&review).await;
}
let fileopt = get_excluded_files(&review);
println!("fileopt = {:?}", &fileopt);
if fileopt.is_none() {
eprintln!("No files to review for PR {}", review.id());
return;
}
let (_, smallfiles) = fileopt.expect("fileopt is empty");
let diffmap = generate_diff(&review, &smallfiles);
println!("diffmap = {:?}", &diffmap);
let linemap = process_diff(&diffmap);
let blamevec = generate_blame(&review, &linemap).await;
let hmapitem = PrHunkItem::new(
review.id().to_string(),
review.author().to_string(),
blamevec,
);
prvec.push(hmapitem);
let hunkmap = HunkMap::new(review.provider().to_string(),
review.repo_owner().to_string(),
review.repo_name().to_string(),
prvec,
format!("{}/hunkmap", review.db_key()),
);
store_hunkmap_to_db(&hunkmap, &review);
publish_hunkmap(&hunkmap);
let hunkmap_async = hunkmap.clone();
process_coverage(&hunkmap_async).await;
}

fn get_tasks(message_data: &Vec<u8>) -> Option<Review>{
Expand Down
1 change: 1 addition & 0 deletions devprofiler/src/core/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crate::bitbucket::auth::get_access_token_from_bitbucket;
use crate::bitbucket::repo::get_workspace_repos;
use crate::bitbucket::workspace::get_bitbucket_workspaces;
use crate::bitbucket::webhook::{get_webhooks_in_repo, add_webhook};
use crate::bitbucket::user::get_and_save_workspace_users;
use crate::db::repo::save_repo_to_db;
use crate::db::webhook::save_webhook_to_db;
use crate::utils::repo::Repository;
Expand Down
3 changes: 2 additions & 1 deletion devprofiler/src/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pub mod repo;
mod config;
pub mod webhook;
pub mod hunk;
pub mod review;
pub mod review;
pub mod user;
18 changes: 18 additions & 0 deletions devprofiler/src/db/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use sled::IVec;

use crate::db::config::get_db;
use crate::utils::user::User;

pub fn save_user_to_db(user: &User) {
let db = get_db();
let provider_obj = user.provider();
let user_key = format!("{}/{}/{}",
provider_obj.provider_type().to_string(), user.workspace(), provider_obj.id());
println!("user_key = {}", &user_key);

// Serialize repo struct to JSON
let json = serde_json::to_vec(user).expect("Failed to serialize user");

// Insert JSON into sled DB
db.insert(IVec::from(user_key.as_bytes()), json).expect("Failed to upsert user into sled DB");
}
15 changes: 10 additions & 5 deletions devprofiler/src/utils/gitops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use serde::Serialize;
use sha256::digest;

use crate::bitbucket::auth::refresh_git_auth;
use crate::bitbucket::user::get_commit_bb;

use super::hunk::BlameItem;
use super::review::Review;
Expand Down Expand Up @@ -181,7 +182,7 @@ pub fn generate_diff(review: &Review, smallfiles: &Vec<StatItem>) -> HashMap<Str
return diffmap;
}

pub fn process_diff(diffmap: &HashMap<String, String>) -> Result<HashMap<String, Vec<String>>,Box<dyn Error>> {
pub fn process_diff(diffmap: &HashMap<String, String>) -> HashMap<String, Vec<String>> {
let mut linemap: HashMap<String, Vec<String>> = HashMap::new();
for (filepath, diff) in diffmap {
let mut limiterpos = Vec::new();
Expand Down Expand Up @@ -228,10 +229,10 @@ pub fn process_diff(diffmap: &HashMap<String, String>) -> Result<HashMap<String,
idx += 1;
}
}
return Ok(linemap);
return linemap;
}

pub fn generate_blame(review: &Review, linemap: &HashMap<String, Vec<String>>) -> Vec<BlameItem>{
pub async fn generate_blame(review: &Review, linemap: &HashMap<String, Vec<String>>) -> Vec<BlameItem>{
let mut blamevec = Vec::<BlameItem>::new();
let commit = review.pr_head_commit();
let clone_dir = review.clone_dir();
Expand Down Expand Up @@ -261,7 +262,8 @@ pub fn generate_blame(review: &Review, linemap: &HashMap<String, Vec<String>>) -
continue;
}
let linenumint = linenum.parse::<usize>().expect("Unable to parse linenum");
let lineauthormap = process_blamelines(&blamelines, linenumint);
let lineauthormap = process_blamelines(&blamelines, linenumint,
&review.repo_name(), &review.repo_owner()).await;
let mut linebreak = linenumint;
for lidx in linenumint..(linenumint + blamelines.len()-1) {
if lineauthormap.contains_key(&lidx) && lineauthormap.contains_key(&(lidx+1)) {
Expand Down Expand Up @@ -321,11 +323,14 @@ impl LineItem {
}
}

fn process_blamelines(blamelines: &Vec<&str>, linenum: usize) -> HashMap<usize, LineItem> {
async fn process_blamelines(blamelines: &Vec<&str>, linenum: usize,
repo_name: &str, repo_owner: &str) -> HashMap<usize, LineItem> {
let mut linemap = HashMap::<usize, LineItem>::new();
for lnum in 0..blamelines.len() {
let ln = blamelines[lnum];
let wordvec: Vec<&str> = ln.split(" ").collect();
let commit = wordvec[0];
let lineitem = get_commit_bb(commit, repo_name, repo_owner).await;
let mut author = wordvec[1];
let mut timestamp = wordvec[2];
let mut idx = 1;
Expand Down
6 changes: 3 additions & 3 deletions devprofiler/src/utils/hunk.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#[derive(Debug, Serialize, Default, Deserialize)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub struct HunkMap {
repo_provider: String,
repo_owner: String,
Expand All @@ -11,15 +11,15 @@ pub struct HunkMap {
use serde::Deserialize;
use serde::Serialize;

#[derive(Debug, Serialize, Default, Deserialize)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub struct PrHunkItem {
pr_number: String,
author: String,
blamevec: Vec<BlameItem>,
}


#[derive(Debug, Serialize, Default, Deserialize)]
#[derive(Debug, Serialize, Default, Deserialize, Clone)]
pub struct BlameItem {
author: String,
timestamp: String,
Expand Down
3 changes: 2 additions & 1 deletion devprofiler/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ pub mod auth;
pub mod webhook;
pub mod hunk;
pub mod review;
pub mod gitops;
pub mod gitops;
pub mod user;
90 changes: 90 additions & 0 deletions devprofiler/src/utils/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
use std::fmt;

use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone)]
pub enum ProviderEnum {
Bitbucket,
Github,
}

impl fmt::Display for ProviderEnum {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
ProviderEnum::Bitbucket => write!(f, "bitbucket"),
ProviderEnum::Github => write!(f, "github"),
}
}
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Provider {
id: String,
provider_type: ProviderEnum,
}

impl Provider {
// Constructor
pub fn new(id: String, provider_type: ProviderEnum) -> Self {
Self { id, provider_type }
}

// Public getter methods
pub fn id(&self) -> &String {
&self.id
}

pub fn provider_type(&self) -> &ProviderEnum {
&self.provider_type
}

// Public setter methods
pub fn set_id(&mut self, id: String) {
self.id = id;
}

pub fn set_provider_type(&mut self, provider_type: ProviderEnum) {
self.provider_type = provider_type;
}
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct User {
provider: Provider,
name: String,
workspace: String,
aliases: Option<Vec<String>>,
}

impl User {
// Constructor
pub fn new(provider: Provider, name: String, workspace: String, aliases: Option<Vec<String>>) -> Self {
Self {
provider,
name,
workspace,
aliases,
}
}

// Public getter methods
pub fn provider(&self) -> &Provider {
&self.provider
}

pub fn name(&self) -> &String {
&self.name
}

pub fn workspace(&self) -> &String {
&self.workspace
}

pub fn aliases(&self) -> &Option<Vec<String>> {
&self.aliases
}

pub fn set_aliases(&mut self, aliases: Option<Vec<String>>) {
self.aliases = aliases;
}
}