diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c667bec..ad8d748 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,8 +13,13 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Add fmt and clippy - run: rustup component add rustfmt clippy + - uses: dtolnay/rust-toolchain@1.51.0 + with: + components: clippy, rustfmt + - name: Print rust version + run: rustup show + - name: Print clippy version + run: cargo clippy --version - name: Lint run: make lint - name: Run tests diff --git a/Cargo.toml b/Cargo.toml index 38b4f8c..5f705ef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gitopen" -version = "0.1.0" +version = "1.1.0" authors = ["oren0e "] edition = "2018" @@ -8,3 +8,4 @@ edition = "2018" webbrowser = "0.5.5" anyhow = "1.0.44" regex = "1.5.4" +clap = "2.33.3" diff --git a/README.md b/README.md index dc91dce..3a80139 100644 --- a/README.md +++ b/README.md @@ -14,4 +14,9 @@ Note: You have to have rust installed with cargo to be able to install this util # Usage -When in git repository in terminal, run `gitopen`. +There are 2 basic usages: + +- When in git repository in terminal, run `gitopen`. +- After you've opened a branch and you are ready to push and open a PR, run `gitopen -p`. This will push the changes to the current branch and open the PR in the browser. + +For help, use `gitopen --help` diff --git a/src/actions.rs b/src/actions.rs new file mode 100644 index 0000000..2cd2840 --- /dev/null +++ b/src/actions.rs @@ -0,0 +1,74 @@ +use crate::match_logic::parse_url_from_git; +use anyhow::anyhow; +use anyhow::Result as AnyhowResult; +use regex::Regex; +use std::process::{Command, Stdio}; + +pub fn open_repo() -> AnyhowResult<()> { + let git_repo = Command::new("git") + .args(&["config", "--get", "remote.origin.url"]) + .stdout(Stdio::piped()) + .output()?; + + let stdout = String::from_utf8(git_repo.stdout)?; + let parsed_url = parse_url_from_git(stdout)?; + webbrowser::open(&parsed_url)?; + Ok(()) +} + +pub fn push_and_open_pr() -> AnyhowResult<()> { + let current_branch = Command::new("git") + .args(&["branch", "--show-current"]) + .stdout(Stdio::piped()) + .output()?; + let current_branch_text = &String::from_utf8(current_branch.stdout)?; + let current_branch_text_stripped = current_branch_text.trim(); + let output_from_push = Command::new("git") + .args(&["push", "origin", ¤t_branch_text_stripped]) + .stderr(Stdio::piped()) + .output()?; + let pr_re = Regex::new(&format!( + r"remote:.*(https.*{}).*\n", + current_branch_text_stripped + ))?; + let output_from_push_text = String::from_utf8(output_from_push.stderr)?; + println!("{:?}", &output_from_push_text); + let captured = pr_re + .captures(&output_from_push_text) + .ok_or_else(|| anyhow!("Error capturing PR url"))?; + println!("{:?}", &captured[1]); + webbrowser::open(&captured[1])?; + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_correct_pr_parsing_from_output() { + let output = r#"Counting objects: 4, done. +Delta compression using up to 12 threads. +Compressing objects: 100% (4/4), done. +Writing objects: 100% (4/4), 3.01 KiB | 3.01 MiB/s, done. +Total 4 (delta 2), reused 0 (delta 0) +remote: Resolving deltas: 100% (2/2), completed with 2 local objects. +remote: +remote: Create a pull request for 'feat/add-more-pokemons' on GitHub by visiting: +remote: https://github.com/tobiasbueschel/awesome-pokemon/pull/new/feat/add-more-pokemons +remote: +To github.com:tobiasbueschel/awesome-pokemon.git + * [new branch] feat/add-more-pokemons -> feat/add-more-pokemons"#; + let current_branch = "feat/add-more-pokemons\n"; + let current_branch_text_stripped = current_branch.trim(); + let re = Regex::new(&format!( + r"remote:.*(https.*{}).*\n", + current_branch_text_stripped + )) + .unwrap(); + let captured = re.captures(&output).unwrap(); + println!("{:?}", &captured[1]); + assert!(&captured[1].starts_with("https")); + assert!(&captured[1].ends_with("add-more-pokemons")); + } +} diff --git a/src/main.rs b/src/main.rs index 5c757ab..7b6cc59 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,17 +1,29 @@ -use crate::match_logic::parse_url_from_git; +extern crate clap; +use clap::{crate_version, App, Arg}; + +use crate::actions::{open_repo, push_and_open_pr}; use anyhow::Result as AnyhowResult; -use std::process::{Command, Stdio}; +mod actions; mod match_logic; fn main() -> AnyhowResult<()> { - let git_repo = Command::new("git") - .args(&["config", "--get", "remote.origin.url"]) - .stdout(Stdio::piped()) - .output()?; - - let stdout = String::from_utf8(git_repo.stdout)?; - let parsed_url = parse_url_from_git(stdout)?; - webbrowser::open(&parsed_url)?; - Ok(()) + let matches = App::new("Gitopen") + .version(crate_version!()) + .author("Oren Epshtain") + .about("Utility to open repo from terminal and pull requests after push") + .arg( + Arg::with_name("push_and_pr") + .short("p") + .long("push-open-pr") + .help("Pushes to current branch and opens corresponding PR"), + ) + .get_matches(); + if matches.is_present("push_and_pr") { + push_and_open_pr()?; + Ok(()) + } else { + open_repo()?; + Ok(()) + } }