google_cloud_artifact_registry/
client.rs

1use crate::grpc::apiv1::artifact_registry_client::Client as ArtifactRegistryGrpcClient;
2use google_cloud_gax::conn::{ConnectionManager, ConnectionOptions, Environment, Error};
3use google_cloud_token::{NopeTokenSourceProvider, TokenSourceProvider};
4use std::ops::{Deref, DerefMut};
5use std::time::Duration;
6
7use crate::grpc::apiv1::{ARTIFACT_REGISTRY, AUDIENCE, SCOPES};
8
9use google_cloud_googleapis::devtools::artifact_registry::v1::artifact_registry_client::ArtifactRegistryClient;
10use google_cloud_longrunning::autogen::operations_client::OperationsClient;
11
12#[derive(Debug)]
13pub struct ClientConfig {
14    pub artifact_registry_endpoint: String,
15    pub token_source_provider: Box<dyn TokenSourceProvider>,
16    pub timeout: Option<Duration>,
17    pub connect_timeout: Option<Duration>,
18}
19
20#[cfg(feature = "auth")]
21pub use google_cloud_auth;
22
23#[cfg(feature = "auth")]
24impl ClientConfig {
25    pub async fn with_auth(self) -> Result<Self, google_cloud_auth::error::Error> {
26        let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new(Self::auth_config()).await?;
27        Ok(self.with_token_source(ts).await)
28    }
29
30    pub async fn with_credentials(
31        self,
32        credentials: google_cloud_auth::credentials::CredentialsFile,
33    ) -> Result<Self, google_cloud_auth::error::Error> {
34        let ts = google_cloud_auth::token::DefaultTokenSourceProvider::new_with_credentials(
35            Self::auth_config(),
36            Box::new(credentials),
37        )
38        .await?;
39        Ok(self.with_token_source(ts).await)
40    }
41
42    async fn with_token_source(mut self, ts: google_cloud_auth::token::DefaultTokenSourceProvider) -> Self {
43        self.token_source_provider = Box::new(ts);
44        self
45    }
46
47    fn auth_config() -> google_cloud_auth::project::Config<'static> {
48        google_cloud_auth::project::Config::default().with_scopes(&SCOPES)
49    }
50}
51
52impl Default for ClientConfig {
53    fn default() -> Self {
54        Self {
55            artifact_registry_endpoint: ARTIFACT_REGISTRY.to_string(),
56            token_source_provider: Box::new(NopeTokenSourceProvider {}),
57            timeout: Some(Duration::from_secs(30)),
58            connect_timeout: Some(Duration::from_secs(30)),
59        }
60    }
61}
62
63#[derive(Clone)]
64pub struct Client {
65    artifact_registry_client: ArtifactRegistryGrpcClient,
66}
67
68impl Client {
69    pub async fn new(config: ClientConfig) -> Result<Self, Error> {
70        let conn_options = ConnectionOptions {
71            timeout: config.timeout,
72            connect_timeout: config.connect_timeout,
73        };
74        let conn_pool = ConnectionManager::new(
75            1,
76            config.artifact_registry_endpoint,
77            AUDIENCE,
78            &Environment::GoogleCloud(config.token_source_provider),
79            &conn_options,
80        )
81        .await?;
82        let conn = conn_pool.conn();
83        let lro_client = OperationsClient::new(conn_pool.conn()).await.unwrap();
84
85        Ok(Self {
86            artifact_registry_client: ArtifactRegistryGrpcClient::new(ArtifactRegistryClient::new(conn), lro_client),
87        })
88    }
89}
90
91impl Deref for Client {
92    type Target = ArtifactRegistryGrpcClient;
93
94    fn deref(&self) -> &Self::Target {
95        &self.artifact_registry_client
96    }
97}
98
99impl DerefMut for Client {
100    fn deref_mut(&mut self) -> &mut Self::Target {
101        &mut self.artifact_registry_client
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use crate::client::{Client, ClientConfig};
108
109    use google_cloud_googleapis::devtools::artifact_registry::v1::repository::Format;
110    use google_cloud_googleapis::devtools::artifact_registry::v1::{
111        CreateRepositoryRequest, DeleteRepositoryRequest, GetRepositoryRequest, ListRepositoriesRequest, Repository,
112        UpdateRepositoryRequest,
113    };
114    use prost_types::FieldMask;
115    use serial_test::serial;
116    use std::time::{SystemTime, UNIX_EPOCH};
117
118    async fn new_client() -> (Client, String) {
119        let cred = google_cloud_auth::credentials::CredentialsFile::new().await.unwrap();
120        let project = cred.project_id.clone().unwrap();
121        let config = ClientConfig::default().with_credentials(cred).await.unwrap();
122        (Client::new(config).await.unwrap(), project)
123    }
124
125    #[ctor::ctor]
126    fn init() {
127        let _ = tracing_subscriber::fmt().try_init();
128    }
129
130    #[tokio::test]
131    #[serial]
132    async fn test_crud_repository() {
133        let (mut client, project) = new_client().await;
134        let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
135        let repository_id = format!("gcrar{now}");
136
137        // create
138        let create_request = CreateRepositoryRequest {
139            parent: format!("projects/{project}/locations/us-central1"),
140            repository_id,
141            repository: Some(Repository {
142                name: "".to_string(),
143                format: Format::Docker as i32,
144                description: "test repository".to_string(),
145                labels: Default::default(),
146                create_time: None,
147                update_time: None,
148                kms_key_name: "".to_string(),
149                mode: 0,
150                cleanup_policies: Default::default(),
151                size_bytes: 0,
152                satisfies_pzs: false,
153                cleanup_policy_dry_run: false,
154                format_config: None,
155                mode_config: None,
156            }),
157        };
158        let mut created_repository = client.create_repository(create_request.clone(), None).await.unwrap();
159        let result = created_repository.wait(None).await.unwrap().unwrap();
160        assert_eq!(
161            format!("{}/repositories/{}", create_request.parent, create_request.repository_id),
162            result.name
163        );
164
165        // get
166        let get_request = GetRepositoryRequest {
167            name: result.name.to_string(),
168        };
169        let get_repository = client.get_repository(get_request.clone(), None).await.unwrap();
170        assert_eq!(get_repository.name, get_request.name);
171
172        // update
173        let update_request = UpdateRepositoryRequest {
174            repository: Some(Repository {
175                description: "update test".to_string(),
176                ..get_repository.clone()
177            }),
178            update_mask: Some(FieldMask {
179                paths: vec!["description".to_string()],
180            }),
181        };
182        let update_repository = client.update_repository(update_request.clone(), None).await.unwrap();
183        assert_eq!(update_repository.description, update_request.repository.unwrap().description);
184
185        // list
186        let list_request = ListRepositoriesRequest {
187            parent: create_request.parent.to_string(),
188            page_size: 0,
189            page_token: "".to_string(),
190        };
191        let list_result = client.list_repositories(list_request, None).await.unwrap();
192        assert!(!list_result.repositories.is_empty());
193
194        // delete
195        let delete_request = DeleteRepositoryRequest {
196            name: get_repository.name.to_string(),
197        };
198        client.delete_repository(delete_request, None).await.unwrap();
199    }
200}