Coder Social home page Coder Social logo

go-gh's Introduction

GitHub CLI

gh is GitHub on the command line. It brings pull requests, issues, and other GitHub concepts to the terminal next to where you are already working with git and your code.

screenshot of gh pr status

GitHub CLI is supported for users on GitHub.com and GitHub Enterprise Server 2.20+ with support for macOS, Windows, and Linux.

Documentation

For installation options see below, for usage instructions see the manual.

Contributing

If anything feels off, or if you feel that some functionality is missing, please check out the contributing page. There you will find instructions for sharing your feedback, building the tool locally, and submitting pull requests to the project.

If you are a hubber and are interested in shipping new commands for the CLI, check out our doc on internal contributions.

Installation

macOS

gh is available via Homebrew, MacPorts, Conda, Spack, Webi, and as a downloadable binary including Mac OS installer .pkg from the releases page.

Note

As of May 29th, Mac OS installer .pkg are unsigned with efforts prioritized in cli/cli#9139 to support signing them.

Homebrew

Install: Upgrade:
brew install gh brew upgrade gh

MacPorts

Install: Upgrade:
sudo port install gh sudo port selfupdate && sudo port upgrade gh

Conda

Install: Upgrade:
conda install gh --channel conda-forge conda update gh --channel conda-forge

Additional Conda installation options available on the gh-feedstock page.

Spack

Install: Upgrade:
spack install gh spack uninstall gh && spack install gh

Webi

Install: Upgrade:
curl -sS https://webi.sh/gh | sh webi gh@stable

For more information about the Webi installer see its homepage.

Linux & BSD

gh is available via:

For more information, see Linux & BSD installation.

Windows

gh is available via WinGet, scoop, Chocolatey, Conda, Webi, and as downloadable MSI.

WinGet

Install: Upgrade:
winget install --id GitHub.cli winget upgrade --id GitHub.cli

Note
The Windows installer modifies your PATH. When using Windows Terminal, you will need to open a new window for the changes to take effect. (Simply opening a new tab will not be sufficient.)

scoop

Install: Upgrade:
scoop install gh scoop update gh

Chocolatey

Install: Upgrade:
choco install gh choco upgrade gh

Signed MSI

MSI installers are available for download on the releases page.

Codespaces

To add GitHub CLI to your codespace, add the following to your devcontainer file:

"features": {
  "ghcr.io/devcontainers/features/github-cli:1": {}
}

GitHub Actions

GitHub CLI comes pre-installed in all GitHub-Hosted Runners.

Other platforms

Download packaged binaries from the releases page.

Build from source

See here on how to build GitHub CLI from source.

Comparison with hub

For many years, hub was the unofficial GitHub CLI tool. gh is a new project that helps us explore what an official GitHub CLI tool can look like with a fundamentally different design. While both tools bring GitHub to the terminal, hub behaves as a proxy to git, and gh is a standalone tool. Check out our more detailed explanation to learn more.

go-gh's People

Contributors

andyfeller avatar bendrucker avatar chelnak avatar dependabot[bot] avatar devonhk avatar ffalor avatar heaths avatar itchyny avatar koozz avatar maaslalani avatar mislav avatar mjpieters avatar mntlty avatar mszostok avatar nobe4 avatar samcoe avatar shawnps avatar sridharavinash avatar stemar94 avatar williammartin avatar y-yagi avatar yin1999 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-gh's Issues

CurrentRepository() fails when executed inside a GH Workflow

Hey - just discovered something that might be interesting.

When a consuming application calls CurrentRepository() from inside a GH workflow I'm seeing the following error:

unable to determine current repository, none of the git remotes configured for this repository point to a known GitHub host

I think this is because ~/.config/gh/hosts.yml does not exist on a runner because of the TOKEN based auth (vs oauth).

This would cause FilterByHosts to return an error.

I have worked around this by. exporting the GH_HOST environment variable.. however it was not immediately obvious what to do.

If this is expected behaviour we could update the README with a note on compatibility with GH Actions.

Cheers!

Template support for additional functions

It'd be great if we could add more functions to the template package, perhaps using the "WithOptions" pattern as mentioned elsewhere. The existing templates are useful, but for extensions to add other useful helpers for their own needs, passing in a map to merge after initializing the default list (so extensions could override) could prove useful.

Add the ability to introduce repository specific configurations for gh-cli and its extensions

