Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create gh search code command #7376

Merged
merged 15 commits into from Jun 9, 2023
Merged

Create gh search code command #7376

merged 15 commits into from Jun 9, 2023

Conversation

joshkraft
Copy link
Contributor

@joshkraft joshkraft commented Apr 27, 2023

Closes #6945

NOTE: These mockups are now outdated - see later comments for updated visuals

Light Theme

light

Dark Theme

dark

@joshkraft joshkraft requested a review from a team as a code owner April 27, 2023 01:18
@joshkraft joshkraft requested review from vilmibm and removed request for a team April 27, 2023 01:18
@cliAutomation cliAutomation added the external pull request originating outside of the CLI core team label Apr 27, 2023
@cliAutomation cliAutomation added this to Needs review 🤔 in The GitHub CLI Apr 27, 2023
var out strings.Builder
for i, c := range tm.Fragment {
if shouldHighlight[i] {
out.WriteString(cs.CyanBold(string(c)))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am open to suggestions on text style for this feature (color and boldness). I initially went with yellow, but it was hard to see in a light terminal. Cyan is pretty readable in both light and dark terminals.

return displayResults(io, results, opts.Query.Limit)
}

func displayResults(io *iostreams.IOStreams, results search.CodeResult, limit int) error {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, displayResults ended up being a bit more complicated than I initially expected. I am pretty new to Go, and I am open to suggestions on ways to make this simpler / more idiomatic.

A few factors at play here:

  1. The code search API does not use the limit flag as you might expect. The limit seems to apply to the number of files returned, but each file might have multiple 'fragments' returned that match the query, and each 'fragment' can also have multiple matches within it. As discussed here, I used limit both when making the request and when rendering the results to stop rendering search results after limit rows had been displayed.

  2. The code search API (as far as I can tell) does not provide line numbers for the matches. As such, rather than rendering line numbers for each result (as discussed here), I chose to render each line with a simple counter that tracks with the number of lines printed for each file. I can easily remove this if desired.

  3. Some of the complexity of this code is because each line in the 'fragment' can have 0, 1, or many matches within it. We want to skip lines with 0 matches, and print each line with 1 or more matches just once. I have a feeling there is a more elegant solution than what I came up with.

Copy link
Contributor

@samcoe samcoe May 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you have is solid, and getHighlightIndices is pretty clever. I took a quick pass at making it a bit simpler and idiomatic, let me know what you think:

func displayResults(io *iostreams.IOStreams, results search.CodeResult, limit int) error {
	cs := io.ColorScheme()
	tp := tableprinter.New(io)
	displayed := 0
outer:
	for _, code := range results.Items {
		if io.IsStdoutTTY() {
			header := fmt.Sprintf("%s %s", cs.GreenBold(code.Repo.FullName), cs.GreenBold(code.Path))
			tp.AddField(header)
			tp.EndRow()
		}
		for _, match := range code.TextMatches {
			fragments := formatMatch(cs, match)
			for i, fragment := range fragments {
				if io.IsStdoutTTY() {
					tp.AddField(fmt.Sprintf("%s. %s", strconv.Itoa(i+1), fragment))
				} else {
					tp.AddField(fmt.Sprintf("%s %s: %s", code.Repo.FullName, code.Path, fragment))
				}
				tp.EndRow()
				displayed++
				if displayed == limit {
					break outer
				}
			}
		}
	}
	if io.IsStdoutTTY() {
		header := fmt.Sprintf("Showing %d of %d results\n\n", displayed, max(displayed, results.Total))
		fmt.Fprintf(io.Out, "\n%s", header)
	}
	return tp.Render()
}

func formatMatch(cs *iostreams.ColorScheme, tm search.TextMatch) []string {
	shouldHighlight := matchHighlightMask(tm.Fragment, tm.Matches)
	var lines []string
	var found bool
	var b strings.Builder
	for i, c := range tm.Fragment {
		if c == '\n' {
			if found {
				lines = append(lines, b.String())
			}
			found = false
			b.Reset()
			continue
		}
		if shouldHighlight[i] {
			b.WriteString(cs.CyanBold(string(c)))
			found = true
		} else {
			b.WriteRune(c)
		}
	}
	return lines
}

func matchHighlightMask(fragment string, matches []search.Match) []bool {
	m := make([]bool, len(fragment))
	for _, match := range matches {
		start := match.Indices[0]
		stop := match.Indices[1]
		for i := start; i < stop; i++ {
			m[i] = true
		}
	}
	return m
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I haven't utilized labels very often but it is a nice fit here. I incorporated these suggestions, with one small tweak - I had to add back in a variable to keep track of the number of overall displayed matches per item in results.Items, so that we can label the results properly as we move through the multiple TextMatches possible for each item/file. I haven't found a way a good way to get rid of this variable without dropping the ability to number the matches for each file.

return out.String(), linesToPrint
}

func getHighlightIndices(matches []search.Match) map[int]bool {
Copy link
Contributor Author

@joshkraft joshkraft Apr 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I started thinking about validating/sorting the intervals provided by the search API, but this seemed like a simple way to get around having to solve that problem. Open to suggestions here as well.

@samcoe samcoe self-assigned this Apr 30, 2023
@samcoe samcoe self-requested a review April 30, 2023 22:22
Copy link
Contributor

@samcoe samcoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshkraft This is coming along excellent! The output with the highlighting looks really elegant in my opinion. I left a handful of comments in the code. Let me know if you have any questions about them.

@@ -148,6 +173,10 @@ func (s searcher) search(query Query, result interface{}) (*http.Response, error
}
req.Header.Set("Content-Type", "application/json; charset=utf-8")
req.Header.Set("Accept", "application/vnd.github.v3+json")
if query.TextMatch {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than introduce the TextMatch boolean to the Query struct I think we could make this simpler by just checking that the query kind is search.KindCode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like this idea. I will refactor this to leverage search.KindCode

Comment on lines 62 to 63
# search code matching "html" in repositories owned by octocat
$ gh search code html --owner=octocat
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example does not seem to add much as the example above shows off the same functionality. Perhaps we should change this one to show off a different flag?

Copy link
Contributor Author

@joshkraft joshkraft May 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially added this to highlight that using --owner works with both organizations and users, but looking at it now it does indeed seem redundant! Dropping this example.

cmd.Flags().StringVar(&opts.Query.Qualifiers.Filename, "filename", "", "Filter on filename")
cmdutil.StringSliceEnumFlag(cmd, &opts.Query.Qualifiers.In, "match", "", nil, []string{"file", "path"}, "Restrict search to file contents or file path")
cmd.Flags().StringVarP(&opts.Query.Qualifiers.Language, "language", "l", "", "Filter results by language")
cmd.Flags().StringSliceVar(&opts.Query.Qualifiers.Repo, "repo", nil, "Filter on repository")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We recently started allowing -R as a shorthand for --repo flag in search commands, let's add that here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

cmd.Flags().StringVar(&opts.Query.Qualifiers.Extension, "extension", "", "Filter on file extension")
cmd.Flags().StringVar(&opts.Query.Qualifiers.Filename, "filename", "", "Filter on filename")
cmdutil.StringSliceEnumFlag(cmd, &opts.Query.Qualifiers.In, "match", "", nil, []string{"file", "path"}, "Restrict search to file contents or file path")
cmd.Flags().StringVarP(&opts.Query.Qualifiers.Language, "language", "l", "", "Filter results by language")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's skip the -l shorthand for now, if we want to add it I would also like to add it to the search repos command since it has an identical flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done 👍

pkg/cmd/search/code/code.go Outdated Show resolved Hide resolved
pkg/search/result.go Outdated Show resolved Hide resolved
pkg/search/result.go Outdated Show resolved Hide resolved
pkg/search/result.go Show resolved Hide resolved
return displayResults(io, results, opts.Query.Limit)
}

func displayResults(io *iostreams.IOStreams, results search.CodeResult, limit int) error {
Copy link
Contributor

@samcoe samcoe May 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what you have is solid, and getHighlightIndices is pretty clever. I took a quick pass at making it a bit simpler and idiomatic, let me know what you think:

func displayResults(io *iostreams.IOStreams, results search.CodeResult, limit int) error {
	cs := io.ColorScheme()
	tp := tableprinter.New(io)
	displayed := 0
outer:
	for _, code := range results.Items {
		if io.IsStdoutTTY() {
			header := fmt.Sprintf("%s %s", cs.GreenBold(code.Repo.FullName), cs.GreenBold(code.Path))
			tp.AddField(header)
			tp.EndRow()
		}
		for _, match := range code.TextMatches {
			fragments := formatMatch(cs, match)
			for i, fragment := range fragments {
				if io.IsStdoutTTY() {
					tp.AddField(fmt.Sprintf("%s. %s", strconv.Itoa(i+1), fragment))
				} else {
					tp.AddField(fmt.Sprintf("%s %s: %s", code.Repo.FullName, code.Path, fragment))
				}
				tp.EndRow()
				displayed++
				if displayed == limit {
					break outer
				}
			}
		}
	}
	if io.IsStdoutTTY() {
		header := fmt.Sprintf("Showing %d of %d results\n\n", displayed, max(displayed, results.Total))
		fmt.Fprintf(io.Out, "\n%s", header)
	}
	return tp.Render()
}

func formatMatch(cs *iostreams.ColorScheme, tm search.TextMatch) []string {
	shouldHighlight := matchHighlightMask(tm.Fragment, tm.Matches)
	var lines []string
	var found bool
	var b strings.Builder
	for i, c := range tm.Fragment {
		if c == '\n' {
			if found {
				lines = append(lines, b.String())
			}
			found = false
			b.Reset()
			continue
		}
		if shouldHighlight[i] {
			b.WriteString(cs.CyanBold(string(c)))
			found = true
		} else {
			b.WriteRune(c)
		}
	}
	return lines
}

func matchHighlightMask(fragment string, matches []search.Match) []bool {
	m := make([]bool, len(fragment))
	for _, match := range matches {
		start := match.Indices[0]
		stop := match.Indices[1]
		for i := start; i < stop; i++ {
			m[i] = true
		}
	}
	return m
}

Copy link
Contributor

@samcoe samcoe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joshkraft Thanks for making the requested changes. This looks great to me!

The GitHub CLI automation moved this from Needs review 🤔 to Needs to be merged 🎉 May 9, 2023
Copy link
Contributor

@mislav mislav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks splendid. Thanks @joshkraft for the hard work and @samcoe for thorough review.

There were a couple of deal-breakers for me, some that I have addressed in changes that I've just added:

  • For some results, the code fragment wasn't rendered. It turned out that if the match is on the final line of the fragment that isn't terminated with \n, it would never get rendered. I've fixed it by ensuring that the final \n terminator is optional.
  • Within a match itself, ANSI escape sequences would get output for each character for a match individually. I've changed this so that the only ANSI codes are printed at the start of the match and at the end of the match.
  • Tableprinter was used, but the output is not a table. I switched to plain Fprintf statements.
  • The color of the matched word was not standing out enough, so I've switched to a bright background color to provide more contrast for matches.
  • The color of the repo name and the color of the filename was identical, making it tricky to distinguish between each other. I've changed the color of the repo name as an experiment for now.
  • The printed numbers looked like line numbers, but did not correspond to the original line numbers from the files that contained matches, since the server doesn't seem to report this information. The fake line numbers for each fragment that always started at 1 were not useful so I removed them. Hopefully in the future we can get the information from the server about actual line numbers.
  • Since we only print matching lines from the fragment returned from the server, preserving original indentation isn't paramount and can lead to visually scattered output. I've switched to trimming all indentation in the output.
  • The header “Showing N of X results” was conflating numbers received from the server (total results) with numbers determined at render time (amount of line matches). When we display pagination info, the only data we ever use for that is server data, not client-side data. For simplicity, I've changed the header to display the number of items returned (len(result.Items)) and the total number of items, both directly taken from the API response payload.

What I feel still needs to be done:

  • Figure out the line number situation so that we can finalize the output formats. After we ship this, it will be disruptive to change the output format, especially when it comes to changing the machine-readable output format.
  • Agree on the final color scheme.
  • Consider the accessibility of default output: if we don't rely on colors, is the textual output understandable enough? Would we need e.g. character separators between the repo name and file names other than a space?
  • Expose the html_url value in the JSON output.
  • Remove the redundant name value from JSON output since we have path.

@joshkraft There are no code changes that I'm requesting that you make to this PR at the moment; I think now our team needs to sync about this and make some decisions on how to roll this out.

The GitHub CLI automation moved this from Needs to be merged 🎉 to Needs review 🤔 May 10, 2023
@mislav mislav added the discuss Feature changes that require discussion primarily among the GitHub CLI team label May 10, 2023
@mislav mislav removed the discuss Feature changes that require discussion primarily among the GitHub CLI team label May 16, 2023
Copy link
Contributor

@mislav mislav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Made some tweaks to this (most notably around polishing --json export formats) and I proclaim this shippable! Thanks for all the hard work @joshkraft. 🙏

The GitHub CLI automation moved this from Needs review 🤔 to Needs to be merged 🎉 Jun 9, 2023
@mislav mislav merged commit a81d014 into cli:trunk Jun 9, 2023
6 checks passed
The GitHub CLI automation moved this from Needs to be merged 🎉 to Pending Release 🥚 Jun 9, 2023
@joshkraft joshkraft deleted the gh-search-code branch June 9, 2023 19:42
renovate bot added a commit to scottames/dots that referenced this pull request Jun 23, 2023
[![Mend
Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com)

This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [aquaproj/aqua-registry](https://togithub.com/aquaproj/aqua-registry)
| minor | `v4.20.0` -> `v4.21.1` |
| [cli/cli](https://togithub.com/cli/cli) | minor | `v2.30.0` ->
`v2.31.0` |
| [weaveworks/eksctl](https://togithub.com/weaveworks/eksctl) | minor |
`v0.145.0` -> `v0.146.0` |
| [zellij-org/zellij](https://togithub.com/zellij-org/zellij) | patch |
`v0.37.1` -> `v0.37.2` |

---

### Release Notes

<details>
<summary>aquaproj/aqua-registry</summary>

###
[`v4.21.1`](https://togithub.com/aquaproj/aqua-registry/releases/tag/v4.21.1)

[Compare
Source](https://togithub.com/aquaproj/aqua-registry/compare/v4.21.0...v4.21.1)


[Issues](https://togithub.com/aquaproj/aqua-registry/issues?q=is%3Aissue+milestone%3Av4.21.1)
| [Pull
Requests](https://togithub.com/aquaproj/aqua-registry/pulls?q=is%3Apr+milestone%3Av4.21.1)
| aquaproj/aqua-registry@v4.21.0...v4.21.1

#### Fixes


[#&#8203;13199](https://togithub.com/aquaproj/aqua-registry/issues/13199)
kubernetes-sigs/kustomize: Follow up changes of kustomize v5.1.0

-
[kubernetes-sigs/kustomize#5220

###
[`v4.21.0`](https://togithub.com/aquaproj/aqua-registry/releases/tag/v4.21.0)

[Compare
Source](https://togithub.com/aquaproj/aqua-registry/compare/v4.20.0...v4.21.0)


[Issues](https://togithub.com/aquaproj/aqua-registry/issues?q=is%3Aissue+milestone%3Av4.21.0)
| [Pull
Requests](https://togithub.com/aquaproj/aqua-registry/pulls?q=is%3Apr+milestone%3Av4.21.0)
| aquaproj/aqua-registry@v4.20.0...v4.21.0

#### 🎉 New Packages


[#&#8203;13173](https://togithub.com/aquaproj/aqua-registry/issues/13173)
[assetnote/surf](https://togithub.com/assetnote/surf): Escalate your
SSRF vulnerabilities on Modern Cloud Environments. `surf` allows you to
filter a list of hosts, returning a list of viable SSRF candidates

[#&#8203;13174](https://togithub.com/aquaproj/aqua-registry/issues/13174)
[iyear/tdl](https://togithub.com/iyear/tdl): A Telegram downloader
written in Golang

[#&#8203;13172](https://togithub.com/aquaproj/aqua-registry/issues/13172)
[nikolaydubina/go-cover-treemap](https://togithub.com/nikolaydubina/go-cover-treemap):
Go code coverage to SVG treemap
[@&#8203;iwata](https://togithub.com/iwata)

</details>

<details>
<summary>cli/cli</summary>

### [`v2.31.0`](https://togithub.com/cli/cli/releases/tag/v2.31.0):
GitHub CLI 2.31.0

[Compare Source](https://togithub.com/cli/cli/compare/v2.30.0...v2.31.0)

#### What's New

- New suite of `project` commands for interacting with and manipulating
projects. Huge shoutout 🥳 for the time and effort put into this work by
[@&#8203;mntlty](https://togithub.com/mntlty) in
[cli/cli#7375
[cli/cli#7578
- New `search code` command by
[@&#8203;joshkraft](https://togithub.com/joshkraft) in
[cli/cli#7376
- New `cs view` command by
[@&#8203;dmgardiner25](https://togithub.com/dmgardiner25) in
[cli/cli#7496
[cli/cli#7539

#### What's Changed

- `api`: output a single JSON array in REST pagination mode by
[@&#8203;mislav](https://togithub.com/mislav) in
[cli/cli#7190
- `api`: support array params in GET queries by
[@&#8203;mislav](https://togithub.com/mislav) in
[cli/cli#7513
- `api`: force method to uppercase by
[@&#8203;ffalor](https://togithub.com/ffalor) in
[cli/cli#7514
- `alias`: Allow aliases to recognize extended commands by
[@&#8203;srz-zumix](https://togithub.com/srz-zumix) in
[cli/cli#7523
- `alias import`: Fix `--clobber` flag by
[@&#8203;samcoe](https://togithub.com/samcoe) in
[cli/cli#7569
- `run rerun`: Improve docs around `--job` flag by
[@&#8203;williammartin](https://togithub.com/williammartin) in
[cli/cli#7527
- `run view`: Support viewing logs for jobs with composite actions by
[@&#8203;williammartin](https://togithub.com/williammartin) in
[cli/cli#7526
- `gist edit`: Add selector option to `gist edit` command by
[@&#8203;kousikmitra](https://togithub.com/kousikmitra) in
[cli/cli#7537
- `repo clone`: Set upstream remote to track all branches after initial
fetch by [@&#8203;samcoe](https://togithub.com/samcoe) in
[cli/cli#7542
- `extension`: Speed up listing extensions by lazy-loading extension
information when needed by [@&#8203;mislav](https://togithub.com/mislav)
in
[cli/cli#7493
- `auth`: Add timeouts to keyring operations by
[@&#8203;samcoe](https://togithub.com/samcoe) in
[cli/cli#7580
- `auth status`: write to stdout on success by
[@&#8203;rajhawaldar](https://togithub.com/rajhawaldar) in
[cli/cli#7540
- `completion`: Fix bash completions for extensions and aliases by
[@&#8203;mislav](https://togithub.com/mislav) in
[cli/cli#7525
- `issue/pr view`: alphabetically sort labels for `gh pr/issue view` by
[@&#8203;ffalor](https://togithub.com/ffalor) in
[cli/cli#7587
- Fix error handling for extension and shell alias commands by
[@&#8203;samcoe](https://togithub.com/samcoe) in
[cli/cli#7567
- Fix pkg imported more than once by
[@&#8203;testwill](https://togithub.com/testwill) in
[cli/cli#7591
- Refactor a nested if statement by
[@&#8203;yanskun](https://togithub.com/yanskun) in
[cli/cli#7596
- Fix a typo by
[@&#8203;lerocknrolla](https://togithub.com/lerocknrolla) in
[cli/cli#7557
- Fix flaky test by [@&#8203;samcoe](https://togithub.com/samcoe) in
[cli/cli#7515
- Credential rotations, renames and decouplings from Mislav by
[@&#8203;williammartin](https://togithub.com/williammartin) in
[cli/cli#7544
- build(deps): bump github.com/cli/go-gh/v2 from 2.0.0 to 2.0.1 by
[@&#8203;dependabot](https://togithub.com/dependabot) in
[cli/cli#7546
- build(deps): bump github.com/AlecAivazis/survey/v2 from 2.3.6 to 2.3.7
by [@&#8203;dependabot](https://togithub.com/dependabot) in
[cli/cli#7576

#### New Contributors

- [@&#8203;srz-zumix](https://togithub.com/srz-zumix) made their first
contribution in
[cli/cli#7523
- [@&#8203;lerocknrolla](https://togithub.com/lerocknrolla) made their
first contribution in
[cli/cli#7557
- [@&#8203;testwill](https://togithub.com/testwill) made their first
contribution in
[cli/cli#7591
- [@&#8203;rajhawaldar](https://togithub.com/rajhawaldar) made their
first contribution in
[cli/cli#7540

**Full Changelog**: cli/cli@v2.30.0...v2.31.0

</details>

<details>
<summary>weaveworks/eksctl</summary>

###
[`v0.146.0`](https://togithub.com/weaveworks/eksctl/releases/tag/v0.146.0):
eksctl 0.146.0 (permalink)

[Compare
Source](https://togithub.com/weaveworks/eksctl/compare/0.145.0...0.146.0)

### Release v0.146.0

#### 🎯 Improvements

- Update vpc-cni to 1.12.6
([#&#8203;6692](https://togithub.com/weaveworks/eksctl/issues/6692))

#### 🧰 Maintenance

- Bump dependencies
([#&#8203;6690](https://togithub.com/weaveworks/eksctl/issues/6690))

#### 📝 Documentation

- New eksctl channel
([#&#8203;6697](https://togithub.com/weaveworks/eksctl/issues/6697))

#### Acknowledgments

Weaveworks would like to sincerely thank:
[@&#8203;wind0r](https://togithub.com/wind0r)

</details>

<details>
<summary>zellij-org/zellij</summary>

###
[`v0.37.2`](https://togithub.com/zellij-org/zellij/releases/tag/v0.37.2)

[Compare
Source](https://togithub.com/zellij-org/zellij/compare/v0.37.1...v0.37.2)

This is a patch release to fix some minor issues in the previous
release.

#### What's Changed

- hotfix: include theme files into binary by
[@&#8203;jaeheonji](https://togithub.com/jaeheonji) in
[zellij-org/zellij#2566
- fix(plugins): make hide_self api idempotent by
[@&#8203;imsnif](https://togithub.com/imsnif) in
[zellij-org/zellij#2568

**Full Changelog**:
zellij-org/zellij@v0.37.1...v0.37.2

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined),
Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the
rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://togithub.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Mend
Renovate](https://www.mend.io/free-developer-tools/renovate/). View
repository job log
[here](https://developer.mend.io/github/scottames/dots).

<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNS4xMzEuMCIsInVwZGF0ZWRJblZlciI6IjM1LjEzMS4wIiwidGFyZ2V0QnJhbmNoIjoibWFpbiJ9-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
@fuckumean

This comment was marked as spam.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external pull request originating outside of the CLI core team
Projects
No open projects
The GitHub CLI
  
Pending Release 🥚
Development

Successfully merging this pull request may close these issues.

Support all flavors of search via gh search <foo>
5 participants