feat!: require repo argument (#11)

* feat: require repo argument

* docs(readme): update repo flag

* chore: add target repo

* refactor: change gh-stack to env file

* chore: bump version to 0.1.8
This commit is contained in:
Luis H. Ball Jr 2021-11-18 20:41:28 -08:00 committed by Luis Ball
parent 5e92f21a90
commit 921996c7ba
5 changed files with 101 additions and 52 deletions

1
.gh-stack.env Normal file
View File

@ -0,0 +1 @@
export GHSTACK_TARGET_REPOSITORY="luqven/gh-stack"

4
Cargo.lock generated
View File

@ -1,5 +1,7 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
version = 3
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.10" version = "0.7.10"
@ -317,7 +319,7 @@ dependencies = [
[[package]] [[package]]
name = "gh-stack" name = "gh-stack"
version = "0.1.7" version = "0.1.8"
dependencies = [ dependencies = [
"clap", "clap",
"console", "console",

View File

@ -1,9 +1,9 @@
[package] [package]
name = "gh-stack" name = "gh-stack"
version = "0.1.7" version = "0.1.8"
authors = ["Timothy Andrew <mail@timothyandrew.net>"] authors = ["Timothy Andrew <mail@timothyandrew.net>, Luis Ball <luqven@gmail.com>"]
license = "MIT" license = "MIT"
repository = "https://github.com/timothyandrew/gh-stack" repository = "https://github.com/luqven/gh-stack"
readme = "README.md" readme = "README.md"
edition = "2018" edition = "2018"
description = "Manage stacked PR workflows on Github" description = "Manage stacked PR workflows on Github"

View File

@ -20,11 +20,14 @@ It then looks for all PRs containing this containing this identifier and builds
--- ---
- [Installation](#installation) - [gh-stack](#gh-stack)
- [Usage](#usage) - [Installation](#installation)
- [Examples](#examples) - [Usage](#usage)
- [Strategy](#strategy) - [Examples](#examples)
- [Disclaimer](#disclaimer) - [Strategy](#strategy)
- [Disclaimer](#disclaimer)
- [Contributors](#contributors)
- [Credits](#credits)
## Installation ## Installation
@ -46,11 +49,20 @@ $ cd gh-stack
$ cargo install --force --path . $ 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='<personal access 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='<github repository name>'
```
You can also store these tokens in a file named `.gh-stack.env` in the project root.
## Usage ## Usage
```bash ```bash
$ export GHSTACK_OAUTH_TOKEN='<personal access token>'
$ gh-stack $ gh-stack
USAGE: USAGE:
@ -65,18 +77,16 @@ SUBCOMMANDS:
log Print a list of all pull requests in a stack to STDOUT 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) 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' $ gh-stack log 'stack-identifier'
# Same as above, but for a specific repository. # # Idempotently add a markdown table summarizing the stack
$ gh-stack log 'stack-identifier' -r 'repo-name' # to the description of each PR in the stack for a specific repository.
# Idempotently add a markdown table summarizing the stack
# to the description of each PR in the stack.
$ gh-stack annotate 'stack-identifier' $ gh-stack annotate 'stack-identifier'
# Same as above, but for a specific repository. # Same as above, but precede the markdown table with the
$ gh-stack annotate 'stack-identifier' -r 'repo-name' # contents of `filename.txt`.
$ gh-stack annotate 'stack-identifier' -p filename.txt
# Same as above, but precede the markdown table with the # Same as above, but precede the markdown table with the
# contents of `filename.txt`. # 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): 8. Use the `autorebase` subcommand to fix this inconsistency (it requires a path to a local checkout of the repository):
```bash ```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" } Checking out Commit { id: 803101159653bf4bf92bf098e577abc436458b17, summary: "initial commit" }
Working on PR: "first" Working on PR: "first"

View File

@ -115,7 +115,12 @@ async fn build_pr_stack_for_repo(
credentials: &Credentials, credentials: &Credentials,
exclude: Vec<String>, exclude: Vec<String>,
) -> Result<FlatDep, Box<dyn Error>> { ) -> Result<FlatDep, Box<dyn Error>> {
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 let prs = prs
.into_iter() .into_iter()
@ -138,7 +143,7 @@ fn get_excluded(m: &ArgMatches) -> Vec<String> {
#[tokio::main] #[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> { async fn main() -> Result<(), Box<dyn Error>> {
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 token = env::var("GHSTACK_OAUTH_TOKEN").expect("You didn't pass `GHSTACK_OAUTH_TOKEN`");
let credentials = Credentials::new(&token); let credentials = Credentials::new(&token);
@ -147,19 +152,28 @@ async fn main() -> Result<(), Box<dyn Error>> {
match matches.subcommand() { match matches.subcommand() {
("annotate", Some(m)) => { ("annotate", Some(m)) => {
let identifier = m.value_of("identifier").unwrap(); let identifier = m.value_of("identifier").unwrap();
// If no repository is specified, use build_pr_stack. Otherwise, use
// build_pr_stack_for_repo. // store the value of GHSTACK_TARGET_REPOSITORY
let stack = if m.value_of("repository").is_none() { let repository = env::var("GHSTACK_TARGET_REPOSITORY").unwrap_or_default();
build_pr_stack(identifier, &credentials, get_excluded(m)).await? // replace it with the -r argument value if set
} else { let repository = m.value_of("repository").unwrap_or(&repository);
let repository = m.value_of("repository").unwrap(); // if repository is still unset, throw an error
println!( if repository.is_empty() {
"Searching for {} identifier in {} repo", panic!(
style(identifier).bold(), "You must pass a repository with the -r flag or set GHSTACK_TARGET_REPOSITORY"
style(repository).bold()
); );
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")); let table = markdown::build_table(&stack, identifier, m.value_of("prelude"));
for (pr, _) in stack.iter() { for (pr, _) in stack.iter() {
@ -175,19 +189,25 @@ async fn main() -> Result<(), Box<dyn Error>> {
("log", Some(m)) => { ("log", Some(m)) => {
let identifier = m.value_of("identifier").unwrap(); let identifier = m.value_of("identifier").unwrap();
// If no repository is specified, use build_pr_stack. Otherwise, use // store the value of GHSTACK_TARGET_REPOSITORY
// build_pr_stack_for_repo. let repository = env::var("GHSTACK_TARGET_REPOSITORY").unwrap_or_default();
let stack = if m.value_of("repository").is_none() { // replace it with the -r argument value if set
build_pr_stack(identifier, &credentials, get_excluded(m)).await? let repository = m.value_of("repository").unwrap_or(&repository);
} else { // if repository is still unset, throw an error
let repository = m.value_of("repository").unwrap(); if repository.is_empty() {
println!( panic!(
"Searching for {} identifier in {} repo", "You must pass a repository with the -r flag or set GHSTACK_TARGET_REPOSITORY"
style(identifier).bold(),
style(repository).bold()
); );
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 { for (pr, maybe_parent) in stack {
match maybe_parent { match maybe_parent {
@ -214,15 +234,26 @@ async fn main() -> Result<(), Box<dyn Error>> {
("autorebase", Some(m)) => { ("autorebase", Some(m)) => {
let identifier = m.value_of("identifier").unwrap(); 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."); // store the value of GHSTACK_TARGET_REPOSITORY
let repository = m.value_of("repository").unwrap(); 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!( println!(
"Searching for {} identifier in {} repo", "Searching for {} identifier in {} repo",
style(identifier).bold(), style(identifier).bold(),
style(repository).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 let project = m
.value_of("project") .value_of("project")
@ -233,8 +264,13 @@ async fn main() -> Result<(), Box<dyn Error>> {
let remote = m.value_of("origin").unwrap_or("origin"); let remote = m.value_of("origin").unwrap_or("origin");
let remote = project.find_remote(remote).unwrap(); let remote = project.find_remote(remote).unwrap();
git::perform_rebase(stack, &project, remote.name().unwrap(), m.value_of("boundary")) git::perform_rebase(
.await?; stack,
&project,
remote.name().unwrap(),
m.value_of("boundary"),
)
.await?;
println!("All done!"); println!("All done!");
} }