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

Add --json export flag for release list #8474

Open
wants to merge 1 commit into
base: trunk
Choose a base branch
from

Conversation

v1v
Copy link

@v1v v1v commented Dec 19, 2023

It was similarly solved in #3869 but for the release list command.

In addition, I added the same logic for empty results as explained in #6419.

$ go run cmd/gh/main.go \
  release list \
  --limit 1 \
  --json name,tagName \
  --jq '.[]' --repo cli/cli
{"name":"GitHub CLI 2.40.1","tagName":"v2.40.1"}
$ go run cmd/gh/main.go \
  release list --help
List releases in a repository

For more information about output formatting flags, see `gh help formatting`.

USAGE
  gh release list [flags]

FLAGS
      --exclude-drafts         Exclude draft releases
      --exclude-pre-releases   Exclude pre-releases
  -q, --jq expression          Filter JSON output using a jq expression
      --json fields            Output JSON with the specified fields
  -L, --limit int              Maximum number of items to fetch (default 30)
  -t, --template string        Format JSON output using a Go template; see "gh help formatting"

Closes #4572

@v1v v1v requested a review from a team as a code owner December 19, 2023 20:38
@v1v v1v requested review from samcoe and removed request for a team December 19, 2023 20:38
@cliAutomation cliAutomation added the external pull request originating outside of the CLI core team label Dec 19, 2023
@cliAutomation cliAutomation added this to Needs review 🤔 in The GitHub CLI Dec 19, 2023
@v1v v1v changed the title release-list: support for --json Add --json export flag for release list Dec 19, 2023
@andyfeller
Copy link
Contributor

@samcoe @williammartin : Are these changes necessary because we have different Release types floating around?

var ReleaseFields = []string{
"url",
"apiUrl",
"uploadUrl",
"tarballUrl",
"zipballUrl",
"id",
"tagName",
"name",
"body",
"isDraft",
"isPrerelease",
"createdAt",
"publishedAt",
"targetCommitish",
"author",
"assets",
}
type Release struct {
DatabaseID int64 `json:"id"`
ID string `json:"node_id"`
TagName string `json:"tag_name"`
Name string `json:"name"`
Body string `json:"body"`
IsDraft bool `json:"draft"`
IsPrerelease bool `json:"prerelease"`
CreatedAt time.Time `json:"created_at"`
PublishedAt *time.Time `json:"published_at"`
TargetCommitish string `json:"target_commitish"`
APIURL string `json:"url"`
UploadURL string `json:"upload_url"`
TarballURL string `json:"tarball_url"`
ZipballURL string `json:"zipball_url"`
URL string `json:"html_url"`
Assets []ReleaseAsset
Author struct {
ID string `json:"node_id"`
Login string `json:"login"`
}
}
type ReleaseAsset struct {
ID string `json:"node_id"`
Name string
Label string
Size int64
State string
APIURL string `json:"url"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DownloadCount int `json:"download_count"`
ContentType string `json:"content_type"`
BrowserDownloadURL string `json:"browser_download_url"`
}
func (rel *Release) ExportData(fields []string) map[string]interface{} {
v := reflect.ValueOf(rel).Elem()
fieldByName := func(v reflect.Value, field string) reflect.Value {
return v.FieldByNameFunc(func(s string) bool {
return strings.EqualFold(field, s)
})
}
data := map[string]interface{}{}
for _, f := range fields {
switch f {
case "author":
data[f] = map[string]interface{}{
"id": rel.Author.ID,
"login": rel.Author.Login,
}
case "assets":
assets := make([]interface{}, 0, len(rel.Assets))
for _, a := range rel.Assets {
assets = append(assets, map[string]interface{}{
"url": a.BrowserDownloadURL,
"apiUrl": a.APIURL,
"id": a.ID,
"name": a.Name,
"label": a.Label,
"size": a.Size,
"state": a.State,
"createdAt": a.CreatedAt,
"updatedAt": a.UpdatedAt,
"downloadCount": a.DownloadCount,
"contentType": a.ContentType,
})
}
data[f] = assets
default:
sf := fieldByName(v, f)
data[f] = sf.Interface()
}
}
return data
}

var ReleaseFields = []string{
"name",
"tagName",
"isDraft",
"isLatest",
"isPrerelease",
"createdAt",
"publishedAt",
}
type Release struct {
Name string
TagName string
IsDraft bool
IsLatest bool
IsPrerelease bool
CreatedAt time.Time
PublishedAt time.Time
}

I haven't dug into the history behind the "shared" version especially given it doesn't seem like the only implementation. I worry having these separate code paths makes it difficult to maintain and ensure a consistent experience.

@andyfeller
Copy link
Contributor

@v1v : Thank you for opening this PR and your patience over the holidays! 🙇

Copy link
Member

@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.

@v1v Thanks for getting started on this work, and your patients. This is looking great so far. I left a couple code comments, please let me know if any of them are unclear. In addition to the addressing the code comments it would be great to add a couple tests to verify the new functionality.

"time"

"github.com/cli/cli/v2/api"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/shurcooL/githubv4"
)

var ReleaseFields = []string{
Copy link
Member

Choose a reason for hiding this comment

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

Two things here:

  1. This does not need to be exported
Suggested change
var ReleaseFields = []string{
var releaseFields = []string{
  1. In other release commands we already support the --json export and we should try to match the fields that are available there as best we can. We are using the GraphQL endpoint here so not all the fields will be available but the ones that are would be nice to include. One exception I would say are the assets. Including the assets would dramatically increase the data retrieved from the release list command and could have detrimental UX implications.

@@ -76,3 +88,20 @@ loop:

return releases, nil
}

func (r *Release) ExportData(fields []string) map[string]interface{} {
Copy link
Member

Choose a reason for hiding this comment

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

This exact function has been copy/pasted a couple times in the code base, it would be nice to have a single place for it. I don't think this needs to be addressed in this PR but just a note for the future.

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
  
Needs review 🤔
Development

Successfully merging this pull request may close these issues.

Extend gh release list to add --json flag
4 participants