Compare commits

...

19 Commits

Author SHA1 Message Date
816a65a04c fix(deps): update rust crate uuid to v1.12.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-21 05:41:33 +00:00
d893e7e21a chore(deps): update rust crate clap to v4.5.27
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-21 01:38:57 +00:00
2a3c4fbb83 fix(deps): update rust crate octocrab to 0.43.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-18 01:38:50 +00:00
9d459f10d5 fix(deps): update rust crate uuid to v1.12.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-15 01:44:24 +00:00
5aa5702272 fix(deps): update rust crate dirs to v6
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-13 01:37:39 +00:00
45b45420f8 fix(deps): update rust crate uuid to v1.11.1
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-10 05:33:24 +00:00
b49da1ca71 chore(deps): update rust crate clap to v4.5.26
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-10 01:34:25 +00:00
3c63992632 chore(deps): update rust crate tokio to v1.43.0
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-09 01:36:46 +00:00
aaf9cd414e chore: update example
All checks were successful
continuous-integration/drone/push Build is passing
2025-01-08 23:03:41 +01:00
0f30aaadf5 chore(release): v0.3.4 (#57)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.3.4

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: #57
2025-01-08 22:55:40 +01:00
84941de931
fix: use correct post clone command
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-08 22:53:22 +01:00
aa1ef7041e
fix: tests for config
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-08 22:49:13 +01:00
2f501c0efd
feat/add-post-clone-command
Some checks failed
continuous-integration/drone/pr Build is failing
continuous-integration/drone/push Build is passing
2025-01-08 22:47:23 +01:00
962425c515
add ability to specify multiple commands
All checks were successful
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
2025-01-08 22:42:35 +01:00
708f8d6388
feat: add ability to specify custom command
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/pr Build is passing
2025-01-08 22:32:39 +01:00
cuddle-please
5e97f68a77 chore(release): 0.3.3
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is failing
2025-01-07 22:22:43 +00:00
eb684ef8e9 chore: replace dotenv with dotenvy, a slightly more maintained version of the same library (#50)
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #50
Co-authored-by: kjuulh <contact@kjuulh.io>
Co-committed-by: kjuulh <contact@kjuulh.io>
2025-01-07 23:21:32 +01:00
176dc9f094 chore(release): v0.3.2 (#45)
All checks were successful
continuous-integration/drone/push Build is passing
continuous-integration/drone/tag Build is passing
chore(release): 0.3.3

Co-authored-by: cuddle-please <bot@cuddle.sh>
Reviewed-on: #45
2025-01-07 23:13:59 +01:00
1b9f8d96fc fix: cargo.lock (#49)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #49
Co-authored-by: kjuulh <contact@kjuulh.io>
Co-committed-by: kjuulh <contact@kjuulh.io>
2025-01-07 22:47:49 +01:00
10 changed files with 611 additions and 453 deletions

View File

@ -6,6 +6,26 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
## [0.3.4] - 2025-01-08
### Added
- feat/add-post-clone-command
- add ability to specify custom command
### Fixed
- use correct post clone command
- tests for config
### Other
- add ability to specify multiple commands
## [0.3.3] - 2025-01-07
### Other
- replace dotenv with dotenvy, a slightly more maintained version of the same library (#50)
## [0.3.2] - 2025-01-07
### Fixed

840
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@ members = ["crates/*"]
resolver = "2"
[workspace.package]
version = "0.3.2"
version = "0.3.4"
[workspace.dependencies]
@ -12,4 +12,4 @@ tokio = { version = "1", features = ["full"] }
tracing = { version = "0.1", features = ["log"] }
tracing-subscriber = { version = "0.3.18", features = ["env-filter"] }
clap = { version = "4", features = ["derive", "env"] }
dotenv = { version = "0.15" }
dotenvy = { version = "0.15.7" }

View File

@ -17,7 +17,7 @@ tokio.workspace = true
tracing.workspace = true
tracing-subscriber.workspace = true
clap.workspace = true
dotenv.workspace = true
dotenvy.workspace = true
serde = { version = "1.0.197", features = ["derive"] }
uuid = { version = "1.7.0", features = ["v4"] }
@ -26,8 +26,8 @@ toml = "0.8.19"
gitea-client = { version = "1.22.1" }
url = "2.5.2"
octocrab = "0.42.0"
dirs = "5.0.1"
octocrab = "0.43.0"
dirs = "6.0.0"
prost = "0.13.2"
prost-types = "0.13.2"
bytes = "1.7.1"

View File

@ -4,6 +4,7 @@ use crate::{
app::App,
cache::CacheApp,
components::inline_command::InlineCommand,
custom_command::CustomCommandApp,
fuzzy_matcher::{FuzzyMatcher, FuzzyMatcherApp},
git_clone::GitCloneApp,
git_provider::Repository,
@ -110,12 +111,22 @@ impl RootCommand {
} else {
eprintln!("cloning repository...");
git_clone.clone_repo(&repo, force_refresh).await?;
self.app
.custom_command()
.execute_post_clone_command(&project_path)
.await?;
}
} else {
tracing::info!("skipping clone for repo: {}", &repo.to_rel_path().display());
}
} else {
tracing::info!("repository already exists");
self.app
.custom_command()
.execute_post_update_command(&project_path)
.await?;
}
if shell {

View File

@ -23,7 +23,7 @@ impl<'a> Spinner<'a> {
}
}
impl<'a> StatefulWidget for Spinner<'a> {
impl StatefulWidget for Spinner<'_> {
type State = SpinnerState;
fn render(

View File

@ -3,7 +3,7 @@ use std::path::{Path, PathBuf};
use anyhow::Context;
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Config {
#[serde(default)]
pub settings: Settings,
@ -12,16 +12,51 @@ pub struct Config {
pub providers: Providers,
}
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Settings {
#[serde(default)]
pub projects: Projects,
#[serde(default)]
pub cache: Cache,
pub post_clone_command: Option<PostCloneCommand>,
pub post_update_command: Option<PostUpdateCommand>,
}
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum PostUpdateCommand {
Single(String),
Multiple(Vec<String>),
}
impl PostUpdateCommand {
pub fn get_commands(&self) -> Vec<String> {
match self.clone() {
PostUpdateCommand::Single(item) => vec![item],
PostUpdateCommand::Multiple(items) => items,
}
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum PostCloneCommand {
Single(String),
Multiple(Vec<String>),
}
impl PostCloneCommand {
pub fn get_commands(&self) -> Vec<String> {
match self.clone() {
PostCloneCommand::Single(item) => vec![item],
PostCloneCommand::Multiple(items) => items,
}
}
}
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Projects {
pub directory: ProjectLocation,
}
@ -57,7 +92,7 @@ impl std::ops::Deref for ProjectLocation {
}
}
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Cache {
#[serde(default)]
pub location: CacheLocation,
@ -89,7 +124,7 @@ impl Default for CacheLocation {
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum CacheDuration {
Enabled(bool),
@ -131,7 +166,7 @@ impl Default for CacheDuration {
}
}
#[derive(Debug, Default, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Default, Serialize, Deserialize, PartialEq, Clone)]
pub struct Providers {
#[serde(default)]
pub github: Vec<GitHub>,
@ -139,7 +174,7 @@ pub struct Providers {
pub gitea: Vec<Gitea>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GitHub {
#[serde(default)]
pub url: Option<String>,
@ -155,7 +190,7 @@ pub struct GitHub {
pub organisations: Vec<GitHubOrganisation>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GitHubUser(String);
impl From<GitHubUser> for String {
@ -170,7 +205,7 @@ impl<'a> From<&'a GitHubUser> for &'a str {
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GitHubOrganisation(String);
impl From<GitHubOrganisation> for String {
@ -185,7 +220,7 @@ impl<'a> From<&'a GitHubOrganisation> for &'a str {
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct Gitea {
pub url: String,
@ -201,21 +236,21 @@ pub struct Gitea {
pub organisations: Vec<GiteaOrganisation>,
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum GiteaAccessToken {
Direct(String),
Env { env: String },
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
#[serde(untagged)]
pub enum GitHubAccessToken {
Direct(String),
Env { env: String },
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GiteaUser(String);
impl From<GiteaUser> for String {
@ -230,7 +265,7 @@ impl<'a> From<&'a GiteaUser> for &'a str {
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct GiteaOrganisation(String);
impl From<GiteaOrganisation> for String {
fn from(value: GiteaOrganisation) -> Self {
@ -361,7 +396,9 @@ mod test {
},
projects: Projects {
directory: PathBuf::from("git").into()
}
},
post_update_command: None,
post_clone_command: None
}
},
config
@ -386,7 +423,9 @@ mod test {
},
settings: Settings {
cache: Cache::default(),
projects: Projects::default()
projects: Projects::default(),
post_update_command: None,
post_clone_command: None
}
},
config

View File

@ -0,0 +1,83 @@
use std::path::Path;
use crate::{app::App, config::Config};
pub struct CustomCommand {
config: Config,
}
impl CustomCommand {
pub fn new(config: Config) -> Self {
Self { config }
}
pub async fn execute_post_clone_command(&self, path: &Path) -> anyhow::Result<()> {
if let Some(post_clone_command) = &self.config.settings.post_clone_command {
for command in post_clone_command.get_commands() {
let command_parts = command.split(' ').collect::<Vec<_>>();
let Some((first, rest)) = command_parts.split_first() else {
return Ok(());
};
let mut cmd = tokio::process::Command::new(first);
cmd.args(rest).current_dir(path);
eprintln!("running command: {}", command);
tracing::info!(
path = path.display().to_string(),
cmd = command,
"running custom post clone command"
);
let output = cmd.output().await?;
let stdout = std::str::from_utf8(&output.stdout)?;
tracing::info!(
stdout = stdout,
"finished running custom post clone command"
);
}
}
Ok(())
}
pub async fn execute_post_update_command(&self, path: &Path) -> anyhow::Result<()> {
if let Some(post_update_command) = &self.config.settings.post_update_command {
for command in post_update_command.get_commands() {
let command_parts = command.split(' ').collect::<Vec<_>>();
let Some((first, rest)) = command_parts.split_first() else {
return Ok(());
};
let mut cmd = tokio::process::Command::new(first);
cmd.args(rest).current_dir(path);
eprintln!("running command: {}", command);
tracing::info!(
path = path.display().to_string(),
cmd = command,
"running custom post update command"
);
let output = cmd.output().await?;
let stdout = std::str::from_utf8(&output.stdout)?;
tracing::info!(
stdout = stdout,
"finished running custom post update command"
);
}
}
Ok(())
}
}
pub trait CustomCommandApp {
fn custom_command(&self) -> CustomCommand;
}
impl CustomCommandApp for App {
fn custom_command(&self) -> CustomCommand {
CustomCommand::new(self.config.clone())
}
}

View File

@ -15,6 +15,7 @@ mod cache_codec;
mod commands;
mod components;
mod config;
mod custom_command;
mod fuzzy_matcher;
mod git_clone;
mod git_provider;
@ -57,7 +58,7 @@ const DEFAULT_CONFIG_PATH: &str = ".config/gitnow/gitnow.toml";
#[tokio::main]
async fn main() -> anyhow::Result<()> {
dotenv::dotenv().ok();
dotenvy::dotenv().ok();
tracing_subscriber::fmt()
.with_env_filter(
EnvFilter::builder()

View File

@ -1,7 +1,31 @@
[settings]
# Runs after a project is fetched for the first time, either a single string, or multiple in an array
post_clone_command = "jj git init --colocate"
# Runs after a project is jumped to if it already exists.
post_update_command = ["git pull", "jj git fetch"]
[[providers.github]]
# Who is the user running the clone command
current_user = "kjuulh"
# How to authenticate to github
access_token = { env = "GITHUB_ACCESS_TOKEN" }
# Which users to index
users = ["kjuulh"]
# Which organisations to index
organisations = ["lunarway"]
[[providers.gitea]]
# WHich gitea instance to authenticate against
url = "https://git.front.kjuulh.io/api/v1"
# How to authenticate to gitea
current_user = "kjuulh"
# WHich token to use to authenticate
access_token = { env = "GITEA_ACCESS_TOKEN" }
# Which users to index
users = ["kjuulh"]
# Which organisations to index
organisation = ["noorgplease"]