use super::{ListOptions, Tag};
use crate::{Error, Result};
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct GitlabTag {
name: String,
commit: GitlabCommit,
}
#[derive(Debug, Deserialize)]
struct GitlabCommit {
created_at: chrono::DateTime<chrono::Utc>,
}
fn tags_endpoint(source: &url::Url) -> Result<gitlab::api::projects::repository::tags::Tags<'_>> {
use gitlab::api::projects::repository::tags;
let path = source.path().strip_prefix('/').unwrap_or(source.path());
tags::Tags::builder()
.project(path)
.build()
.map_err(|err| Error::gitlab_boxed(err, "Could not construct the tags endpoint"))
}
pub async fn list_tags(source: &url::Url, options: &ListOptions<'_>) -> Result<Vec<Tag>> {
use gitlab::{GitlabBuilder, api::AsyncQuery};
let host = source
.host_str()
.ok_or_else(|| Error::invalid_source(source.clone(), "No host provided"))?;
let client = GitlabBuilder::new_unauthenticated(host)
.build_async()
.await
.map_err(|err| Error::gitlab(err, "Could not connect to GitLab"))?;
let gitlab_tags: Vec<GitlabTag> = tags_endpoint(source)?
.query_async(&client)
.await
.map_err(|err| Error::gitlab(err, "Could not fetch project tags"))?;
let tags = gitlab_tags
.into_iter()
.map(|tag| Tag::new(tag.name, tag.commit.created_at))
.collect();
Ok(options.filter_tags(tags))
}
#[cfg(test)]
mod tests {
use gitlab::api::Endpoint as _;
use super::tags_endpoint;
#[test]
fn the_endpoint_names_the_project_the_source_points_at() {
for (source, expected) in [
(
"terraform://gitlab.com/vigigloo/tf-modules/k8slimitednamespace",
"projects/vigigloo%2Ftf-modules%2Fk8slimitednamespace/repository/tags",
),
(
"https://gitlab.com/group/project",
"projects/group%2Fproject/repository/tags",
),
] {
let url = source.parse().unwrap();
assert_eq!(tags_endpoint(&url).unwrap().endpoint(), expected);
}
}
#[test]
fn the_project_is_the_only_field_the_endpoint_requires() {
use gitlab::api::projects::repository::tags;
assert!(tags::Tags::builder().build().is_err());
assert!(
tags::Tags::builder()
.project("group/project")
.build()
.is_ok()
);
}
}