Skip to main content

ironflow_ops_gitlab/
operation.rs

1//! [`GitLabOp`] -- wraps any [`Endpoint`] as a tracked [`Operation`].
2
3use async_trait::async_trait;
4use gitlab::AsyncGitlab;
5use gitlab::api::{AsyncQuery, Endpoint};
6use ironflow_core::error::OperationError;
7use ironflow_core::operation::{Operation, OperationContext};
8use serde_json::Value;
9
10/// A GitLab endpoint wrapped as an Ironflow [`Operation`].
11///
12/// Created via [`GitLab::op`](crate::GitLab::op). Implements `Operation` so it
13/// can be passed to `WorkflowContext::operation()` for step lifecycle tracking
14/// (step record, status transitions, duration, output persistence).
15///
16/// The endpoint is executed against the cloned [`AsyncGitlab`] client and the
17/// response is deserialized as a JSON [`Value`].
18///
19/// # Examples
20///
21/// ```no_run
22/// use ironflow_ops_gitlab::GitLab;
23/// use ironflow_core::operation::{Operation, OperationContext, NoopSecretResolver};
24/// use gitlab::api::projects;
25/// use std::sync::Arc;
26///
27/// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
28/// let ctx = OperationContext::new(Arc::new(NoopSecretResolver));
29/// let gitlab = GitLab::from_context(&ctx).await?;
30///
31/// let endpoint = projects::Project::builder().project(42).build()?;
32/// let op = gitlab.op(endpoint);
33///
34/// assert_eq!(op.kind(), "gitlab");
35/// # Ok(())
36/// # }
37/// ```
38pub struct GitLabOp<E> {
39    client: AsyncGitlab,
40    endpoint: E,
41}
42
43impl<E> GitLabOp<E> {
44    pub(crate) fn new(client: AsyncGitlab, endpoint: E) -> Self {
45        Self { client, endpoint }
46    }
47}
48
49#[async_trait]
50impl<E> Operation for GitLabOp<E>
51where
52    E: Endpoint + Sync + Send,
53{
54    fn kind(&self) -> &str {
55        "gitlab"
56    }
57
58    async fn execute(&self, _ctx: &OperationContext) -> Result<Value, OperationError> {
59        let result: Value =
60            self.endpoint
61                .query_async(&self.client)
62                .await
63                .map_err(|e| OperationError::Http {
64                    status: None,
65                    message: e.to_string(),
66                })?;
67        Ok(result)
68    }
69
70    fn input(&self) -> Option<Value> {
71        Some(Value::Object(serde_json::Map::from_iter([(
72            "endpoint".to_string(),
73            Value::String(self.endpoint.endpoint().into_owned()),
74        )])))
75    }
76}