Skip to content

Commit

Permalink
[suiop][image] add list and get current status endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
pei-mysten committed Jun 22, 2024
1 parent f8611af commit d0ae2c1
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 5 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/suiop-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ edition = "2021"
license = "Apache-2.0"
name = "suiop-cli"
publish = false
version = "0.2.3"
version = "0.2.4"

[lib]
name = "suioplib"
Expand Down
202 changes: 199 additions & 3 deletions crates/suiop-cli/src/cli/ci/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use anyhow::Result;
use chrono::{DateTime, Local, Utc};
use clap::{Parser, ValueEnum};
use colored::Colorize;
use serde::{self, Serialize};
use serde::{self, Deserialize, Serialize};
use std::{fmt::Display, str::FromStr};
use tabled::{settings::Style, Table, Tabled};
use tracing::debug;
Expand Down Expand Up @@ -89,6 +89,26 @@ pub enum ImageAction {
#[arg(short, long)]
limit: Option<u32>,
},
#[command(name = "status")]
Status {
#[arg(short = 'r', long)]
repo_name: String,
#[arg(short = 'i', long)]
image_name: String,
#[arg(short = 't', long)]
ref_type: Option<RefType>,
#[arg(short = 'v', long)]
ref_val: Option<String>,
},
#[command(name = "list")]
List {
#[arg(short, long)]
repo_name: String,
#[arg(short, long)]
image_name: Option<String>,
#[arg(short, long)]
limit: Option<i32>,
},
}

#[derive(serde::Serialize, Debug)]
Expand All @@ -107,7 +127,17 @@ struct QueryBuildsRequest {
limit: u32,
}

#[derive(serde::Serialize)]
struct ImageStatusRequest {
repo_name: String,
image_name: String,
repo_ref_type: RefType,
repo_ref: String,
}

const ENDPOINT: &str = "/automation/image-build";
const STATUS_ENDPOINT: &str = "/automation/image-status";
const LIST_ENDPOINT: &str = "/automation/images";

pub async fn image_cmd(args: &ImageArgs) -> Result<()> {
let token = get_oauth_token().await?;
Expand All @@ -130,6 +160,85 @@ struct QueryBuildResponse {
pods: Vec<JobStatus>,
}

#[derive(ValueEnum, Clone, Debug)]
// #[clap(rename_all = "snake_case")]
enum ImageStatus {
Found,
Pending,
Building,
BuiltNotFound,
Failed,
Unknown,
NotBuiltNotFound,
}

impl<'a> Deserialize<'a> for ImageStatus {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'a>,
{
let s = i32::deserialize(deserializer)?;
match s {
0 => Ok(ImageStatus::Found),
1 => Ok(ImageStatus::Pending),
2 => Ok(ImageStatus::Building),
3 => Ok(ImageStatus::BuiltNotFound),
4 => Ok(ImageStatus::Failed),
5 => Ok(ImageStatus::Unknown),
6 => Ok(ImageStatus::NotBuiltNotFound),
_ => Ok(ImageStatus::Unknown),
}
}
}

impl Display for ImageStatus {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ImageStatus::Found => write!(f, "Found"),
ImageStatus::Pending => write!(f, "Pending"),
ImageStatus::Building => write!(f, "Building"),
ImageStatus::BuiltNotFound => {
write!(f, "Build succeed but image not found")
}
ImageStatus::Failed => write!(f, "Failed"),
ImageStatus::Unknown => write!(f, "Unknown"),
ImageStatus::NotBuiltNotFound => {
write!(f, "Not built and image not found")
}
}
}
}

#[derive(serde::Deserialize)]
struct ImageStatusResponse {
pub status: ImageStatus,
pub image_sha: String,
}

#[derive(serde::Serialize)]
struct ImageListRequest {
repo_name: String,
image_name: Option<String>,
limit: Option<i32>,
}

#[derive(serde::Deserialize)]
struct ImageDetails {
pub name: String,
pub tags: Vec<String>,
}

#[derive(Tabled)]
struct ImageRow {
name: String,
tags: String,
}

#[derive(serde::Deserialize)]
struct ImageListResponse {
pub images: Vec<ImageDetails>,
}