Feature request description

I would like to propose the addition of a feature that enables the integration of repository-specific configurations into the pkg/config package, drawing inspiration from the way Git handles local .git/config versus XDG_CONFIG_HOME configurations. This enhancement could prove invaluable for various extensions creators who could leverage distinct settings tailored to each repository's requirements.

Motivation

Consider a chat-op deployment scenario - a good gh extension that integrates well with external platforms like Discord or Slack, having the ability to define and commit repository-specific configurations directly within the repository itself can offer significant advantages. For instance, imagine a use case where different repositories need to route communications to specific channels on these platforms. The current config package is limited in that the configs are global (AFAIK - please let me know if this is incorrect) which leaves the current approach of providing options each time a command is invoked which can become cumbersome, especially when the values for channels differ across repositories. This is just one scenario where repo specific configs might be useful but I'm sure extension creators can think of creative ways to use this feature 😄

Implementation

The proposed implementation could involve creating a dedicated configuration file within the repository, such as .ghconfig, where users can define repository-specific settings. This file would be committed alongside other source code and assets.

Conclusion

Introducing repository-specific configurations to the "gh" library has the potential to enhance the usability, consistency, and flexibility of the tool in scenarios where distinct settings are essential on a per-repository basis. This feature aligns with the natural progression of version control practices and would undoubtedly contribute to streamlining workflows and improving overall efficiency.

Add support for GH_REPO environment variable

The CurrentRepository function should take into account the GH_REPO environment variable, and if it is specified return that repository rather than the current flow of looking at the filesystem and git remotes.

As part of this work we should make the parsing function used for parsing GH_REPO into a repository available for user consumption.

cc #5

resolveOptions not updating ClientOptions

I noticed this when running some tests with the new version.

resolveOptions is not updating the pointer reference. So any changes made locally in the method are not reflected in the caller.

For example: gh.HTTPClient(nil) causes a nil value for ClientOptions to be passed to the underlying NewHTTPClient.

Consider exposing a raw http.Client

Hey - this is a great project and helped me get up and running quickly!

I was looking at integrating https://github.com/google/go-github in to my project. It allows you to pass a pre-configured http client when creating a new GitHubClient instance. The abstraction (RESTClient) doesn't implement the interface so cannot be used as a parameter.

Would you consider exposing a configured raw http.Client instance or the config package to allow us to build our own?

I'd be happy to help out with the implementation if it's something of use.

API Authentication Fails When Using OAuth or App Tokens

I've noticed what seems like some unexpected behavior when using OAuth (start with gho_) or App (start with ghs_) tokens. I wrote an extension that utilizes the ClientOptions struct and when I provide ClientOptions.AuthToken for either OAuth or App generated tokens, I get a 401.

Upon analyzing what's taking place, it appears that the authorization header that go-gh is using has token instead of bearer. This works for PATs, but not for the aforementioned token types.

To get around this I had to set ClientOptions.AuthToken and then also override ClientOptions.Headers providing the Authorization:bearer <token> key-value manually.

If I try to just add the header key-value override, the lib falls back to using built-in authentication (gh auth login) instead of the provided token.

At least, this is the functionality I'm seeing. Help?

Change example_gh_test.go to package `gh_test`

Being in the same package, the example test file can refer to functions such as RESTClient and Exec as local, as opposed to gh.RESTClient and gh.Exec. This presents some challenges:

  • the examples cannot be copied as is
  • it can be confusing to Go newcomers, who may not be familiar with how to solve the issue

I would like to suggest changing the package of the example file and updating the functions in it.

Rest client support for endpoint not returning a JSON

Problem statement

While working on gh-not I started experimenting with Actors interacting with the GitHub API.

A very simple one would be to mark a notification as read, as per https://docs.github.com/en/rest/activity/notifications?apiVersion=2022-11-28#mark-a-thread-as-read.

Here's a simplified version of the code I wanted to use:

func main() {
	client, err := api.DefaultRESTClient()
	if err != nil {
		panic(err)
	}

	url := "https://api.github.com/notifications/threads/[REDACTED]"

	resp := []interface{}{}
	err = client.Patch(url, nil, &resp)
	if err != nil {
		panic(err)
	}

}

And I always get: panic: unexpected end of JSON input

Possible fix 1

The documentation specifies status codes, but no response content; expecting one is thus useless in this context.

