remodeling our structure with git a bit

This commit is contained in:
Christoph J. Scherr 2024-04-26 10:03:52 +02:00
parent e66550f2ef
commit 181954cbce
8 changed files with 68 additions and 54 deletions

View File

@ -119,6 +119,20 @@ pub struct Api {
/// Name of the repository on the Git server, as git itself has no concept of repository name
pub repository: String,
}
impl std::fmt::Display for Api {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.server_type {
ApiType::Github => write!(
f,
"{}",
self.server_type
.default_endpoint()
.expect("no default endpoint set for github")
),
_ => write!(f, "{}", self.endpoint.clone().expect("no endpoint set")),
}
}
}
impl YamlConfigSection for Api {
fn check(&self) -> Result<()> {
self.server_type.check()?;
@ -259,10 +273,10 @@ impl YamlConfig {
}
}
#[derive(Clone)]
pub struct Config {
pub yaml: YamlConfig,
pub cli: Cli,
pub repo: git2::Repository,
pub path: PathBuf,
}
@ -319,7 +333,6 @@ impl Config {
Ok(Config {
yaml,
repo,
path,
cli: cli.clone(),
})

View File

@ -1,26 +1,38 @@
use std::process::Command;
use git2;
use libpt::log::error;
use crate::error::ConfigError;
use crate::{config::Config, error::Result};
pub async fn tag(cfg: &Config) -> Result<git2::Tag> {
pub(crate) fn get_repo() -> Result<git2::Repository> {
let repo = match git2::Repository::open_from_env() {
Ok(repo) => repo,
Err(_err) => {
let err = ConfigError::GitRepoNotFound.into();
error!("{err}");
return Err(err);
}
};
Ok(repo)
}
pub async fn tag<'repo>(repo: &'repo mut git2::Repository, cfg: &Config) -> Result<git2::Tag<'repo>> {
// TODO: error handling
// TODO: allow force
// TODO: allow setting a message
// TODO: maybe using git as cmd is fancier?
let target = cfg
.repo
let target = repo
.find_object(
cfg.repo.head().unwrap().target().unwrap(),
repo.head().unwrap().target().unwrap(),
Some(git2::ObjectType::Commit),
)
.unwrap();
let tagger = cfg.repo.signature().expect("could not get signature");
let tagger = repo.signature().expect("could not get signature");
let message = String::new();
let force = true;
let tag = cfg
.repo
let tag = repo
.tag(
&cfg.yaml.version.get_version(),
// "importantversion",
@ -30,7 +42,7 @@ pub async fn tag(cfg: &Config) -> Result<git2::Tag> {
force,
)
.unwrap();
let tag: git2::Tag = cfg.repo.find_tag(tag).unwrap();
let tag: git2::Tag = repo.find_tag(tag).unwrap();
Ok(tag)
}
@ -41,12 +53,11 @@ pub async fn push(_cfg: &Config) -> Result<()> {
Ok(())
}
pub async fn get_commit_sig(cfg: &Config) -> Result<String> {
pub async fn get_commit_sig<'repo>(repo: &'repo git2::Repository) -> Result<String> {
// TODO: error handling
// TODO: maybe using git as cmd is fancier?
let target = cfg
.repo
.find_commit(cfg.repo.head().unwrap().target().unwrap())
let target = repo
.find_commit(repo.head().unwrap().target().unwrap())
.unwrap();
Ok(target.id().to_string())
}

View File

@ -1,11 +1,12 @@
use crate::{
config::Config,
error::*,
git::{get_commit_sig, push, tag},
git::{self, get_commit_sig, push, tag},
serverapi::ApiCollection,
};
use futures::{self, stream::FuturesUnordered, StreamExt};
use libpt::log::info;
#[derive(Debug, Clone, PartialEq, Hash)]
pub struct ReleaseContext {
@ -20,8 +21,10 @@ pub struct ReleaseContext {
pub async fn release(cfg: &Config, apis: &mut ApiCollection) -> Result<()> {
// TODO: Error handling
let tag = tag(cfg).await?.name().unwrap().to_string();
let commit_sig = get_commit_sig(cfg).await?;
let _changelog = crate::changelog::Changelog::build(cfg)?.to_string();
let mut repo = git::get_repo()?;
let tag = tag(&mut repo, cfg).await?.name().unwrap().to_string();
let commit_sig = get_commit_sig(&repo).await?;
push(cfg).await?; // we assume that we only need to push the current branch to the singular
// remote, expecting that the repositories are somehow mirrored
// TODO: push to multiple remotes?
@ -33,16 +36,17 @@ pub async fn release(cfg: &Config, apis: &mut ApiCollection) -> Result<()> {
draft: true,
prerelease: true,
username: api
.get_cfg()
.get_inner()
.clone()
.auth
.expect("no auth but trying to publish")
.user,
repository: api.get_cfg().repository.clone(),
repository: api.get_inner().repository.clone(),
text: crate::changelog::Changelog::build(cfg)?.to_string(),
tag: tag.clone(),
commit_sig: commit_sig.clone(),
};
info!("pushing release for {}", api.get_inner());
results.push(api.push_release(specific_rc));
}

View File

@ -8,11 +8,12 @@ use forgejo_api;
pub struct Forgejo {
api: Api,
cfg: Config,
api_wrapper: forgejo_api::Forgejo,
}
impl Forgejo {
pub async fn build(api: &Api) -> Result<Self> {
pub async fn build(api: &Api, cfg: &Config) -> Result<Self> {
let api_wrapper: forgejo_api::Forgejo = forgejo_api::Forgejo::new(
forgejo_api::Auth::Token(&api.auth.clone().unwrap().pass.get_pass()?),
api.endpoint.clone().unwrap(),
@ -20,6 +21,7 @@ impl Forgejo {
.map_err(ServerApiError::from)?;
Ok(Self {
api: api.clone(),
cfg: cfg.clone(),
api_wrapper,
})
}
@ -27,9 +29,6 @@ impl Forgejo {
#[async_trait]
impl ServerApi for Forgejo {
async fn init(&mut self, _cfg: &Config) -> Result<()> {
Ok(())
}
async fn push_release(&mut self, rc: ReleaseContext) -> Result<()> {
let body: forgejo_api::structs::CreateReleaseOption =
forgejo_api::structs::CreateReleaseOption {
@ -52,7 +51,7 @@ impl ServerApi for Forgejo {
async fn push_pkg(&mut self, _pc: PublishContext) -> Result<()> {
todo!()
}
fn get_cfg(&self) -> &Api {
fn get_inner(&self) -> &Api {
&self.api
}
}

View File

@ -6,14 +6,11 @@ use crate::{
error::*,
};
pub struct Gitea {
cfg: Api,
api: Api,
}
#[async_trait]
impl ServerApi for Gitea {
async fn init(&mut self, _cfg: &Config) -> Result<()> {
todo!()
}
async fn push_release(&mut self, _rc: ReleaseContext) -> Result<()> {
todo!()
}
@ -23,13 +20,13 @@ impl ServerApi for Gitea {
async fn push_pkg(&mut self, _pc: PublishContext) -> Result<()> {
todo!()
}
fn get_cfg(&self) -> &Api {
&self.cfg
fn get_inner(&self) -> &Api {
&self.api
}
}
impl Gitea {
pub async fn build(api: &Api) -> Result<Self> {
Ok(Self { cfg: api.clone() })
pub async fn build(api: &Api, cfg: &Config) -> Result<Self> {
Ok(Self { api: api.clone() })
}
}

View File

@ -11,7 +11,7 @@ pub struct Github {
}
impl Github {
pub async fn build(api: &Api) -> Result<Self> {
pub async fn build(api: &Api, cfg: &Config) -> Result<Self> {
Ok(Self {
api: api.to_owned(),
})
@ -20,9 +20,6 @@ impl Github {
#[async_trait]
impl ServerApi for Github {
async fn init(&mut self, _cfg: &Config) -> Result<()> {
Ok(())
}
async fn push_release(&mut self, rc: ReleaseContext) -> Result<()> {
let response = octocrab::instance()
.repos(rc.username, rc.repository)
@ -44,7 +41,7 @@ impl ServerApi for Github {
async fn push_pkg(&mut self, _pc: PublishContext) -> Result<()> {
todo!()
}
fn get_cfg(&self) -> &Api {
fn get_inner(&self) -> &Api {
&self.api
}
}

View File

@ -6,14 +6,11 @@ use crate::{
error::*,
};
pub struct Gitlab {
cfg: Api,
api: Api,
}
#[async_trait]
impl ServerApi for Gitlab {
async fn init(&mut self, _cfg: &Config) -> Result<()> {
todo!()
}
async fn push_release(&mut self, _rc: ReleaseContext) -> Result<()> {
todo!()
}
@ -23,13 +20,13 @@ impl ServerApi for Gitlab {
async fn push_pkg(&mut self, _pc: PublishContext) -> Result<()> {
todo!()
}
fn get_cfg(&self) -> &Api {
&self.cfg
fn get_inner(&self) -> &Api {
&self.api
}
}
impl Gitlab {
pub async fn build(api: &Api) -> Result<Self> {
Ok(Self { cfg: api.clone() })
pub async fn build(api: &Api, cfg: &Config) -> Result<Self> {
Ok(Self { api: api.clone() })
}
}

View File

@ -26,11 +26,10 @@ pub static USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_P
// The `async_trait` crate can be used to work around this limitation.
#[async_trait]
pub trait ServerApi {
async fn init(&mut self, cfg: &Config) -> Result<()>;
async fn push_release(&mut self, rc: ReleaseContext) -> Result<()>;
async fn push_release_artifact(&mut self, rc: ReleaseContext) -> Result<()>;
async fn push_pkg(&mut self, pc: PublishContext) -> Result<()>;
fn get_cfg(&self) -> &config::Api;
fn get_inner(&self) -> &config::Api;
}
pub(crate) type ApiCollectionInner = Vec<Box<dyn ServerApi>>;
@ -45,22 +44,19 @@ impl ApiCollection {
for api in &cfg.yaml.api {
match api.1.server_type {
ApiType::Gitea => {
collection.push(Box::new(Gitea::build(api.1).await?));
collection.push(Box::new(Gitea::build(api.1, cfg).await?));
}
ApiType::Gitlab => {
collection.push(Box::new(Gitlab::build(api.1).await?));
collection.push(Box::new(Gitlab::build(api.1, cfg).await?));
}
ApiType::Github => {
collection.push(Box::new(Github::build(api.1).await?));
collection.push(Box::new(Github::build(api.1, cfg).await?));
}
ApiType::Forgejo => {
collection.push(Box::new(Forgejo::build(api.1).await?));
collection.push(Box::new(Forgejo::build(api.1, cfg).await?));
}
}
}
for api in collection.iter_mut() {
api.init(cfg).await?;
}
Ok(ApiCollection { collection })
}