async fn send_image_request(token: &str, action: &ImageAction) -> Result<()> {
let req = generate_image_request(token, action);

Expand Down Expand Up @@ -193,6 +302,57 @@ async fn send_image_request(token: &str, action: &ImageAction) -> Result<()> {
let mut tabled = Table::new(job_statuses);
tabled.with(Style::rounded());

let tabled_str = tabled.to_string();
println!("{}", tabled_str);
}
ImageAction::Status {
repo_name,
image_name,
ref_type,
ref_val,
} => {
let mut ref_name = "".to_string();
if let Some(ref_type) = ref_type {
ref_name.push_str(&ref_type.to_string())
} else {
ref_name.push_str("branch");
}
if let Some(ref_val) = ref_val {
ref_name.push_str(&format!(":{}", ref_val))
} else {
ref_name.push_str(":main")
}
println!(
"Requested status for repo: {}, image: {}, ref: {}",
repo_name.green(),
image_name.green(),
ref_name.green()
);
// println!("resp: {:?}", resp.text().await?);

let json_resp = resp.json::<ImageStatusResponse>().await?;
println!("Image Status: {}", json_resp.status.to_string().green());
println!("Image SHA: {}", json_resp.image_sha.green());
}
ImageAction::List {
repo_name,
image_name: _,
limit: _,
} => {
println!("Requested list for repo: {}", repo_name.green());
let json_resp = resp.json::<ImageListResponse>().await?;
let details = json_resp.images.into_iter().map(|image| {
let image_name = image.name;
let image_tags = image.tags;
ImageRow {
name: image_name,
// convert images tags vec to multiple strings
tags: image_tags.join(" | "),
}
});
let mut tabled = Table::new(details);
tabled.with(Style::rounded());

let tabled_str = tabled.to_string();
println!("{}", tabled_str);
}
Expand Down Expand Up @@ -233,8 +393,6 @@ fn generate_headers_with_auth(token: &str) -> reqwest::header::HeaderMap {
fn generate_image_request(token: &str, action: &ImageAction) -> reqwest::RequestBuilder {
let client = reqwest::Client::new();
let api_server = get_api_server();
let full_url = format!("{}{}", api_server, ENDPOINT);
debug!("full_url: {}", full_url);
let req = match action {
ImageAction::Build {
repo_name,
Expand All @@ -244,6 +402,8 @@ fn generate_image_request(token: &str, action: &ImageAction) -> reqwest::Request
ref_type,
ref_val,
} => {
let full_url = format!("{}{}", api_server, ENDPOINT);
debug!("full_url: {}", full_url);
let req = client.post(full_url);
let body = RequestBuildRequest {
repo_name: repo_name.clone(),
Expand All @@ -257,6 +417,8 @@ fn generate_image_request(token: &str, action: &ImageAction) -> reqwest::Request
req.json(&body).headers(generate_headers_with_auth(token))
}
ImageAction::Query { repo_name, limit } => {
let full_url = format!("{}{}", api_server, ENDPOINT);
debug!("full_url: {}", full_url);
let req = client.get(full_url);
let limit = (*limit).unwrap_or(10);
let query = QueryBuildsRequest {
Expand All @@ -265,6 +427,40 @@ fn generate_image_request(token: &str, action: &ImageAction) -> reqwest::Request
};
req.query(&query).headers(generate_headers_with_auth(token))
}
ImageAction::Status {
repo_name,
image_name,
ref_type,
ref_val,
} => {
let full_url = format!("{}{}", api_server, STATUS_ENDPOINT);
debug!("full_url: {}", full_url);
let req = client.get(full_url);
let ref_type = ref_type.clone().unwrap_or(RefType::Branch);
let ref_val = ref_val.clone().unwrap_or("main".to_string());
let query = ImageStatusRequest {
repo_name: repo_name.clone(),
image_name: image_name.clone(),
repo_ref_type: ref_type,
repo_ref: ref_val,
};
req.query(&query).headers(generate_headers_with_auth(token))
}
ImageAction::List {
repo_name,
image_name,
limit,
} => {
let full_url = format!("{}{}", api_server, LIST_ENDPOINT);
debug!("full_url: {}", full_url);
let req = client.get(full_url);
let query = ImageListRequest {
repo_name: repo_name.clone(),
image_name: image_name.clone(),
limit: *limit,
};
req.query(&query).headers(generate_headers_with_auth(token))
}
};
debug!("req: {:?}", req);

Expand Down

0 comments on commit d0ae2c1

Please sign in to comment.