summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatthias Beyer <mail@beyermatthias.de>2021-01-17 11:44:49 +0100
committerMatthias Beyer <mail@beyermatthias.de>2021-01-17 12:25:52 +0100
commit63a6fa0c43d885b5f367372c06c578548d0b6384 (patch)
tree4192b76c8aae7927b2a16766b7832df6c05626e1 /src
Initial import
Diffstat (limited to 'src')
-rw-r--r--src/main.rs156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..0b21c92
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,156 @@
+use std::path::PathBuf;
+
+use anyhow::anyhow;
+use anyhow::Error;
+use anyhow::Result;
+use elefren::MastodonClient;
+use structopt::StructOpt;
+
+#[derive(serde::Deserialize, getset::Getters, Debug)]
+pub struct Conf {
+ #[getset(get = "pub")]
+ mastodon_data: PathBuf,
+
+ #[getset(get = "pub")]
+ repository_path: PathBuf,
+
+ #[getset(get = "pub")]
+ master_branch_name: String,
+
+ #[getset(get = "pub")]
+ origin_remote_name: String,
+
+ #[getset(get = "pub")]
+ hours_to_check: i64,
+
+ #[getset(get = "pub")]
+ status_language: String,
+
+ #[getset(get = "pub")]
+ status_template: String,
+}
+
+#[derive(structopt::StructOpt, getset::Getters, Debug)]
+pub struct Opts {
+ #[structopt(short, long, parse(from_os_str))]
+ #[getset(get = "pub")]
+ config: PathBuf,
+}
+
+
+fn main() -> Result<()> {
+ env_logger::init();
+ log::debug!("Logger initialized");
+
+ let opts = Opts::from_args_safe()?;
+ let config: Conf = {
+ let mut config = ::config::Config::default();
+
+ config
+ .merge(::config::File::from(opts.config().to_path_buf()))?
+ .merge(::config::Environment::with_prefix("COMBOT"))?;
+ config.try_into()?
+ };
+ let mastodon_data: elefren::Data = toml::de::from_str(&std::fs::read_to_string(config.mastodon_data())?)?;
+ let client = elefren::Mastodon::from(mastodon_data);
+ let status_language = elefren::Language::from_639_1(config.status_language())
+ .ok_or_else(|| anyhow!("Could not parse status language code: {}", config.status_language()))?;
+ log::debug!("config parsed");
+
+ let repo = git2::Repository::open(config.repository_path())?;
+ log::debug!("Repo opened successfully");
+ let _ = fetch_main_remote(&repo, &config)?;
+ log::debug!("Main branch fetched successfully");
+
+ let (commits, merges, nonmerges) = count_commits_on_main_branch(&repo, &config)?;
+ log::debug!("Counted commits successfully");
+
+ log::info!("Commits = {}", commits);
+ log::info!("Merges = {}", merges);
+ log::info!("Non-Merges = {}", nonmerges);
+
+ {
+ let status_text = {
+ let mut hb = handlebars::Handlebars::new();
+ hb.register_template_string("status", config.status_template())?;
+ let mut data = std::collections::BTreeMap::new();
+ data.insert("commits", commits);
+ data.insert("merges", merges);
+ data.insert("nonmerges", nonmerges);
+ hb.render("status", &data)?
+ };
+
+ let status = elefren::StatusBuilder::new()
+ .status(status_text)
+ .language(status_language)
+ .build()
+ .expect("Failed to build status");
+
+ let status = client.new_status(status)
+ .expect("Failed to post status");
+ if let Some(url) = status.url.as_ref() {
+ log::info!("Status posted: {}", url);
+ } else {
+ log::info!("Status posted, no url");
+ }
+ log::debug!("New status = {:?}", status);
+ }
+
+ Ok(())
+}
+
+fn fetch_main_remote(repo: &git2::Repository, config: &Conf) -> Result<()> {
+ log::debug!("Fetch: {} / {}", config.origin_remote_name(), config.master_branch_name());
+ repo.find_remote(config.origin_remote_name())?
+ .fetch(&[config.master_branch_name()], None, None)
+ .map_err(Error::from)
+}
+
+fn count_commits_on_main_branch(repo: &git2::Repository, config: &Conf) -> Result<(usize, usize, usize)> {
+ let branchname = format!("{}/{}", config.origin_remote_name(), config.master_branch_name());
+ let minimum_time_epoch = chrono::offset::Local::now().timestamp() - (config.hours_to_check() * 60 * 60);
+
+ log::debug!("Branch to count : {}", branchname);
+ log::debug!("Earliest commit time: {:?}", minimum_time_epoch);
+
+ let revwalk_start = repo
+ .find_branch(&branchname, git2::BranchType::Remote)?
+ .get()
+ .peel_to_commit()?
+ .id();
+
+ log::debug!("Starting at: {}", revwalk_start);
+
+ let mut rw = repo.revwalk()?;
+ rw.simplify_first_parent()?;
+ rw.push(revwalk_start)?;
+
+ let mut commits = 0;
+ let mut merges = 0;
+ let mut nonmerges = 0;
+
+ for rev in rw {
+ let rev = rev?;
+ let commit = repo.find_commit(rev)?;
+ log::trace!("Found commit: {:?}", commit);
+
+ if commit.time().seconds() < minimum_time_epoch {
+ log::trace!("Commit too old, stopping iteration");
+ break;
+ }
+ commits += 1;
+
+ let is_merge = commit.parent_ids().count() > 1;
+ log::trace!("Merge: {:?}", is_merge);
+
+ if is_merge {
+ merges += 1;
+ } else {
+ nonmerges += 1;
+ }
+ }
+
+ log::trace!("Ready iterating");
+ Ok((commits, merges, nonmerges))
+}
+