Compare commits

...

54 Commits
v0.1.1 ... main

Author SHA1 Message Date
a2849226ce
chore(release) with args 2023-01-12 07:32:05 +01:00
a6c26a9213
chore(release) with bug fixes 2023-01-12 07:29:49 +01:00
5ea2ff445a
fix tests 2023-01-12 07:28:29 +01:00
819e5d23bb
with more options 2023-01-12 07:26:44 +01:00
5ac9d474f2
chore(release) with github review
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-11 22:48:59 +01:00
d9ddb7139b
hardcode to @me
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-11 22:46:20 +01:00
c933073e32 Merge pull request 'feature/review' (#6) from feature/review into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #6
2023-01-11 21:45:17 +00:00
6f3625c2fe Merge pull request 'feature/review-add-select' (#5) from feature/review-add-select into feature/review
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
Reviewed-on: #5
2023-01-11 21:40:45 +00:00
35b50d802a Merge pull request 'Added display review' (#4) from feature/review into main
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #4
2023-01-11 21:40:35 +00:00
92eab2361e
with actual review functionality
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-01-11 22:39:42 +01:00
97e988e99e
fixed tests
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-01-10 22:54:18 +01:00
784329a703
limit table to 20 items
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-10 22:33:35 +01:00
f912217549
colored table
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-10 22:33:11 +01:00
06b673286a
Added display review
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing
2023-01-10 22:27:12 +01:00
0cfd38e682
chore(release) git pull should not cause error if no upstream
Some checks failed
continuous-integration/drone/push Build is failing
2023-01-10 20:21:11 +01:00
a1f337dac2 Update all dependencies
Some checks failed
continuous-integration/drone/pr Build is passing
continuous-integration/drone/push Build is failing
2022-12-22 19:46:31 +00:00
64897d32e4
chore(release) fix errors 2022-12-19 10:11:05 +01:00
0408fe856d
chore(release) with updated formula for sourcegraph tap 2022-12-19 09:20:58 +01:00
4e3b711567
chore(release) with dependencies v0.1.7
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 23:18:42 +01:00
7f0bff57eb
forgot string
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 23:18:05 +01:00
92f167e7e8
fix name of drone
All checks were successful
continuous-integration/drone/push Build is passing
2022-12-18 23:14:11 +01:00
c7ebd6350e
chore(release) v0.1.6
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/tag Build is failing
2022-12-18 23:10:29 +01:00
d7d55d24f5
with proper name for version
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone Build is failing
2022-12-18 23:01:43 +01:00
6381c189cb
correct binName
Some checks failed
continuous-integration/drone Build is failing
2022-12-18 22:54:52 +01:00
d0568e48ec
with drone 2022-12-18 22:54:28 +01:00
f66a6c858d
chore(release) with dependencies v0.1.5 2022-12-18 22:53:14 +01:00
267d546d2e
chore(release) with dependencies 2022-12-18 22:49:48 +01:00
87c9c36f6c
Add new dependencies 2022-12-18 22:48:29 +01:00
2f19707e94
chore(release) with updated version 2022-12-18 22:40:18 +01:00
a79d0ee6d4
chore(release) working on homebrew tap releaser 2022-12-18 22:30:16 +01:00
32ad2b3fd7
remove constraint 2022-12-18 22:29:18 +01:00
0a3a4d4f74
updated tag name 2022-12-18 22:28:04 +01:00
95f3254f81
chore(release) with updated version 2022-12-18 22:24:08 +01:00
5894bd5bb1
chore(release) fix pipeline 2022-12-18 22:21:07 +01:00
560f8f4fd0
chore(release) rename again 2022-12-18 22:12:17 +01:00
e1d8e27c23
rename formulas 2022-12-18 22:06:54 +01:00
2e19df72b0
chore(release) working on homebrew tap releaser 2022-12-18 22:03:21 +01:00
08b3e1cf5b
chore(release) working on homebrew tap releaser 2022-12-18 21:56:54 +01:00
d592b5f2d8
brew github token 2022-12-18 21:56:27 +01:00
3f06afce02
chore(release) with other owner 2022-12-18 21:45:29 +01:00
d553bf06b7
remove arrow 2022-12-18 21:39:35 +01:00
7427f8f8d8
chore(release) with debug 2022-12-18 21:37:13 +01:00
e350d8c13d
chore(release) with tag in release 2022-12-18 21:32:26 +01:00
27f5287c82
chore(release) with renamed release 2022-12-18 21:27:21 +01:00
cf7ce40afd
move releaser 2022-12-18 21:22:18 +01:00
8149da56fb
chore(release) working on homebrew tap releaser 2022-12-18 21:18:29 +01:00
af591b9802
fix lock 2022-12-18 21:15:36 +01:00
300d16d630
chore(release) working on homebrew tap releaser 2022-12-18 21:13:45 +01:00
09f6ad35f9
with license-file 2022-12-18 21:10:10 +01:00
64f853d025
with bin install 2022-12-18 21:06:42 +01:00
07a2143d50
with homebrew releaser 2022-12-18 21:05:31 +01:00
0ca6347f1f
chore(release) add github release 2022-12-18 20:18:08 +01:00
9fc27f2c0e
with required fields 2022-12-18 20:14:28 +01:00
98cb397ea9
add releaser 2022-12-18 20:05:49 +01:00
22 changed files with 1356 additions and 33 deletions

5
.drone.yml Normal file
View File

@ -0,0 +1,5 @@
kind: template
load: bust_rustbin_default_template.yaml
name: toolkit
data:
binName: toolkit

89
.github/workflows/release-published.yml vendored Normal file
View File

@ -0,0 +1,89 @@
name: release-published
on:
release:
types: [published]
jobs:
brew-releaser:
name: Homebrew releaser
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Release to homebrew tap
uses: Justintime50/homebrew-releaser@v1
with:
# The name of the homebrew tap to publish your formula to as it appears on GitHub.
# Required - strings.
homebrew_owner: kjuulh
homebrew_tap: homebrew-brew
# The name of the folder in your homebrew tap where formula will be committed to.
# Default is shown - string.
formula_folder: formula
# The GitHub Token (saved as a repo secret) that has `repo` permissions for the homebrew tap you want to release to.
# Required - string.
github_token: ${{ secrets.BREW_GITHUB_TOKEN }}
# Git author info used to commit to the homebrew tap.
# Defaults are shown - strings.
commit_owner: kjuulh
commit_email: homebrew-releaser@kjuulh.io
# Custom dependencies in case other formulas are needed to build the current one.
# Optional - multiline string.
depends_on: |
"fzf"
"gh"
"dust"
"bottom"
"procs"
"sourcegraph/src-cli/src-cli"
"tokei"
"bandwhich"
# Custom install command for your formula.
# Required - string.
install: 'bin.install "toolkit"'
# Custom test command for your formula so you can run `brew test`.
# Optional - string.
#test: 'assert_match("my script output", shell_output("my-script-command"))'
# Adds URL and checksum targets for different OS and architecture pairs. Using this option assumes
# a tar archive exists on your GitHub repo with the following URL pattern (this cannot be customized):
# https://github.com/{GITHUB_OWNER}/{REPO_NAME}/releases/download/{TAG}/{REPO_NAME}-{VERSION}-{OPERATING_SYSTEM}-{ARCHITECTURE}.tar.gz'
# Darwin AMD pre-existing path example: https://github.com/justintime50/myrepo/releases/download/v1.2.0/myrepo-1.2.0-darwin-amd64.tar.gz
# Linux ARM pre-existing path example: https://github.com/justintime50/myrepo/releases/download/v1.2.0/myrepo-1.2.0-linux-arm64.tar.gz
# Optional - booleans.
target_darwin_amd64: true
target_darwin_arm64: true
target_linux_amd64: true
target_linux_arm64: true
# Update your homebrew tap's README with a table of all projects in the tap.
# This is done by pulling the information from all your formula.rb files - eg:
#
# | Project | Description | Install |
# | ------------------------------------------ | ------------ | ------------------------ |
# | [formula_1](https://github.com/user/repo1) | helpful text | `brew install formula_1` |
# | [formula_2](https://github.com/user/repo2) | helpful text | `brew install formula_2` |
# | [formula_3](https://github.com/user/repo3) | helpful text | `brew install formula_3` |
#
# Simply place the following in your README or wrap your project in these comment tags:
# <!-- project_table_start -->
# TABLE HERE
# <!--project_table_end -->
#
# Finally, mark `update_readme_table` as `true` in your GitHub Action config and we'll do the work of building a custom table for you.
# Default is `false` - boolean.
update_readme_table: true
# Skips committing the generated formula to a homebrew tap (useful for local testing).
# Default is shown - boolean.
skip_commit: false
# Logs debugging info to console.
# Default is shown - boolean.
debug: true

114
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,114 @@
name: release
on:
push:
branches:
- main
- next
pull_request:
workflow_dispatch:
env:
CARGO_INCREMENTAL: 0
jobs:
release:
name: ${{ matrix.target }}
permissions:
contents: write
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
target: x86_64-unknown-linux-musl
release-target: linux-amd64
deb: true
- os: ubuntu-latest
target: arm-unknown-linux-musleabihf
release-target: linux-arm
- os: ubuntu-latest
target: armv7-unknown-linux-musleabihf
release-target: linux-arm7
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
release-target: linux-arm64
deb: true
- os: macos-11
target: x86_64-apple-darwin
release-target: darwin-amd64
- os: macos-11
target: aarch64-apple-darwin
release-target: darwin-arm64
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Get version
id: get_version
run: sed -En 's/^version = "(.*)"/value=\1/p' Cargo.toml >> $GITHUB_OUTPUT
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
profile: minimal
override: true
target: ${{ matrix.target }}
- name: Setup cache
uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.target }}
- name: Build binary
uses: actions-rs/cargo@v1
with:
command: build
args: --release --locked --target=${{ matrix.target }} --color=always --verbose
use-cross: ${{ runner.os == 'Linux' }}
- name: Install cargo-deb
if: ${{ matrix.deb == true }}
uses: actions-rs/install@v0.1
with:
crate: cargo-deb
- name: Build deb
if: ${{ matrix.deb == true }}
uses: actions-rs/cargo@v1
with:
command: deb
args: --no-build --no-strip --output=. --target=${{ matrix.target }}
- name: Package (*nix)
if: runner.os != 'Windows'
run: >
tar -cv
LICENSE README.md
man/
-C target/${{ matrix.target }}/release/ toolkit
| gzip --best
> 'toolkit-${{ steps.get_version.outputs.value }}-${{ matrix.release-target }}.tar.gz'
- name: Upload artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.release-target }}
path: |
*.deb
*.tar.gz
*.zip
- name: Create release
if: ${{ github.ref == 'refs/heads/main' && startsWith(github.event.head_commit.message, 'chore(release)') }}
uses: softprops/action-gh-release@v1
with:
draft: true
files: |
*.deb
*.tar.gz
*.zip
name: v${{ steps.get_version.outputs.value }}
tag_name: v${{ steps.get_version.outputs.value }}

