diff --git a/.gh-stack.env b/.gh-stack.env new file mode 100644 index 0000000..4a5abe6 --- /dev/null +++ b/.gh-stack.env @@ -0,0 +1 @@ +export GHSTACK_TARGET_REPOSITORY="luqven/gh-stack" \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ab6a615..da19946 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.10" @@ -317,7 +319,7 @@ dependencies = [ [[package]] name = "gh-stack" -version = "0.1.7" +version = "0.1.8" dependencies = [ "clap", "console", diff --git a/Cargo.toml b/Cargo.toml index a164914..5b33c1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,9 +1,9 @@ [package] name = "gh-stack" -version = "0.1.7" -authors = ["Timothy Andrew "] +version = "0.1.8" +authors = ["Timothy Andrew , Luis Ball "] license = "MIT" -repository = "https://github.com/timothyandrew/gh-stack" +repository = "https://github.com/luqven/gh-stack" readme = "README.md" edition = "2018" description = "Manage stacked PR workflows on Github" diff --git a/README.md b/README.md index 170e132..aef3acd 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,14 @@ It then looks for all PRs containing this containing this identifier and builds --- -- [Installation](#installation) -- [Usage](#usage) - - [Examples](#examples) -- [Strategy](#strategy) -- [Disclaimer](#disclaimer) +- [gh-stack](#gh-stack) + - [Installation](#installation) + - [Usage](#usage) + - [Examples](#examples) + - [Strategy](#strategy) + - [Disclaimer](#disclaimer) + - [Contributors](#contributors) + - [Credits](#credits) ## Installation @@ -46,11 +49,20 @@ $ cd gh-stack $ cargo install --force --path . ``` +```bash +# Required. +# Make sure to give your token read/write access to repositories you want to manage. +$ export GHSTACK_OAUTH_TOKEN='' +# Optional, but recommended. +# If you don't supply this environment variable, you have to pass the `--repository` or `-r` flag to `gh-stack` commands. +$ export GHSTACK_TARGET_REPOSITORY='' +``` + +You can also store these tokens in a file named `.gh-stack.env` in the project root. + ## Usage ```bash -$ export GHSTACK_OAUTH_TOKEN='' - $ gh-stack USAGE: @@ -65,18 +77,16 @@ SUBCOMMANDS: log Print a list of all pull requests in a stack to STDOUT rebase Print a bash script to STDOUT that can rebase/update the stack (with a little help) -# Print a description of the stack to stdout. +# Print a description of the stack to stdout. for a specific repository. $ gh-stack log 'stack-identifier' -# Same as above, but for a specific repository. -$ gh-stack log 'stack-identifier' -r 'repo-name' - -# Idempotently add a markdown table summarizing the stack -# to the description of each PR in the stack. +# # Idempotently add a markdown table summarizing the stack +# to the description of each PR in the stack for a specific repository. $ gh-stack annotate 'stack-identifier' -# Same as above, but for a specific repository. -$ gh-stack annotate 'stack-identifier' -r 'repo-name' +# Same as above, but precede the markdown table with the +# contents of `filename.txt`. +$ gh-stack annotate 'stack-identifier' -p filename.txt # Same as above, but precede the markdown table with the # contents of `filename.txt`. @@ -193,7 +203,7 @@ _This is a quick overview of the ways this tool could be used in practice._ 8. Use the `autorebase` subcommand to fix this inconsistency (it requires a path to a local checkout of the repository): ```bash - $ gh-stack autorebase --repo /tmp/test EXAMPLE-13799 + $ gh-stack autorebase --project /tmp/test EXAMPLE-13799 Checking out Commit { id: 803101159653bf4bf92bf098e577abc436458b17, summary: "initial commit" } Working on PR: "first" diff --git a/src/main.rs b/src/main.rs index 5551471..66b1437 100644 --- a/src/main.rs +++ b/src/main.rs @@ -115,7 +115,12 @@ async fn build_pr_stack_for_repo( credentials: &Credentials, exclude: Vec, ) -> Result> { - let prs = api::search::fetch_matching_pull_requests_from_repository(pattern, repository, &credentials).await?; + let prs = api::search::fetch_matching_pull_requests_from_repository( + pattern, + repository, + &credentials, + ) + .await?; let prs = prs .into_iter() @@ -138,7 +143,7 @@ fn get_excluded(m: &ArgMatches) -> Vec { #[tokio::main] async fn main() -> Result<(), Box> { - dotenv::from_filename(".gh-stack").ok(); + dotenv::from_filename(".gh-stack.env").ok(); let token = env::var("GHSTACK_OAUTH_TOKEN").expect("You didn't pass `GHSTACK_OAUTH_TOKEN`"); let credentials = Credentials::new(&token); @@ -147,19 +152,28 @@ async fn main() -> Result<(), Box> { match matches.subcommand() { ("annotate", Some(m)) => { let identifier = m.value_of("identifier").unwrap(); - // If no repository is specified, use build_pr_stack. Otherwise, use - // build_pr_stack_for_repo. - let stack = if m.value_of("repository").is_none() { - build_pr_stack(identifier, &credentials, get_excluded(m)).await? - } else { - let repository = m.value_of("repository").unwrap(); - println!( - "Searching for {} identifier in {} repo", - style(identifier).bold(), - style(repository).bold() + + // store the value of GHSTACK_TARGET_REPOSITORY + let repository = env::var("GHSTACK_TARGET_REPOSITORY").unwrap_or_default(); + // replace it with the -r argument value if set + let repository = m.value_of("repository").unwrap_or(&repository); + // if repository is still unset, throw an error + if repository.is_empty() { + panic!( + "You must pass a repository with the -r flag or set GHSTACK_TARGET_REPOSITORY" ); - build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)).await? - }; + } + + println!( + "Searching for {} identifier in {} repo", + style(identifier).bold(), + style(repository).bold() + ); + + let stack = + build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)) + .await?; + let table = markdown::build_table(&stack, identifier, m.value_of("prelude")); for (pr, _) in stack.iter() { @@ -175,19 +189,25 @@ async fn main() -> Result<(), Box> { ("log", Some(m)) => { let identifier = m.value_of("identifier").unwrap(); - // If no repository is specified, use build_pr_stack. Otherwise, use - // build_pr_stack_for_repo. - let stack = if m.value_of("repository").is_none() { - build_pr_stack(identifier, &credentials, get_excluded(m)).await? - } else { - let repository = m.value_of("repository").unwrap(); - println!( - "Searching for {} identifier in {} repo", - style(identifier).bold(), - style(repository).bold() + // store the value of GHSTACK_TARGET_REPOSITORY + let repository = env::var("GHSTACK_TARGET_REPOSITORY").unwrap_or_default(); + // replace it with the -r argument value if set + let repository = m.value_of("repository").unwrap_or(&repository); + // if repository is still unset, throw an error + if repository.is_empty() { + panic!( + "You must pass a repository with the -r flag or set GHSTACK_TARGET_REPOSITORY" ); - build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)).await? - }; + } + + println!( + "Searching for {} identifier in {} repo", + style(identifier).bold(), + style(repository).bold() + ); + let stack = + build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)) + .await?; for (pr, maybe_parent) in stack { match maybe_parent { @@ -214,15 +234,26 @@ async fn main() -> Result<(), Box> { ("autorebase", Some(m)) => { let identifier = m.value_of("identifier").unwrap(); - // Log an error if repository is not specified. - m.value_of("repository").expect("The --repository argument is required."); - let repository = m.value_of("repository").unwrap(); + + // store the value of GHSTACK_TARGET_REPOSITORY + let repository = env::var("GHSTACK_TARGET_REPOSITORY").unwrap_or_default(); + // replace it with the -r argument value if set + let repository = m.value_of("repository").unwrap_or(&repository); + // if repository is still unset, throw an error + if repository.is_empty() { + panic!( + "You must pass a repository with the -r flag or set GHSTACK_TARGET_REPOSITORY" + ); + } + println!( "Searching for {} identifier in {} repo", style(identifier).bold(), style(repository).bold() ); - let stack = build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)).await?; + let stack = + build_pr_stack_for_repo(identifier, repository, &credentials, get_excluded(m)) + .await?; let project = m .value_of("project") @@ -233,8 +264,13 @@ async fn main() -> Result<(), Box> { let remote = m.value_of("origin").unwrap_or("origin"); let remote = project.find_remote(remote).unwrap(); - git::perform_rebase(stack, &project, remote.name().unwrap(), m.value_of("boundary")) - .await?; + git::perform_rebase( + stack, + &project, + remote.name().unwrap(), + m.value_of("boundary"), + ) + .await?; println!("All done!"); }