~ knotless Search/
↑↓ move↵ open⇧↵ all results

johnandersen777.bsky.social/knotless

git that lives in your Atmosphere account

Forked from chadtmiller.com/knotless

0
0
439 lines · 16.0 KB Raw History
//! The views answers share, as `dev.knotless.defs` defines them: of
//! repositories, commits, checks and diffs.

use super::*;

/// `dev.knotless.defs#repoViewDetailed`: a repository, with what its pages
/// show above themselves.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct RepoViewDetailed {
    pub uri: String,
    pub owner: ActorView,
    pub name: String,
    /// Its key, which a rename keeps, as its record holds it.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub key: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    /// The links its pages show, in order, each an http or https address.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub links: Vec<ProfileLink>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub fork_of: Option<RepoViewBasic>,
    /// The default branch: empty, for a repository never pushed.
    pub default_branch: String,
    pub open_pulls: usize,
    pub open_issues: usize,
    /// Whether its pages lead to its merge queue: a branch's rule takes
    /// pulls through it, or a pull waits in it still.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub merge_queue: bool,
    /// The path of the picture its pages unfurl into.
    pub card: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub star_count: Option<u64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub fork_count: Option<u64>,
    /// What it publishes, in brief: none, with no releases.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub releases: Option<super::releases::ReleasesView>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub viewer: Option<RepoViewerState>,
    /// Whether it is private: in a space, shown only to its members.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub private: bool,
    /// When its owner archived it, making it read only.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub archived_at: Option<String>,
    /// What it is about, as its record names them.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub topics: Vec<knotless::records::Topic>,
    /// The first of those who may push to it besides its owner.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub collaborators: Vec<ActorView>,
    /// How many may push to it besides its owner: none, absent.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub collaborator_count: Option<usize>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub site: Option<SiteView>,
}

/// `dev.knotless.defs#repoViewerState`.
/// A repository's website: where it is served, and what it was deployed
/// from.
#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct SiteView {
    pub url: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub commit: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub check: Option<String>,
    pub deployed_at: String,
}

#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct RepoViewerState {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub star: Option<String>,
    /// Where the owner offered to move it, when that is to the asker.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub transfer: Option<RepoViewBasic>,
    /// The labels it defines that the asker may put on its pulls and issues.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub labels: Vec<LabelView>,
    /// What the asker chose to hear of it: `all`, `releases` or `ignore`.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub subscription: Option<String>,
    /// Whether the asker may change its settings: its owner, or an admin
    /// who joined the organization that owns it.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub admin: bool,
}

/// `dev.knotless.defs#commitView`.
#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct CommitView {
    pub sha: String,
    pub parents: Vec<CommitRefView>,
    pub author: CommitAuthorView,
    /// Who its message's `Co-authored-by` trailers name.
    pub coauthors: Vec<CommitAuthorView>,
    /// Who committed it, when that is someone other than its author.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub committer: Option<CommitAuthorView>,
    /// When its author wrote it, which a rebase or a squash keeps.
    pub date: String,
    /// When it was committed: what history runs in, and the pages go by.
    pub committed_at: String,
    /// Its message, less the line naming the pull it merged, if it did.
    pub message: String,
    /// The pull its message's last line names, as a squash merge records
    /// it, when that is a pull on this repository.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pull: Option<ItemViewBasic>,
}

/// `dev.knotless.defs#commitRefView`.
#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct CommitRefView {
    pub sha: String,
}

/// `dev.knotless.defs#commitAuthorView`: who wrote a commit or helped to,
/// by the name git gives, and by account when that is one of the
/// repository's own people whose address it is (`knotless::emails`).
#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct CommitAuthorView {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub actor: Option<ActorView>,
    /// The coding agent whose address it is, when the pages know its face.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub agent: Option<&'static str>,
}

/// `dev.knotless.defs#itemViewBasic`: a pull or an issue, by its record
/// and its title.
#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct ItemViewBasic {
    pub uri: String,
    pub title: String,
}

