anesis 0.12.5

CLI for scaffolding projects from remote templates and extending them with project addons
Documentation
use anyhow::{Context, Result};
use serde::Deserialize;

use super::manifest::{StackManifest, validate};
use crate::{
  auth::token::get_auth_user,
  context::AppContext,
  utils::{
    http::fetch_paginated,
    picker::{ItemKind, PickItem},
  },
};

#[derive(Deserialize)]
struct StackResponse {
  config: StackManifest,
}

#[derive(Deserialize)]
pub struct CatalogStack {
  pub stack_id: String,
  pub name: String,
  #[serde(default)]
  pub description: String,
  #[serde(default)]
  pub star_count: i64,
  pub config: StackManifest,
}

pub async fn fetch_stack_manifest(ctx: &AppContext, stack_id: &str) -> Result<StackManifest> {
  let token = get_auth_user(&ctx.paths.auth).ok().map(|u| u.token);
  let mut req = ctx
    .client
    .get(format!("{}/stack/{stack_id}", ctx.backend_url));
  if let Some(token) = token {
    req = req.bearer_auth(token);
  }
  let res: StackResponse = req
    .send()
    .await
    .with_context(|| format!("Failed to fetch stack '{stack_id}' from registry"))?
    .error_for_status()
    .with_context(|| format!("Stack '{stack_id}' not found in registry"))?
    .json()
    .await
    .with_context(|| format!("Failed to parse stack '{stack_id}'"))?;
  validate(&res.config)?;
  Ok(res.config)
}

pub async fn fetch_stack_catalog(ctx: &AppContext) -> Result<Vec<CatalogStack>> {
  fetch_paginated(ctx, "/stack/all", "stack catalog").await
}

impl CatalogStack {
  pub fn to_pick_item(&self) -> PickItem {
    let meta = if self.star_count > 0 {
      format!(" · {}", self.star_count)
    } else {
      String::new()
    };
    PickItem {
      kind: ItemKind::Stack,
      haystack: format!("{} {} {}", self.stack_id, self.name, self.description).to_lowercase(),
      id: self.stack_id.clone(),
      name: self.name.clone(),
      meta,
      description: self.description.clone(),
    }
  }
}

pub async fn stack_pick_items(ctx: &AppContext) -> Result<Vec<PickItem>> {
  let stacks = fetch_stack_catalog(ctx).await?;
  Ok(stacks.iter().map(CatalogStack::to_pick_item).collect())
}