octocrab/api/
workflows.rs

1use crate::models::RunId;
2use crate::{models, Octocrab, Page, Result};
3
4pub struct WorkflowsHandler<'octo> {
5    crab: &'octo Octocrab,
6    owner: String,
7    repo: String,
8}
9
10/// Handler for GitHub's workflows API for actions.
11///
12/// Created with [`Octocrab::workflows`].
13impl<'octo> WorkflowsHandler<'octo> {
14    pub(crate) fn new(crab: &'octo Octocrab, owner: String, repo: String) -> Self {
15        Self { crab, owner, repo }
16    }
17
18    /// List workflow definitions in the repository.
19    /// ```no_run
20    /// # async fn run() -> octocrab::Result<()> {
21    /// # let octocrab = octocrab::Octocrab::default();
22    ///
23    /// let issue = octocrab.workflows("owner", "repo")
24    ///     .list()
25    ///     // Optional Parameters
26    ///     .per_page(100)
27    ///     .page(1u8)
28    ///     // Send the request
29    ///     .send()
30    ///     .await?;
31    /// # Ok(())
32    /// # }
33    /// ```
34    pub fn list(&self) -> ListWorkflowsBuilder<'_, '_> {
35        ListWorkflowsBuilder::new(self)
36    }
37
38    pub async fn get(&self, run_id: RunId) -> Result<models::workflows::Run> {
39        let route = format!(
40            "/repos/{owner}/{repo}/actions/runs/{run_id}",
41            owner = self.owner,
42            repo = self.repo,
43            run_id = run_id,
44        );
45
46        self.crab.get(route, None::<&()>).await
47    }
48
49    /// List runs in the specified workflow.
50    /// workflow_file_or_id can be either file name or numeric expression.
51    /// ```no_run
52    /// # async fn run() -> octocrab::Result<()> {
53    /// # let octocrab = octocrab::Octocrab::default();
54    ///
55    /// let issue = octocrab.workflows("owner", "repo")
56    ///     .list_runs("ci.yml")
57    ///     // Optional Parameters
58    ///     .actor("octocat")
59    ///     .branch("master")
60    ///     .event("push")
61    ///     .status("success")
62    ///     .per_page(100)
63    ///     .page(1u8)
64    ///     // Send the request
65    ///     .send()
66    ///     .await?;
67    /// # Ok(())
68    /// # }
69    /// ```
70    pub fn list_runs(&self, workflow_file_or_id: impl Into<String>) -> ListRunsBuilder<'_, '_> {
71        ListRunsBuilder::new(
72            self,
73            ListRunsRequestType::ByWorkflow(workflow_file_or_id.into()),
74        )
75    }
76
77    /// List runs for the specified owner and repository.
78    /// ```no_run
79    /// # async fn run() -> octocrab::Result<()> {
80    /// let octocrab = octocrab::Octocrab::default();
81    ///
82    /// let runs = octocrab.workflows("owner", "repo")
83    ///     .list_all_runs()
84    ///     // Optional Parameters
85    ///     .actor("octocat")
86    ///     .branch("master")
87    ///     .event("pull_request")
88    ///     .status("success")
89    ///     .per_page(100)
90    ///     .page(1u8)
91    ///     // Send the request
92    ///     .send()
93    ///     .await?;
94    /// # Ok(())
95    /// # }
96    /// ```
97    pub fn list_all_runs(&self) -> ListRunsBuilder<'_, '_> {
98        ListRunsBuilder::new(self, ListRunsRequestType::ByRepo)
99    }
100
101    /// List job results in the specified run.
102    /// ```no_run
103    /// # async fn run() -> octocrab::Result<()> {
104    /// # let octocrab = octocrab::Octocrab::default();
105    /// use octocrab::params::workflows::Filter;
106    ///
107    /// let issue = octocrab.workflows("owner", "repo")
108    ///     .list_jobs(1234u64.into())
109    ///     // Optional Parameters
110    ///     .per_page(100)
111    ///     .page(1u8)
112    ///     .filter(Filter::All)
113    ///     // Send the request
114    ///     .send()
115    ///     .await?;
116    /// # Ok(())
117    /// # }
118    /// ```
119    pub fn list_jobs(&self, run_id: RunId) -> ListJobsBuilder<'_, '_> {
120        ListJobsBuilder::new(self, run_id)
121    }
122}
123
124#[derive(serde::Serialize)]
125pub struct ListWorkflowsBuilder<'octo, 'b> {
126    #[serde(skip)]
127    handler: &'b WorkflowsHandler<'octo>,
128    #[serde(skip_serializing_if = "Option::is_none")]
129    per_page: Option<u8>,
130    #[serde(skip_serializing_if = "Option::is_none")]
131    page: Option<u32>,
132}
133
134impl<'octo, 'b> ListWorkflowsBuilder<'octo, 'b> {
135    pub(crate) fn new(handler: &'b WorkflowsHandler<'octo>) -> Self {
136        Self {
137            handler,
138            per_page: None,
139            page: None,
140        }
141    }
142
143    /// Results per page (max 100).
144    pub fn per_page(mut self, per_page: impl Into<u8>) -> Self {
145        self.per_page = Some(per_page.into());
146        self
147    }
148
149    /// Page number of the results to fetch.
150    pub fn page(mut self, page: impl Into<u32>) -> Self {
151        self.page = Some(page.into());
152        self
153    }
154
155    /// Sends the actual request.
156    pub async fn send(self) -> Result<Page<models::workflows::WorkFlow>> {
157        let route = format!(
158            "/repos/{owner}/{repo}/actions/workflows",
159            owner = self.handler.owner,
160            repo = self.handler.repo
161        );
162        self.handler.crab.get(route, Some(&self)).await
163    }
164}
165
166/// The type of list workflow runs request.
167pub(crate) enum ListRunsRequestType {
168    ByRepo,
169    ByWorkflow(String),
170}
171
172#[derive(serde::Serialize)]
173pub struct ListRunsBuilder<'octo, 'b> {
174    #[serde(skip)]
175    handler: &'b WorkflowsHandler<'octo>,
176    #[serde(skip)]
177    r#type: ListRunsRequestType,
178    #[serde(skip_serializing_if = "Option::is_none")]
179    actor: Option<String>,
180    #[serde(skip_serializing_if = "Option::is_none")]
181    branch: Option<String>,
182    #[serde(skip_serializing_if = "Option::is_none")]
183    event: Option<String>,
184    #[serde(skip_serializing_if = "Option::is_none")]
185    status: Option<String>,
186    #[serde(skip_serializing_if = "Option::is_none")]
187    per_page: Option<u8>,
188    #[serde(skip_serializing_if = "Option::is_none")]
189    page: Option<u32>,
190    #[serde(skip_serializing_if = "Option::is_none")]
191    exclude_pull_requests: Option<bool>,
192}
193
194impl<'octo, 'b> ListRunsBuilder<'octo, 'b> {
195    pub(crate) fn new(handler: &'b WorkflowsHandler<'octo>, r#type: ListRunsRequestType) -> Self {
196        Self {
197            handler,
198            r#type,
199            actor: None,
200            branch: None,
201            event: None,
202            status: None,
203            per_page: None,
204            page: None,
205            exclude_pull_requests: None,
206        }
207    }
208
209    /// Someone who runs workflows. Use the login to specify a user.
210    pub fn actor(mut self, actor: impl Into<String>) -> Self {
211        self.actor = Some(actor.into());
212        self
213    }
214
215    /// A branch associated with workflows. Use the name of the branch of the push.
216    pub fn branch(mut self, branch: impl Into<String>) -> Self {
217        self.branch = Some(branch.into());
218        self
219    }
220
221    /// An event associated with workflows. Can be e.g. push, pull_request, issue,
222    /// ... and many variations. See official "Events that trigger workflows." doc.
223    pub fn event(mut self, event: impl Into<String>) -> Self {
224        self.event = Some(event.into());
225        self
226    }
227
228    /// A status associated with workflows.
229    /// status or conclusion can be specified. e.g. success, in_progress, waiting...
230    pub fn status(mut self, status: impl Into<String>) -> Self {
231        self.status = Some(status.into());
232        self
233    }
234
235    /// Results per page (max 100).
236    pub fn per_page(mut self, per_page: impl Into<u8>) -> Self {
237        self.per_page = Some(per_page.into());
238        self
239    }
240
241    /// Page number of the results to fetch.
242    pub fn page(mut self, page: impl Into<u32>) -> Self {
243        self.page = Some(page.into());
244        self
245    }
246
247    /// Whether to exclude the pull requests or not.
248    pub fn exclude_pull_requests(mut self, exclude_pull_requests: impl Into<bool>) -> Self {
249        self.exclude_pull_requests = Some(exclude_pull_requests.into());
250        self
251    }
252
253    /// Sends the actual request.
254    pub async fn send(self) -> Result<Page<models::workflows::Run>> {
255        let route = match self.r#type {
256            ListRunsRequestType::ByRepo => format!(
257                "/repos/{owner}/{repo}/actions/runs",
258                owner = self.handler.owner,
259                repo = self.handler.repo
260            ),
261            ListRunsRequestType::ByWorkflow(ref workflow_id) => format!(
262                "/repos/{owner}/{repo}/actions/workflows/{workflow_id}/runs",
263                owner = self.handler.owner,
264                repo = self.handler.repo,
265                workflow_id = workflow_id
266            ),
267        };
268        self.handler.crab.get(route, Some(&self)).await
269    }
270}
271
272#[derive(serde::Serialize)]
273pub struct ListJobsBuilder<'octo, 'b> {
274    #[serde(skip)]
275    handler: &'b WorkflowsHandler<'octo>,
276    #[serde(skip)]
277    run_id: RunId,
278    #[serde(skip_serializing_if = "Option::is_none")]
279    filter: Option<crate::params::workflows::Filter>,
280    #[serde(skip_serializing_if = "Option::is_none")]
281    per_page: Option<u8>,
282    #[serde(skip_serializing_if = "Option::is_none")]
283    page: Option<u32>,
284}
285
286impl<'octo, 'b> ListJobsBuilder<'octo, 'b> {
287    pub(crate) fn new(handler: &'b WorkflowsHandler<'octo>, run_id: RunId) -> Self {
288        Self {
289            handler,
290            run_id,
291            per_page: None,
292            page: None,
293            filter: None,
294        }
295    }
296
297    /// Results per page (max 100).
298    pub fn per_page(mut self, per_page: impl Into<u8>) -> Self {
299        self.per_page = Some(per_page.into());
300        self
301    }
302
303    /// Page number of the results to fetch.
304    pub fn page(mut self, page: impl Into<u32>) -> Self {
305        self.page = Some(page.into());
306        self
307    }
308
309    /// Filters jobs by their completed_at timestamp. Choose latest or all.
310    pub fn filter(mut self, filter: impl Into<crate::params::workflows::Filter>) -> Self {
311        self.filter = Some(filter.into());
312        self
313    }
314
315    /// Sends the actual request.
316    pub async fn send(self) -> Result<Page<models::workflows::Job>> {
317        let route = format!(
318            "/repos/{owner}/{repo}/actions/runs/{run_id}/jobs",
319            owner = self.handler.owner,
320            repo = self.handler.repo,
321            run_id = self.run_id,
322        );
323        self.handler.crab.get(route, Some(&self)).await
324    }
325}
326
327#[cfg(test)]
328mod tests {
329    #[tokio::test]
330    async fn serialize() {
331        use crate::params::workflows::Filter;
332
333        let octocrab = crate::Octocrab::default();
334        let handler = octocrab.workflows("rust-lang", "rust");
335        let list_jobs = handler
336            .list_jobs(1234u64.into())
337            .filter(Filter::All)
338            .per_page(100)
339            .page(1u8);
340
341        assert_eq!(
342            serde_json::to_value(list_jobs).unwrap(),
343            serde_json::json!({
344                "filter": "all",
345                "per_page": 100,
346                "page": 1,
347            })
348        )
349    }
350}