/// `dev.knotless.defs#checkView`: the newest run of one workflow, as a
/// runner the repository names in its record reported it.
#[derive(Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CheckView {
    pub uri: String,
    /// The repository it is of, whose pages show it.
    pub repo: RepoViewBasic,
    pub workflow: String,
    pub status: String,
    pub commit: String,
    pub started_at: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub finished_at: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub error: Option<String>,
    /// For a `success` that ran nothing, as the change touched none of the
    /// paths its workflow names: why.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub skipped: Option<String>,
    /// The pictures it made to be looked at, in order.
    pub images: Vec<CheckImageView>,
}

/// `dev.knotless.defs#checkImageView`: a picture a check made, such as
/// screenshots of the pages a change moved.
#[derive(Clone, Serialize)]
pub struct CheckImageView {
    /// What it shows.
    pub alt: String,
    /// Where this server serves it, as a path.
    pub url: String,
}

/// `dev.knotless.defs#fileDiffView`: one file of a diff, or why its rows
/// are not shown.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct FileDiffView {
    pub old: String,
    pub new: String,
    /// `added`, `deleted`, `renamed` or `modified`.
    pub status: String,
    pub added: usize,
    pub removed: usize,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub note: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub ranges: Option<String>,
    pub rows: Vec<DiffRowView>,
    /// Where its rows are left out but would be shown, how many there are,
    /// and of them how many are hunk headers: the room a page keeps for
    /// them until they come.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub row_count: Option<usize>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub hunk_count: Option<usize>,
}

/// `dev.knotless.defs#diffRowView`: one row of a file's diff, a hunk
/// header, a note, or a line with its old and new numbers.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct DiffRowView {
    /// `h`, `x`, `a`, `d`, or empty for context.
    pub kind: String,
    pub line: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub old: Option<u32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub new: Option<u32>,
    pub text: String,
}

/// `dev.knotless.defs#languageView`: one language a repository is written
/// in, its share in tenths of a percent, as a lexicon has no fractions.
#[derive(Serialize)]
pub struct LanguageView {
    pub name: String,
    pub color: String,
    pub bytes: u64,
    pub permille: u32,
}

impl From<Language> for LanguageView {
    fn from(l: Language) -> LanguageView {
        LanguageView {
            name: l.name,
            color: l.color,
            bytes: l.bytes,
            permille: (l.percent * 10.0).round() as u32,
        }
    }
}

/// `dev.knotless.repo#label`: a label, as the repository defines it.
#[derive(Serialize, Clone, Debug, PartialEq)]
pub struct LabelView {
    pub name: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub color: Option<String>,
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub exclusive: bool,
}

/// `label` as `dev.knotless.repo#label` shows it.
pub fn label_view(l: &knotless::records::Label) -> LabelView {
    LabelView {
        name: l.name.clone(),
        description: l.description.clone(),
        color: l.color.clone(),
        exclusive: l.exclusive,
    }
}

/// `dev.knotless.defs#itemView`: a pull or an issue in a list of them.
#[derive(Serialize, Clone, Debug, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct ItemView {
    pub uri: String,
    /// `pull` or `issue`.
    pub kind: String,
    pub title: String,
    /// `open`, `closed` or `merged`.
    pub state: String,
    pub author: ActorView,
    pub created_at: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<String>,
    pub comments: usize,
    /// A pull its author has not marked ready.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub draft: bool,
    /// Those asked to review a pull: by its author, then by the owner or
    /// a collaborator, then the required reviewers its base's rule names.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub reviewers: Vec<ActorView>,
    /// Of `reviewers`, those its base's rule requires: asked of every
    /// pull into it, and stopped only by changing the rule.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub required_reviewers: Vec<ActorView>,
    /// Those the owner or a collaborator assigns it to.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub assignees: Vec<ActorView>,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub labels: Vec<LabelView>,
}