I wonder if

b, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
err = json.Unmarshal(b, &response)
if err != nil {
return err
}
could be modified in the following way:

	b, err := io.ReadAll(resp.Body)
	if err != nil {
		return err
	}

+        if len(b) > 0{
        	err = json.Unmarshal(b, &response)
        	if err != nil {
        		return err
        	}
+        }

This would prevent breaking on invalid JSON when none is expected.

POC implemented in #162

Possible fix 2

The 205 status code spec specifies:

a server MUST NOT generate content in a 205 response

So maybe a better fix would be:

	if resp.StatusCode == http.StatusNoContent {
		return nil
	}

+	if resp.StatusCode == http.StatusResetContent {
+		return nil
+	}

Implementation PR: #163

Current workaround

func main() {
	client, err := api.DefaultRESTClient()
	if err != nil {
		panic(err)
	}

	url := "https://api.github.com/notifications/threads/[REDACTED]"

	resp := []interface{}{}
	err = client.Patch(url, nil, &resp)
	if err != nil && err.Error() != "unexpected end of JSON input" {
		panic(err)
	}
        // continue as planned
}

Additional questions

  • Is there another way to use go-gh's REST client for Patch requests if the endpoint doesn't return a valid JSON?
  • Would there be any benefits in returning the response code from those requests? It seems that implementing custom logic solely based on JSON breaks as soon as no JSON is returned

docs: Example of reading an octet stream

Hello!

Loving the abstraction so far, great job!

Was wondering if we could add an example that reads an octet-stream similar to this in the cli repo using net/http?

I'm trying a couple of different approaches, but I'm not sure what's the best way to define the response to facilitate reading bytes?

Let me know if I can help in any way as well 😄

Edit: I'm using the rest client for reference, and looking at

b, err := io.ReadAll(resp.Body)
I'm not sure this is possible currently?

Using Get or Do I get:

invalid character '\x1f' looking for beginning of value

Add context to possibly long-running methods (external API)

Describe the feature or problem you’d like to solve

Currently, there is no option to cancel the ongoing request.

Here is a small example of pagination request where this would be helpful https://gist.github.com/mszostok/b68ff95f85d4b4ff8a27aeed56f9d3ca.

This only fetches GitHub stars, so the payload is not heavy, however if you want to fetch all issues then you have even a bigger problem.

Proposed solution

How will it benefit CLI and its users?

  • It improves UX as you can cancel executed command, and it will be released immediately instead of being unresponsive for a few seconds.

  • It reduces the quota consumption, as you won't execute next calls if not needed and also save the bandwidth as you will inform server that the client is not waiting for the response anymore.

Additional context

There are at least two options how it can be achieved:

  1. Add new methods with the WithContext suffix. For example:

    // GQLClient is the interface that wraps methods for the different types of
    // API requests that are supported by the server.
    type GQLClient interface {
      // Do executes a GraphQL query request.
      // The response is populated into the response argument.
      Do(query string, variables map[string]interface{}, response interface{}) error
    
      // DoWithContext executes a GraphQL query request.
      // The response is populated into the response argument.
      DoWithContext(ctx context.Context, query string, variables map[string]interface{}, response interface{}) error
    }

    Similar approach as Go has for http.Request. It's not a breaking change.

  2. Change all func signature and add the context.Context as a first parameter. It's a breaking change in external API.

There is also an option to add context.Context to struct but it won't work in this case and it's ugly and problematic.

If you agree with one of the provided option, I can create a dedicated PR 👍

Issue with `gh.CurrentRepository`: `unable to determine current repository, none of the git remotes configured for this repository point to a known GitHub host`

Hello! 👋

I have recently created a GitHub CLI extension, gh-collab-scanner, that relies on gh.CurrentRepository to detect the current GitHub repository.

I don't understand why it does not work on my Ubuntu laptop: unable to determine current repository, none of the git remotes configured for this repository point to a known GitHub host error occurs, see nicokosi/gh-collab-scanner#13 (but it works on my macOS laptop).

Thanks in advance for your help.

Add a GraphQL Mutation with an `input` object to examples

I noticed that there are no examples of Mutations in https://github.com/cli/go-gh/blob/trunk/example_gh_test.go

