qlty_coverage/publish/
upload.rs1use crate::publish::Report;
2use anyhow::{Context, Result};
3use qlty_cloud::{export::CoverageExport, Client as QltyClient};
4use std::path::PathBuf;
5
6#[derive(Default, Clone, Debug)]
7pub struct Upload {
8 pub id: String,
9 pub project_id: String,
10 pub file_coverages_url: String,
11 pub report_files_url: String,
12 pub metadata_url: String,
13}
14
15impl Upload {
16 pub fn prepare(token: &str, report: &mut Report) -> Result<Self> {
17 let client = QltyClient::new(token);
18
19 let response = client
20 .post("/coverage")
21 .send_json(ureq::json!({
22 "data": report.metadata,
23 }))?
24 .into_json::<serde_json::Value>()?;
25
26 let file_coverages_url = response
27 .get("data")
28 .and_then(|data| data.get("file_coverages.json.gz"))
29 .and_then(|upload_url| upload_url.as_str())
30 .with_context(|| {
31 format!(
32 "Unable to find file coverages URL in response body: {:?}",
33 response
34 )
35 })
36 .context("Failed to extract file coverages URL from response")?;
37
38 let report_files_url = response
39 .get("data")
40 .and_then(|data| data.get("report_files.json.gz"))
41 .and_then(|upload_url| upload_url.as_str())
42 .with_context(|| {
43 format!(
44 "Unable to find report files URL in response body: {:?}",
45 response
46 )
47 })
48 .context("Failed to extract report files URL from response")?;
49
50 let metadata_url = response
51 .get("data")
52 .and_then(|data| data.get("metadata.json"))
53 .and_then(|upload_url| upload_url.as_str())
54 .with_context(|| {
55 format!(
56 "Unable to find metadata URL in response body: {:?}",
57 response
58 )
59 })
60 .context("Failed to extract metadata URL from response")?;
61
62 let id = response
63 .get("data")
64 .and_then(|data| data.get("id"))
65 .and_then(|upload_url| upload_url.as_str())
66 .with_context(|| format!("Unable to find upload ID in response body: {:?}", response))
67 .context("Failed to extract upload ID from response")?;
68
69 let project_id = response
70 .get("data")
71 .and_then(|data| data.get("projectId"))
72 .and_then(|project_id| project_id.as_str())
73 .with_context(|| format!("Unable to find project ID in response body: {:?}", response))
74 .context("Failed to extract project ID from response")?;
75
76 report.set_upload_id(&id);
77 report.set_project_id(&project_id);
78
79 Ok(Self {
80 id: id.to_string(),
81 project_id: project_id.to_string(),
82 file_coverages_url: file_coverages_url.to_string(),
83 report_files_url: report_files_url.to_string(),
84 metadata_url: metadata_url.to_string(),
85 })
86 }
87
88 pub fn upload(&self, export: &CoverageExport) -> Result<()> {
89 self.upload_data(
90 &self.file_coverages_url,
91 "application/gzip",
92 export.read_file(&PathBuf::from("file_coverages.json.gz"))?,
93 )?;
94
95 self.upload_data(
96 &self.report_files_url,
97 "application/gzip",
98 export.read_file(&PathBuf::from("report_files.json.gz"))?,
99 )?;
100
101 self.upload_data(
102 &self.metadata_url,
103 "application/json",
104 export.read_file(&PathBuf::from("metadata.json"))?,
105 )?;
106
107 Ok(())
108 }
109
110 fn upload_data(
111 &self,
112 url: &str,
113 content_type: &str,
114 data: Vec<u8>,
115 ) -> Result<(), anyhow::Error> {
116 let response = ureq::put(url)
117 .set("Content-Type", content_type)
118 .send_bytes(&data)
119 .context("Failed to send PUT request")?;
120
121 if response.status() < 200 || response.status() >= 300 {
122 let error_message = format!(
123 "PUT request for uploading file returned {} status with response: {:?}",
124 response.status(),
125 response
126 .into_string()
127 .unwrap_or_else(|_| "Unknown error".to_string())
128 );
129 return Err(anyhow::anyhow!(error_message));
130 }
131
132 Ok(())
133 }
134}