1use chrono::{DateTime, Utc};
8use derive_builder::Builder;
9
10use crate::api::common::{NameOrId, SortOrder};
11use crate::api::endpoint_prelude::*;
12use crate::api::ParamValue;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16#[non_exhaustive]
17pub enum PipelineScope {
18 Running,
20 Pending,
22 Finished,
24 Branches,
26 Tags,
28}
29
30impl PipelineScope {
31 fn as_str(self) -> &'static str {
33 match self {
34 PipelineScope::Running => "running",
35 PipelineScope::Pending => "pending",
36 PipelineScope::Finished => "finished",
37 PipelineScope::Branches => "branches",
38 PipelineScope::Tags => "tags",
39 }
40 }
41}
42
43impl ParamValue<'static> for PipelineScope {
44 fn as_value(&self) -> Cow<'static, str> {
45 self.as_str().into()
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51#[non_exhaustive]
52pub enum PipelineStatus {
53 Running,
55 Pending,
57 Success,
59 Failed,
61 Canceled,
63 Skipped,
65 Created,
67 Manual,
69 Scheduled,
71 Preparing,
73 WaitingForResource,
75}
76
77impl PipelineStatus {
78 fn as_str(self) -> &'static str {
80 match self {
81 PipelineStatus::Running => "running",
82 PipelineStatus::Pending => "pending",
83 PipelineStatus::Success => "success",
84 PipelineStatus::Failed => "failed",
85 PipelineStatus::Canceled => "canceled",
86 PipelineStatus::Skipped => "skipped",
87 PipelineStatus::Created => "created",
88 PipelineStatus::Manual => "manual",
89 PipelineStatus::Scheduled => "scheduled",
90 PipelineStatus::Preparing => "preparing",
91 PipelineStatus::WaitingForResource => "waiting_for_resource",
92 }
93 }
94}
95
96impl ParamValue<'static> for PipelineStatus {
97 fn as_value(&self) -> Cow<'static, str> {
98 self.as_str().into()
99 }
100}
101
102#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
104#[non_exhaustive]
105pub enum PipelineOrderBy {
106 #[default]
108 Id,
109 Status,
111 Ref,
113 UpdatedAt,
115 UserId,
117}
118
119impl PipelineOrderBy {
120 fn as_str(self) -> &'static str {
122 match self {
123 PipelineOrderBy::Id => "id",
124 PipelineOrderBy::Status => "status",
125 PipelineOrderBy::Ref => "ref",
126 PipelineOrderBy::UpdatedAt => "updated_at",
127 PipelineOrderBy::UserId => "user_id",
128 }
129 }
130}
131
132impl ParamValue<'static> for PipelineOrderBy {
133 fn as_value(&self) -> Cow<'static, str> {
134 self.as_str().into()
135 }
136}
137
138#[derive(Debug, Clone, Copy, PartialEq, Eq)]
140#[non_exhaustive]
141pub enum PipelineSource {
142 Push,
144 Web,
146 Trigger,
148 Schedule,
150 Api,
152 External,
154 Pipeline,
156 Chat,
158 WebIde,
160 MergeRequestEvent,
162 ExternalPullRequestEvent,
164 ParentPipeline,
166 OnDemandDastScan,
168 OnDemandDastValidation,
170 SecurityOrchestrationPolicy,
172}
173
174impl PipelineSource {
175 fn as_str(self) -> &'static str {
177 match self {
178 PipelineSource::Push => "push",
179 PipelineSource::Web => "web",
180 PipelineSource::Trigger => "trigger",
181 PipelineSource::Schedule => "schedule",
182 PipelineSource::Api => "api",
183 PipelineSource::External => "external",
184 PipelineSource::Pipeline => "pipeline",
185 PipelineSource::Chat => "chat",
186 PipelineSource::WebIde => "web_ide",
187 PipelineSource::MergeRequestEvent => "merge_request_event",
188 PipelineSource::ExternalPullRequestEvent => "external_pull_request_event",
189 PipelineSource::ParentPipeline => "parent_pipeline",
190 PipelineSource::OnDemandDastScan => "ondemand_dast_scan",
191 PipelineSource::OnDemandDastValidation => "ondemand_dast_validation",
192 PipelineSource::SecurityOrchestrationPolicy => "security_orchestration_policy",
193 }
194 }
195}
196
197impl ParamValue<'static> for PipelineSource {
198 fn as_value(&self) -> Cow<'static, str> {
199 self.as_str().into()
200 }
201}
202
203#[derive(Debug, Builder, Clone)]
205#[builder(setter(strip_option))]
206pub struct Pipelines<'a> {
207 #[builder(setter(into))]
209 project: NameOrId<'a>,
210
211 #[builder(default)]
213 scope: Option<PipelineScope>,
214 #[builder(default)]
216 status: Option<PipelineStatus>,
217 #[builder(setter(into), default)]
219 ref_: Option<Cow<'a, str>>,
220 #[builder(setter(into), default)]
222 sha: Option<Cow<'a, str>>,
223 #[builder(default)]
225 yaml_errors: Option<bool>,
226 #[builder(setter(into), default)]
228 username: Option<Cow<'a, str>>,
229
230 #[builder(default)]
232 order_by: Option<PipelineOrderBy>,
233 #[builder(default)]
235 sort: Option<SortOrder>,
236
237 #[builder(default)]
239 updated_before: Option<DateTime<Utc>>,
240 #[builder(default)]
242 updated_after: Option<DateTime<Utc>>,
243 #[builder(default)]
245 source: Option<PipelineSource>,
246}
247
248impl<'a> Pipelines<'a> {
249 pub fn builder() -> PipelinesBuilder<'a> {
251 PipelinesBuilder::default()
252 }
253}
254
255impl Endpoint for Pipelines<'_> {
256 fn method(&self) -> Method {
257 Method::GET
258 }
259
260 fn endpoint(&self) -> Cow<'static, str> {
261 format!("projects/{}/pipelines", self.project).into()
262 }
263
264 fn parameters(&self) -> QueryParams {
265 let mut params = QueryParams::default();
266
267 params
268 .push_opt("scope", self.scope)
269 .push_opt("status", self.status)
270 .push_opt("ref", self.ref_.as_ref())
271 .push_opt("sha", self.sha.as_ref())
272 .push_opt("yaml_errors", self.yaml_errors)
273 .push_opt("username", self.username.as_ref())
274 .push_opt("updated_after", self.updated_after)
275 .push_opt("updated_before", self.updated_before)
276 .push_opt("source", self.source)
277 .push_opt("order_by", self.order_by)
278 .push_opt("sort", self.sort);
279
280 params
281 }
282}
283
284impl Pageable for Pipelines<'_> {}
285
286#[cfg(test)]
287mod tests {
288 use chrono::{TimeZone, Utc};
289
290 use crate::api::common::SortOrder;
291 use crate::api::projects::pipelines::{
292 PipelineOrderBy, PipelineScope, PipelineSource, PipelineStatus, Pipelines,
293 PipelinesBuilderError,
294 };
295 use crate::api::{self, Query};
296 use crate::test::client::{ExpectedUrl, SingleTestClient};
297
298 #[test]
299 fn pipeline_scope_as_str() {
300 let items = &[
301 (PipelineScope::Running, "running"),
302 (PipelineScope::Pending, "pending"),
303 (PipelineScope::Finished, "finished"),
304 (PipelineScope::Branches, "branches"),
305 (PipelineScope::Tags, "tags"),
306 ];
307
308 for (i, s) in items {
309 assert_eq!(i.as_str(), *s);
310 }
311 }
312
313 #[test]
314 fn pipeline_status_as_str() {
315 let items = &[
316 (PipelineStatus::Running, "running"),
317 (PipelineStatus::Pending, "pending"),
318 (PipelineStatus::Success, "success"),
319 (PipelineStatus::Failed, "failed"),
320 (PipelineStatus::Canceled, "canceled"),
321 (PipelineStatus::Skipped, "skipped"),
322 (PipelineStatus::Created, "created"),
323 (PipelineStatus::Manual, "manual"),
324 (PipelineStatus::Scheduled, "scheduled"),
325 (PipelineStatus::Preparing, "preparing"),
326 (PipelineStatus::WaitingForResource, "waiting_for_resource"),
327 ];
328
329 for (i, s) in items {
330 assert_eq!(i.as_str(), *s);
331 }
332 }
333
334 #[test]
335 fn order_by_default() {
336 assert_eq!(PipelineOrderBy::default(), PipelineOrderBy::Id);
337 }
338
339 #[test]
340 fn order_by_as_str() {
341 let items = &[
342 (PipelineOrderBy::Id, "id"),
343 (PipelineOrderBy::Status, "status"),
344 (PipelineOrderBy::Ref, "ref"),
345 (PipelineOrderBy::UpdatedAt, "updated_at"),
346 (PipelineOrderBy::UserId, "user_id"),
347 ];
348
349 for (i, s) in items {
350 assert_eq!(i.as_str(), *s);
351 }
352 }
353
354 #[test]
355 fn pipeline_source_as_str() {
356 let items = &[
357 (PipelineSource::Push, "push"),
358 (PipelineSource::Web, "web"),
359 (PipelineSource::Trigger, "trigger"),
360 (PipelineSource::Schedule, "schedule"),
361 (PipelineSource::Api, "api"),
362 (PipelineSource::External, "external"),
363 (PipelineSource::Pipeline, "pipeline"),
364 (PipelineSource::Chat, "chat"),
365 (PipelineSource::WebIde, "web_ide"),
366 (PipelineSource::MergeRequestEvent, "merge_request_event"),
367 (
368 PipelineSource::ExternalPullRequestEvent,
369 "external_pull_request_event",
370 ),
371 (PipelineSource::ParentPipeline, "parent_pipeline"),
372 (PipelineSource::OnDemandDastScan, "ondemand_dast_scan"),
373 (
374 PipelineSource::OnDemandDastValidation,
375 "ondemand_dast_validation",
376 ),
377 (
378 PipelineSource::SecurityOrchestrationPolicy,
379 "security_orchestration_policy",
380 ),
381 ];
382
383 for (i, s) in items {
384 assert_eq!(i.as_str(), *s);
385 }
386 }
387
388 #[test]
389 fn project_is_needed() {
390 let err = Pipelines::builder().build().unwrap_err();
391 crate::test::assert_missing_field!(err, PipelinesBuilderError, "project");
392 }
393
394 #[test]
395 fn project_is_sufficient() {
396 Pipelines::builder().project(1).build().unwrap();
397 }
398
399 #[test]
400 fn endpoint() {
401 let endpoint = ExpectedUrl::builder()
402 .endpoint("projects/simple%2Fproject/pipelines")
403 .build()
404 .unwrap();
405 let client = SingleTestClient::new_raw(endpoint, "");
406
407 let endpoint = Pipelines::builder()
408 .project("simple/project")
409 .build()
410 .unwrap();
411 api::ignore(endpoint).query(&client).unwrap();
412 }
413
414 #[test]
415 fn endpoint_scope() {
416 let endpoint = ExpectedUrl::builder()
417 .endpoint("projects/1/pipelines")
418 .add_query_params(&[("scope", "finished")])
419 .build()
420 .unwrap();
421 let client = SingleTestClient::new_raw(endpoint, "");
422
423 let endpoint = Pipelines::builder()
424 .project(1)
425 .scope(PipelineScope::Finished)
426 .build()
427 .unwrap();
428 api::ignore(endpoint).query(&client).unwrap();
429 }
430
431 #[test]
432 fn endpoint_status() {
433 let endpoint = ExpectedUrl::builder()
434 .endpoint("projects/1/pipelines")
435 .add_query_params(&[("status", "failed")])
436 .build()
437 .unwrap();
438 let client = SingleTestClient::new_raw(endpoint, "");
439
440 let endpoint = Pipelines::builder()
441 .project(1)
442 .status(PipelineStatus::Failed)
443 .build()
444 .unwrap();
445 api::ignore(endpoint).query(&client).unwrap();
446 }
447
448 #[test]
449 fn endpoint_ref() {
450 let endpoint = ExpectedUrl::builder()
451 .endpoint("projects/1/pipelines")
452 .add_query_params(&[("ref", "master")])
453 .build()
454 .unwrap();
455 let client = SingleTestClient::new_raw(endpoint, "");
456
457 let endpoint = Pipelines::builder()
458 .project(1)
459 .ref_("master")
460 .build()
461 .unwrap();
462 api::ignore(endpoint).query(&client).unwrap();
463 }
464
465 #[test]
466 fn endpoint_sha() {
467 let endpoint = ExpectedUrl::builder()
468 .endpoint("projects/1/pipelines")
469 .add_query_params(&[("sha", "0000000000000000000000000000000000000000")])
470 .build()
471 .unwrap();
472 let client = SingleTestClient::new_raw(endpoint, "");
473
474 let endpoint = Pipelines::builder()
475 .project(1)
476 .sha("0000000000000000000000000000000000000000")
477 .build()
478 .unwrap();
479 api::ignore(endpoint).query(&client).unwrap();
480 }
481
482 #[test]
483 fn endpoint_yaml_errors() {
484 let endpoint = ExpectedUrl::builder()
485 .endpoint("projects/1/pipelines")
486 .add_query_params(&[("yaml_errors", "true")])
487 .build()
488 .unwrap();
489 let client = SingleTestClient::new_raw(endpoint, "");
490
491 let endpoint = Pipelines::builder()
492 .project(1)
493 .yaml_errors(true)
494 .build()
495 .unwrap();
496 api::ignore(endpoint).query(&client).unwrap();
497 }
498
499 #[test]
500 fn endpoint_username() {
501 let endpoint = ExpectedUrl::builder()
502 .endpoint("projects/1/pipelines")
503 .add_query_params(&[("username", "name")])
504 .build()
505 .unwrap();
506 let client = SingleTestClient::new_raw(endpoint, "");
507
508 let endpoint = Pipelines::builder()
509 .project(1)
510 .username("name")
511 .build()
512 .unwrap();
513 api::ignore(endpoint).query(&client).unwrap();
514 }
515
516 #[test]
517 fn endpoint_updated_before() {
518 let endpoint = ExpectedUrl::builder()
519 .endpoint("projects/1/pipelines")
520 .add_query_params(&[("updated_before", "2020-01-01T00:00:00Z")])
521 .build()
522 .unwrap();
523 let client = SingleTestClient::new_raw(endpoint, "");
524
525 let endpoint = Pipelines::builder()
526 .project(1)
527 .updated_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
528 .build()
529 .unwrap();
530 api::ignore(endpoint).query(&client).unwrap();
531 }
532
533 #[test]
534 fn endpoint_updated_after() {
535 let endpoint = ExpectedUrl::builder()
536 .endpoint("projects/1/pipelines")
537 .add_query_params(&[("updated_after", "2020-01-01T00:00:00Z")])
538 .build()
539 .unwrap();
540 let client = SingleTestClient::new_raw(endpoint, "");
541
542 let endpoint = Pipelines::builder()
543 .project(1)
544 .updated_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
545 .build()
546 .unwrap();
547 api::ignore(endpoint).query(&client).unwrap();
548 }
549
550 #[test]
551 fn endpoint_source() {
552 let endpoint = ExpectedUrl::builder()
553 .endpoint("projects/1/pipelines")
554 .add_query_params(&[("source", "trigger")])
555 .build()
556 .unwrap();
557 let client = SingleTestClient::new_raw(endpoint, "");
558
559 let endpoint = Pipelines::builder()
560 .project(1)
561 .source(PipelineSource::Trigger)
562 .build()
563 .unwrap();
564 api::ignore(endpoint).query(&client).unwrap();
565 }
566
567 #[test]
568 fn endpoint_order_by() {
569 let endpoint = ExpectedUrl::builder()
570 .endpoint("projects/1/pipelines")
571 .add_query_params(&[("order_by", "updated_at")])
572 .build()
573 .unwrap();
574 let client = SingleTestClient::new_raw(endpoint, "");
575
576 let endpoint = Pipelines::builder()
577 .project(1)
578 .order_by(PipelineOrderBy::UpdatedAt)
579 .build()
580 .unwrap();
581 api::ignore(endpoint).query(&client).unwrap();
582 }
583
584 #[test]
585 fn endpoint_sort() {
586 let endpoint = ExpectedUrl::builder()
587 .endpoint("projects/1/pipelines")
588 .add_query_params(&[("sort", "desc")])
589 .build()
590 .unwrap();
591 let client = SingleTestClient::new_raw(endpoint, "");
592
593 let endpoint = Pipelines::builder()
594 .project(1)
595 .sort(SortOrder::Descending)
596 .build()
597 .unwrap();
598 api::ignore(endpoint).query(&client).unwrap();
599 }
600}