use reqwest::Client; use semver::Version; use serde::{Deserialize, Serialize}; #[derive(serde::Deserialize, serde::Serialize)] pub struct GitCommit { pub commit: GitCommitDetails, pub sha: String, } #[derive(serde::Deserialize, serde::Serialize)] pub struct GitCommitDetails { pub message: String, } pub async fn get_pull_request_commits( base_url: &str, owner: &str, repo: &str, pull_request_id: u32, access_token: &str, ) -> eyre::Result> { let client = Client::new(); let api_url = format!( "{}/api/v1/repos/{}/{}/pulls/{}/commits", base_url, owner, repo, pull_request_id ); let response = client .get(&api_url) .bearer_auth(access_token) .send() .await?; let commits: Vec = response.json().await?; let mut commit_titles = Vec::new(); tracing::debug!( commits = serde_json::to_string(&commits)?, "fetched commits" ); for entry in commits { commit_titles.push(entry.commit.message); } Ok(commit_titles) } #[derive(Serialize, Deserialize, Debug)] pub struct ReleaseRequest { pub tag_name: String, pub target_commitish: String, pub name: String, pub body: String, pub draft: bool, pub prerelease: bool, } #[derive(Deserialize, Debug)] pub struct ReleaseResponse { pub id: u64, pub url: String, // Add other fields as needed } pub async fn create_gitea_release( base_url: &str, owner: &str, repo: &str, access_token: &str, release_request: &ReleaseRequest, ) -> eyre::Result { let client = Client::new(); let releases_url = format!("{}/api/v1/repos/{}/{}/releases", base_url, owner, repo); let response = client .post(&releases_url) .bearer_auth(access_token) .json(release_request) .send() .await?; if !response.status().is_success() { eyre::bail!("failed to handle request: {}", response.text().await?); } let response = response.json::().await?; Ok(response) } #[derive(Deserialize, Debug, Clone)] pub struct Release { pub id: u64, pub tag_name: String, pub draft: bool, pub prerelease: bool, // Add other fields as needed pub target_commitish: String, pub name: String, pub body: String, } pub async fn get_newest_release( base_url: &str, owner: &str, repo: &str, personal_access_token: &str, ) -> eyre::Result { let client = Client::new(); let releases_url = format!("{}/api/v1/repos/{}/{}/releases", base_url, owner, repo); let response = client .get(&releases_url) .bearer_auth(personal_access_token) .send() .await?; if !response.status().is_success() { eyre::bail!("failed to handle request: {}", response.text().await?); } let response = response.json::>().await?; match response.first() { Some(release) => Ok(release.clone()), None => Err(eyre::anyhow!("No releases found")), } } pub async fn is_newest_release_draft( gitea_base_url: &str, owner: &str, repo: &str, personal_access_token: &str, ) -> eyre::Result<(bool, Release)> { let release = get_newest_release(gitea_base_url, owner, repo, personal_access_token).await?; Ok((release.draft, release)) } #[derive(Serialize, Debug)] pub struct UpdateReleaseRequest { pub tag_name: Option, pub target_commitish: Option, pub name: Option, pub body: Option, pub draft: Option, pub prerelease: Option, } pub async fn modify_release( base_url: &str, owner: &str, repo: &str, token: &str, release_id: u64, update_request: &UpdateReleaseRequest, ) -> eyre::Result { tracing::info!( base_url = base_url, owner = owner, repo = repo, release_id = release_id, "modifying release" ); let client = Client::new(); let release_url = format!( "{}/api/v1/repos/{}/{}/releases/{}", base_url, owner, repo, release_id ); let response = client .patch(&release_url) .bearer_auth(token) .json(&update_request) .send() .await?; if !response.status().is_success() { eyre::bail!("failed to handle request: {}", response.text().await?); } let response = response.json::().await?; Ok(response) } #[derive(Deserialize, Debug)] pub struct Commit { pub sha: String, } #[derive(Deserialize, Debug)] pub struct Tag { pub name: String, pub commit: Commit, // Add other fields as needed } pub async fn get_highest_semver_from_tags( base_url: &str, owner: &str, repo: &str, token: &str, ) -> eyre::Result<(Version, Tag)> { let client = Client::new(); let tags_url = format!("{}/api/v1/repos/{}/{}/tags", base_url, owner, repo); let response = client.get(&tags_url).bearer_auth(token).send().await?; if !response.status().is_success() { eyre::bail!("failed to handle request: {}", response.text().await?); } let response = response.json::>().await?; let highest_version = response .into_iter() .filter_map(|tag| { Version::parse(&tag.name.replace("v", "")) .and_then(|v| Ok((v, tag))) .ok() }) .max_by(|(x, _), (y, _)| x.cmp(y)); match highest_version { Some(version) => Ok(version), None => Err(eyre::anyhow!("No valid SemVer tags found",)), } } pub async fn get_commits_from_commit_to_newest( base_url: &str, owner: &str, repo: &str, token: &str, branch: &str, start_commit_sha: &str, ) -> eyre::Result> { let client = Client::new(); let commits_url = format!( "{}/api/v1/repos/{}/{}/commits?sha={}", base_url, owner, repo, branch ); let response = client.get(&commits_url).bearer_auth(token).send().await?; if !response.status().is_success() { eyre::bail!("failed to handle request: {}", response.text().await?); } //tracing::info!(request = response.text().await?, "test"); let mut response = response.json::>().await?; //let mut response: Vec = Vec::new(); let index_of_start_commit = response .iter() .position(|commit| commit.sha == start_commit_sha); match index_of_start_commit { Some(index) => { response.truncate(index); Ok(response) } None => Err(eyre::anyhow!("Start commit not found",)), } } #[cfg(test)] mod tests { use tracing_test::traced_test; use super::*; #[tokio::test] #[traced_test] async fn test_get_pull_request_commits() { dotenv::dotenv().unwrap(); let base_url = "https://git.front.kjuulh.io"; let owner = "kjuulh"; let repo = "test-repo"; let pull_request_id = 3; let access_token = &std::env::var("GITEA_ACCESS_TOKEN").unwrap(); let commits = get_pull_request_commits(base_url, owner, repo, pull_request_id, access_token) .await .unwrap(); assert!( !commits.is_empty(), "Expected at least one commit in the pull request" ); // You can add more assertions here to check the contents of the commits vector } }