I think this is important for a few reasons:

  • there's no mention of Mutate in the examples or in the readme. including it in the examples may make it more discoverable
  • unlike queries, many of the GitHub GraphQL mutations take an input object, for example the addStar mutation and its input. because this is a nested object, it has a different format than queries such as
    func ExampleGQLClient_advanced() {
    Figuring out the right Go syntax took me some time even when I had a properly formed GraphQL mutation to compare it to

If you agree, I'd be happy to open a PR to update, and would like to know:

  1. is addStar a good reference, or is there another that looks better?
  2. for variables, would it be better to use https://github.com/shurcooL/githubv4 or to use only standard types?
  3. should the Readme also mention mutations, or is it sufficient to have them in the examples?

Allow default host to be determined based on configuration preference

Problem I'm dealing with

Terminal users who are not terminal savvy finding the environment variable only approach to overriding the default host logic confusing.

For multi-account users whose primary GitHub host is not github.com, they must use GH_HOST environment variable to target the appropriate host for core GitHub CLI commands or GitHub CLI extensions without repository context. It is also possible for core GitHub CLI commands and GitHub CLI extension authors to add support for --hostname flag to explicitly communicate this can be set / overridden but must be added intentionally.

The problem comes in for terminal users who are not savvy to working with terminals:

  1. This setting must be managed separately from hosts authenticated via gh auth login
    if the user gh auth logout from this host, then errors occur

  2. Shells offer different levels of scoping environment variables

    • Command-specific (GH_HOST=... gh api ...)
      PowerShell does not support this
    • Session-specific (export GH_HOST=...)
    • Semi-permanent (.zshrc, .bashrc, ~/.config/powershell/profile.ps1)
  3. Inconsistent experiences for users unfamiliar with login sessions versus non-interactive sessions
    .zprofile vs .zshrc, .bashrc vs .bash_profile

Ideas to address this

What if we could indicate which host should be the default?

$ cat ~/.config/gh/hosts.yml 
github.ghe.com:
    default: true
    git_protocol: https
    users:
        andyfeller:
    user: andyfeller
github.com:
    git_protocol: https
    users:
        andyfeller:
    user: andyfeller

In the example above, I want to specify that github.ghe.com is my default host in the event that the host can't be determined by repository context.

This would involve change to the following logic for determining default host:

go-gh/pkg/auth/auth.go

Lines 130 to 150 in dbd982e

// DefaultHost retrieves an authenticated host and the source of host.
// The source can be either an environment variable or from the
// configuration file.
// Returns "github.com", "default" if no viable host is found.
func DefaultHost() (string, string) {
cfg, _ := config.Read(nil)
return defaultHost(cfg)
}
func defaultHost(cfg *config.Config) (string, string) {
if host := os.Getenv(ghHost); host != "" {
return host, ghHost
}
if cfg != nil {
keys, err := cfg.Keys([]string{hostsKey})
if err == nil && len(keys) == 1 {
return keys[0], hostsKey
}
}
return github, defaultSource
}

Allow RESTClient and GQLClient to support automatic pagination

Pagination is currently not possible using RESTClient and takes lots of manual work using GQLClient. We should support this feature for both. Initial implementation idea is to add a pagination options to ClientOptions which would enable this for both clients and be a noop for the HTTPClient.

Support passing httptest URLs in api.ClientOptions

The standard library's httptest package makes stubbing APIs easy, if the client calls the test server's URL:

package main

import (
	"fmt"
	"net/http"
	"net/http/httptest"
)

func main() {
	tls := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer tls.Close()
	fmt.Println("tls hostname - ", tls.URL)
	// prints: tls hostname - https://127.0.0.1:42002

	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
	defer ts.Close()
	fmt.Println("ts hostname - ", ts.URL)
	// prints: ts hostname -  http://127.0.0.1:35061
}

In api.ClientOptions, one of the configuration fields is Host

Host string

for certain values the argument is returned unmodified

func restURL(hostname string, pathOrURL string) string {
if strings.HasPrefix(pathOrURL, "https://") || strings.HasPrefix(pathOrURL, "http://") {
return pathOrURL
}

I would like to propose adding another condition to the restURL function which would return the unmodified httptest server URL

if strings.HasPrefix(hostname, "https://127.0.0.1:") || strings.HasPrefix(hostname, "http://127.0.0.1:") {
	return hostname
}

This aligns with the conditional check on the prefix for the pathOrURL argument.

For reference, setting the ts.URL value to Host results in a URL similar to:

https://http//127.0.0.1:56261/api/v3/

as it satisfies this condition

if isEnterprise(hostname) {

I don't know if this means my proposed solution would break with Enterprises.

In writing this all out, I also realized that passing the hostname + path to client.Get, rather than just the api path, solves this issue.

GQLCLient should return GQLError for query and mutation methods

Right now the query and mutations methods on GQLCLient return an error type from shurcooL-graphql which does not match the concrete error type from the do methods. This causes unnecessary complexity when trying to do type assertion on the errors returned from the GQLCLient methods. To fix this we can wrap the errors returned from query and mutations methods in a GQLError.

initial feedback

suggestions for the example:

  • Include use of graphql
  • Include the gh external call fallback

Regarding the package API:

  • Is it worth including a shortcut way to get a REST/GQL client that auto-resolves host/token/remote based on the kind of logic we do in gh itself? As opposed to always requiring the three step process (pick remote, determine host, get+set token) to create clients?

Misc:

  • I agree that inline docs with examples for godoc to pick up is A+ like we talked about in sync in addition to a full example
  • something I've seen is running a full example as part of some build automation to make sure that it stays up to date. I'm not sure if that's too much effort here but it might be worth considering.

[Discussion] Desired features

This looks like a great start and has good features for basic binary extensions, but when I opened cli/cli#4264 I was hoping to see more low-level implementations either ported or refactored out into a shared library both the CLI and binary extension developers could use. For example,

  • Support for -R command line switch, or at least the APIs to make adding one work. I do see that environment variables that gh uses are parsed, but it would be great to provide the same command line switches (even if you don't force a dependency on Cobra Command).
  • Expose some of the formatting like the templating APIs already there and ones I've helped improve. Binary extensions could just shell out to gh but this seems otherwise unnecessary if more of the formatting code was expose from cli/cli/pkg.

Flag for printing only GraphQL information

This project has made my work significantly easier, thank you!

I am finding that often I am wanting to print only the GraphQL query & GraphQL variables but not the HTTP information. I know you can set os.Setenv("GH_DEBUG", "api") to print the GraphQL & HTTP information. I am finding that when I am developing my GraphQL struct that it would be useful to reduce some of the noise and only print out the GraphQL information.

Expose `ghLookupPath` or a better way to run `gh`

Been using go-gh for a few things and liking it so far!

I have a use case where I want to run gh as a long running command and I want to take over the writer for stdout and stderr. With the current APIs, I can't do this.

See example of how I am doing it right now by directly invoking gh: https://github.com/josebalius/gh-csfs/blob/main/internal/csfs/ssh.go#L37-L56

This solution works perfectly, but I am hardcoding gh, so it would be nice to either expose the lookup path function or a way to inject writers.

@eXamadeus GitHub CLI currently has no mechanism for switching between multiple GitHub accounts and I don't really have a workaround to suggest for you at this moment, sorry.

    @eXamadeus GitHub CLI currently has no mechanism for switching between multiple GitHub accounts and I don't really have a workaround to suggest for you at this moment, sorry.

The only approach I could imagine, but would not recommend to anyone, would be to authenticate with 1st account, save a copy of ~/.config/gh/hosts.yml somewhere & delete the original file, authenticate again with the 2nd account, and now you can swap the ~/.config/gh/hosts.yml file with the backup file when you need to switch accounts.

Since this solution involves using SSH for git protocol, make sure both configuration files include the git_protocol: ssh line.

Originally posted by @mislav in cli/cli#326 (comment)

Status code extraction on response/error

I had a quick question/feedback - I was wondering if a status code could be included along with the response from the gh.RESTClient().Get?

for example I was making a call

client, err := gh.RESTClient(options)
<snip>
err = client.Get("enterprises/avocado-corp/audit-log", &response)
Unfortunately err  cannot be type-casted to api.httperror since api.httperror is not exported, so Id have to rely on string parsing to figure out the error code here. Alternatively api.httpError could be exported to api.HTTPError , in which case the caller can then typecast the error and get all the relevant bits in the struct and do things like retry on certain statusCodes etc.
e.g
err = client.Get(blah)
if err != nil {
    httpError := err.(*api.HttpError)
    if httpError.statusCode == 502 {
            ...retry
     }else{
            ...do something else
      }
}

or the other option would be to read the statusCode, if it’s set on the response.

Does that make sense?

I started a PR to export api.HttpError here - 6596865

Thanks for reading ❤️ .

RestClient no longer returns an HTTPError

Before the bump to v2, I could do this:

import {
  ...
  "github.com/cli/go-gh/v2/pkg/api"
}
...

err = restClient.Get(path, &resp)
if err != nil {
  if err.(api.HTTPError).StatusCode == 404 {
    log.Fatal("special message")
  }
  log.Fatal("general message")
}

Since updating, that is no longer a valid casting. I tried doing errors.As, but that didn't seem to work either.

Based on some other repositories I found, I tried this:

import {
  ...
  ghApi "github.com/cli/go-gh/v2/pkg/api"
  "github.com/cli/cli/v2/api"
}
...

restClient, err := ghApi.DefaultRESTClient()
if err != nil {
  log.Fatal(err)
}
...

err = restClient.Get(path, &resp)
if err != nil {
  var httpErr api.HTTPError
  if errors.As(err, &httpErr) && httpErr.StatusCode == 404 {
    log.Fatal("special message")
  }
  log.Fatal("general message")
}

This is always going to the general Fatal response message and not the special message. It seems that the errors.As casting is not working here, and the error is a simple string error. I'd love to be able to parse this status code without examining the error string (which does return "HTTP 404: Not Found...").

Is there some new, undocumented method to consume these errors, or was this an accidental regression? Thanks.

`asciisanitizer.Sanitizer` mishandled the `�` unicode character

We have encountered an error when using the GitHub cli to fetch commits in an MDN repository. And I found this error is coursed by the sanitizer which is used by GitHub cli.

So I created a demo to reproduce the problem:

the plain text to transform:

�, plain text

When we read the plain text, and use transform with the the sanitizer , we would got an error:

image

But this should be the correct text. I found the error is returned here.

So I read the signature of utf8.DecodeRune. It may also return utf8.RuneError if the bytes are correctly decoded. And if there does be a decode error, it will return (RuneError, 0) or (RuneError, 1).

So we can't judge whether there is a decoding error just based on the first value returned, like the text I used above, which uses this unicode character. The sanitizer mishandled it.

RESTClient not accepting query string

I have a use case where I need to search for repositories containing certain query criteria (say name or language): essentially reproducing the standard repository search. Using the gh CLI this can be achieved via:

gh api -X GET /search/repositories -f q='<name> in:name language: <lang>'

I am trying to reproduce the above with the RESTClient call, passing the query search somehow as header string; however, according to the docs this grammar is not accepted (namely there is no way to pass a query string to the RESTClient object). Practically speaking I am looking to do something along the lines of

opts := api.ClientOptions{
	...
	Headers:  <insert grammar for query string>  <---- this bit must be filled correctly
	Log:       os.Stdout,
}
...
...
client, err := RESTClient(&opts) <--- the query string is passed to the client
...
err = client.Get("search/repositories", &response) <--- notice the endpoint /search/repositories

Question

What is the correct way to achieve the above?

releasing/installing extensions

First, this is awesome. I started out assuming I was going to need to hack my commands into the CLI proper and then found the extension mechanism. Perfect.

I have a question about how to release the extension so others can install it. I wrote up a quick Go-based extension, put it in a gh-* repo and installed it locally (gh extension install .). Worked like a charm. So good I want to share. I saw the template put in a release workflow so I went ahead and tagged and pushed and the workflow ran and I duly got a mess of binaries in a release. Great.

I flipped back to my client and ran gh extension install org/gh-repo and it complains that extension is uninstallable: missing executable. I'm not sure how this is supposed to work. The doc said a few things about having to have "the executable" in the root of the repo but for compiled code

  • What's the executable for native code where many platforms are supported?
  • If we are meant to put all of the various executables at the root of the repo,
    • what's the naming convention for the executables at the root for all the different platforms?
    • it would be great to have some helpers to generate all those. Even better if we can use Actions and the release workflow.
  • Can you pick a Git ref (sha, tag, branch) of the repo that people will get by default? Users randomly getting the latest WIP form the default branch or forcing the dev team's normal development out of the default branch feels troublesome.
  • These files can start to get large. (my trivial one is ~8MB but then times 7 platforms)... and I'll inevitably keep accidentally pushing new versions all the time with my WIP code changes
  • What's the role of a release and the workflow in all of this?

Seems ideal here to use the Release mechanism and say that installing gets the executables from latest release by default and you can say something like install org/[email protected] if you want a specific release.

`isEnterprise` returns `true` incorrectly on `github.localhost`

Hello! I have an admittedly niche problem - I'm working on a CLI extension against github.localhost, which means setting GH_HOST=github.localhost for each command. Calling isEnterprise returns true in that case, because it is not github.com:

func isEnterprise(host string) bool {
return host != defaultHost
}

That results in an incorrect (and un-fixable) URL here:

func restPrefix(hostname string) string {
if isEnterprise(hostname) {
return fmt.Sprintf("https://%s/api/v3/", hostname)
}
return "https://api.github.com/"
}

As far as I can tell, there's no way for me to say "use GH_HOST, but also use api.<GH_HOST> instead of <GH_HOST>/api/v3". Is that correct, or is there a patch needed here? Happy to open a PR adding an exception for github.localhost if that makes sense, or some more consistent way of setting the full URL?


FWIW, I did think that maybe have GH_HOST=http://api.github.localhost would work, but that gives:

Post "https://http//api.github.localhost/api/v3/repos/:owner/:repo/<REDACTED>"

TokenForHost returns string "oauth_token" as source when config is read from file

TokenForHost source return value should be a value like GH_TOKEN or GITHUB_TOKEN when the token comes from an environment variable, or a file path (e.g. /path/to/hosts.yml) when the value comes from a file. However, a static string oauth_token is returned instead of a file name:

return token, oauthToken

Since oauth_token source is not useful to find out where a value comes from, printing the file name would be better.

Ref. #44

Support for paginating API responses?

I'm using this for getting changed files between two commits, I presume this will split across pages, is there a way using the HTTPClient to get at the Link headers?

hyperlink truncated at end of row isn't closed correctly

When using a template with a hyperlink at the end, if the the line is truncated the link its closed correctly.

gh api notifications --template '{{tablerow "Reason" "When" "Repo" "Title" -}}
{{ range . -}}
{{tablerow (.reason | autocolor "cyan") (timeago .updated_at) (.repository.full_name) (hyperlink "https://github.com/notifications" (.subject.title | autocolor "yellow")) -}}
{{end -}}'

Below output is from redirecting to a file, and using sed -n l0 file

With a the available space in terminal window the link is closed correctly:

\033]8;;https://github.com/notifications\033\\build(deps): bump pre-commit helm-docs to v1.13.0\033]8;;\033\\$

When the terminal is too small, the link isn't closed

\033]8;;https://github.com/notifications\033\\build(deps):...$

Therefore turning everything after that in terminal too a link, running the following clears it printf '\e]8;;'

Issue while using from remote connection

As I am utilizing this module for using browser on my cli, I tried to generate error using the cli using ssh connection, but no any error is thrown and the browser also cannot start sitting on CLI.

Actual:

Press Enter to continue.. 
[22660:22660:0710/170853.558426:ERROR:ozone_platform_x11.cc(239)] Missing X server or $DISPLAY
[22660:22660:0710/170853.558460:ERROR:env.cc(255)] The platform failed to initialize.  Exiting.
Err: <nil>

Expected: error to be not nil in value.

If anyone wants to watch out the code, then I will dump it here.

Check auth status

If the CLI isn't already authenticated, extensions can fail in various ways depending on what they call. For example, using gh.CurrentRepository() - even in a repo - fails with errors.New("unable to determine current repository, none of the git remotes configured for this repository point to a known GitHub host"). If you specify a repo explicitly, gh.GQLClient() can fail with an internal config.NotFoundError which, given it's in internal, cannot be referenced so might as well be a generic error. To the user, the error simply prints "not found" which isn't actionable. Even the more wordy error mentioned first isn't that actionable, though more useful.

Instead, what about something like gh.IsAuthenticated() bool? It could, for example, call config.Load() and then check the Config.AuthToken for a known host. This would allow extensions to easily check up front if they should prompt the user to authenticate.

Alternatively, expose any auth-related errors in pkg or something so we can do type assertions.

Incorrect tag format for latest release

Hey - thank you for pushing out the latest release. Please could you correct the tag as it has a . between the v and semver.

https://github.com/cli/go-gh/releases/tag/v.0.0.2

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.