wakapi 0.3.1

Wakatime API client
Documentation
//! Commits endpoint
//!
//! - Ref : <https://wakatime.com/developers#commits>
//! - Last checked : 2026-05-15

use serde::{Deserialize, Serialize};

use crate::{WakapiClient, WakapiError};

use super::commit::{CommitDetails, CommitProjectDetails};

/// Request parameters for the Commits endpoint.
///
/// Ref: <https://wakatime.com/developers#commits>
pub struct CommitsParams {
    url: CommitsParamsUrl,
    params: CommitsParamsParams,
}

struct CommitsParamsUrl {
    /// required - Project
    project: String,
}

#[derive(Serialize, Default)]
struct CommitsParamsParams {
    /// optional - Filter commits to only those authored by the given username
    author: Option<String>,
    /// optional - Filter commits to a branch; defaults to the repo’s default branch name
    branch: Option<String>,
    /// optional - Page number of commits
    page: Option<usize>,
}

impl CommitsParams {
    /// Create a new CommitsParams with default values (no author, no branch, page 1).
    /// The project parameter is required.
    pub fn new(project: &str) -> CommitsParams {
        CommitsParams {
            url: CommitsParamsUrl {
                project: project.to_string(),
            },
            params: CommitsParamsParams {
                author: None,
                branch: None,
                page: None,
            },
        }
    }

    /// Set the author parameter for the request.
    /// This will filter the commits to only those authored by the given username.
    pub fn author(mut self, author: &str) -> CommitsParams {
        self.params.author = Some(author.to_string());
        self
    }

    /// Set the branch parameter for the request.
    /// This will filter the commits to a branch; defaults to the repo’s default branch name.
    pub fn branch(mut self, branch: &str) -> CommitsParams {
        self.params.branch = Some(branch.to_string());
        self
    }

    /// Set the page parameter for the request.
    /// This will set the page number of commits to return.
    pub fn page(mut self, page: usize) -> CommitsParams {
        self.params.page = Some(page);
        self
    }
}

/// Commits endpoint
///
/// Ref : <https://wakatime.com/developers#commits>
#[derive(Deserialize, Debug)]
pub struct Commits {
    /// List of commits
    pub commits: Vec<CommitDetails>,
    /// current author or null if showing commits from all authors
    pub author: Option<String>,
    /// current page number
    pub page: usize,
    /// next page number or null if last page
    pub next_page: Option<usize>,
    /// next_page url or null if last page
    pub next_page_url: Option<String>,
    /// previous page number or null if first page
    pub prev_page: Option<usize>,
    /// previous_page url or null if first page
    pub prev_page_url: Option<String>,
    /// branch name containig the commits
    pub branch: String,
    /// project details
    pub project: CommitProjectDetails,
    /// project's sync status
    pub status: String,
    /// total number of commits available
    pub total: usize,
    /// total number of pages available
    pub total_pages: usize,
}

impl Commits {
    #[cfg(feature = "blocking")]
    pub fn fetch(client: &WakapiClient, params: CommitsParams) -> Result<Self, WakapiError> {
        let url = client.build_url(
            format!(
                "/api/v1/users/:user/projects/{}/commits",
                &params.url.project
            )
            .as_str(),
            Some(serde_url_params::to_string(&params.params)?),
        );
        // // Debug, print url and response body
        // println!(
        //     "url: {}\nbody: {}",
        //     url,
        //     reqwest::blocking::Client::new()
        //         .get(&url)
        //         .header("Authorization", client.get_auth_header())
        //         .send()?
        //         .text()?
        // );

        let response = reqwest::blocking::Client::new()
            .get(&url)
            .header("Authorization", client.get_auth_header())
            .send()?;
        if response.status().is_success() {
            let body = response.json::<Commits>()?;
            Ok(body)
        } else {
            let error = response.json::<crate::error::ErrorMessage>()?;
            Err(WakapiError::ResponseError(error))
        }
    }

    #[cfg(not(feature = "blocking"))]
    pub async fn fetch(client: &WakapiClient, params: CommitsParams) -> Result<Self, WakapiError> {
        let url = client.build_url(
            format!(
                "/api/v1/users/:user/projects/{}/commits",
                &params.url.project
            )
            .as_str(),
            Some(serde_url_params::to_string(&params.params)?),
        );
        // // Debug, print url and response body
        // println!(
        //     "url: {}\nbody: {}",
        //     url,
        //     reqwest::Client::new()
        //         .get(&url)
        //         .header("Authorization", client.get_auth_header())
        //         .send()
        //         .await?
        //         .text()
        // );

        let response = reqwest::Client::new()
            .get(&url)
            .header("Authorization", client.get_auth_header())
            .send()
            .await?;
        if response.status().is_success() {
            let body = response.json::<Commits>().await?;
            Ok(body)
        } else {
            let error = response.json::<crate::error::ErrorMessage>().await?;
            Err(WakapiError::ResponseError(error))
        }
    }
}