a73x

src/server/http/repo/patch_diff.rs

Ref:   Size: 2.4 KiB   History

//! The whole change a patch carries, base to head.
//!
//! Distinct from `/diff/{oid}`, which is one commit against its parent. A
//! patch of seven commits has seven such views and none of them is the patch,
//! which is the confusion this page exists to end.

use std::sync::Arc;

use axum::extract::{Path as AxumPath, State};
use axum::response::{IntoResponse, Response};

use super::diff::{collect_diff_files, DiffFile};
use super::{collab_counts, internal_error, not_found, open_repo, AppState};

#[derive(askama::Template, askama_web::WebTemplate)]
#[template(path = "patch_diff.html")]
pub struct PatchDiffTemplate {
    pub site_title: String,
    pub repo_name: String,
    pub active_section: String,
    pub open_patches: usize,
    pub open_issues: usize,
    pub patch_id: String,
    pub short_id: String,
    pub title: String,
    pub branch: String,
    pub base_ref: String,
    pub file_count: usize,
    pub diff_files: Vec<DiffFile>,
}

pub async fn patch_diff(
    AxumPath((repo_name, patch_id)): AxumPath<(String, String)>,
    State(state): State<Arc<AppState>>,
) -> Response {
    let (_entry, repo) = match open_repo(&state, &repo_name) {
        Ok(r) => r,
        Err(resp) => return resp,
    };

    let (open_patches, open_issues) = collab_counts(&repo);

    let (ref_name, full_id) = match git_collab::state::resolve_patch_ref(&repo, &patch_id) {
        Ok(r) => r,
        Err(_) => return not_found(&state, format!("Patch '{}' not found.", patch_id)),
    };

    let ps = match git_collab::state::PatchState::from_ref(&repo, &ref_name, &full_id) {
        Ok(s) => s,
        Err(_) => return internal_error(&state, "Failed to load patch state."),
    };

    // The CLI's own base resolution, not a second one — see `patch::patch_diff`.
    let opts = git_collab::patch::DiffOpts::default();
    let diff_files = match git_collab::patch::patch_diff(&repo, &ps, &opts) {
        Ok(diff) => collect_diff_files(&diff),
        Err(_) => Vec::new(),
    };

    let short_id = git_collab::abbrev::for_patches(&repo)
        .of(&full_id)
        .to_string();

    PatchDiffTemplate {
        site_title: state.site_title.clone(),
        repo_name,
        active_section: "patches".to_string(),
        open_patches,
        open_issues,
        patch_id: full_id,
        short_id,
        title: ps.title,
        branch: ps.branch,
        base_ref: ps.base_ref,
        file_count: diff_files.len(),
        diff_files,
    }
    .into_response()
}