/// `item`, by its author's account, carrying the labels `record` defines.
pub async fn item_view(app: &App, record: &RepoRecord, item: &Item) -> ItemView {
    let labels = item.labels.iter().filter_map(|name| record.label(name));
    let labels = labels.map(label_view);
    let base = item.base.as_deref().unwrap_or_default();
    let required = record
        .required_reviewers(base)
        .filter(|r| item.reviewers.iter().any(|d| d == r));
    ItemView {
        uri: item.uri.clone(),
        kind: item.kind.clone(),
        title: item.title.clone(),
        state: item.state.clone(),
        author: actor(app, &item.author).await,
        created_at: item.created_at.clone(),
        updated_at: item.updated_at.clone(),
        comments: item.comments,
        draft: item.draft,
        reviewers: futures::future::join_all(item.reviewers.iter().map(|r| actor(app, r))).await,
        required_reviewers: futures::future::join_all(required.map(|r| actor(app, r))).await,
        assignees: futures::future::join_all(item.assignees.iter().map(|a| actor(app, a))).await,
        labels: labels.collect(),
    }
}

/// `items`, each by `item_view`.
pub async fn item_views<'a>(
    app: &App,
    record: &RepoRecord,
    items: impl IntoIterator<Item = &'a Item>,
) -> Vec<ItemView> {
    let views = items.into_iter().map(|i| item_view(app, record, i));
    futures::future::join_all(views).await
}

/// `dev.knotless.defs#commentView`: something said on a pull or an issue.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CommentView {
    /// Its record, for its author to change or take back.
    pub uri: String,
    pub author: ActorView,
    pub created_at: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub updated_at: Option<String>,
    /// What it says, as its author wrote it, to change it from.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub body: Option<String>,
    pub html: String,
    /// `approve` or `changes`, for a review.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub verdict: Option<String>,
    /// The head a review looked at, or the commit a line comment's lines
    /// are in.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub commit: Option<String>,
    /// For a comment on a pull's lines, which, as they stand now.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub line: Option<LineView>,
    /// The comment starting the thread it answers.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub reply: Option<String>,
    /// The review it was sent with.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub review: Option<String>,
    /// The review it dismissed, from the owner or a collaborator.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub dismisses: Option<String>,
    /// Whether the thread it starts is resolved.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub resolved: bool,
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub reactions: Vec<super::reactions::ReactionCountView>,
}

/// `dev.knotless.defs#lineView`: the lines of a pull's diff a comment is
/// on.
#[derive(Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct LineView {
    pub path: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub side: Option<String>,
    pub line: u32,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub start_line: Option<u32>,
    /// Whether the file on that side has changed since.
    pub outdated: bool,
    /// The lines as they were, and a few before one alone.
    #[serde(skip_serializing_if = "Vec::is_empty")]
    pub lines: Vec<LineTextView>,
}

/// `dev.knotless.defs#lineText`: one line of a file.
#[derive(Serialize, Clone)]
pub struct LineTextView {
    pub number: u32,
    pub text: String,
}

/// `dev.knotless.defs#reviewView`: where one reviewer stands on a pull.
#[derive(Serialize)]
#[serde(rename_all = "camelCase")]
pub struct ReviewView {
    pub reviewer: ActorView,
    pub verdict: String,
    /// The comment that reviewed it.
    pub uri: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub commit: Option<String>,
    /// Whether the pull has moved past the head it looked at.
    pub outdated: bool,
    /// Whether the reviewer is the repository's owner or a collaborator.
    pub maintainer: bool,
    /// Whether the owner or a collaborator dismissed it.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub dismissed: bool,
    /// Whether the rule protecting the pull's base names the reviewer as
    /// a gate.
    #[serde(skip_serializing_if = "std::ops::Not::not")]
    pub gate: bool,
}

/// `dev.knotless.defs#pullHeadView`: the branch a pull brings in.
#[derive(Serialize)]
pub struct PullHeadView {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub repo: Option<RepoViewBasic>,
    pub branch: String,
}

/// `dev.knotless.defs#changesView`: what a pull brings in, its commits
/// oldest first.
#[derive(Serialize)]
pub struct ChangesView {
    /// The repository whose commit pages show them.
    pub repo: RepoViewBasic,
    pub commits: Vec<CommitView>,
    pub files: Vec<FileDiffView>,
    /// The head an unmerged pull is at, whose checks alone it shows.
    #[serde(skip_serializing_if = "Option::is_none")]
    pub head: Option<String>,
}