chore(merge): bump v0.1.0, housekeeping, #8 from cafkafk/dev

- added changelog
- bumped cargo version
- fixed readme
- other minor fixes

Signed-off-by: Christina Sørensen <christina@cafkafk.com>
This commit is contained in:
Christina Sørensen 2023-07-03 09:49:49 +00:00 committed by GitHub
commit 200fe55feb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 129 additions and 73 deletions

View file

@ -2,6 +2,24 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
## [0.1.0] - 2023-07-03
### Documentation
- Changed roadmap
- Updated roadmap
### Features
- Implemented CoC flag
- Quiet flag
- Made SUCCESS/FAILURE emoji const
- Added flag no-emoji
### Refactor
- Made code more idiomatic
## [0.0.7] - 2023-07-02 ## [0.0.7] - 2023-07-02
### Bug Fixes ### Bug Fixes

2
Cargo.lock generated
View file

@ -179,7 +179,7 @@ dependencies = [
[[package]] [[package]]
name = "gg" name = "gg"
version = "0.0.6" version = "0.1.0"
dependencies = [ dependencies = [
"clap", "clap",
"clap_mangen", "clap_mangen",

View file

@ -1,6 +1,6 @@
[package] [package]
name = "gg" name = "gg"
version = "0.0.7" version = "0.1.0"
edition = "2021" edition = "2021"
authors = ["Christina Sørensen"] authors = ["Christina Sørensen"]
repository = "https://github.com/cafkafk/gg" repository = "https://github.com/cafkafk/gg"

View file

@ -9,15 +9,17 @@ those that use declarative operating systems and package managers.
Although this isn't really a case where it matters *that* much for performance, Although this isn't really a case where it matters *that* much for performance,
being written in rust instead of e.g. /janky/ scripting languages does also mean being written in rust instead of e.g. /janky/ scripting languages does also mean
it is snappy and reliable, and the /extensive/ testing helps ensure regressions it is snappy and reliable, and the /extensive/ (hardly, but eventually) testing
aren't introduced. helps ensure regressions aren't introduced.
That said, we're in 0.0.Z, *here be dragons* for now. That said, we're in 0.Y.Z, *here be dragons* for now (although a little less each
commit).
** Installation ** Installation
#+begin_src sh #+begin_src sh
$ git clone https://github.com/cafkafk/git $ git clone https://github.com/cafkafk/gg
$ ./install $ cd gg
$ cargo install --path .
#+end_src #+end_src
** Configuration ** Configuration

View file

@ -1,3 +1,2 @@
#!/usr/bin/env bash #!/usr/bin/env bash
cargo rustc --release -- -C target-cpu=native
cargo install --path . cargo install --path .

View file

@ -1,15 +1,27 @@
#+title: Roadmap #+title: Roadmap
* 0.2.0 (maybe)
- [ ] Links in categories?
* 0.1.2
- [ ] Implement Quiet flag
* 0.1.1
- [ ] Implement no-emoji flag
* 0.1.0 [100%] [5/5]
- [X] No functionality regressions
- [X] commit works in quick, fast
- [X] commit with edit works
- [X] Repo Flags Finished
- [X] Optional Fields
- [X] Subcommands
- [X] Quiet flag (wont rn)
- [X] Do something about coc flag
- [X] UX
- [X] Change failure emotes
- [X] Flag for disabling emotes
* Roadmap [0%] [0/4] * Roadmap [0%] [0/4]
- [ ] Custom operation sequences - [ ] Custom operation sequences
- [ ] Generic repositories - [ ] Generic repositories
- [ ] Version pinning - [ ] Version pinning
- [ ] libgit2 (maybe) - [ ] libgit2 (maybe)
* 0.1.0 [60%] [3/5]
- [X] No functionality regressions
- [X] commit works in quick, fast
- [X] commit with edit works
- [X] Repo Flags Finished
- [ ] Category Flags Finished - [ ] Category Flags Finished
- [X] Optional Fields
- [ ] Subcommands

View file

@ -59,10 +59,18 @@ pub struct Args {
#[arg(long)] #[arg(long)]
pub warranty: bool, pub warranty: bool,
/// Print code-of-conduct information (not implemented) /// Print code-of-conduct information
#[arg(long)] #[arg(long)]
pub code_of_conduct: bool, pub code_of_conduct: bool,
/// Try to be as quiet as possible (unix philosophy) (not imlemented)
#[arg(short, long)]
pub quiet: bool,
/// No emoji (not imlemented)
#[arg(short, long)]
pub no_emoji: bool,
#[command(subcommand)] #[command(subcommand)]
pub command: Option<Commands>, pub command: Option<Commands>,
} }

View file

@ -25,6 +25,8 @@ use std::os::unix::fs::symlink;
use std::path::Path; use std::path::Path;
use std::{fs, process::Command}; use std::{fs, process::Command};
use crate::utils::strings::{FAILURE_EMOJI, SUCCESS_EMOJI};
/// An enum containing flags that change behaviour of repos and categories /// An enum containing flags that change behaviour of repos and categories
#[derive(PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Debug)] #[derive(PartialOrd, Ord, PartialEq, Eq, Serialize, Deserialize, Debug)]
pub enum RepoFlags { pub enum RepoFlags {
@ -53,7 +55,7 @@ pub enum RepoFlags {
/// For diagrams of the underlying architecture, consult ARCHITECHTURE.md /// For diagrams of the underlying architecture, consult ARCHITECHTURE.md
/// ///
/// ///
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Config { pub struct Config {
/// map of all categories /// map of all categories
/// ///
@ -66,7 +68,7 @@ pub struct Config {
/// Represents a category of repositories /// Represents a category of repositories
/// ///
/// This allows you to organize your repositories into categories /// This allows you to organize your repositories into categories
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Category { pub struct Category {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub flags: Option<Vec<RepoFlags>>, // FIXME: not implemented pub flags: Option<Vec<RepoFlags>>, // FIXME: not implemented
@ -78,7 +80,7 @@ pub struct Category {
} }
/// Contain fields for a single link. /// Contain fields for a single link.
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Links { pub struct Links {
/// The name of the link /// The name of the link
pub name: String, pub name: String,
@ -87,7 +89,7 @@ pub struct Links {
} }
/// Holds a single git repository and related fields. /// Holds a single git repository and related fields.
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct GitRepo { pub struct GitRepo {
pub name: String, pub name: String,
pub path: String, pub path: String,
@ -101,7 +103,7 @@ pub struct GitRepo {
//////////////////////////////////// ////////////////////////////////////
/// Represents a single operation on a repository /// Represents a single operation on a repository
struct SeriesItem<'series> { pub struct SeriesItem<'series> {
/// The string to be displayed to the user /// The string to be displayed to the user
operation: &'series str, operation: &'series str,
/// The closure representing the actual operation /// The closure representing the actual operation
@ -114,7 +116,10 @@ struct SeriesItem<'series> {
fn handle_file_exists(selff: &Links, tx_path: &Path, rx_path: &Path) { fn handle_file_exists(selff: &Links, tx_path: &Path, rx_path: &Path) {
match rx_path.read_link() { match rx_path.read_link() {
Ok(file) if file.canonicalize().unwrap() == tx_path.canonicalize().unwrap() => { Ok(file)
if file.canonicalize().expect("failed to canonicalize file")
== tx_path.canonicalize().expect("failed to canonicalize path") =>
{
debug!( debug!(
"Linking {} -> {} failed: file already linked", "Linking {} -> {} failed: file already linked",
&selff.tx, &selff.rx &selff.tx, &selff.rx
@ -291,7 +296,7 @@ impl GitRepo {
/// Removes a repository (not implemented) /// Removes a repository (not implemented)
/// ///
/// Kept here as a reminder that we probably shouldn't do this /// Kept here as a reminder that we probably shouldn't do this
fn remove(&self) -> Result<(), std::io::Error> { fn remove() -> Result<(), std::io::Error> {
// https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html // https://doc.rust-lang.org/std/fs/fn.remove_dir_all.html
unimplemented!("This seems to easy to missuse/exploit"); unimplemented!("This seems to easy to missuse/exploit");
// fs::remove_dir_all(format!("{}{}", &self.path, &self.name)) // fs::remove_dir_all(format!("{}{}", &self.path, &self.name))
@ -327,7 +332,7 @@ impl Config {
where where
F: Fn(&GitRepo), F: Fn(&GitRepo),
{ {
for (_, category) in self.categories.iter() { for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() { for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
f(repo); f(repo);
} }
@ -342,14 +347,13 @@ impl Config {
where where
F: Fn(&GitRepo) -> bool, F: Fn(&GitRepo) -> bool,
{ {
for (_, category) in self.categories.iter() { for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() { for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
let mut sp = let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op).into());
if f(repo) { if f(repo) {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into()); sp.stop_and_persist(SUCCESS_EMOJI, format!("{}: {}", repo.name, op));
} else { } else {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into()); sp.stop_and_persist(FAILURE_EMOJI, format!("{}: {}", repo.name, op));
} }
} }
} }
@ -396,17 +400,16 @@ impl Config {
/// self.series_on_all(series); /// self.series_on_all(series);
/// ``` /// ```
pub fn series_on_all(&self, closures: Vec<SeriesItem>) { pub fn series_on_all(&self, closures: Vec<SeriesItem>) {
for (_, category) in self.categories.iter() { for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() { for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
for instruction in closures.iter() { for instruction in &closures {
let f = &instruction.closure; let f = &instruction.closure;
let op = instruction.operation; let op = instruction.operation;
let mut sp = let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op).into());
if f(repo) { if f(repo) {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into()); sp.stop_and_persist(SUCCESS_EMOJI, format!("{}: {}", repo.name, op));
} else { } else {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into()); sp.stop_and_persist(FAILURE_EMOJI, format!("{}: {}", repo.name, op));
break; break;
} }
} }
@ -443,17 +446,16 @@ impl Config {
/// self.all_on_all(series); /// self.all_on_all(series);
/// ``` /// ```
pub fn all_on_all(&self, closures: Vec<SeriesItem>) { pub fn all_on_all(&self, closures: Vec<SeriesItem>) {
for (_, category) in self.categories.iter() { for category in self.categories.values() {
for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() { for (_, repo) in category.repos.as_ref().expect("failed to get repos").iter() {
for instruction in closures.iter() { for instruction in &closures {
let f = &instruction.closure; let f = &instruction.closure;
let op = instruction.operation; let op = instruction.operation;
let mut sp = let mut sp = Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op));
Spinner::new(Spinners::Dots10, format!("{}: {}", repo.name, op).into());
if f(repo) { if f(repo) {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into()); sp.stop_and_persist(SUCCESS_EMOJI, format!("{}: {}", repo.name, op));
} else { } else {
sp.stop_and_persist("", format!("{}: {}", repo.name, op).into()); sp.stop_and_persist(FAILURE_EMOJI, format!("{}: {}", repo.name, op));
} }
} }
} }
@ -465,22 +467,22 @@ impl Config {
/// Tries to pull all repositories, skips if fail. /// Tries to pull all repositories, skips if fail.
pub fn pull_all(&self) { pub fn pull_all(&self) {
debug!("exectuting pull_all"); debug!("exectuting pull_all");
self.on_all_spinner("pull", |repo| repo.pull()); self.on_all_spinner("pull", GitRepo::pull);
} }
/// Tries to clone all repositories, skips if fail. /// Tries to clone all repositories, skips if fail.
pub fn clone_all(&self) { pub fn clone_all(&self) {
debug!("exectuting clone_all"); debug!("exectuting clone_all");
self.on_all_spinner("clone", |repo| repo.clone()); self.on_all_spinner("clone", GitRepo::clone);
} }
/// Tries to add all work in all repositories, skips if fail. /// Tries to add all work in all repositories, skips if fail.
pub fn add_all(&self) { pub fn add_all(&self) {
debug!("exectuting clone_all"); debug!("exectuting clone_all");
self.on_all_spinner("add", |repo| repo.add_all()); self.on_all_spinner("add", GitRepo::add_all);
} }
/// Tries to commit all repositories one at a time, skips if fail. /// Tries to commit all repositories one at a time, skips if fail.
pub fn commit_all(&self) { pub fn commit_all(&self) {
debug!("exectuting clone_all"); debug!("exectuting clone_all");
self.on_all_spinner("commit", |repo| repo.commit()); self.on_all_spinner("commit", GitRepo::commit);
} }
/// Tries to commit all repositories with msg, skips if fail. /// Tries to commit all repositories with msg, skips if fail.
pub fn commit_all_msg(&self, msg: &str) { pub fn commit_all_msg(&self, msg: &str) {
@ -494,11 +496,11 @@ impl Config {
let series: Vec<SeriesItem> = vec![ let series: Vec<SeriesItem> = vec![
SeriesItem { SeriesItem {
operation: "pull", operation: "pull",
closure: Box::new(move |repo: &GitRepo| repo.pull()), closure: Box::new(GitRepo::pull),
}, },
SeriesItem { SeriesItem {
operation: "add", operation: "add",
closure: Box::new(move |repo: &GitRepo| repo.add_all()), closure: Box::new(GitRepo::add_all),
}, },
SeriesItem { SeriesItem {
operation: "commit", operation: "commit",
@ -506,7 +508,7 @@ impl Config {
}, },
SeriesItem { SeriesItem {
operation: "push", operation: "push",
closure: Box::new(move |repo: &GitRepo| repo.push()), closure: Box::new(GitRepo::push),
}, },
]; ];
self.all_on_all(series); self.all_on_all(series);
@ -518,19 +520,19 @@ impl Config {
let series: Vec<SeriesItem> = vec![ let series: Vec<SeriesItem> = vec![
SeriesItem { SeriesItem {
operation: "pull", operation: "pull",
closure: Box::new(move |repo: &GitRepo| repo.pull()), closure: Box::new(GitRepo::pull),
}, },
SeriesItem { SeriesItem {
operation: "add", operation: "add",
closure: Box::new(move |repo: &GitRepo| repo.add_all()), closure: Box::new(GitRepo::add_all),
}, },
SeriesItem { SeriesItem {
operation: "commit", operation: "commit",
closure: Box::new(move |repo: &GitRepo| repo.commit()), closure: Box::new(move |repo: &GitRepo| repo.commit_with_msg(msg)),
}, },
SeriesItem { SeriesItem {
operation: "push", operation: "push",
closure: Box::new(move |repo: &GitRepo| repo.push()), closure: Box::new(GitRepo::push),
}, },
]; ];
self.series_on_all(series); self.series_on_all(series);
@ -541,7 +543,7 @@ impl Config {
/// Tries to link all repositories, skips if fail. /// Tries to link all repositories, skips if fail.
pub fn link_all(&self) { pub fn link_all(&self) {
debug!("exectuting link_all"); debug!("exectuting link_all");
for link in self.links.iter() { for link in &self.links {
link.link(); link.link();
} }
} }

View file

@ -61,7 +61,8 @@ fn main() {
match &args { match &args {
args if args.license => println!("{}", utils::strings::INTERACTIVE_LICENSE), args if args.license => println!("{}", utils::strings::INTERACTIVE_LICENSE),
args if args.warranty => println!("{}", utils::strings::INTERACTIVE_WARRANTY), args if args.warranty => println!("{}", utils::strings::INTERACTIVE_WARRANTY),
args if args.code_of_conduct => unimplemented!(), args if args.code_of_conduct => println!("{}", utils::strings::INTERACTIVE_COC),
args if args.quiet => todo!(),
_ => (), _ => (),
} }
match &mut args.command { match &mut args.command {
@ -99,7 +100,7 @@ fn main() {
config.commit_all(); config.commit_all();
} }
Some(Commands::CommitMsg { msg }) => { Some(Commands::CommitMsg { msg }) => {
config.commit_all_msg(msg.as_ref().unwrap()); config.commit_all_msg(msg.as_ref().expect("failed to get message from input"));
} }
None => (), None => (),
} }
@ -154,8 +155,6 @@ mod config {
}, },
); );
} }
// let yaml = serde_yaml::to_string(&config).unwrap();
// println!("{}", yaml);
} }
#[test] #[test]
fn read_config_populate() { fn read_config_populate() {
@ -163,13 +162,13 @@ mod config {
} }
#[test] #[test]
fn write_config() { fn write_config() {
let root = current_dir().unwrap(); let root = current_dir().expect("failed to get current dir");
let config = Config::new( let config = Config::new(
&RelativePath::new("./src/test/config.yaml") &RelativePath::new("./src/test/config.yaml")
.to_logical_path(&root) .to_logical_path(&root)
.into_os_string() .into_os_string()
.into_string() .into_string()
.unwrap(), .expect("failed to turn config into string"),
); );
let mut test_file = File::create( let mut test_file = File::create(
@ -177,11 +176,13 @@ mod config {
.to_logical_path(&root) .to_logical_path(&root)
.into_os_string() .into_os_string()
.into_string() .into_string()
.unwrap(), .expect("failed to turn config into string"),
) )
.expect("failed to create test file"); .expect("failed to create test file");
let contents = serde_yaml::to_string(&config).unwrap(); let contents = serde_yaml::to_string(&config).expect("failed to turn config into string");
test_file.write_all(contents.as_bytes()).unwrap(); test_file
.write_all(contents.as_bytes())
.expect("failed to write contents of config into file");
let test_config = Config::new(&RelativePath::new("./src/test/test.yaml").to_string()); let test_config = Config::new(&RelativePath::new("./src/test/test.yaml").to_string());
assert_eq!(config, test_config); assert_eq!(config, test_config);
@ -205,13 +206,13 @@ mod config {
} }
#[test] #[test]
fn is_config_readable() { fn is_config_readable() {
let root = current_dir().unwrap(); let root = current_dir().expect("failed to get current dir");
let config = Config::new( let config = Config::new(
&RelativePath::new("./src/test/config.yaml") &RelativePath::new("./src/test/config.yaml")
.to_logical_path(root) .to_logical_path(root)
.into_os_string() .into_os_string()
.into_string() .into_string()
.unwrap(), .expect("failed to turnn config into string"),
); );
let flags = vec![Clone, Push]; let flags = vec![Clone, Push];

View file

@ -15,6 +15,7 @@ categories:
flags: flags:
- Clone - Clone
- Push - Push
empty: {}
stuff: stuff:
flags: [] flags: []
repos: repos:
@ -29,13 +30,6 @@ categories:
config: config:
flags: [] flags: []
repos: repos:
qmk_firmware:
name: qmk_firmware
path: /home/ces/org/src/git/
url: git@github.com:cafkafk/qmk_firmware.git
flags:
- Clone
- Push
starship: starship:
name: starship name: starship
path: /home/ces/org/src/git/ path: /home/ces/org/src/git/
@ -43,7 +37,13 @@ categories:
flags: flags:
- Clone - Clone
- Push - Push
empty: {} qmk_firmware:
name: qmk_firmware
path: /home/ces/org/src/git/
url: git@github.com:cafkafk/qmk_firmware.git
flags:
- Clone
- Push
links: links:
- name: gg - name: gg
rx: /home/ces/.config/gg rx: /home/ces/.config/gg

View file

@ -50,7 +50,7 @@ pub fn home_dir() -> String {
/// ///
/// WARNING: NOT THREAD SAFE /// WARNING: NOT THREAD SAFE
fn change_dir_repo(path: &str, name: &str) { fn change_dir_repo(path: &str, name: &str) {
let mut full_path: String = "".to_owned(); let mut full_path: String = String::new();
full_path.push_str(path); full_path.push_str(path);
full_path.push_str(name); full_path.push_str(name);
let root = Path::new(&full_path); let root = Path::new(&full_path);

View file

@ -46,8 +46,22 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
"; ";
pub const INTERACTIVE_COC: &str = "\
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of
experience, nationality, personal appearance, race, religion, or sexual identity
and orientation. For more, see http://contributor-covenant.org/version/1/4";
/// Contains the message for quick commit subcommand /// Contains the message for quick commit subcommand
pub const QUICK_COMMIT: &str = "git: quick commit"; pub const QUICK_COMMIT: &str = "git: quick commit";
/// Contains the message for fast commit subcommand /// Contains the message for fast commit subcommand
pub const FAST_COMMIT: &str = "git: fast commit"; pub const FAST_COMMIT: &str = "git: fast commit";
/// Success emoji
pub const SUCCESS_EMOJI: &str = "";
/// Failure emoji
pub const FAILURE_EMOJI: &str = "";