diff --git a/backend/backend.did b/backend/backend.did index 3e475f7..a898131 100644 --- a/backend/backend.did +++ b/backend/backend.did @@ -18,7 +18,7 @@ type IssueLink = record { }; type FixedByErr = variant { - IssueNotFound : record { issue_nbr : int32 }; + IssueNotFound : record { github_issue_id : text }; }; type FixedByReceipt = variant { @@ -67,7 +67,7 @@ service : (authority: principal) -> { "get_merged_details": (GithubToken) -> (PrDetailsResponse); // Bounty Service "healthcheck": () -> (text); - "accept": (Contributor, github_issue_id: int32, github_pr_id: int32) -> (); + "accept": (Contributor, github_issue_id: text, github_pr_id: text) -> (); "deposit": () -> (DepositReceipt); } diff --git a/backend/src/bounty/api/accept.rs b/backend/src/bounty/api/accept.rs index 48123c0..8f07c95 100644 --- a/backend/src/bounty/api/accept.rs +++ b/backend/src/bounty/api/accept.rs @@ -1,6 +1,6 @@ use super::state::{Contributor, PullRequest, BOUNTY_STATE}; -pub fn accept_impl(contributor: Contributor, github_issue_id: i32, github_pr_id: i32) -> () { +pub fn accept_impl(contributor: Contributor, github_issue_id: String, github_pr_id: String) -> () { BOUNTY_STATE.with(|state| { if let Some(ref mut bounty_canister) = *state.borrow_mut() { let mut issue_exists = false; @@ -10,10 +10,10 @@ pub fn accept_impl(contributor: Contributor, github_issue_id: i32, github_pr_id: issue_exists = true; if !issue.bounty.accepted_prs.contains_key(&github_pr_id) { let pr = PullRequest { - id: github_pr_id, + id: github_pr_id.clone(), contributor, }; - issue.bounty.accepted_prs.insert(github_pr_id, pr); + issue.bounty.accepted_prs.insert(github_pr_id.clone(), pr); pr_exists = true; } } @@ -45,7 +45,7 @@ mod test_accept { Principal::from_text("t2y5w-qp34w-qixaj-s67wp-syrei-5yqse-xbed6-z5nsd-fszmf-izgt2-lqe") .unwrap(); init_impl(authority); - let github_issue_id = 123; + let github_issue_id = "input-output-hk/hydra/issues/1370".to_string(); BOUNTY_STATE.with(|state| { let bounty_canister = state.borrow(); if let Some(ref bounty_canister) = *bounty_canister { @@ -67,14 +67,14 @@ mod test_accept { let contributor = Principal::from_text("t2y5w-qp34w-qixaj-s67wp-syrei-5yqse-xbed6-z5nsd-fszmf-izgt2-lqe") .unwrap(); - let github_pr_id = 88; + let github_pr_id = "input-output-hk/hydra/pull/1266".to_string(); accept_impl( Contributor { address: contributor, crypto_address: "contributor_address".to_string(), }, - github_issue_id, - github_pr_id, + github_issue_id.clone(), + github_pr_id.clone(), ); BOUNTY_STATE.with(|state| { let bounty_canister = state.borrow(); diff --git a/backend/src/bounty/api/claim.rs b/backend/src/bounty/api/claim.rs index 68cb97a..c343898 100644 --- a/backend/src/bounty/api/claim.rs +++ b/backend/src/bounty/api/claim.rs @@ -1,6 +1,7 @@ use crate::bounty::api::state::{Contributor, IssueId, PullRequestId, BOUNTY_STATE}; use crate::provider::github::api::get_fixed_by::GetFixedByError; use candid::{CandidType, Principal}; +use regex::Regex; use serde::{Deserialize, Serialize}; use crate::provider::github::api::{ @@ -10,9 +11,9 @@ use crate::provider::github::client::IGithubClient; #[derive(Debug, Serialize, Deserialize, CandidType)] pub enum ClaimError { - IssueNotFound { github_issue_id: i32 }, - PRNotAccepted { github_pr_id: i32 }, - PRNotMerged { github_pr_id: i32 }, + IssueNotFound { github_issue_id: String }, + PRNotAccepted { github_pr_id: String }, + PRNotMerged { github_pr_id: String }, } // TODO: remove this after finishing draft impl. @@ -59,13 +60,20 @@ pub async fn claim_impl( }); match issue_opt { - None => return Some(ClaimError::IssueNotFound { github_issue_id }), + None => { + return Some(ClaimError::IssueNotFound { + github_issue_id: github_issue_id.clone(), + }) + } Some(issue) => match issue.bounty.accepted_prs.get(&github_pr_id) { - None => Some(ClaimError::PRNotAccepted { github_pr_id }), + None => Some(ClaimError::PRNotAccepted { + github_pr_id: github_pr_id.clone(), + }), Some(pull_request) => { let pr_response: PrDetailsResponse = - github_client.get_merged_details(github_pr_id).await; - let issue_response: IssueResponse = github_client.get_issue(github_pr_id).await; + github_client.get_merged_details(extract_pull_number(&github_pr_id).unwrap()).await; + let issue_response: IssueResponse = + github_client.get_issue(extract_issue_number(&github_issue_id).unwrap()).await; todo!() } @@ -86,22 +94,24 @@ mod test_claim { fn accept_contributor( principal: &str, crypto_address: &str, - github_issue_id: i32, - github_pr_id: i32, + github_issue_id: &str, + github_pr_id: &str, ) { accept_impl( Contributor { address: Principal::from_text(principal).unwrap(), crypto_address: crypto_address.to_string(), }, - github_issue_id, - github_pr_id, + github_issue_id.to_string(), + github_pr_id.to_string(), ); } #[test] fn test_accept() { - let github_issue_id = 123; + let github_issue_id = "input-output-hk/hydra/issues/1370"; + let github_pr_id_1 = "input-output-hk/hydra/pull/1"; + let github_pr_id_2 = "input-output-hk/hydra/pull/2"; let authority = Principal::from_text("rdmx6-jaaaa-aaaaa-aaadq-cai").unwrap(); @@ -111,20 +121,24 @@ mod test_claim { "mxzaz-hqaaa-aaaar-qaada-cai", "contributor_address_1", github_issue_id, - 1, + github_pr_id_1, ); accept_contributor( "n5wcd-faaaa-aaaar-qaaea-cai", "contributor_address_2", github_issue_id, - 2, + github_pr_id_2, ); let github_client = GithubClientMock { principal: authority, }; - let result = block_on(claim_impl(&github_client, github_issue_id, 2)); + let result = block_on(claim_impl( + &github_client, + github_issue_id.to_string(), + github_pr_id_2.to_string(), + )); match result { None => assert!(true), @@ -141,12 +155,11 @@ mod test_claim { assert_eq!( bounty_canister .github_issues - .get(&github_issue_id) + .get(&github_issue_id.to_string()) .unwrap() .bounty - .winner - .unwrap(), - 2 + .winner, + Some(github_pr_id_2.to_string()) ); } else { panic!("Bounty canister state not initialized"); @@ -154,3 +167,25 @@ mod test_claim { }); } } + +#[cfg(test)] +fn extract_pull_number(url: &str) -> Option { + let re = Regex::new(r"/pull/(\d+)").unwrap(); + if let Some(captures) = re.captures(url) { + if let Some(number) = captures.get(1) { + return number.as_str().parse().ok(); + } + } + None +} + +#[cfg(test)] +fn extract_issue_number(url: &str) -> Option { + let re = Regex::new(r"/issues/(\d+)").unwrap(); + if let Some(captures) = re.captures(url) { + if let Some(number) = captures.get(1) { + return number.as_str().parse().ok(); + } + } + None +} diff --git a/backend/src/bounty/api/state.rs b/backend/src/bounty/api/state.rs index 8d07cd9..64126be 100644 --- a/backend/src/bounty/api/state.rs +++ b/backend/src/bounty/api/state.rs @@ -3,8 +3,8 @@ use std::collections::HashMap; use candid::{CandidType, Principal}; use serde::{Deserialize, Serialize}; -pub type IssueId = i32; -pub type PullRequestId = i32; +pub type IssueId = String; +pub type PullRequestId = String; #[derive(Debug, Serialize, Deserialize, CandidType, Clone, Builder)] pub struct Contributor { diff --git a/backend/src/lib.rs b/backend/src/lib.rs index 9d176cc..f4d1d06 100644 --- a/backend/src/lib.rs +++ b/backend/src/lib.rs @@ -96,7 +96,7 @@ fn init(authority: Principal) -> () { } #[ic_cdk::update] -fn accept(contributor: Contributor, github_issue_id: i32, github_pr_id: i32) -> () { +fn accept(contributor: Contributor, github_issue_id: String, github_pr_id: String) -> () { accept_impl(contributor, github_issue_id, github_pr_id); } diff --git a/backend/src/provider/github/api/get_fixed_by.rs b/backend/src/provider/github/api/get_fixed_by.rs index ac75238..bf2f733 100644 --- a/backend/src/provider/github/api/get_fixed_by.rs +++ b/backend/src/provider/github/api/get_fixed_by.rs @@ -12,7 +12,7 @@ use regex::Regex; #[derive(Debug, Serialize, Deserialize, CandidType)] pub enum GetFixedByError { - IssueNotFound { issue_nbr: i32 }, + IssueNotFound { github_issue_id: String }, } // curl https://github.com/input-output-hk/hydra/issues/1370 @@ -64,7 +64,15 @@ pub async fn get_fixed_by_impl(owner: String, repo: String, issue_nbr: i32) -> R if let Some(pull_request) = extract_pull_request(&result) { return Ok(remove_github_prefix(&pull_request)); } - return Err(GetFixedByError::IssueNotFound{issue_nbr}); + + let issue_not_found = format!( + "https://{}/{}/{}/issue/{}", + github_host(), + owner, + repo, + issue_nbr + ); + return Err(GetFixedByError::IssueNotFound{github_issue_id: issue_not_found}); } Err((rejection_code, message)) => {