Compare commits
52 Commits
v0.2.1
...
some-examp
Author | SHA1 | Date | |
---|---|---|---|
c5245cb7fe
|
|||
|
5e97f68a77 | ||
eb684ef8e9 | |||
176dc9f094 | |||
1b9f8d96fc | |||
|
69d008feb6 | ||
ada020e283
|
|||
708180f9a2 | |||
33ba27bf77 | |||
74a1daac4c
|
|||
3bd243b45c | |||
15620da103 | |||
a228ec82a3 | |||
503680d81c | |||
d13dc5b0a2 | |||
a1a993957b | |||
916beffb6d | |||
291d056dd7 | |||
dfacf96967 | |||
3524847d9f | |||
48b77deb5c | |||
c3f626cce0 | |||
52d522107d | |||
4dd8e58122 | |||
aa399e11c1 | |||
e670dc0384 | |||
8eb2970f5d | |||
f94ef8e919 | |||
62c9166677 | |||
5e859f99a9 | |||
4d78609839 | |||
90b7fe9b03 | |||
79ad2e872c | |||
ab963600f3 | |||
1aab9c2970 | |||
9dfcb52010 | |||
659f2247ff | |||
76f82f9060 | |||
bdfd001458 | |||
f4a2b52c72 | |||
aa78933f0e | |||
b242128d52 | |||
17cb06904f
|
|||
e3292b0c73 | |||
cc70131101
|
|||
784c7303a5 | |||
bf6d637095 | |||
7231c85448
|
|||
b5c3c9bac9
|
|||
1a2958a6e3
|
|||
1f5ad2a216
|
|||
|
f117f74130 |
75
CHANGELOG.md
75
CHANGELOG.md
@@ -6,6 +6,81 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [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
|
||||
- *(deps)* update rust crate async-trait to v0.1.85
|
||||
|
||||
## [0.3.1] - 2025-01-02
|
||||
|
||||
### Other
|
||||
- enable publish
|
||||
|
||||
## [0.3.0] - 2025-01-01
|
||||
|
||||
### Added
|
||||
- add small help to see how much time is left in cache
|
||||
|
||||
### Fixed
|
||||
- *(deps)* update rust crate serde to v1.0.217
|
||||
- *(deps)* update rust crate serde to v1.0.216
|
||||
- *(deps)* update tokio-prost monorepo to v0.13.4
|
||||
- *(deps)* update rust crate bytes to v1.9.0
|
||||
- *(deps)* update all dependencies
|
||||
- *(deps)* update rust crate octocrab to 0.42.0
|
||||
- *(deps)* update rust crate serde to v1.0.215
|
||||
- *(deps)* update rust crate url to v2.5.3
|
||||
- *(deps)* update rust crate serde to v1.0.214
|
||||
- *(deps)* update rust crate serde to v1.0.213
|
||||
- *(deps)* update all dependencies
|
||||
- *(deps)* update all dependencies
|
||||
- *(deps)* update rust crate octocrab to v0.41.1
|
||||
- *(deps)* update rust crate futures to v0.3.31
|
||||
- *(deps)* update rust crate octocrab to 0.41.0
|
||||
|
||||
### Other
|
||||
- bump default cache duration to 7 days
|
||||
- *(deps)* update rust crate anyhow to v1.0.95
|
||||
- *(deps)* update rust crate clap to v4.5.23
|
||||
- *(deps)* update all dependencies
|
||||
- *(deps)* update rust crate tracing-subscriber to v0.3.19
|
||||
- *(deps)* update rust crate tracing to v0.1.41
|
||||
- *(deps)* update rust crate clap to v4.5.21
|
||||
- *(deps)* update rust crate tokio to v1.41.1
|
||||
- *(deps)* update rust crate anyhow to v1.0.93
|
||||
- *(deps)* update rust crate anyhow to v1.0.92
|
||||
- *(deps)* update all dependencies to v1.0.91
|
||||
- *(deps)* update rust crate anyhow to v1.0.90
|
||||
- *(deps)* update rust crate clap to v4.5.20
|
||||
- *(deps)* update rust crate clap to v4.5.19
|
||||
|
||||
## [0.2.3] - 2024-09-26
|
||||
|
||||
### Added
|
||||
- add update command
|
||||
- only do clone if not exists
|
||||
|
||||
### Fixed
|
||||
- *(deps)* update rust crate async-trait to v0.1.83
|
||||
- *(deps)* update rust crate octocrab to 0.40.0
|
||||
|
||||
## [0.2.2] - 2024-09-23
|
||||
|
||||
### Other
|
||||
- add docs
|
||||
|
||||
main@origin
|
||||
|
||||
- add license
|
||||
- update to gitea-client
|
||||
- add publish
|
||||
- *(release)* 0.2.1
|
||||
|
||||
## [0.2.1] - 2024-09-23
|
||||
|
||||
### Added
|
||||
|
1117
Cargo.lock
generated
1117
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@ members = ["crates/*"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.package]
|
||||
version = "0.2.1"
|
||||
version = "0.3.3"
|
||||
|
||||
[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" }
|
||||
|
18
README.md
18
README.md
@@ -1,9 +1,27 @@
|
||||
# Git Now
|
||||
|
||||
Some example change
|
||||
|
||||
Git Now is a utility for easily navigating git projects from common upstream providers. Search, Download, and Enter projects as quickly as you can type.
|
||||
|
||||

|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
cargo (b)install gitnow
|
||||
|
||||
# You can either use gitnow directly (and use spawned shell sessions)
|
||||
gitnow
|
||||
|
||||
# Or install gitnow scripts (in your .bashrc, .zshrc) this will use native shell commands to move you around
|
||||
eval $(gitnow init zsh)
|
||||
git-now # Long
|
||||
gn # Short alias
|
||||
```
|
||||
|
||||
## Reasoning
|
||||
|
||||
How many steps do you normally do to download a project?
|
||||
|
||||
1. Navigate to github.com
|
||||
|
@@ -1,8 +1,15 @@
|
||||
[package]
|
||||
name = "gitnow"
|
||||
description = "Git Now is a utility for easily navigating git projects from common upstream providers. Search, Download, and Enter projects as quickly as you can type."
|
||||
edition = "2021"
|
||||
readme = "../../README.md"
|
||||
repository = "https://github.com/kjuulh/gitnow"
|
||||
homepage = "https://gitnow-client.prod.kjuulh.app"
|
||||
license = "MIT"
|
||||
|
||||
version.workspace = true
|
||||
publish = true
|
||||
|
||||
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
@@ -10,22 +17,22 @@ 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"] }
|
||||
async-trait = "0.1.82"
|
||||
toml = "0.8.19"
|
||||
|
||||
gitea-rs = { git = "https://git.front.kjuulh.io/kjuulh/gitea-rs", version = "1.22.1" }
|
||||
gitea-client = { version = "1.22.1" }
|
||||
url = "2.5.2"
|
||||
octocrab = "0.39.0"
|
||||
octocrab = "0.42.0"
|
||||
dirs = "5.0.1"
|
||||
prost = "0.13.2"
|
||||
prost-types = "0.13.2"
|
||||
bytes = "1.7.1"
|
||||
nucleo-matcher = "0.3.1"
|
||||
ratatui = { version = "0.28.1", features = ["termwiz"] }
|
||||
ratatui = { version = "0.29.0", features = ["termwiz"] }
|
||||
crossterm = { version = "0.28.0", features = ["event-stream"] }
|
||||
futures = "0.3.30"
|
||||
termwiz = "0.22.0"
|
||||
|
@@ -1,9 +1,16 @@
|
||||
function git-now {
|
||||
# Run an update in the background
|
||||
(
|
||||
nohup gitnow update > /dev/null 2>&1 &
|
||||
)
|
||||
|
||||
# Find the repository of choice
|
||||
choice=$(gitnow "$@" --no-shell)
|
||||
if [[ $? -ne 0 ]]; then
|
||||
return $?
|
||||
fi
|
||||
|
||||
|
||||
# Enter local repository path
|
||||
cd "$(echo "$choice" | tail --lines 1)"
|
||||
}
|
||||
|
||||
|
@@ -79,6 +79,11 @@ impl Cache {
|
||||
tracing::debug!("cache has expired");
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
tracing::debug!(
|
||||
"cache is valid for: {} mins",
|
||||
cache_duration.saturating_sub(file_modified_last).as_secs() / 60
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,2 +1,3 @@
|
||||
pub mod root;
|
||||
pub mod shell;
|
||||
pub mod update;
|
||||
|
@@ -85,26 +85,37 @@ impl RootCommand {
|
||||
}
|
||||
};
|
||||
|
||||
if clone {
|
||||
let git_clone = self.app.git_clone();
|
||||
let project_path = self
|
||||
.app
|
||||
.config
|
||||
.settings
|
||||
.projects
|
||||
.directory
|
||||
.join(repo.to_rel_path());
|
||||
if !project_path.exists() {
|
||||
if clone {
|
||||
let git_clone = self.app.git_clone();
|
||||
|
||||
if std::io::stdout().is_terminal() && shell {
|
||||
let mut wrap_cmd =
|
||||
InlineCommand::new(format!("cloning: {}", repo.to_rel_path().display()));
|
||||
let repo = repo.clone();
|
||||
wrap_cmd
|
||||
.execute(move || async move {
|
||||
git_clone.clone_repo(&repo, force_refresh).await?;
|
||||
if std::io::stdout().is_terminal() && shell {
|
||||
let mut wrap_cmd =
|
||||
InlineCommand::new(format!("cloning: {}", repo.to_rel_path().display()));
|
||||
let repo = repo.clone();
|
||||
wrap_cmd
|
||||
.execute(move || async move {
|
||||
git_clone.clone_repo(&repo, force_refresh).await?;
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
Ok(())
|
||||
})
|
||||
.await?;
|
||||
} else {
|
||||
eprintln!("cloning repository...");
|
||||
git_clone.clone_repo(&repo, force_refresh).await?;
|
||||
}
|
||||
} else {
|
||||
eprintln!("cloning repository...");
|
||||
git_clone.clone_repo(&repo, force_refresh).await?;
|
||||
tracing::info!("skipping clone for repo: {}", &repo.to_rel_path().display());
|
||||
}
|
||||
} else {
|
||||
tracing::info!("skipping clone for repo: {}", &repo.to_rel_path().display());
|
||||
tracing::info!("repository already exists");
|
||||
}
|
||||
|
||||
if shell {
|
||||
|
14
crates/gitnow/src/commands/update.rs
Normal file
14
crates/gitnow/src/commands/update.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use crate::{app::App, cache::CacheApp, projects_list::ProjectsListApp};
|
||||
|
||||
#[derive(clap::Parser)]
|
||||
pub struct Update {}
|
||||
|
||||
impl Update {
|
||||
pub async fn execute(&mut self, app: &'static App) -> anyhow::Result<()> {
|
||||
let repositories = app.projects_list().get_projects().await?;
|
||||
|
||||
app.cache().update(&repositories).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@@ -124,7 +124,7 @@ impl CacheDuration {
|
||||
impl Default for CacheDuration {
|
||||
fn default() -> Self {
|
||||
Self::Precise {
|
||||
days: 1,
|
||||
days: 7,
|
||||
hours: 0,
|
||||
minutes: 0,
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
use anyhow::Context;
|
||||
use gitea_rs::apis::configuration::Configuration;
|
||||
use gitea_client::apis::configuration::Configuration;
|
||||
use url::Url;
|
||||
|
||||
use crate::{app::App, config::GiteaAccessToken};
|
||||
@@ -68,9 +68,9 @@ impl GiteaProvider {
|
||||
&self,
|
||||
config: &Configuration,
|
||||
page: usize,
|
||||
) -> anyhow::Result<Vec<gitea_rs::models::Repository>> {
|
||||
) -> anyhow::Result<Vec<gitea_client::models::Repository>> {
|
||||
let repos =
|
||||
gitea_rs::apis::user_api::user_current_list_repos(config, Some(page as i32), None)
|
||||
gitea_client::apis::user_api::user_current_list_repos(config, Some(page as i32), None)
|
||||
.await
|
||||
.context("failed to fetch repos for users")?;
|
||||
|
||||
@@ -125,9 +125,9 @@ impl GiteaProvider {
|
||||
user: &str,
|
||||
config: &Configuration,
|
||||
page: usize,
|
||||
) -> anyhow::Result<Vec<gitea_rs::models::Repository>> {
|
||||
) -> anyhow::Result<Vec<gitea_client::models::Repository>> {
|
||||
let repos =
|
||||
gitea_rs::apis::user_api::user_list_repos(config, user, Some(page as i32), None)
|
||||
gitea_client::apis::user_api::user_list_repos(config, user, Some(page as i32), None)
|
||||
.await
|
||||
.context("failed to fetch repos for users")?;
|
||||
|
||||
@@ -184,8 +184,8 @@ impl GiteaProvider {
|
||||
organisation: &str,
|
||||
config: &Configuration,
|
||||
page: usize,
|
||||
) -> anyhow::Result<Vec<gitea_rs::models::Repository>> {
|
||||
let repos = gitea_rs::apis::organization_api::org_list_repos(
|
||||
) -> anyhow::Result<Vec<gitea_client::models::Repository>> {
|
||||
let repos = gitea_client::apis::organization_api::org_list_repos(
|
||||
config,
|
||||
organisation,
|
||||
Some(page as i32),
|
||||
@@ -202,7 +202,7 @@ impl GiteaProvider {
|
||||
api: &str,
|
||||
access_token: Option<&GiteaAccessToken>,
|
||||
) -> anyhow::Result<Configuration> {
|
||||
let mut config = gitea_rs::apis::configuration::Configuration::new();
|
||||
let mut config = gitea_client::apis::configuration::Configuration::new();
|
||||
config.base_path = api.into();
|
||||
match access_token {
|
||||
Some(GiteaAccessToken::Env { env }) => {
|
||||
|
@@ -36,6 +36,7 @@ impl InteractiveApp for &'static crate::app::App {
|
||||
}
|
||||
|
||||
mod app {
|
||||
use crossterm::event::KeyModifiers;
|
||||
use ratatui::{
|
||||
crossterm::event::{self, Event, KeyCode},
|
||||
layout::{Constraint, Layout},
|
||||
@@ -92,6 +93,12 @@ mod app {
|
||||
terminal.draw(|frame| self.draw(frame))?;
|
||||
|
||||
if let Event::Key(key) = event::read()? {
|
||||
if let KeyCode::Char('c') = key.code {
|
||||
if key.modifiers.contains(KeyModifiers::CONTROL) {
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
|
||||
match key.code {
|
||||
KeyCode::Char(letter) => {
|
||||
self.current_search.push(letter);
|
||||
|
@@ -4,7 +4,7 @@ use std::path::PathBuf;
|
||||
|
||||
use anyhow::Context;
|
||||
use clap::{Parser, Subcommand};
|
||||
use commands::{root::RootCommand, shell::Shell};
|
||||
use commands::{root::RootCommand, shell::Shell, update::Update};
|
||||
use config::Config;
|
||||
use tracing::level_filters::LevelFilter;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
@@ -50,13 +50,14 @@ struct Command {
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Init(Shell),
|
||||
Update(Update),
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -80,7 +81,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
tracing::debug!("Starting cli");
|
||||
|
||||
match cli.command {
|
||||
Some(Commands::Init(mut shell)) => shell.execute().await?,
|
||||
Some(cmd) => match cmd {
|
||||
Commands::Init(mut shell) => {
|
||||
shell.execute().await?;
|
||||
}
|
||||
Commands::Update(mut update) => {
|
||||
update.execute(app).await?;
|
||||
}
|
||||
},
|
||||
None => {
|
||||
RootCommand::new(app)
|
||||
.execute(
|
||||
|
@@ -6,6 +6,9 @@ vars:
|
||||
service: "gitnow"
|
||||
registry: kasperhermansen
|
||||
|
||||
rust:
|
||||
publish: {}
|
||||
|
||||
please:
|
||||
project:
|
||||
owner: kjuulh
|
||||
|
Reference in New Issue
Block a user