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 #[builder(setter(into), default)]
231 name: Option<Cow<'a, str>>,
232
233 #[builder(default)]
235 order_by: Option<PipelineOrderBy>,
236 #[builder(default)]
238 sort: Option<SortOrder>,
239
240 #[builder(default)]
242 updated_before: Option<DateTime<Utc>>,
243 #[builder(default)]
245 updated_after: Option<DateTime<Utc>>,
246 #[builder(default)]
248 source: Option<PipelineSource>,
249}
250
251impl<'a> Pipelines<'a> {
252 pub fn builder() -> PipelinesBuilder<'a> {
254 PipelinesBuilder::default()
255 }
256}
257
258impl Endpoint for Pipelines<'_> {
259 fn method(&self) -> Method {
260 Method::GET
261 }
262
263 fn endpoint(&self) -> Cow<'static, str> {
264 format!("projects/{}/pipelines", self.project).into()
265 }
266
267 fn parameters(&self) -> QueryParams {
268 let mut params = QueryParams::default();
269
270 params
271 .push_opt("scope", self.scope)
272 .push_opt("status", self.status)
273 .push_opt("ref", self.ref_.as_ref())
274 .push_opt("sha", self.sha.as_ref())
275 .push_opt("yaml_errors", self.yaml_errors)
276 .push_opt("username", self.username.as_ref())
277 .push_opt("name", self.name.as_ref())
278 .push_opt("updated_after", self.updated_after)
279 .push_opt("updated_before", self.updated_before)
280 .push_opt("source", self.source)
281 .push_opt("order_by", self.order_by)
282 .push_opt("sort", self.sort);
283
284 params
285 }
286}
287
288impl Pageable for Pipelines<'_> {}
289
290#[cfg(test)]
291mod tests {
292 use chrono::{TimeZone, Utc};
293
294 use crate::api::common::SortOrder;
295 use crate::api::projects::pipelines::{
296 PipelineOrderBy, PipelineScope, PipelineSource, PipelineStatus, Pipelines,
297 PipelinesBuilderError,
298 };
299 use crate::api::{self, Query};
300 use crate::test::client::{ExpectedUrl, SingleTestClient};
301
302 #[test]
303 fn pipeline_scope_as_str() {
304 let items = &[
305 (PipelineScope::Running, "running"),
306 (PipelineScope::Pending, "pending"),
307 (PipelineScope::Finished, "finished"),
308 (PipelineScope::Branches, "branches"),
309 (PipelineScope::Tags, "tags"),
310 ];
311
312 for (i, s) in items {
313 assert_eq!(i.as_str(), *s);
314 }
315 }
316
317 #[test]
318 fn pipeline_status_as_str() {
319 let items = &[
320 (PipelineStatus::Running, "running"),
321 (PipelineStatus::Pending, "pending"),
322 (PipelineStatus::Success, "success"),
323 (PipelineStatus::Failed, "failed"),
324 (PipelineStatus::Canceled, "canceled"),
325 (PipelineStatus::Skipped, "skipped"),
326 (PipelineStatus::Created, "created"),
327 (PipelineStatus::Manual, "manual"),
328 (PipelineStatus::Scheduled, "scheduled"),
329 (PipelineStatus::Preparing, "preparing"),
330 (PipelineStatus::WaitingForResource, "waiting_for_resource"),
331 ];
332
333 for (i, s) in items {
334 assert_eq!(i.as_str(), *s);
335 }
336 }
337
338 #[test]
339 fn order_by_default() {
340 assert_eq!(PipelineOrderBy::default(), PipelineOrderBy::Id);
341 }
342
343 #[test]
344 fn order_by_as_str() {
345 let items = &[
346 (PipelineOrderBy::Id, "id"),
347 (PipelineOrderBy::Status, "status"),
348 (PipelineOrderBy::Ref, "ref"),
349 (PipelineOrderBy::UpdatedAt, "updated_at"),
350 (PipelineOrderBy::UserId, "user_id"),
351 ];
352
353 for (i, s) in items {
354 assert_eq!(i.as_str(), *s);
355 }
356 }
357
358 #[test]
359 fn pipeline_source_as_str() {
360 let items = &[
361 (PipelineSource::Push, "push"),
362 (PipelineSource::Web, "web"),
363 (PipelineSource::Trigger, "trigger"),
364 (PipelineSource::Schedule, "schedule"),
365 (PipelineSource::Api, "api"),
366 (PipelineSource::External, "external"),
367 (PipelineSource::Pipeline, "pipeline"),
368 (PipelineSource::Chat, "chat"),
369 (PipelineSource::WebIde, "web_ide"),
370 (PipelineSource::MergeRequestEvent, "merge_request_event"),
371 (
372 PipelineSource::ExternalPullRequestEvent,
373 "external_pull_request_event",
374 ),
375 (PipelineSource::ParentPipeline, "parent_pipeline"),
376 (PipelineSource::OnDemandDastScan, "ondemand_dast_scan"),
377 (
378 PipelineSource::OnDemandDastValidation,
379 "ondemand_dast_validation",
380 ),
381 (
382 PipelineSource::SecurityOrchestrationPolicy,
383 "security_orchestration_policy",
384 ),
385 ];
386
387 for (i, s) in items {
388 assert_eq!(i.as_str(), *s);
389 }
390 }
391
392 #[test]
393 fn project_is_needed() {
394 let err = Pipelines::builder().build().unwrap_err();
395 crate::test::assert_missing_field!(err, PipelinesBuilderError, "project");
396 }
397
398 #[test]
399 fn project_is_sufficient() {
400 Pipelines::builder().project(1).build().unwrap();
401 }
402
403 #[test]
404 fn endpoint() {
405 let endpoint = ExpectedUrl::builder()
406 .endpoint("projects/simple%2Fproject/pipelines")
407 .build()
408 .unwrap();
409 let client = SingleTestClient::new_raw(endpoint, "");
410
411 let endpoint = Pipelines::builder()
412 .project("simple/project")
413 .build()
414 .unwrap();
415 api::ignore(endpoint).query(&client).unwrap();
416 }
417
418 #[test]
419 fn endpoint_scope() {
420 let endpoint = ExpectedUrl::builder()
421 .endpoint("projects/1/pipelines")
422 .add_query_params(&[("scope", "finished")])
423 .build()
424 .unwrap();
425 let client = SingleTestClient::new_raw(endpoint, "");
426
427 let endpoint = Pipelines::builder()
428 .project(1)
429 .scope(PipelineScope::Finished)
430 .build()
431 .unwrap();
432 api::ignore(endpoint).query(&client).unwrap();
433 }
434
435 #[test]
436 fn endpoint_status() {
437 let endpoint = ExpectedUrl::builder()
438 .endpoint("projects/1/pipelines")
439 .add_query_params(&[("status", "failed")])
440 .build()
441 .unwrap();
442 let client = SingleTestClient::new_raw(endpoint, "");
443
444 let endpoint = Pipelines::builder()
445 .project(1)
446 .status(PipelineStatus::Failed)
447 .build()
448 .unwrap();
449 api::ignore(endpoint).query(&client).unwrap();
450 }
451
452 #[test]
453 fn endpoint_ref() {
454 let endpoint = ExpectedUrl::builder()
455 .endpoint("projects/1/pipelines")
456 .add_query_params(&[("ref", "master")])
457 .build()
458 .unwrap();
459 let client = SingleTestClient::new_raw(endpoint, "");
460
461 let endpoint = Pipelines::builder()
462 .project(1)
463 .ref_("master")
464 .build()
465 .unwrap();
466 api::ignore(endpoint).query(&client).unwrap();
467 }
468
469 #[test]
470 fn endpoint_sha() {
471 let endpoint = ExpectedUrl::builder()
472 .endpoint("projects/1/pipelines")
473 .add_query_params(&[("sha", "0000000000000000000000000000000000000000")])
474 .build()
475 .unwrap();
476 let client = SingleTestClient::new_raw(endpoint, "");
477
478 let endpoint = Pipelines::builder()
479 .project(1)
480 .sha("0000000000000000000000000000000000000000")
481 .build()
482 .unwrap();
483 api::ignore(endpoint).query(&client).unwrap();
484 }
485
486 #[test]
487 fn endpoint_yaml_errors() {
488 let endpoint = ExpectedUrl::builder()
489 .endpoint("projects/1/pipelines")
490 .add_query_params(&[("yaml_errors", "true")])
491 .build()
492 .unwrap();
493 let client = SingleTestClient::new_raw(endpoint, "");
494
495 let endpoint = Pipelines::builder()
496 .project(1)
497 .yaml_errors(true)
498 .build()
499 .unwrap();
500 api::ignore(endpoint).query(&client).unwrap();
501 }
502
503 #[test]
504 fn endpoint_username() {
505 let endpoint = ExpectedUrl::builder()
506 .endpoint("projects/1/pipelines")
507 .add_query_params(&[("username", "name")])
508 .build()
509 .unwrap();
510 let client = SingleTestClient::new_raw(endpoint, "");
511
512 let endpoint = Pipelines::builder()
513 .project(1)
514 .username("name")
515 .build()
516 .unwrap();
517 api::ignore(endpoint).query(&client).unwrap();
518 }
519
520 #[test]
521 fn endpoint_name() {
522 let endpoint = ExpectedUrl::builder()
523 .endpoint("projects/1/pipelines")
524 .add_query_params(&[("name", "my-pipeline-name")])
525 .build()
526 .unwrap();
527 let client = SingleTestClient::new_raw(endpoint, "");
528
529 let endpoint = Pipelines::builder()
530 .project(1)
531 .name("my-pipeline-name")
532 .build()
533 .unwrap();
534 api::ignore(endpoint).query(&client).unwrap();
535 }
536
537 #[test]
538 fn endpoint_updated_after() {
539 let endpoint = ExpectedUrl::builder()
540 .endpoint("projects/1/pipelines")
541 .add_query_params(&[("updated_after", "2020-01-01T00:00:00Z")])
542 .build()
543 .unwrap();
544 let client = SingleTestClient::new_raw(endpoint, "");
545
546 let endpoint = Pipelines::builder()
547 .project(1)
548 .updated_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
549 .build()
550 .unwrap();
551 api::ignore(endpoint).query(&client).unwrap();
552 }
553
554 #[test]
555 fn endpoint_updated_before() {
556 let endpoint = ExpectedUrl::builder()
557 .endpoint("projects/1/pipelines")
558 .add_query_params(&[("updated_before", "2020-01-01T00:00:00Z")])
559 .build()
560 .unwrap();
561 let client = SingleTestClient::new_raw(endpoint, "");
562
563 let endpoint = Pipelines::builder()
564 .project(1)
565 .updated_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
566 .build()
567 .unwrap();
568 api::ignore(endpoint).query(&client).unwrap();
569 }
570
571 #[test]
572 fn endpoint_source() {
573 let endpoint = ExpectedUrl::builder()
574 .endpoint("projects/1/pipelines")
575 .add_query_params(&[("source", "trigger")])
576 .build()
577 .unwrap();
578 let client = SingleTestClient::new_raw(endpoint, "");
579
580 let endpoint = Pipelines::builder()
581 .project(1)
582 .source(PipelineSource::Trigger)
583 .build()
584 .unwrap();
585 api::ignore(endpoint).query(&client).unwrap();
586 }
587
588 #[test]
589 fn endpoint_order_by() {
590 let endpoint = ExpectedUrl::builder()
591 .endpoint("projects/1/pipelines")
592 .add_query_params(&[("order_by", "updated_at")])
593 .build()
594 .unwrap();
595 let client = SingleTestClient::new_raw(endpoint, "");
596
597 let endpoint = Pipelines::builder()
598 .project(1)
599 .order_by(PipelineOrderBy::UpdatedAt)
600 .build()
601 .unwrap();
602 api::ignore(endpoint).query(&client).unwrap();
603 }
604
605 #[test]
606 fn endpoint_sort() {
607 let endpoint = ExpectedUrl::builder()
608 .endpoint("projects/1/pipelines")
609 .add_query_params(&[("sort", "desc")])
610 .build()
611 .unwrap();
612 let client = SingleTestClient::new_raw(endpoint, "");
613
614 let endpoint = Pipelines::builder()
615 .project(1)
616 .sort(SortOrder::Descending)
617 .build()
618 .unwrap();
619 api::ignore(endpoint).query(&client).unwrap();
620 }
621}