jinxapi_github/v1_1_4/request/
pulls_create_review.rs

1//! Create a review for a pull request
2//! 
3//! This endpoint triggers [notifications](https://docs.github.com/en/github/managing-subscriptions-and-notifications-on-github/about-notifications). Creating content too quickly using this endpoint may result in secondary rate limiting. See "[Secondary rate limits](https://docs.github.com/rest/overview/resources-in-the-rest-api#secondary-rate-limits)" and "[Dealing with secondary rate limits](https://docs.github.com/rest/guides/best-practices-for-integrators#dealing-with-secondary-rate-limits)" for details.
4//! 
5//! Pull request reviews created in the `PENDING` state do not include the `submitted_at` property in the response.
6//! 
7//! **Note:** To comment on a specific line in a file, you need to first determine the _position_ of that line in the diff. The GitHub REST API v3 offers the `application/vnd.github.v3.diff` [media type](https://docs.github.com/rest/overview/media-types#commits-commit-comparison-and-pull-requests). To see a pull request diff, add this media type to the `Accept` header of a call to the [single pull request](https://docs.github.com/rest/reference/pulls#get-a-pull-request) endpoint.
8//! 
9//! The `position` value equals the number of lines down from the first "@@" hunk header in the file you want to add a comment. The line just below the "@@" line is position 1, the next line is position 2, and so on. The position in the diff continues to increase through lines of whitespace and additional hunks until the beginning of a new file.
10//! 
11//! [API method documentation](https://docs.github.com/rest/reference/pulls#create-a-review-for-a-pull-request)
12
13pub struct Content<Body>
14{
15    body: Body,
16    content_type_value: Option<::std::borrow::Cow<'static, [u8]>>,
17}
18
19impl<Body> Content<Body> {
20    pub fn new(body: Body) -> Self {
21        Self { body, content_type_value: None }
22    }
23
24    #[must_use]
25    pub fn with_content_type(mut self, content_type: impl Into<::std::borrow::Cow<'static, [u8]>>) -> Self {
26        self.content_type_value = Some(content_type.into());
27        self
28    }
29
30    fn content_type(&self) -> Option<&[u8]> {
31        self.content_type_value.as_deref()
32    }
33
34    fn into_body(self) -> Body {
35        self.body
36    }
37}
38
39fn url_string(
40    base_url: &str,
41    p_owner: &str,
42    p_repo: &str,
43    p_pull_number: i64,
44) -> Result<String, crate::v1_1_4::ApiError> {
45    let trimmed = if base_url.is_empty() {
46        "https://api.github.com"
47    } else {
48        base_url.trim_end_matches('/')
49    };
50    let mut url = String::with_capacity(trimmed.len() + 42);
51    url.push_str(trimmed);
52    url.push_str("/repos/");
53    ::querylizer::Simple::extend(&mut url, &p_owner, false, &::querylizer::encode_path)?;
54    url.push('/');
55    ::querylizer::Simple::extend(&mut url, &p_repo, false, &::querylizer::encode_path)?;
56    url.push_str("/pulls/");
57    ::querylizer::Simple::extend(&mut url, &p_pull_number, false, &::querylizer::encode_path)?;
58    url.push_str("/reviews");
59    Ok(url)
60}
61
62#[cfg(feature = "hyper")]
63pub fn http_builder(
64    base_url: &str,
65    p_owner: &str,
66    p_repo: &str,
67    p_pull_number: i64,
68    h_user_agent: &str,
69    h_accept: ::std::option::Option<&str>,
70) -> Result<::http::request::Builder, crate::v1_1_4::ApiError> {
71    let url = url_string(
72        base_url,
73        p_owner,
74        p_repo,
75        p_pull_number,
76    )?;
77    let mut builder = ::http::request::Request::post(url);
78    builder = builder.header(
79        "User-Agent",
80        &::querylizer::Simple::to_string(&h_user_agent, false, &::querylizer::passthrough)?
81    );
82    if let Some(value) = &h_accept {
83        builder = builder.header(
84            "Accept",
85            &::querylizer::Simple::to_string(value, false, &::querylizer::passthrough)?
86        );
87    }
88    Ok(builder)
89}
90
91#[cfg(feature = "hyper")]
92pub fn hyper_request(
93    mut builder: ::http::request::Builder,
94    content: Content<::hyper::Body>,
95) -> Result<::http::request::Request<::hyper::Body>, crate::v1_1_4::ApiError>
96{
97    if let Some(content_type) = content.content_type() {
98        builder = builder.header(::http::header::CONTENT_TYPE, content_type);
99    }
100    Ok(builder.body(content.into_body())?)
101}
102
103#[cfg(feature = "hyper")]
104impl From<::hyper::Body> for Content<::hyper::Body> {
105    fn from(body: ::hyper::Body) -> Self {
106        Self::new(body)
107    }
108}
109
110#[cfg(feature = "reqwest")]
111pub fn reqwest_builder(
112    base_url: &str,
113    p_owner: &str,
114    p_repo: &str,
115    p_pull_number: i64,
116    h_user_agent: &str,
117    h_accept: ::std::option::Option<&str>,
118) -> Result<::reqwest::Request, crate::v1_1_4::ApiError> {
119    let url = url_string(
120        base_url,
121        p_owner,
122        p_repo,
123        p_pull_number,
124    )?;
125    let reqwest_url = ::reqwest::Url::parse(&url)?;
126    let mut request = ::reqwest::Request::new(::reqwest::Method::POST, reqwest_url);
127    let headers = request.headers_mut();
128    headers.append(
129        "User-Agent",
130        ::querylizer::Simple::to_string(&h_user_agent, false, &::querylizer::passthrough)?.try_into()?
131    );
132    if let Some(value) = &h_accept {
133        headers.append(
134            "Accept",
135            ::querylizer::Simple::to_string(value, false, &::querylizer::passthrough)?.try_into()?
136        );
137    }
138    Ok(request)
139}
140
141#[cfg(feature = "reqwest")]
142pub fn reqwest_request(
143    mut builder: ::reqwest::Request,
144    content: Content<::reqwest::Body>,
145) -> Result<::reqwest::Request, crate::v1_1_4::ApiError> {
146    if let Some(content_type) = content.content_type() {
147        builder.headers_mut().append(
148            ::reqwest::header::HeaderName::from_static("content-type"),
149            ::reqwest::header::HeaderValue::try_from(content_type)?,
150        );
151    }
152    *builder.body_mut() = Some(content.into_body());
153    Ok(builder)
154}
155
156#[cfg(feature = "reqwest")]
157impl From<::reqwest::Body> for Content<::reqwest::Body> {
158    fn from(body: ::reqwest::Body) -> Self {
159        Self::new(body)
160    }
161}
162
163#[cfg(feature = "reqwest-blocking")]
164pub fn reqwest_blocking_builder(
165    base_url: &str,
166    p_owner: &str,
167    p_repo: &str,
168    p_pull_number: i64,
169    h_user_agent: &str,
170    h_accept: ::std::option::Option<&str>,
171) -> Result<::reqwest::blocking::Request, crate::v1_1_4::ApiError> {
172    let url = url_string(
173        base_url,
174        p_owner,
175        p_repo,
176        p_pull_number,
177    )?;
178    let reqwest_url = ::reqwest::Url::parse(&url)?;
179    let mut request = ::reqwest::blocking::Request::new(::reqwest::Method::POST, reqwest_url);
180    let headers = request.headers_mut();
181    headers.append(
182        "User-Agent",
183        ::querylizer::Simple::to_string(&h_user_agent, false, &::querylizer::passthrough)?.try_into()?
184    );
185    if let Some(value) = &h_accept {
186        headers.append(
187            "Accept",
188            ::querylizer::Simple::to_string(value, false, &::querylizer::passthrough)?.try_into()?
189        );
190    }
191    Ok(request)
192}
193
194#[cfg(feature = "reqwest-blocking")]
195pub fn reqwest_blocking_request(
196    mut builder: ::reqwest::blocking::Request,
197    content: Content<::reqwest::blocking::Body>,
198) -> Result<::reqwest::blocking::Request, crate::v1_1_4::ApiError> {
199    if let Some(content_type) = content.content_type() {
200        builder.headers_mut().append(
201            ::reqwest::header::HeaderName::from_static("content-type"),
202            ::reqwest::header::HeaderValue::try_from(content_type)?,
203        );
204    }
205    *builder.body_mut() = Some(content.into_body());
206    Ok(builder)
207}
208
209#[cfg(feature = "reqwest-blocking")]
210impl From<::reqwest::blocking::Body> for Content<::reqwest::blocking::Body> {
211    fn from(body: ::reqwest::blocking::Body) -> Self {
212        Self::new(body)
213    }
214}
215
216/// Types for body parameter in [`super::pulls_create_review`]
217pub mod body {
218    #[allow(non_snake_case)]
219    #[derive(Clone, Eq, PartialEq, Debug, Default, ::serde::Serialize, ::serde::Deserialize)]
220    pub struct Json<'a> {
221        /// The SHA of the commit that needs a review. Not using the latest commit SHA may render your review comment outdated if a subsequent commit modifies the line you specify as the `position`. Defaults to the most recent commit in the pull request when you do not specify a value.
222        #[serde(skip_serializing_if = "Option::is_none", default)]
223        pub commit_id: ::std::option::Option<::std::borrow::Cow<'a, str>>,
224
225        /// **Required** when using `REQUEST_CHANGES` or `COMMENT` for the `event` parameter. The body text of the pull request review.
226        #[serde(skip_serializing_if = "Option::is_none", default)]
227        pub body: ::std::option::Option<::std::borrow::Cow<'a, str>>,
228
229        /// The review action you want to perform. The review actions include: `APPROVE`, `REQUEST_CHANGES`, or `COMMENT`. By leaving this blank, you set the review action state to `PENDING`, which means you will need to [submit the pull request review](https://docs.github.com/rest/reference/pulls#submit-a-review-for-a-pull-request) when you are ready.
230        #[serde(skip_serializing_if = "Option::is_none", default)]
231        pub event: ::std::option::Option<::std::borrow::Cow<'a, str>>,
232
233        /// Use the following table to specify the location, destination, and contents of the draft review comment.
234        #[serde(skip_serializing_if = "Option::is_none", default)]
235        pub comments: ::std::option::Option<::std::borrow::Cow<'a, [crate::v1_1_4::request::pulls_create_review::body::json::Comments<'a>]>>,
236
237        #[serde(flatten)]
238        pub additionalProperties: ::std::collections::HashMap<::std::borrow::Cow<'a, str>, ::serde_json::value::Value>
239    }
240
241    /// Types for fields in [`Json`]
242    pub mod json {
243        #[allow(non_snake_case)]
244        #[derive(Clone, Eq, PartialEq, Debug, Default, ::serde::Serialize, ::serde::Deserialize)]
245        pub struct Comments<'a> {
246            /// The relative path to the file that necessitates a review comment.
247            pub path: ::std::borrow::Cow<'a, str>,
248
249            /// The position in the diff where you want to add a review comment. Note this value is not the same as the line number in the file. For help finding the position value, read the note below.
250            #[serde(skip_serializing_if = "Option::is_none", default)]
251            pub position: ::std::option::Option<i64>,
252
253            /// Text of the review comment.
254            pub body: ::std::borrow::Cow<'a, str>,
255
256            /// # Example
257            /// 
258            /// ```json
259            /// 28
260            /// ```
261            #[serde(skip_serializing_if = "Option::is_none", default)]
262            pub line: ::std::option::Option<i64>,
263
264            /// # Example
265            /// 
266            /// ```json
267            /// "RIGHT"
268            /// ```
269            #[serde(skip_serializing_if = "Option::is_none", default)]
270            pub side: ::std::option::Option<::std::borrow::Cow<'a, str>>,
271
272            /// # Example
273            /// 
274            /// ```json
275            /// 26
276            /// ```
277            #[serde(skip_serializing_if = "Option::is_none", default)]
278            pub start_line: ::std::option::Option<i64>,
279
280            /// # Example
281            /// 
282            /// ```json
283            /// "LEFT"
284            /// ```
285            #[serde(skip_serializing_if = "Option::is_none", default)]
286            pub start_side: ::std::option::Option<::std::borrow::Cow<'a, str>>,
287
288            #[serde(flatten)]
289            pub additionalProperties: ::std::collections::HashMap<::std::borrow::Cow<'a, str>, ::serde_json::value::Value>
290        }
291    }
292
293    #[cfg(feature = "hyper")]
294    impl<'a> TryFrom<&Json<'a>> for super::Content<::hyper::Body> {
295        type Error = crate::v1_1_4::ApiError;
296
297        fn try_from(value: &Json<'a>) -> Result<Self, Self::Error> {
298            Ok(
299                Self::new(::serde_json::to_vec(value)?.into())
300                .with_content_type(&b"application/json"[..])
301            )
302        }
303    }
304
305    #[cfg(feature = "reqwest")]
306    impl<'a> TryFrom<&Json<'a>> for super::Content<::reqwest::Body> {
307        type Error = crate::v1_1_4::ApiError;
308
309        fn try_from(value: &Json<'a>) -> Result<Self, Self::Error> {
310            Ok(
311                Self::new(::serde_json::to_vec(value)?.into())
312                .with_content_type(&b"application/json"[..])
313            )
314        }
315    }
316
317    #[cfg(feature = "reqwest-blocking")]
318    impl<'a> TryFrom<&Json<'a>> for super::Content<::reqwest::blocking::Body> {
319        type Error = crate::v1_1_4::ApiError;
320
321        fn try_from(value: &Json<'a>) -> Result<Self, Self::Error> {
322            Ok(
323                Self::new(::serde_json::to_vec(value)?.into())
324                .with_content_type(&b"application/json"[..])
325            )
326        }
327    }
328}