Compare commits

..

No commits in common. "main" and "v0.3.4" have entirely different histories.
main ... v0.3.4

17 changed files with 438 additions and 873 deletions

View File

@ -1,16 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "cargo"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"

View File

@ -1,19 +0,0 @@
on: workflow_dispatch
name: Build packages
jobs:
build_deb:
name: Build .deb package
runs-on: ubuntu-latest
env:
RUSTFLAGS: "-C strip=debuginfo"
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- run: cargo install cargo-deb
- run: cargo build --release
- run: cargo deb
- uses: actions/upload-artifact@v4
with:
path: target/debian/*.deb

View File

@ -1,53 +0,0 @@
on:
- push
- workflow_dispatch
name: CI
jobs:
lint_and_test:
name: lint and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- uses: Swatinem/rust-cache@v2
- run: cargo clippy --all-features -- -D warnings
- run: cargo check --workspace --all-features
- run: cargo test --all-targets
- run: cargo fmt --all -- --check
build_package:
needs: lint_and_test
if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/build-') }}
name: Build package
env:
RUSTFLAGS: "-C strip=debuginfo"
strategy:
matrix:
os:
- ubuntu-latest
- macos-latest
# - windows-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- uses: Swatinem/rust-cache@v2
- run: cargo build --release
- name: prepare release artifact
shell: bash
run: |
mkdir -p target/{bin,man}
cp target/release/*.1 target/man
cp target/release/git-{mob,solo,{add,edit,delete}-coauthor} target/bin
- uses: actions/upload-artifact@v4
with:
name: git-mob-${{ matrix.os }}
path: |
target/bin
target/man

8
.travis.yml Normal file
View File

@ -0,0 +1,8 @@
language: rust
rust:
- stable
- beta
- nightly
matrix:
allow_failures:
- rust: nightly

834
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
[package]
name = "git-mob"
version = "0.6.0"
authors = [ "Martin Frost <martin@frost.ws>" ]
name = "git_mob"
version = "0.3.4"
authors = ["Martin Frost <martin@frost.ws>"]
edition = "2018"
description = "A CLI tool for social coding."
license = "MIT"
@ -9,36 +9,11 @@ homepage = "https://github.com/Frost/git-mob"
repository = "https://github.com/Frost/git-mob"
readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
git2 = { version = "0.19", default-features = false }
dirs = "2.0"
git2 = "0.13"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
clap = { version = "~4.5", features = ["derive"] }
clap_mangen = "~0.2"
env_home = "0.1.0"
[build-dependencies]
clap_mangen = "~0.2"
clap = { version = "~4.5", features = ["derive"]}
clap_complete = "~4.5"
[package.metadata.deb]
name = "git-mob"
revision = "1"
section = "vcs"
priority = "optional"
extended-description = """\
A set of git subcommands for including co-authors to your git commits."""
assets = [
["target/release/git-mob", "usr/bin/", "755"],
["target/release/git-solo", "usr/bin/", "755"],
["target/release/git-add-coauthor", "usr/bin/", "755"],
["target/release/git-edit-coauthor", "usr/bin/", "755"],
["target/release/git-delete-coauthor", "usr/bin/", "755"],
["target/release/git-mob.1", "usr/share/man/man1/", "644"],
["target/release/git-solo.1", "usr/share/man/man1/", "644"],
["target/release/git-add-coauthor.1", "usr/share/man/man1/", "644"],
["target/release/git-edit-coauthor.1", "usr/share/man/man1/", "644"],
["target/release/git-delete-coauthor.1", "usr/share/man/man1/", "644"],
["README.md", "usr/share/doc/git-mob/README", "644"],
]
structopt = "0.3"

View File

@ -10,20 +10,6 @@ It is essentially a Rust clone of the [git-mob NPM package](https://www.npmjs.co
## Install
### MacOS
If you have [Homebrew](https://brew.sh) installed, you can install `git-mob` using my tap:
brew install frost/tap/git-mob
Otherwise, see the section on binary packages
### Binary packages for MacOS, Ubuntu, and Windows
Download the [latest release](https://github.com/Frost/git-mob/releases/latest) and extract it somewhere so that the binaries end up in your `$PATH`.
### From source
Just run `cargo install git_mob` and you should be all set.
## A note on commit template and git-mob

View File

@ -1,31 +0,0 @@
use clap::CommandFactory;
use clap_mangen::Man;
use std::env;
use std::path::Path;
#[path = "src/cli.rs"]
mod cli;
macro_rules! generate_manpage {
($struct:ident) => {
let target_dir = env::var("CARGO_TARGET_DIR").unwrap_or("target".to_string());
let output_dir = Path::new(&target_dir).join(env::var("PROFILE").unwrap());
let cmd = cli::$struct::command();
let cmd_name = format!("{}.1", cmd.get_name());
let man = Man::new(cmd);
let mut buffer: Vec<u8> = Default::default();
man.render(&mut buffer)?;
std::fs::write(output_dir.join(cmd_name), buffer)?;
};
}
fn main() -> std::io::Result<()> {
generate_manpage!(GitMob);
generate_manpage!(GitSolo);
generate_manpage!(GitAddCoauthor);
generate_manpage!(GitEditCoauthor);
generate_manpage!(GitDeleteCoauthor);
Ok(())
}

View File

@ -1,75 +0,0 @@
{
"nodes": {
"flake-utils": {
"locked": {
"lastModified": 1678901627,
"narHash": "sha256-U02riOqrKKzwjsxc/400XnElV+UtPUQWpANPlyazjH0=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "93a2b84fc4b70d9e089d029deacc3583435c2ed6",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"naersk": {
"inputs": {
"nixpkgs": "nixpkgs"
},
"locked": {
"lastModified": 1671096816,
"narHash": "sha256-ezQCsNgmpUHdZANDCILm3RvtO1xH8uujk/+EqNvzIOg=",
"owner": "nix-community",
"repo": "naersk",
"rev": "d998160d6a076cfe8f9741e56aeec7e267e3e114",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "naersk",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1670507980,
"narHash": "sha256-riNZa0xzM1it3pzxciwALeMs+0CsBMWIW2FqulzK8vM=",
"path": "/nix/store/2i8zqmz2cqa0grjagw94z7g47199db9k-source",
"rev": "2787fc7d1e51404678614bf0fe92fc296746eec0",
"type": "path"
},
"original": {
"id": "nixpkgs",
"type": "indirect"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1678875422,
"narHash": "sha256-T3o6NcQPwXjxJMn2shz86Chch4ljXgZn746c2caGxd8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "126f49a01de5b7e35a43fd43f891ecf6d3a51459",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"naersk": "naersk",
"nixpkgs": "nixpkgs_2"
}
}
},
"root": "root",
"version": 7
}

View File

@ -1,24 +0,0 @@
{
inputs = {
flake-utils.url = "github:numtide/flake-utils";
naersk.url = "github:nix-community/naersk";
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs = { self, flake-utils, naersk, nixpkgs }:
{
overlays.default = (final: prev:
let naersk' = final.callPackage naersk { };
in { git-mob = naersk'.buildPackage { src = ./.; }; });
} // flake-utils.lib.eachDefaultSystem (system:
let
pkgs = (import nixpkgs) {
inherit system;
overlays = [ self.overlays.default ];
};
in rec {
defaultPackage = pkgs.git-mob;
devShell =
pkgs.mkShell { nativeBuildInputs = with pkgs; [ rustc cargo ]; };
});
}

View File

@ -1,14 +1,23 @@
use clap::Parser;
use git_mob::{cli, parse_coauthors_file, write_coauthors_file, Author};
use git_mob::{get_available_coauthors, write_coauthors_file, Author};
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
struct Opt {
/// Co-author initials
initials: String,
/// The name of the co-author, in quotes, e.g. "Foo Bar"
name: String,
/// The email of the co-author
email: String,
}
fn main() {
let opt = cli::GitAddCoauthor::parse();
let mut authors = parse_coauthors_file().unwrap_or_default();
let opt = Opt::from_args();
let mut authors = get_available_coauthors();
let new_author = Author {
name: opt.name,
email: opt.email,
};
authors.insert(opt.initials, new_author);
write_coauthors_file(authors);

View File

@ -1,8 +1,14 @@
use clap::Parser;
use git_mob::{cli, get_available_coauthors, write_coauthors_file};
use git_mob::{get_available_coauthors, write_coauthors_file};
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
struct Opt {
/// Initials of the co-author to delete
initials: String,
}
fn main() {
let opt = cli::GitDeleteCoauthor::parse();
let opt = Opt::from_args();
let mut authors = get_available_coauthors();
authors.remove(&opt.initials);
write_coauthors_file(authors);

View File

@ -1,22 +1,41 @@
use clap::Parser;
use git_mob::{cli, get_available_coauthors, write_coauthors_file, Author};
use git_mob::{get_available_coauthors, write_coauthors_file, Author};
use std::process;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
struct Opt {
/// Co-author initials
initials: String,
/// The name of the co-author, in quotes, e.g. "Foo Bar"
#[structopt(long, required_unless("email"))]
name: Option<String>,
/// The email of the co-author
#[structopt(long, required_unless("name"))]
email: Option<String>,
}
fn main() {
let opt = cli::GitDeleteCoauthor::parse();
let opt = Opt::from_args();
let mut authors = get_available_coauthors();
let mut updated_author: Author;
if let Some(author) = authors.get(&opt.initials) {
let mut updated_author: Author = author.clone();
updated_author.name = opt.name;
updated_author.email = opt.email;
authors.insert(opt.initials, updated_author);
write_coauthors_file(authors);
updated_author = author.clone();
} else {
eprintln!("No author found with initials {}", &opt.initials);
process::exit(1);
};
}
if let Some(name) = opt.name {
updated_author.name = name;
}
if let Some(email) = opt.email {
updated_author.email = email;
}
authors.insert(opt.initials, updated_author);
write_coauthors_file(authors);
}

View File

@ -1,61 +1,72 @@
use clap::Parser;
use git_mob::{
cli, ensure_commit_template_is_set, get_available_coauthors, get_main_author, set_main_author,
ensure_commit_template_is_set, get_available_coauthors, get_main_author, set_main_author,
with_gitmessage_template_path_or_exit, Author,
};
use std::fmt::Write;
use std::fs;
use std::process;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
struct Opt {
/// Prints list of available co-authors
#[structopt(short, long)]
list: bool,
/// Overwrite the main author
#[structopt(short, long)]
overwrite: Option<String>,
/// A list of co-author initials
coauthors: Vec<String>,
}
fn main() {
let args = cli::GitMob::parse();
let opt = Opt::from_args();
if args.list {
if opt.list {
list_coauthors();
process::exit(0);
}
if let Some(initials) = args.overwrite {
if let Some(initials) = opt.overwrite {
override_main_author(&initials);
}
write_coauthors_to_gitmessage_file(&args.coauthors);
write_coauthors_to_gitmessage_file(&opt.coauthors);
ensure_commit_template_is_set();
}
fn list_coauthors() {
for (abbrev, author) in &get_available_coauthors() {
println!("{abbrev}\t{author}");
println!("{}\t{}", abbrev, author);
}
}
fn override_main_author(initials: &str) {
fn override_main_author(initials: &String) {
let all_authors = get_available_coauthors();
match all_authors.get(initials) {
Some(new_main_author) => set_main_author(new_main_author),
Some(new_main_author) => set_main_author(&new_main_author),
None => {
eprintln!("Error: author with initials {initials} not found");
eprintln!("Error: author with initials {} not found", initials);
process::exit(1);
}
}
}
fn write_coauthors_to_gitmessage_file(coauthor_initials: &[String]) {
let coauthors = select_coauthors(coauthor_initials);
let coauthors = select_coauthors(&coauthor_initials);
let mut content = String::from("\n\n");
for author in &coauthors {
_ = writeln!(content, "Co-authored-by: {}", &author.to_string());
content.push_str(&format!("Co-authored-by: {}\n", &author.to_string()));
}
with_gitmessage_template_path_or_exit(|path| match fs::write(path, content) {
Ok(_) => {
println!("{}", get_main_author());
for author in &coauthors {
println!("{author}");
println!("{}", author);
}
}
Err(e) => {
eprintln!("Error writing to .gitmessage template: {e}");
eprintln!("Error writing to .gitmessage template: {}", e);
process::exit(1);
}
});
@ -69,7 +80,7 @@ fn select_coauthors(coauthor_initials: &[String]) -> Vec<Author> {
match all_coauthors.get(initial) {
Some(coauthor) => coauthors.push(coauthor.clone()),
None => {
eprintln!("Error: author with initials {initial} not found");
eprintln!("Error: atuhor with initials {} not found", initial);
process::exit(1);
}
}

View File

@ -1,13 +1,11 @@
use clap::Parser;
use git_mob::{
cli, ensure_commit_template_is_set, get_main_author, with_gitmessage_template_path_or_exit,
ensure_commit_template_is_set, get_main_author, with_gitmessage_template_path_or_exit,
};
use std::fs::File;
fn main() {
let _opt = cli::GitSolo::parse();
let main_author = get_main_author();
println!("{main_author}");
println!("{}", main_author);
with_gitmessage_template_path_or_exit(|path| {
let _template = File::create(path);

View File

@ -1,56 +0,0 @@
use clap::Parser;
#[derive(Parser, Debug)]
#[clap(version, name = "git-mob")]
/// Assemble a group of co-authors to help you on your coding quest
pub struct GitMob {
/// Prints list of available co-authors
#[clap(short, long)]
pub list: bool,
/// Overwrite the main author
#[clap(short, long)]
pub overwrite: Option<String>,
/// A list of co-author initials
pub coauthors: Vec<String>,
}
#[derive(Parser, Debug)]
#[clap(name = "git-add-coauthor", version)]
/// Add a co-author to your list of available co-authors
pub struct GitAddCoauthor {
/// Co-author initials
pub initials: String,
/// The name of the co-author, in quotes, e.g. "Foo Bar"
pub name: String,
/// The email of the co-author
pub email: String,
}
#[derive(Parser, Debug)]
#[clap(name = "git-edit-coauthor", version)]
/// Edit a co-author in your list of available co-authors
pub struct GitEditCoauthor {
/// Co-author initials
pub initials: String,
/// The name of the co-author, in quotes, e.g. "Foo Bar"
pub name: String,
/// The email of the co-author
pub email: String,
}
#[derive(Parser, Debug)]
#[clap(name = "git-delete-coauthor", version)]
/// Delete a co-author from your list of available co-authors
pub struct GitDeleteCoauthor {
/// Co-author initials
pub initials: String,
/// The name of the co-author, in quotes, e.g. "Foo Bar"
pub name: String,
/// The email of the co-author
pub email: String,
}
#[derive(Parser, Debug)]
#[clap(name = "git-solo", version)]
/// Disband the mob and continue working solo.
pub struct GitSolo {}

View File

@ -1,4 +1,4 @@
use env_home::env_home_dir as home_dir;
use dirs::home_dir;
use git2::{Config, Repository};
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
@ -11,8 +11,6 @@ use std::io::BufReader;
use std::process;
use std::string::String;
pub mod cli;
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct Author {
pub name: String,
@ -28,7 +26,7 @@ impl fmt::Display for Author {
pub fn get_main_author() -> Author {
let cfg = match Repository::open_from_env() {
Ok(repo) => repo.config().unwrap(),
Err(_e) => Config::open_default().unwrap(),
Err(_e) => Config::open_default().unwrap()
};
let name = cfg.get_entry("user.name").unwrap();
@ -51,10 +49,9 @@ pub fn set_main_author(author: &Author) {
pub fn ensure_commit_template_is_set() {
with_git_repo_or_exit(|repo| {
let mut config = repo.config().unwrap();
let template_path = repo.path().join(".gitmessage");
if let Some(template_path) = template_path.to_str() {
config.set_str("commit.template", template_path).unwrap();
}
config
.set_str("commit.template", &".git/.gitmessage")
.unwrap();
})
}
@ -62,13 +59,13 @@ pub fn get_available_coauthors() -> BTreeMap<String, Author> {
match parse_coauthors_file() {
Ok(coauthors) => coauthors,
Err(e) => {
eprintln!("{e:?}");
eprintln!("{}", e);
BTreeMap::new()
}
}
}
pub fn parse_coauthors_file() -> Result<BTreeMap<String, Author>, Box<dyn Error>> {
fn parse_coauthors_file() -> Result<BTreeMap<String, Author>, Box<dyn Error>> {
let coauthors_path = coauthors_file_path();
let coauthors_file = File::open(coauthors_path)?;
let reader = BufReader::new(coauthors_file);
@ -107,7 +104,7 @@ pub fn write_coauthors_file(authors: BTreeMap<String, Author>) {
match fs::write(coauthors_file_path(), json_data) {
Ok(_) => {}
Err(e) => {
eprintln!("Error writing git-coauthors file: {e:?}");
eprintln!("Error writing git-coauthors file: {:?}", e);
process::exit(1);
}
}