refactor: move gitea out of the way

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
2023-08-01 16:38:30 +02:00
parent 39db4b8d1c
commit e51454088e
11 changed files with 481 additions and 277 deletions

View File

@@ -1,19 +1,24 @@
use std::{
env::current_dir,
io::Read,
ops::Deref,
path::{Path, PathBuf},
rc::Rc,
sync::{Arc, Mutex},
};
use ::semver::Version;
use anyhow::Context;
use clap::{Parser, Subcommand};
use cuddle_please_frontend::{gatheres::ConfigArgs, PleaseConfigBuilder};
use cuddle_please_frontend::{gatheres::ConfigArgs, PleaseConfig, PleaseConfigBuilder};
use cuddle_please_misc::{
changelog_parser, get_most_significant_version, ChangeLogBuilder, ConsoleUi, DynUi,
GiteaClient, GlobalArgs, NextVersion, StdinFn, VcsClient,
changelog_parser, get_most_significant_version, ChangeLogBuilder, ConsoleUi,
DynRemoteGitClient, DynUi, GiteaClient, GlobalArgs, LocalGitClient, NextVersion,
RemoteGitEngine, StdinFn, VcsClient,
};
use crate::release_command::ReleaseCommand;
#[derive(Parser)]
#[command(author, version, about, long_about = None)]
pub struct Command {
@@ -84,124 +89,13 @@ impl Command {
pub fn execute(self, current_dir: Option<&Path>) -> anyhow::Result<()> {
let config = self.build_config(current_dir)?;
let git_client = self.get_git(config.get_source())?;
let gitea_client = self.get_gitea_client();
match &self.commands {
Some(Commands::Release {}) => {
tracing::debug!("running bare command");
// 2. Parse the cuddle.please.yaml let cuddle.please.yaml take precedence
// 2a. if not existing use default.
// 2b. if not in a git repo abort. (unless --no-vcs is turned added)
let git_client = self.get_git(config.get_source())?;
// 3. Create gitea client and do a health check
let gitea_client = self.get_gitea_client();
gitea_client
.connect(config.get_owner(), config.get_repository())
.context("failed to connect to gitea repository")?;
// 4. Fetch git tags for the current repository
let tags = gitea_client.get_tags(config.get_owner(), config.get_repository())?;
let significant_tag = get_most_significant_version(tags.iter().collect());
// 5. Fetch git commits since last git tag
let commits = gitea_client.get_commits_since(
config.get_owner(),
config.get_repository(),
significant_tag.map(|st| st.commit.sha.clone()),
config.get_branch(),
)?;
// 7. Create a versioning client
let current_version = significant_tag
.map(|st| Version::try_from(st).unwrap())
.unwrap_or(Version::new(0, 1, 0));
// 8. Parse conventional commits and determine next version
let commit_strs = commits
.iter()
.map(|c| c.commit.message.as_str())
.collect::<Vec<&str>>();
if commit_strs.is_empty() {
tracing::info!("no commits to base release on");
return Ok(());
}
let next_version = current_version.next(&commit_strs);
// Compose changelog
let builder = ChangeLogBuilder::new(&commit_strs, next_version.to_string()).build();
let changelog_placement = config.get_source().join("CHANGELOG.md");
let changelog = match std::fs::read_to_string(&changelog_placement).ok() {
Some(existing_changelog) => builder.prepend(existing_changelog)?,
None => builder.generate()?,
};
let changelog_last_changes = changelog_parser::last_changes(&changelog)?;
// 9b. check for release commit and release, if release exists continue
// 10b. create release
if let Some(first_commit) = commit_strs.first() {
if first_commit.contains("chore(release): ") {
if !self.global.dry_run {
gitea_client.create_release(
config.get_owner(),
config.get_repository(),
next_version.to_string(),
changelog_last_changes.unwrap(),
!next_version.pre.is_empty(),
)?;
} else {
tracing::debug!("creating release (dry_run)");
}
return Ok(());
}
}
// 9a. Create / Update Pr
// Create or update branch
git_client.checkout_branch()?;
std::fs::write(changelog_placement, changelog.as_bytes())?;
git_client.commit_and_push(next_version.to_string(), self.global.dry_run)?;
let _pr_number = match gitea_client
.get_pull_request(config.get_owner(), config.get_repository())?
{
Some(existing_pr) => {
if !self.global.dry_run {
gitea_client.update_pull_request(
config.get_owner(),
config.get_repository(),
next_version.to_string(),
changelog_last_changes.unwrap(),
existing_pr,
)?
} else {
tracing::debug!("updating pull request (dry_run)");
1
}
}
None => {
if !self.global.dry_run {
gitea_client.create_pull_request(
config.get_owner(),
config.get_repository(),
next_version.to_string(),
changelog,
config.get_branch(),
)?
} else {
tracing::debug!("creating pull request (dry_run)");
1
}
}
};
ReleaseCommand::new(config, git_client, gitea_client)
.execute(self.global.dry_run)?;
}
Some(Commands::Config { command }) => match command {
@@ -222,7 +116,7 @@ impl Command {
url.push_str(format!(":{port}").as_str());
}
let client = GiteaClient::new(url, self.global.token);
let client = GiteaClient::new(&url, self.global.token.as_ref().map(|t| t.as_str()));
match command {
GiteaCommand::Connect {} => {
client.connect(config.get_owner(), config.get_repository())?;
@@ -302,10 +196,7 @@ impl Command {
Ok(())
}
fn build_config(
&self,
current_dir: Option<&Path>,
) -> Result<cuddle_please_frontend::PleaseConfig, anyhow::Error> {
fn build_config(&self, current_dir: Option<&Path>) -> Result<PleaseConfig, anyhow::Error> {
let mut builder = &mut PleaseConfigBuilder::new();
if self.global.config_stdin {
if let Some(stdin_fn) = self.stdin.clone() {
@@ -316,6 +207,7 @@ impl Command {
let current_dir = get_current_path(current_dir, self.config.source.clone())?;
let config = builder
.with_config_file(&current_dir)
.with_source(&current_dir)
.with_execution_env(std::env::vars())
.with_cli(self.config.clone())
.build()?;
@@ -323,14 +215,21 @@ impl Command {
}
fn get_git(&self, current_dir: &Path) -> anyhow::Result<VcsClient> {
VcsClient::new_git(current_dir)
if self.global.no_vcs {
Ok(VcsClient::new_noop())
} else {
VcsClient::new_git(current_dir)
}
}
fn get_gitea_client(&self) -> GiteaClient {
GiteaClient::new(
self.config.api_url.clone().expect("api_url to be set"),
self.global.token.clone(),
)
fn get_gitea_client(&self) -> DynRemoteGitClient {
match self.global.engine {
cuddle_please_misc::RemoteEngine::Local => Box::new(LocalGitClient::new()),
cuddle_please_misc::RemoteEngine::Gitea => Box::new(GiteaClient::new(
&self.config.api_url.clone().expect("api_url to be set"),
self.global.token.as_ref().map(|t| t.as_str()),
)),
}
}
}

View File

@@ -1,3 +1,4 @@
mod command;
mod release_command;
pub use command::Command as PleaseCommand;

View File

@@ -0,0 +1,159 @@
use cuddle_please_frontend::PleaseConfig;
use std::{
io::Read,
ops::Deref,
path::{Path, PathBuf},
sync::{Arc, Mutex},
};
use ::semver::Version;
use anyhow::Context;
use clap::{Parser, Subcommand};
use cuddle_please_frontend::{gatheres::ConfigArgs, PleaseConfigBuilder};
use cuddle_please_misc::{
changelog_parser, get_most_significant_version, ChangeLogBuilder, ConsoleUi,
DynRemoteGitClient, DynUi, GiteaClient, GlobalArgs, NextVersion, StdinFn, VcsClient,
};
pub struct ReleaseCommand {
config: PleaseConfig,
git_client: VcsClient,
gitea_client: DynRemoteGitClient,
}
impl ReleaseCommand {
pub fn new(
config: PleaseConfig,
git_client: VcsClient,
gitea_client: DynRemoteGitClient,
) -> Self {
Self {
config,
git_client,
gitea_client,
}
}
pub fn execute(&self, dry_run: bool) -> anyhow::Result<()> {
tracing::debug!("running bare command");
let owner = self.config.get_owner();
let repository = self.config.get_repository();
let branch = self.config.get_branch();
let source = self.config.get_source();
// 2. Parse the cuddle.please.yaml let cuddle.please.yaml take precedence
// 2a. if not existing use default.
// 2b. if not in a git repo abort. (unless --no-vcs is turned added)
// 3. Create gitea client and do a health check
self.gitea_client
.connect(owner, repository)
.context("failed to connect to gitea repository")?;
// 4. Fetch git tags for the current repository
let tags = self.gitea_client.get_tags(owner, repository)?;
let significant_tag = get_most_significant_version(tags.iter().collect());
// 5. Fetch git commits since last git tag
let commits = self.gitea_client.get_commits_since(
owner,
repository,
significant_tag.map(|st| st.commit.sha.as_str()),
branch,
)?;
// 7. Create a versioning client
let current_version = significant_tag
.map(|st| Version::try_from(st).unwrap())
.unwrap_or(Version::new(0, 1, 0));
// 8. Parse conventional commits and determine next version
let commit_strs = commits
.iter()
.map(|c| c.commit.message.as_str())
.collect::<Vec<&str>>();
if commit_strs.is_empty() {
tracing::info!("no commits to base release on");
return Ok(());
}
let next_version = current_version.next(&commit_strs);
// Compose changelog
let builder = ChangeLogBuilder::new(&commit_strs, next_version.to_string()).build();
let changelog_placement = source.join("CHANGELOG.md");
let changelog = match std::fs::read_to_string(&changelog_placement).ok() {
Some(existing_changelog) => builder.prepend(existing_changelog)?,
None => builder.generate()?,
};
let changelog_last_changes = changelog_parser::last_changes(&changelog)?;
// 9b. check for release commit and release, if release exists continue
// 10b. create release
if let Some(first_commit) = commit_strs.first() {
if first_commit.contains("chore(release): ") {
if !dry_run {
self.gitea_client.create_release(
owner,
repository,
&next_version.to_string(),
&changelog_last_changes.unwrap(),
!next_version.pre.is_empty(),
)?;
} else {
tracing::debug!("creating release (dry_run)");
}
return Ok(());
}
}
// 9a. Create / Update Pr
// Create or update branch
self.git_client.checkout_branch()?;
std::fs::write(changelog_placement, changelog.as_bytes())?;
self.git_client
.commit_and_push(next_version.to_string(), dry_run)?;
let _pr_number = match self.gitea_client.get_pull_request(owner, repository)? {
Some(existing_pr) => {
if !dry_run {
self.gitea_client.update_pull_request(
owner,
repository,
&next_version.to_string(),
&changelog_last_changes.unwrap(),
existing_pr,
)?
} else {
tracing::debug!("updating pull request (dry_run)");
1
}
}
None => {
if !dry_run {
self.gitea_client.create_pull_request(
owner,
repository,
&next_version.to_string(),
&changelog,
branch,
)?
} else {
tracing::debug!("creating pull request (dry_run)");
1
}
}
};
Ok(())
}
}