Parent [>]
1//! Route handlers for tag pages.
2//!
3//! Covers two routes: the tag list (`/{repo}/tags`) and the tag detail page
4//! (`/{repo}/tags/{*tag}`).  The detail handler peels the tag ref to its
5//! commit and presents a release-oriented view with the annotation message,
6//! commit info, and archive download links.
7
8use askama::Template;
9use askama_web::WebTemplate;
10use axum::extract::{Path, State};
11use axum::response::IntoResponse;
12use serde::Deserialize;
13
14use crate::config::SiteConfig;
15use crate::error::Result;
16use crate::git;
17use crate::routes::{AppState, RepoName};
18
19#[derive(Deserialize)]
20pub(super) struct TagPath {
21    tag: String,
22}
23
24/// Template context for the tag list page.
25#[derive(Template, WebTemplate)]
26#[template(path = "tag_list.html")]
27struct TagList {
28    repo: String,
29    tags: Vec<git::TagInfo>,
30    site: std::sync::Arc<SiteConfig>,
31}
32
33/// Template context for the tag detail page.
34#[derive(Template, WebTemplate)]
35#[template(path = "tag_detail.html")]
36struct TagDetail {
37    repo: String,
38    tag: String,
39    tagger: Option<String>,
40    tag_date: Option<String>,
41    message: Option<String>,
42    commit_sha: String,
43    commit_author: String,
44    commit_date: String,
45    site: std::sync::Arc<SiteConfig>,
46}
47
48/// Renders the full list of tags for a repository, sorted newest first.
49pub async fn list(
50    State(state): State<AppState>,
51    RepoName(repo): RepoName,
52) -> Result<impl IntoResponse> {
53    let git_repo = git::open_repo(&state.root, &repo)?;
54    let tags = git::load_tags(&git_repo);
55    Ok(TagList {
56        repo,
57        tags,
58        site: state.site,
59    })
60}
61
62/// Renders the detail page for a single tag.
63pub async fn detail(
64    State(state): State<AppState>,
65    RepoName(repo): RepoName,
66    Path(params): Path<TagPath>,
67) -> Result<impl IntoResponse> {
68    let git_repo = git::open_repo(&state.root, &repo)?;
69    let (annotation, commit) = git::load_tag(&git_repo, &params.tag)?;
70
71    Ok(TagDetail {
72        repo,
73        tag: params.tag,
74        tagger: annotation.tagger,
75        tag_date: annotation.date,
76        message: annotation.message,
77        commit_sha: commit.sha,
78        commit_author: commit.author,
79        commit_date: commit.date,
80        site: state.site,
81    })
82}