Skip to content

Commit

Permalink
add gm repo bisect (#158)
Browse files Browse the repository at this point in the history
adds a new command to run a `test: closure` against a repo to bisect a
new bug.
as can be seen in the
[documentation](https://github.com/amtoine/nu-git-manager/blob/gm-repo-bisect/docs/nu-git-manager-sugar/git/gm-repo-bisect.md)
- the `test: closure` should return non-zero exit codes for _bad_
revisions
- the `--good` and `--bad` options should point to the first valid known
_good_ and _bad_ revisions
- when the `test: closure` is expensive to run and `--good` and `--bad`
are assument to be valid, their checks can be skipped with `--no-check`
  • Loading branch information
amtoine authored Jan 21, 2024
1 parent ba3a88d commit 28f1fa2
Show file tree
Hide file tree
Showing 5 changed files with 170 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
- [`gm status`](nu-git-manager/gm-status.md)
- [`gm update-cache`](nu-git-manager/gm-update-cache.md)
- [`gm report`](nu-git-manager-sugar/extra/gm-report.md)
- [`gm repo bisect`](nu-git-manager-sugar/git/gm-repo-bisect.md)
- [`gm repo branch interactive-delete`](nu-git-manager-sugar/git/gm-repo-branch-interactive-delete.md)
- [`gm repo branch wipe`](nu-git-manager-sugar/git/gm-repo-branch-wipe.md)
- [`gm repo branches`](nu-git-manager-sugar/git/gm-repo-branches.md)
Expand Down
48 changes: 48 additions & 0 deletions docs/nu-git-manager-sugar/git/gm-repo-bisect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# `gm repo bisect` (`nu-git-manager-sugar git`)
bisect a worktree by running a piece of code repeatedly

# Examples
```nushell
# find a bug that was introduced in Nushell in `nushell/nushell
gm repo bisect --good 0.89.0 --bad 4458aae {
cargo run -- -n -c "def foo [x: list<string>] { $x }; foo []"
}
```
```
724818030dd1de392c54788eab5030074d694ecd
```
---
```nushell
# avoid running the test twice more if it is expensive and you're sure
# `--good` and `--bad` are indeed "good" and "bad"
gm repo bisect --good $good --bad $bad --no-check $test
```

## Parameters
- parameter_name: test
- parameter_type: positional
- syntax_shape: closure()
- is_optional: false
- description: the code to run to check a given revision, should return a non-zero exit code for bad revisions
---
- parameter_name: good
- parameter_type: named
- syntax_shape: string
- is_optional: true
- description: the initial known "good" revision
---
- parameter_name: bad
- parameter_type: named
- syntax_shape: string
- is_optional: true
- description: the initial known "bad" revision
---
- parameter_name: no-check
- parameter_type: switch
- is_optional: true
- description: don't check if `--good` and `--bad` are indeed "good" and "bad"

## Signatures
| input | output |
| --------- | -------- |
| `nothing` | `string` |
1 change: 1 addition & 0 deletions docs/nu-git-manager-sugar/git/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@


## Commands
- [`gm repo bisect`](gm-repo-bisect.md)
- [`gm repo branch interactive-delete`](gm-repo-branch-interactive-delete.md)
- [`gm repo branch wipe`](gm-repo-branch-wipe.md)
- [`gm repo branches`](gm-repo-branches.md)
Expand Down
119 changes: 119 additions & 0 deletions pkgs/nu-git-manager-sugar/nu-git-manager-sugar/git/mod.nu
Original file line number Diff line number Diff line change
Expand Up @@ -345,3 +345,122 @@ export def "gm repo query" [table: string@git-query-tables]: nothing -> table {
query git $"select * from ($table)"
}
}

# NOTE: would be cool to use the `throw-error` from `nu-git-manager`
def throw-error [
error: record<msg: string, text: string, span: record<start: int, end: int>>
]: nothing -> error {
error make {
msg: $"(ansi red_bold)($error.msg)(ansi reset)",
label: {
text: $error.text,
span: $error.span,
},
}
}

# bisect a worktree by running a piece of code repeatedly
#
# # Examples
# ```nushell
# # find a bug that was introduced in Nushell in `nushell/nushell
# gm repo bisect --good 0.89.0 --bad 4458aae {
# cargo run -- -n -c "def foo [x: list<string>] { $x }; foo []"
# }
# ```
# ```
# 724818030dd1de392c54788eab5030074d694ecd
# ```
# ---
# ```nushell
# # avoid running the test twice more if it is expensive and you're sure
# # `--good` and `--bad` are indeed "good" and "bad"
# gm repo bisect --good $good --bad $bad --no-check $test
# ```
export def "gm repo bisect" [
test: closure, # the code to run to check a given revision, should return a non-zero exit code for bad revisions
--good: string, # the initial known "good" revision
--bad: string, # the initial known "bad" revision
--no-check, # don't check if `--good` and `--bad` are indeed "good" and "bad"
]: nothing -> string {
let res = ^git rev-parse $good | complete
if $res.exit_code != 0 {
throw-error {
msg: "invalid_git_revision",
text: $"not a valid revision in current repository",
span: (metadata $good).span,
}
}

let res = ^git rev-parse $bad | complete
if $res.exit_code != 0 {
throw-error {
msg: "invalid_git_revision",
text: "not a valid revision in current repository",
span: (metadata $bad).span,
}
}

if not $no_check {
print $"checking that ($good) is good..."
^git checkout $good
try {
do $test
} catch {
throw-error {
msg: "invalid_good_revision",
text: "not a good revision",
span: (metadata $good).span,
}
}

print $"checking that ($bad) is bad..."
^git checkout $bad
let res = try {
do $test
true
} catch {
false
}
if $res {
throw-error {
msg: "invalid_bad_revision",
text: "not a bad revision",
span: (metadata $bad).span,
}
}
}

^git bisect start
^git bisect good $good
^git bisect bad $bad

print $"starting bisecting at (^git rev-parse HEAD)"

mut first_bad = ""
while $first_bad == "" {
let head = try {
do $test
"good"
} catch {
"bad"
}

let res = ^git bisect $head
let done = $res
| lines
| get 0
| parse "{hash} is the first bad commit"
| into record
| get hash?
if $done != null {
$first_bad = $done
} else {
print $res
}
}

^git bisect reset

$first_bad
}
1 change: 1 addition & 0 deletions pkgs/nu-git-manager-sugar/tests/mod.nu
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export module imports {

export def git [] {
assert imports $MODULE "git" [
"gm repo bisect",
"gm repo branch interactive-delete",
"gm repo branch wipe",
"gm repo branches",
Expand Down

0 comments on commit 28f1fa2

Please sign in to comment.