Compare commits
54 Commits
Author | SHA1 | Date | |
---|---|---|---|
a2849226ce | |||
a6c26a9213 | |||
5ea2ff445a | |||
819e5d23bb | |||
5ac9d474f2 | |||
d9ddb7139b | |||
c933073e32 | |||
6f3625c2fe | |||
35b50d802a | |||
92eab2361e | |||
97e988e99e | |||
784329a703 | |||
f912217549 | |||
06b673286a | |||
0cfd38e682 | |||
a1f337dac2 | |||
64897d32e4 | |||
0408fe856d | |||
4e3b711567 | |||
7f0bff57eb | |||
92f167e7e8 | |||
c7ebd6350e | |||
d7d55d24f5 | |||
6381c189cb | |||
d0568e48ec | |||
f66a6c858d | |||
267d546d2e | |||
87c9c36f6c | |||
2f19707e94 | |||
a79d0ee6d4 | |||
32ad2b3fd7 | |||
0a3a4d4f74 | |||
95f3254f81 | |||
5894bd5bb1 | |||
560f8f4fd0 | |||
e1d8e27c23 | |||
2e19df72b0 | |||
08b3e1cf5b | |||
d592b5f2d8 | |||
3f06afce02 | |||
d553bf06b7 | |||
7427f8f8d8 | |||
e350d8c13d | |||
27f5287c82 | |||
cf7ce40afd | |||
8149da56fb | |||
af591b9802 | |||
300d16d630 | |||
09f6ad35f9 | |||
64f853d025 | |||
07a2143d50 | |||
0ca6347f1f | |||
9fc27f2c0e | |||
98cb397ea9 |
5
.drone.yml
Normal file
5
.drone.yml
Normal 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
89
.github/workflows/release-published.yml
vendored
Normal 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
114
.github/workflows/release.yml
vendored
Normal 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
469
Cargo.lock
generated
@ -2,6 +2,27 @@
|
|||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "1.3.2"
|
version = "1.3.2"
|
||||||
@ -22,9 +43,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.0.29"
|
version = "4.0.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
checksum = "a7db700bc935f9e43e88d00b0850dae18a63773cfbec6d8e070fccf7fef89a39"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"clap_lex",
|
"clap_lex",
|
||||||
@ -43,6 +64,65 @@ dependencies = [
|
|||||||
"os_str_bytes",
|
"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]]
|
[[package]]
|
||||||
name = "dirs"
|
name = "dirs"
|
||||||
version = "4.0.0"
|
version = "4.0.0"
|
||||||
@ -63,6 +143,18 @@ dependencies = [
|
|||||||
"winapi",
|
"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]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -94,6 +186,21 @@ dependencies = [
|
|||||||
"once_cell",
|
"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]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
@ -109,12 +216,25 @@ dependencies = [
|
|||||||
name = "github"
|
name = "github"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"base64",
|
||||||
"clap",
|
"clap",
|
||||||
|
"comfy-table",
|
||||||
"dirs",
|
"dirs",
|
||||||
"eyre",
|
"eyre",
|
||||||
|
"mockall",
|
||||||
|
"pretty_assertions",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror",
|
||||||
"util",
|
"util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "heck"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hermit-abi"
|
name = "hermit-abi"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
@ -152,6 +272,27 @@ dependencies = [
|
|||||||
"windows-sys",
|
"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]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.138"
|
version = "0.2.138"
|
||||||
@ -164,6 +305,85 @@ version = "0.1.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
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]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.16.0"
|
version = "1.16.0"
|
||||||
@ -177,19 +397,93 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "output_vt100"
|
||||||
version = "1.0.47"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.21"
|
version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@ -214,6 +508,23 @@ dependencies = [
|
|||||||
"thiserror",
|
"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]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.36.5"
|
version = "0.36.5"
|
||||||
@ -228,6 +539,18 @@ dependencies = [
|
|||||||
"windows-sys",
|
"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]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
@ -237,6 +560,79 @@ dependencies = [
|
|||||||
"winapi-util",
|
"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]]
|
[[package]]
|
||||||
name = "sourcegraph"
|
name = "sourcegraph"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -264,10 +660,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "strum"
|
||||||
version = "1.0.105"
|
version = "0.24.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -284,19 +699,25 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "termtree"
|
||||||
version = "1.0.37"
|
version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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 = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.37"
|
version = "1.0.38"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -316,7 +737,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toolkit"
|
name = "toolkit"
|
||||||
version = "0.1.0"
|
version = "0.1.14"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"eyre",
|
"eyre",
|
||||||
@ -329,9 +750,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.5"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
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]]
|
[[package]]
|
||||||
name = "util"
|
name = "util"
|
||||||
@ -445,3 +872,9 @@ name = "windows_x86_64_msvc"
|
|||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "toolkit"
|
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"
|
edition = "2021"
|
||||||
|
license-file = "LICENSE"
|
||||||
|
authors = ["Kasper J. Hermansen contact@kjuulh.io"]
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [
|
members = [
|
||||||
@ -13,7 +17,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
clap = { version = "4.0.29", features = ["cargo"] }
|
clap = { version = "4.0.32", features = ["cargo"] }
|
||||||
eyre = "0.6.8"
|
eyre = "0.6.8"
|
||||||
dirs = "4.0.0"
|
dirs = "4.0.0"
|
||||||
walkdir = "2.3.2"
|
walkdir = "2.3.2"
|
||||||
|
61
README.md
Normal file
61
README.md
Normal 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
|
||||||
|
```
|
||||||
|
|
||||||
|

|
BIN
assets/demo.gif
Normal file
BIN
assets/demo.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 MiB |
@ -11,3 +11,13 @@ util = { path = "../util" }
|
|||||||
eyre.workspace = true
|
eyre.workspace = true
|
||||||
clap.workspace = true
|
clap.workspace = true
|
||||||
dirs.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"
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
|
use clap::value_parser;
|
||||||
use eyre::Context;
|
use eyre::Context;
|
||||||
|
|
||||||
pub struct FuzzyClone;
|
pub struct FuzzyClone;
|
||||||
@ -201,13 +202,18 @@ impl FuzzyClone {
|
|||||||
}),
|
}),
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} 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)
|
Ok(git_repo_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> eyre::Result<()> {
|
fn run(print_dest: &bool) -> eyre::Result<()> {
|
||||||
let settings = Self::get_settings()?;
|
let settings = Self::get_settings()?;
|
||||||
if settings.auto_update {
|
if settings.auto_update {
|
||||||
println!("running 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 = util::shell::run_with_input_and_output(&["fzf"], entries_str)?;
|
||||||
let chosen = std::str::from_utf8(&chosen.stdout)?;
|
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>"
|
"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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,13 +268,24 @@ impl util::Cmd for FuzzyClone {
|
|||||||
Ok(clap::Command::new("fuzzy-clone")
|
Ok(clap::Command::new("fuzzy-clone")
|
||||||
.alias("fc")
|
.alias("fc")
|
||||||
.alias("c")
|
.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")))
|
.subcommand(clap::Command::new("update")))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
|
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
|
||||||
|
let print_dest = args.get_one::<bool>("print-dest").unwrap_or(&false);
|
||||||
|
|
||||||
match args.subcommand() {
|
match args.subcommand() {
|
||||||
Some(("update", _)) => Self::update()?,
|
Some(("update", _)) => Self::update()?,
|
||||||
_ => Self::run()?,
|
_ => Self::run(print_dest)?,
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
mod auth;
|
mod auth;
|
||||||
mod fuzzy_clone;
|
mod fuzzy_clone;
|
||||||
mod gh;
|
mod gh;
|
||||||
|
mod review;
|
||||||
|
pub(crate) mod review_backend;
|
||||||
|
|
||||||
pub struct GitHub;
|
pub struct GitHub;
|
||||||
|
|
||||||
@ -31,6 +33,7 @@ impl util::Cmd for GitHub {
|
|||||||
auth::Auth::cmd()?,
|
auth::Auth::cmd()?,
|
||||||
gh::Gh::cmd()?,
|
gh::Gh::cmd()?,
|
||||||
fuzzy_clone::FuzzyClone::cmd()?,
|
fuzzy_clone::FuzzyClone::cmd()?,
|
||||||
|
review::Review::cmd()?,
|
||||||
])
|
])
|
||||||
.allow_external_subcommands(true))
|
.allow_external_subcommands(true))
|
||||||
}
|
}
|
||||||
@ -41,6 +44,7 @@ impl util::Cmd for GitHub {
|
|||||||
Some(("fuzzy-clone", subm)) => fuzzy_clone::FuzzyClone::exec(subm),
|
Some(("fuzzy-clone", subm)) => fuzzy_clone::FuzzyClone::exec(subm),
|
||||||
Some(("fc", subm)) => fuzzy_clone::FuzzyClone::exec(subm),
|
Some(("fc", subm)) => fuzzy_clone::FuzzyClone::exec(subm),
|
||||||
Some(("gh", subm)) => gh::Gh::exec(subm),
|
Some(("gh", subm)) => gh::Gh::exec(subm),
|
||||||
|
Some(("review", subm)) => review::Review::exec(subm),
|
||||||
Some((external, args)) => Self::run(external, args),
|
Some((external, args)) => Self::run(external, args),
|
||||||
_ => Err(eyre::anyhow!("missing argument")),
|
_ => Err(eyre::anyhow!("missing argument")),
|
||||||
}
|
}
|
||||||
|
298
crates/github/src/review.rs
Normal file
298
crates/github/src/review.rs
Normal 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"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
207
crates/github/src/review_backend/mod.rs
Normal file
207
crates/github/src/review_backend/mod.rs
Normal 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 {}
|
||||||
|
}
|
||||||
|
}
|
37
crates/github/src/review_backend/models.rs
Normal file
37
crates/github/src/review_backend/models.rs
Normal 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,
|
||||||
|
}
|
@ -1,5 +1,3 @@
|
|||||||
use std::{borrow::Borrow, ffi::OsString};
|
|
||||||
|
|
||||||
pub struct Search;
|
pub struct Search;
|
||||||
|
|
||||||
impl util::Cmd for Search {
|
impl util::Cmd for Search {
|
||||||
@ -12,8 +10,8 @@ impl util::Cmd for Search {
|
|||||||
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
|
fn exec(args: &clap::ArgMatches) -> eyre::Result<()> {
|
||||||
match args.subcommand() {
|
match args.subcommand() {
|
||||||
Some((external, args)) => {
|
Some((external, args)) => {
|
||||||
let mut raw = args
|
let raw = args
|
||||||
.get_many::<OsString>("")
|
.get_many::<std::ffi::OsString>("")
|
||||||
.ok_or(eyre::anyhow!("please pass some args to search"))?
|
.ok_or(eyre::anyhow!("please pass some args to search"))?
|
||||||
.map(|s| s.as_os_str())
|
.map(|s| s.as_os_str())
|
||||||
.map(|s| s.to_string_lossy().to_string())
|
.map(|s| s.to_string_lossy().to_string())
|
||||||
|
@ -2,13 +2,13 @@ pub struct Perf;
|
|||||||
|
|
||||||
impl Perf {
|
impl Perf {
|
||||||
fn run() -> eyre::Result<()> {
|
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!(
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ impl Procs {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
util::shell::run(&["procs"], None)?;
|
util::shell::run_with_input(&["procs"], "".into())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,9 @@ impl util::Cmd for Update {
|
|||||||
let mut tldr_cache_dir = cache_dir.clone();
|
let mut tldr_cache_dir = cache_dir.clone();
|
||||||
tldr_cache_dir.push("kah-toolkit/tldr/store/");
|
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)?;
|
std::fs::create_dir_all(&tldr_cache_dir)?;
|
||||||
|
|
||||||
util::shell::run(
|
util::shell::run(
|
||||||
|
0
man/.gitkeep
Normal file
0
man/.gitkeep
Normal file
13
src/init/fish.rs
Normal file
13
src/init/fish.rs
Normal 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
20
src/init/mod.rs
Normal 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!")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
use util::Cmd;
|
use util::Cmd;
|
||||||
|
|
||||||
|
mod init;
|
||||||
mod prereqs;
|
mod prereqs;
|
||||||
|
|
||||||
fn main() -> eyre::Result<()> {
|
fn main() -> eyre::Result<()> {
|
||||||
@ -10,7 +11,9 @@ fn main() -> eyre::Result<()> {
|
|||||||
sourcegraph::Sourcegraph::cmd()?,
|
sourcegraph::Sourcegraph::cmd()?,
|
||||||
github::GitHub::cmd()?,
|
github::GitHub::cmd()?,
|
||||||
stats::Stats::cmd()?,
|
stats::Stats::cmd()?,
|
||||||
|
init::Init::cmd()?,
|
||||||
])
|
])
|
||||||
|
.subcommand_required(true)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
|
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
@ -19,6 +22,7 @@ fn main() -> eyre::Result<()> {
|
|||||||
Some(("sourcegraph", subcmd)) => sourcegraph::Sourcegraph::exec(subcmd),
|
Some(("sourcegraph", subcmd)) => sourcegraph::Sourcegraph::exec(subcmd),
|
||||||
Some(("github", subcmd)) => github::GitHub::exec(subcmd),
|
Some(("github", subcmd)) => github::GitHub::exec(subcmd),
|
||||||
Some(("stats", subcmd)) => stats::Stats::exec(subcmd),
|
Some(("stats", subcmd)) => stats::Stats::exec(subcmd),
|
||||||
|
Some(("init", subcmd)) => init::Init::exec(subcmd),
|
||||||
_ => Err(eyre::anyhow!("no command selected!")),
|
_ => Err(eyre::anyhow!("no command selected!")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user