469
Cargo.lock generated
View File

@ -2,6 +2,27 @@
# It is not intended for manual editing.
version = 3
[[package]]
name = "aho-corasick"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "base64"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
[[package]]
name = "bitflags"
version = "1.3.2"
@ -22,9 +43,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.0.29"
version = "4.0.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
dependencies = [
"bitflags",
"clap_lex",
@ -43,6 +64,65 @@ dependencies = [
"os_str_bytes",
]
[[package]]
name = "comfy-table"
version = "6.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e7b787b0dc42e8111badfdbe4c3059158ccb2db8780352fa1b01e8ccf45cc4d"
dependencies = [
"crossterm",
"strum",
"strum_macros",
"unicode-width",
]
[[package]]
name = "crossterm"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67"
dependencies = [
"bitflags",
"crossterm_winapi",
"libc",
"mio",
"parking_lot",
"signal-hook",
"signal-hook-mio",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c"
dependencies = [
"winapi",
]
[[package]]
name = "ctor"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096"
dependencies = [
"quote",
"syn",
]
[[package]]
name = "diff"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
[[package]]
name = "difflib"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8"
[[package]]
name = "dirs"
version = "4.0.0"
@ -63,6 +143,18 @@ dependencies = [
"winapi",
]
[[package]]
name = "downcast"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1"
[[package]]
name = "either"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
[[package]]
name = "errno"
version = "0.2.8"
@ -94,6 +186,21 @@ dependencies = [
"once_cell",
]
[[package]]
name = "float-cmp"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4"
dependencies = [
"num-traits",
]
[[package]]
name = "fragile"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa"
[[package]]
name = "getrandom"
version = "0.2.8"
@ -109,12 +216,25 @@ dependencies = [
name = "github"
version = "0.1.0"
dependencies = [
"base64",
"clap",
"comfy-table",
"dirs",
"eyre",
"mockall",
"pretty_assertions",
"serde",
"serde_json",
"thiserror",
"util",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.2.6"
@ -152,6 +272,27 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "itertools"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
dependencies = [
"either",
]
[[package]]
name = "itoa"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
version = "0.2.138"
@ -164,6 +305,85 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "mio"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
]
[[package]]
name = "mockall"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50e4a1c770583dac7ab5e2f6c139153b783a53a1bbee9729613f193e59828326"
dependencies = [
"cfg-if",
"downcast",
"fragile",
"lazy_static",
"mockall_derive",
"predicates",
"predicates-tree",
]
[[package]]
name = "mockall_derive"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "832663583d5fa284ca8810bf7015e46c9fff9622d3cf34bd1eea5003fec06dd0"
dependencies = [
"cfg-if",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "normalize-line-endings"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be"
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "once_cell"
version = "1.16.0"
@ -177,19 +397,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "proc-macro2"
version = "1.0.47"
name = "output_vt100"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66"
dependencies = [
"winapi",
]
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "predicates"
version = "2.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd"
dependencies = [
"difflib",
"float-cmp",
"itertools",
"normalize-line-endings",
"predicates-core",
"regex",
]
[[package]]
name = "predicates-core"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72f883590242d3c6fc5bf50299011695fa6590c2c70eac95ee1bdb9a733ad1a2"
[[package]]
name = "predicates-tree"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54ff541861505aabf6ea722d2131ee980b8276e10a1297b94e896dd8b621850d"
dependencies = [
"predicates-core",
"termtree",
]
[[package]]
name = "pretty_assertions"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755"
dependencies = [
"ctor",
"diff",
"output_vt100",
"yansi",
]
[[package]]
name = "proc-macro2"
version = "1.0.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.21"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
@ -214,6 +508,23 @@ dependencies = [
"thiserror",
]
[[package]]
name = "regex"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "rustix"
version = "0.36.5"
@ -228,6 +539,18 @@ dependencies = [
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
[[package]]
name = "ryu"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "same-file"
version = "1.0.6"
@ -237,6 +560,79 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "signal-hook"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
dependencies = [
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-mio"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "sourcegraph"
version = "0.1.0"
@ -264,10 +660,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.105"
name = "strum"
version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f"
[[package]]
name = "strum_macros"
version = "0.24.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59"
dependencies = [
"heck",
"proc-macro2",
"quote",
"rustversion",
"syn",
]
[[package]]
name = "syn"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
@ -284,19 +699,25 @@ dependencies = [
]
[[package]]
name = "thiserror"
version = "1.0.37"
name = "termtree"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
checksum = "95059e91184749cb66be6dc994f67f182b6d897cb3df74a5bf66b5e709295fd8"
[[package]]
name = "thiserror"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.37"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
dependencies = [
"proc-macro2",
"quote",
@ -316,7 +737,7 @@ dependencies = [
[[package]]
name = "toolkit"
version = "0.1.0"
version = "0.1.14"
dependencies = [
"clap",
"eyre",
@ -329,9 +750,15 @@ dependencies = [
[[package]]
name = "unicode-ident"
version = "1.0.5"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "unicode-width"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "util"
@ -445,3 +872,9 @@ name = "windows_x86_64_msvc"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "yansi"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"

View File

@ -1,7 +1,11 @@
[package]
name = "toolkit"
version = "0.1.0"
description = "Toolkit is an opinionated toolkit complementing a personal development workflow. Many of the commands are quite verbose, and well suited for adding to your shell toolbelt"
version = "0.1.14"
edition = "2021"
license-file = "LICENSE"
authors = ["Kasper J. Hermansen contact@kjuulh.io"]
readme = "README.md"
[workspace]
members = [
@ -13,7 +17,7 @@ members = [
]
[workspace.dependencies]
clap = { version = "4.0.29", features = ["cargo"] }
clap = { version = "4.0.32", features = ["cargo"] }
eyre = "0.6.8"
dirs = "4.0.0"
walkdir = "2.3.2"

0
LICENSE Normal file
View File

61
README.md Normal file
View File

@ -0,0 +1,61 @@
# Toolkit
This is an opinionated toolkit, which reflect my (@kjuulh) way of working. This
project aims to enhance a general workflow, and provides tools that may be
useful outside of project work. For project work see repo:kjuulh/bust or
repo:kjuulh/char, which aims for the same thing, but for projects themselves.
## Install
Currenly I only publish homebrew packages, however, all artifacts are released
via. released, that includes deb packages as well.
### Homebrew
```
brew install kjuulh/brew/toolkit
```
## Configuration
To use toolkit you will need a series of environment variables, they are only
needed if you need the associated tool.
```
export SRC_ENDPOINT=https://sourcegraph.com
export SRC_ACCESS_TOKEN=
export GITHUB_FC_ROOT="/Users/<username>/git/github.com"
export GITHUB_FC_ORGS="kjuulh"
```
`SRC` is sourcegraph integration. The endpoint is either to the public instance,
or your own domain. The access token is a personal access token. If either of
these are missing. A prompt will be shown on the first run
`GITHUB_FC` is the fuzzy clone setup. First is the destination path, this is
where the orgs will be placed. Second is ORGS, that is which orgs to subscribe
to. The total path in this case will end up being
`/Users/<username>/git/github.com/kjuulh`.
You will also require other integration such as a GitHub integration through
`gh`.
## Usage
```
Usage: toolkit <COMMAND>
Commands:
prereqs
tldr
sourcegraph
github
stats
init
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help information
```
![demo](assets/demo.gif)

BIN
assets/demo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

View File

@ -11,3 +11,13 @@ util = { path = "../util" }
eyre.workspace = true
clap.workspace = true
dirs.workspace = true
serde = { version = "1.0.152", features = ["derive"] }
serde_json = "1.0.91"
comfy-table = "6.1.4"
pretty_assertions = "1.3.0"
base64 = "0.21.0"
thiserror = "1.0.38"
[dev-dependencies]
mockall = "0.11.2"

View File

@ -1,5 +1,6 @@
use std::io::Write;
use clap::value_parser;
use eyre::Context;
pub struct FuzzyClone;
@ -201,13 +202,18 @@ impl FuzzyClone {
}),
)?;
} else {
util::shell::run(&["git", "pull"], None)?;
let _ = util::shell::run(
&["git", "pull"],
Some(util::shell::RunOptions {
path: git_repo_path.clone(),
}),
);
}
Ok(git_repo_path)
}
fn run() -> eyre::Result<()> {
fn run(print_dest: &bool) -> eyre::Result<()> {
let settings = Self::get_settings()?;
if settings.auto_update {
println!("running auto update");
@ -234,10 +240,17 @@ impl FuzzyClone {
let chosen = util::shell::run_with_input_and_output(&["fzf"], entries_str)?;
let chosen = std::str::from_utf8(&chosen.stdout)?;
Self::clone(GitHubEntry::from(chosen.to_string()).ok_or(eyre::anyhow!(
let path = Self::clone(GitHubEntry::from(chosen.to_string()).ok_or(eyre::anyhow!(
"could not parse choice as github entry <org>/<repo>"
))?)?;
if *print_dest {
print!(
"{}",
path.to_str().ok_or(eyre::anyhow!("path was not found"))?
);
}
Ok(())
}
@ -255,13 +268,24 @@ impl util::Cmd for FuzzyClone {
Ok(clap::Command::new("fuzzy-clone")
.alias("fc")
.alias("c")
.arg(
clap::Arg::new("print-dest")
.long("print-dest")
.value_name("print-dest")
.value_parser(value_parser!(bool))
.num_args(0..=1)
.require_equals(true)
.default_missing_value("true"),
)
.subcommand(clap::Command::new("update")))
}
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
let print_dest = args.get_one::<bool>("print-dest").unwrap_or(&false);
match args.subcommand() {
Some(("update", _)) => Self::update()?,
_ => Self::run()?,
_ => Self::run(print_dest)?,
}
Ok(())

View File

@ -1,6 +1,8 @@
mod auth;
mod fuzzy_clone;
mod gh;
mod review;
pub(crate) mod review_backend;
pub struct GitHub;
@ -31,6 +33,7 @@ impl util::Cmd for GitHub {
auth::Auth::cmd()?,
gh::Gh::cmd()?,
fuzzy_clone::FuzzyClone::cmd()?,
review::Review::cmd()?,
])
.allow_external_subcommands(true))
}
@ -41,6 +44,7 @@ impl util::Cmd for GitHub {
Some(("fuzzy-clone", subm)) => fuzzy_clone::FuzzyClone::exec(subm),
Some(("fc", subm)) => fuzzy_clone::FuzzyClone::exec(subm),
Some(("gh", subm)) => gh::Gh::exec(subm),
Some(("review", subm)) => review::Review::exec(subm),
Some((external, args)) => Self::run(external, args),
_ => Err(eyre::anyhow!("missing argument")),
}

298
crates/github/src/review.rs Normal file
View File

@ -0,0 +1,298 @@
use crate::review_backend::{
models::{MenuChoice, MergeStrategy, PullRequest, ReviewMenuChoice},
DefaultReviewBackend, DynReviewBackend,
};
use comfy_table::{presets::UTF8_HORIZONTAL_ONLY, Cell, Table};
use thiserror::Error;
pub struct Review {
backend: DynReviewBackend,
}
impl Default for Review {
fn default() -> Self {
Self::new(std::sync::Arc::new(DefaultReviewBackend::new()))
}
}
#[derive(Debug, Error)]
pub enum ReviewErrors {
#[error("user chose to exit")]
UserExit,
}
impl Review {
fn new(backend: DynReviewBackend) -> Self {
Self { backend }
}
/// Workflow
/// 1. Fetch list of repos
/// 2. Present menu
/// 3. Choose begin quick review
/// 4. Present pr and use delta to view changes
/// 5. Approve, open, skip or quit
/// 6. Repeat from 4
fn run(
&self,
review_requested: Option<String>,
merge_strategy: &Option<MergeStrategy>,
) -> eyre::Result<()> {
let prs = self.backend.get_prs(review_requested.clone())?;
let prs_table = Self::generate_prs_table(&prs);
self.backend.present_prs(prs_table)?;
match self.backend.present_menu()? {
MenuChoice::Exit => eyre::bail!(ReviewErrors::UserExit),
MenuChoice::Begin => match self.review(&prs, &merge_strategy)? {
Some(choice) => match choice {
MenuChoice::Exit => eyre::bail!(ReviewErrors::UserExit),
MenuChoice::List => return self.run(review_requested.clone(), merge_strategy),
_ => eyre::bail!("invalid choice"),
},
None => {}
},
MenuChoice::Search => todo!(),
MenuChoice::List => return self.run(review_requested.clone(), merge_strategy),
}
Ok(())
}
fn generate_prs_table(prs: &[PullRequest]) -> String {
let mut table = Table::new();
let table = table
.load_preset(UTF8_HORIZONTAL_ONLY)
.set_content_arrangement(comfy_table::ContentArrangement::Dynamic)
.set_header(vec![
Cell::new("repo").add_attribute(comfy_table::Attribute::Bold),
Cell::new("title").add_attribute(comfy_table::Attribute::Bold),
Cell::new("number").add_attribute(comfy_table::Attribute::Bold),
])
.add_rows(prs.iter().take(20).map(|pr| {
let pr = pr.clone();
vec![
Cell::new(pr.repository.name).fg(comfy_table::Color::Green),
Cell::new(pr.title),
Cell::new(pr.number.to_string()),
]
}));
table.to_string()
}
fn review(
&self,
prs: &Vec<PullRequest>,
merge_strategy: &Option<MergeStrategy>,
) -> eyre::Result<Option<MenuChoice>> {
for pr in prs {
self.backend.clear()?;
self.backend.present_pr(pr)?;
self.review_pr(pr)?;
if let Some(choice) = self.present_pr_menu(pr, merge_strategy)? {
return Ok(Some(choice));
}
}
Ok(None)
}
fn review_pr(&self, pr: &PullRequest) -> eyre::Result<()> {
self.backend.present_diff(pr)?;
Ok(())
}
fn approve(&self, pr: &PullRequest) -> eyre::Result<()> {
self.backend.approve(pr)?;
Ok(())
}
fn open_browser(
&self,
pr: &PullRequest,
merge_strategy: &Option<MergeStrategy>,
) -> eyre::Result<Option<MenuChoice>> {
self.backend.pr_open_browser(pr)?;
self.present_pr_menu(pr, merge_strategy)
}
fn present_pr_menu(
&self,
pr: &PullRequest,
merge_strategy: &Option<MergeStrategy>,
) -> eyre::Result<Option<MenuChoice>> {
self.backend.present_pr(pr)?;
match self.backend.present_review_menu(pr)? {
ReviewMenuChoice::Exit => return Ok(Some(MenuChoice::Exit)),
ReviewMenuChoice::List => return Ok(Some(MenuChoice::List)),
ReviewMenuChoice::Approve => {
self.approve(pr)?;
return self.present_pr_menu(pr, merge_strategy);
}
ReviewMenuChoice::Open => return self.open_browser(pr, merge_strategy),
ReviewMenuChoice::Skip => {}
ReviewMenuChoice::Merge => self.merge(pr, merge_strategy)?,
ReviewMenuChoice::ApproveAndMerge => {
self.approve(pr)?;
self.merge(pr, merge_strategy)?;
}
}
Ok(None)
}
fn merge(&self, pr: &PullRequest, merge_strategy: &Option<MergeStrategy>) -> eyre::Result<()> {
self.backend.enable_auto_merge(pr, merge_strategy)?;
Ok(())
}
}
impl util::Cmd for Review {
fn cmd() -> eyre::Result<clap::Command> {
Ok(clap::Command::new("review")
.arg(
clap::Arg::new("review-requested")
.long("review-requested")
.default_value("@me")
.help("which user or team to pull reviews from"),
)
.arg(
clap::Arg::new("merge-strategy")
.long("merge-strategy")
.help(
"when merging which merge strategy to use, possible values: [squash, merge]",
),
))
}
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
let request_requested = args
.get_one::<String>("review-requested")
.map(|r| r.clone());
let squash = args
.get_one::<String>("merge-strategy")
.and_then(|s| match s.as_str() {
"squash" => Some(MergeStrategy::Squash),
"merge" => Some(MergeStrategy::MergeCommit),
_ => None,
});
Self::default().run(request_requested, &squash)
}
}
#[cfg(test)]
mod tests {
use crate::review_backend::{
models::{self, Repository},
MockReviewBackend,
};
use super::*;
use base64::Engine;
use mockall::predicate::eq;
use pretty_assertions::assert_eq;
#[test]
fn can_fetch_prs() {
let mut backend = MockReviewBackend::new();
let prs = vec![
PullRequest {
title: "some-title".into(),
number: 0,
repository: Repository {
name: "some-name".into(),
},
},
PullRequest {
title: "some-other-title".into(),
number: 1,
repository: Repository {
name: "some-other-name".into(),
},
},
];
let backendprs = prs.clone();
backend
.expect_get_prs()
.with(eq(Some("kjuulh".into())))
.times(1)
.returning(move |_| Ok(backendprs.clone()));
backend
.expect_present_menu()
.times(1)
.returning(|| Ok(models::MenuChoice::Exit));
backend.expect_present_prs().times(1).returning(|_| Ok(()));
let review = Review::new(std::sync::Arc::new(backend));
let res = review.run(None, &None);
assert_err::<ReviewErrors, _>(res)
}
#[test]
fn can_generate_table() {
let prs = vec![
PullRequest {
title: "some-title".into(),
number: 0,
repository: Repository {
name: "some-name".into(),
},
},
PullRequest {
title: "some-other-title".into(),
number: 1,
repository: Repository {
name: "some-other-name".into(),
},
},
];
let expected_table = "4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAChtbMW0gcmVwbyAgICAgICAgICAgIBtbMG0gG1sxbSB0aXRsZSAgICAgICAgICAgIBtbMG0gG1sxbSBudW1iZXIgG1swbQrilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZDilZAKG1szODs1OzEwbSBzb21lLW5hbWUgICAgICAgG1szOW0gIHNvbWUtdGl0bGUgICAgICAgICAwICAgICAgCuKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgAobWzM4OzU7MTBtIHNvbWUtb3RoZXItbmFtZSAbWzM5bSAgc29tZS1vdGhlci10aXRsZSAgIDEgICAgICAK4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA";
let output = Review::generate_prs_table(&prs);
compare_tables(output, expected_table)
}
fn compare_tables(actual: String, snapshot: &str) {
let b64 = base64::engine::general_purpose::STANDARD_NO_PAD;
let snapshot = snapshot.clone().replace("\n", "").replace(" ", "");
println!("expected");
println!(
"{}",
std::str::from_utf8(
b64.decode(&snapshot)
.expect("table to be decodeable")
.as_slice()
)
.expect("to be utf8")
);
println!("actual");
println!("{actual}");
assert_eq!(b64.encode(actual), snapshot);
}
fn assert_err<TExpected, TVal>(res: eyre::Result<TVal>) {
match res {
Err(e) => {
if !e.is::<ReviewErrors>() {
panic!("invalid error: {}", e)
}
}
_ => panic!("error not thrown"),
}
}
}

View File

@ -0,0 +1,207 @@
pub mod models;
use std::io::Write;
use self::models::{MenuChoice, MergeStrategy, PullRequest, ReviewMenuChoice};
#[cfg(test)]
use mockall::{automock, predicate::*};
#[cfg_attr(test, automock)]
pub trait ReviewBackend {
fn get_prs(&self, review_request: Option<String>) -> eyre::Result<Vec<PullRequest>>;
fn present_prs(&self, table: String) -> eyre::Result<()>;
fn present_menu(&self) -> eyre::Result<MenuChoice>;
fn present_diff(&self, pr: &PullRequest) -> eyre::Result<()>;
fn present_review_menu(&self, pr: &PullRequest) -> eyre::Result<ReviewMenuChoice>;
fn approve(&self, pr: &PullRequest) -> eyre::Result<()>;
fn pr_open_browser(&self, pr: &PullRequest) -> eyre::Result<()>;
fn clear(&self) -> eyre::Result<()>;
fn enable_auto_merge(
&self,
pr: &PullRequest,
merge_strategy: &Option<MergeStrategy>,
) -> eyre::Result<()>;
fn present_pr(&self, pr: &PullRequest) -> eyre::Result<()>;
}
pub type DynReviewBackend = std::sync::Arc<dyn ReviewBackend + Send + Sync>;
#[derive(Default)]
pub struct DefaultReviewBackend;
impl ReviewBackend for DefaultReviewBackend {
fn get_prs(&self, review_request: Option<String>) -> eyre::Result<Vec<PullRequest>> {
let raw_prs = util::shell::run_with_input_and_output(
&[
"gh",
"search",
"prs",
"--state=open",
"--review-requested",
review_request.unwrap_or("@me".into()).as_str(),
"--label",
"dependencies",
"--json",
"repository,number,title",
],
"".into(),
)?;
let prs_json = std::str::from_utf8(raw_prs.stdout.as_slice())?;
let prs: Vec<PullRequest> = serde_json::from_str(prs_json)?;
Ok(prs)
}
fn present_prs(&self, table: String) -> eyre::Result<()> {
println!("{table}");
Ok(())
}
fn present_menu(&self) -> eyre::Result<MenuChoice> {
println!("Menu");
println!("Begin (b), Exit (q), Menu (m), Search (s), List (l)");
print!("> ");
std::io::stdout().flush()?;
let mut raw_choice = String::new();
std::io::stdin().read_line(&mut raw_choice)?;
let choice = match raw_choice.chars().take(1).next() {
None => models::MenuChoice::Exit,
Some(raw_choice) => match raw_choice {
'b' => models::MenuChoice::Begin,
'q' => models::MenuChoice::Exit,
'm' => self.present_menu()?,
's' => models::MenuChoice::Search,
'l' => models::MenuChoice::List,
_ => self.present_menu()?,
},
};
Ok(choice)
}
fn present_diff(&self, pr: &PullRequest) -> eyre::Result<()> {
util::shell::run(
&[
"gh",
"pr",
"diff",
pr.number.to_string().as_str(),
"--repo",
pr.repository.name.as_str(),
],
None,
)?;
Ok(())
}
fn present_review_menu(&self, pr: &PullRequest) -> eyre::Result<ReviewMenuChoice> {
println!("");
println!("Review - Menu");
println!("Approve (a), Merge (m), Approve and auto-merge (c), Skip (s), List (l), Open in browser (o), Exit (q)");
print!("> ");
std::io::stdout().flush()?;
let mut raw_choice = String::new();
std::io::stdin().read_line(&mut raw_choice)?;
let choice = match raw_choice.chars().take(1).next() {
None => ReviewMenuChoice::Exit,
Some(raw_choice) => match raw_choice {
'q' => ReviewMenuChoice::Exit,
'l' => ReviewMenuChoice::List,
'a' => ReviewMenuChoice::Approve,
'o' => ReviewMenuChoice::Open,
's' | 'n' => ReviewMenuChoice::Skip,
'm' => ReviewMenuChoice::Merge,
'c' => ReviewMenuChoice::ApproveAndMerge,
_ => self.present_review_menu(pr)?,
},
};
Ok(choice)
}
fn approve(&self, pr: &PullRequest) -> eyre::Result<()> {
util::shell::run(
&[
"gh",
"pr",
"review",
pr.number.to_string().as_str(),
"--approve",
"--repo",
pr.repository.name.as_str(),
],
None,
)?;
Ok(())
}
fn pr_open_browser(&self, pr: &PullRequest) -> eyre::Result<()> {
util::shell::run(
&[
"gh",
"pr",
"view",
pr.number.to_string().as_str(),
"-w",
"--repo",
pr.repository.name.as_str(),
],
None,
)?;
Ok(())
}
fn clear(&self) -> eyre::Result<()> {
print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
std::io::stdout().flush()?;
Ok(())
}
fn enable_auto_merge(
&self,
pr: &PullRequest,
merge_strategy: &Option<MergeStrategy>,
) -> eyre::Result<()> {
let number = pr.number.to_string();
let mut args = vec![
"gh",
"pr",
"merge",
number.as_str(),
"--auto",
"--repo",
pr.repository.name.as_str(),
];
if let Some(merge_strategy) = merge_strategy {
match merge_strategy {
MergeStrategy::Squash => args.push("--squash"),
MergeStrategy::MergeCommit => args.push("--merge"),
}
}
util::shell::run(args.as_slice(), None)?;
Ok(())
}
fn present_pr(&self, pr: &PullRequest) -> eyre::Result<()> {
println!("repo: {} - title: {}", pr.repository.name, pr.title);
Ok(())
}
}
impl DefaultReviewBackend {
pub fn new() -> Self {
Self {}
}
}

View File

@ -0,0 +1,37 @@
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct Repository {
#[serde(rename(deserialize = "nameWithOwner"))]
pub name: String,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Debug)]
pub struct PullRequest {
pub title: String,
pub number: usize,
pub repository: Repository,
}
#[derive(Debug, Clone)]
pub enum MergeStrategy {
Squash,
MergeCommit,
}
pub enum MenuChoice {
Exit,
Begin,
Search,
List,
}
pub enum ReviewMenuChoice {
Exit,
List,
Approve,
Open,
Skip,
Merge,
ApproveAndMerge,
}

View File

@ -1,5 +1,3 @@
use std::{borrow::Borrow, ffi::OsString};
pub struct Search;
impl util::Cmd for Search {
@ -12,8 +10,8 @@ impl util::Cmd for Search {
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
match args.subcommand() {
Some((external, args)) => {
let mut raw = args
.get_many::<OsString>("")
let raw = args
.get_many::<std::ffi::OsString>("")
.ok_or(eyre::anyhow!("please pass some args to search"))?
.map(|s| s.as_os_str())
.map(|s| s.to_string_lossy().to_string())

View File

@ -2,13 +2,13 @@ pub struct Perf;
impl Perf {
fn run() -> eyre::Result<()> {
if let Err(_) = util::shell::run_with_input_and_output(&["ytop", "--version"], "".into()) {
if let Err(_) = util::shell::run_with_input_and_output(&["btm", "--version"], "".into()) {
return Err(eyre::anyhow!(
"could not find ytop, please install or add to PATH"
"could not find btm, please install or add to PATH"
));
}
util::shell::run(&["ytop"], None)?;
util::shell::run(&["btm"], None)?;
Ok(())
}

View File

@ -8,7 +8,7 @@ impl Procs {
));
}
util::shell::run(&["procs"], None)?;
util::shell::run_with_input(&["procs"], "".into())?;
Ok(())
}

View File

@ -12,7 +12,9 @@ impl util::Cmd for Update {
let mut tldr_cache_dir = cache_dir.clone();
tldr_cache_dir.push("kah-toolkit/tldr/store/");
std::fs::remove_dir_all(&tldr_cache_dir)?;
if let Err(_) = std::fs::remove_dir_all(&tldr_cache_dir) {
// ignored
}
std::fs::create_dir_all(&tldr_cache_dir)?;
util::shell::run(

0
man/.gitkeep Normal file
View File

13
src/init/fish.rs Normal file
View File

@ -0,0 +1,13 @@
pub struct Fish;
impl util::Cmd for Fish {
fn cmd() -> eyre::Result<clap::Command> {
let cmd = clap::Command::new("fish").subcommands(&[]);
Ok(cmd)
}
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
Ok(())
}
}

20
src/init/mod.rs Normal file
View File

@ -0,0 +1,20 @@
mod fish;
pub struct Init;
impl util::Cmd for Init {
fn cmd() -> eyre::Result<clap::Command> {
let cmd = clap::Command::new("init")
.subcommands(&[fish::Fish::cmd()?])
.subcommand_required(true);
Ok(cmd)
}
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
match args.subcommand() {
Some(("fish", args)) => fish::Fish::exec(args),
_ => Err(eyre::anyhow!("missing command!")),
}
}
}

View File

@ -1,5 +1,6 @@
use util::Cmd;
mod init;
mod prereqs;
fn main() -> eyre::Result<()> {
@ -10,7 +11,9 @@ fn main() -> eyre::Result<()> {
sourcegraph::Sourcegraph::cmd()?,
github::GitHub::cmd()?,
stats::Stats::cmd()?,
init::Init::cmd()?,
])
.subcommand_required(true)
.get_matches();
match matches.subcommand() {
@ -19,6 +22,7 @@ fn main() -> eyre::Result<()> {
Some(("sourcegraph", subcmd)) => sourcegraph::Sourcegraph::exec(subcmd),
Some(("github", subcmd)) => github::GitHub::exec(subcmd),
Some(("stats", subcmd)) => stats::Stats::exec(subcmd),
Some(("init", subcmd)) => init::Init::exec(subcmd),
_ => Err(eyre::anyhow!("no command selected!")),
}
}