Skip to main content

ephemeris_forge_github/api/http/
actions.rs

1use ephemeris_forge::{RepoRef, encode};
2use facet::Facet;
3use reqwest::Method;
4
5use crate::api::HttpApi;
6use crate::api::error::ForgeError;
7use crate::api::model::actions::routes::ActionsGroup;
8use crate::api::model::actions::{CacheRetentionResponse, CacheStorageResponse};
9use crate::api::operations::ActionsApi;
10use crate::api::request::{CacheRetentionBody, CacheStorageBody};
11use crate::config::actions::Cache;
12
13/// The cache limits are unavailable on a plan that does not include them.
14const CACHE_UNAVAILABLE_STATUS: u16 = 402;
15const CACHE_RETENTION_ROUTE: &str = "actions/cache/retention-limit";
16const CACHE_STORAGE_ROUTE: &str = "actions/cache/storage-limit";
17
18impl HttpApi {
19    async fn read_actions<R: for<'a> Facet<'a>>(
20        &self,
21        repository: &RepoRef,
22        route: &str,
23        unavailable: Option<u16>,
24    ) -> Result<Option<R>, ForgeError> {
25        match self.optional(&repository.path(route)).await {
26            Err(error) if unavailable.is_some_and(|status| error.status() == Some(status)) => {
27                Ok(None)
28            }
29            result => result,
30        }
31    }
32
33    async fn put_actions(
34        &self,
35        repository: &RepoRef,
36        route: &str,
37        body: String,
38    ) -> Result<(), ForgeError> {
39        self.empty(Method::PUT, &repository.path(route), Some(body))
40            .await
41    }
42}
43
44impl ActionsApi for HttpApi {
45    async fn actions_cache(&self, repository: &RepoRef) -> Result<Option<Cache>, ForgeError> {
46        let retention: Option<CacheRetentionResponse> = self
47            .read_actions(
48                repository,
49                CACHE_RETENTION_ROUTE,
50                Some(CACHE_UNAVAILABLE_STATUS),
51            )
52            .await?;
53        let storage: Option<CacheStorageResponse> = self
54            .read_actions(
55                repository,
56                CACHE_STORAGE_ROUTE,
57                Some(CACHE_UNAVAILABLE_STATUS),
58            )
59            .await?;
60        Ok(retention
61            .zip(storage)
62            .map(|(retention, storage)| Cache::from_responses(retention, storage)))
63    }
64
65    async fn actions_group<G: ActionsGroup>(
66        &self,
67        repository: &RepoRef,
68    ) -> Result<Option<G>, ForgeError> {
69        let wire: Option<G::Wire> = self
70            .read_actions(repository, G::ROUTE, G::UNAVAILABLE_STATUS)
71            .await?;
72        Ok(wire.map(Into::into))
73    }
74
75    async fn set_actions_cache(
76        &self,
77        repository: &RepoRef,
78        group: &Cache,
79    ) -> Result<(), ForgeError> {
80        self.put_actions(
81            repository,
82            CACHE_RETENTION_ROUTE,
83            encode(&CacheRetentionBody {
84                max_cache_retention_days: group.max_cache_retention_days,
85            }),
86        )
87        .await?;
88        self.put_actions(
89            repository,
90            CACHE_STORAGE_ROUTE,
91            encode(&CacheStorageBody {
92                max_cache_size_gb: group.max_cache_size_gb,
93            }),
94        )
95        .await
96    }
97
98    async fn set_actions_group<G: ActionsGroup>(
99        &self,
100        repository: &RepoRef,
101        group: &G,
102    ) -> Result<(), ForgeError> {
103        self.put_actions(repository, G::ROUTE, group.body()).await
104    }
105}