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.
# 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",

View File

@ -1,9 +1,9 @@
[package]
name = "gh-stack"
version = "0.1.7"
authors = ["Timothy Andrew <mail@timothyandrew.net>"]
version = "0.1.8"
authors = ["Timothy Andrew <mail@timothyandrew.net>, Luis Ball <luqven@gmail.com>"]
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"

View File

@ -20,11 +20,14 @@ It then looks for all PRs containing this containing this identifier and builds
---
- [Installation](#installation)
- [Usage](#usage)
- [gh-stack](#gh-stack)
- [Installation](#installation)
- [Usage](#usage)
- [Examples](#examples)
- [Strategy](#strategy)
- [Disclaimer](#disclaimer)
- [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='<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
```bash
$ export GHSTACK_OAUTH_TOKEN='<personal access 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"

View File

@ -115,7 +115,12 @@ async fn build_pr_stack_for_repo(
credentials: &Credentials,
exclude: Vec<String>,
) -> 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
.into_iter()
@ -138,7 +143,7 @@ fn get_excluded(m: &ArgMatches) -> Vec<String> {
#[tokio::main]
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 credentials = Credentials::new(&token);
@ -147,19 +152,28 @@ async fn main() -> Result<(), Box<dyn Error>> {
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();
// 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()
);
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 table = markdown::build_table(&stack, identifier, m.value_of("prelude"));
for (pr, _) in stack.iter() {
@ -175,19 +189,25 @@ async fn main() -> Result<(), Box<dyn Error>> {
("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();
// 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()
);
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?;
for (pr, maybe_parent) in stack {
match maybe_parent {
@ -214,15 +234,26 @@ async fn main() -> Result<(), Box<dyn Error>> {
("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,7 +264,12 @@ async fn main() -> Result<(), Box<dyn Error>> {
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"))
git::perform_rebase(
stack,
&project,
remote.name().unwrap(),
m.value_of("boundary"),
)
.await?;
println!("All done!");
}