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:
parent
5e92f21a90
commit
921996c7ba
|
@ -0,0 +1 @@
|
||||||
|
export GHSTACK_TARGET_REPOSITORY="luqven/gh-stack"
|
|
@ -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",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
40
README.md
40
README.md
|
@ -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)
|
||||||
|
- [Usage](#usage)
|
||||||
- [Examples](#examples)
|
- [Examples](#examples)
|
||||||
- [Strategy](#strategy)
|
- [Strategy](#strategy)
|
||||||
- [Disclaimer](#disclaimer)
|
- [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"
|
||||||
|
|
82
src/main.rs
82
src/main.rs
|
@ -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
|
||||||
|
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()
|
||||||
);
|
);
|
||||||
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"));
|
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() {
|
||||||
|
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()
|
||||||
);
|
);
|
||||||
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 {
|
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,7 +264,12 @@ 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(
|
||||||
|
stack,
|
||||||
|
&project,
|
||||||
|
remote.name().unwrap(),
|
||||||
|
m.value_of("boundary"),
|
||||||
|
)
|
||||||
.await?;
|
.await?;
|
||||||
println!("All done!");
|
println!("All done!");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue