Add repo view --json export functionality
This commit is contained in:
parent
5f0301c990
commit
02a2ed2f73
10 changed files with 447 additions and 46 deletions
|
|
@ -13,7 +13,7 @@ func (issue *Issue) ExportData(fields []string) *map[string]interface{} {
|
|||
switch f {
|
||||
case "milestone":
|
||||
if issue.Milestone.Title != "" {
|
||||
data[f] = &issue.Milestone
|
||||
data[f] = map[string]string{"title": issue.Milestone.Title}
|
||||
} else {
|
||||
data[f] = nil
|
||||
}
|
||||
|
|
@ -44,7 +44,7 @@ func (pr *PullRequest) ExportData(fields []string) *map[string]interface{} {
|
|||
data[f] = map[string]string{"name": pr.HeadRepository.Name}
|
||||
case "milestone":
|
||||
if pr.Milestone.Title != "" {
|
||||
data[f] = &pr.Milestone
|
||||
data[f] = map[string]string{"title": pr.Milestone.Title}
|
||||
} else {
|
||||
data[f] = nil
|
||||
}
|
||||
|
|
|
|||
53
api/export_repo.go
Normal file
53
api/export_repo.go
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
func (repo *Repository) ExportData(fields []string) *map[string]interface{} {
|
||||
v := reflect.ValueOf(repo).Elem()
|
||||
data := map[string]interface{}{}
|
||||
|
||||
for _, f := range fields {
|
||||
switch f {
|
||||
case "parent":
|
||||
data[f] = miniRepoExport(repo.Parent)
|
||||
case "templateRepository":
|
||||
data[f] = miniRepoExport(repo.TemplateRepository)
|
||||
case "languages":
|
||||
data[f] = repo.Languages.Edges
|
||||
case "labels":
|
||||
data[f] = repo.Labels.Nodes
|
||||
case "assignableUsers":
|
||||
data[f] = repo.AssignableUsers.Nodes
|
||||
case "mentionableUsers":
|
||||
data[f] = repo.MentionableUsers.Nodes
|
||||
case "milestones":
|
||||
data[f] = repo.Milestones.Nodes
|
||||
case "projects":
|
||||
data[f] = repo.Projects.Nodes
|
||||
case "repositoryTopics":
|
||||
var topics []RepositoryTopic
|
||||
for _, n := range repo.RepositoryTopics.Nodes {
|
||||
topics = append(topics, n.Topic)
|
||||
}
|
||||
data[f] = topics
|
||||
default:
|
||||
sf := fieldByName(v, f)
|
||||
data[f] = sf.Interface()
|
||||
}
|
||||
}
|
||||
|
||||
return &data
|
||||
}
|
||||
|
||||
func miniRepoExport(r *Repository) map[string]interface{} {
|
||||
if r == nil {
|
||||
return nil
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"id": r.ID,
|
||||
"name": r.Name,
|
||||
"owner": r.Owner,
|
||||
}
|
||||
}
|
||||
|
|
@ -91,7 +91,10 @@ func (p ProjectCards) ProjectNames() []string {
|
|||
}
|
||||
|
||||
type Milestone struct {
|
||||
Title string `json:"title"`
|
||||
Number int `json:"number"`
|
||||
Title string `json:"title"`
|
||||
Description string `json:"description"`
|
||||
DueOn *time.Time `json:"dueOn"`
|
||||
}
|
||||
|
||||
type IssuesDisabledError struct {
|
||||
|
|
|
|||
|
|
@ -16,25 +16,100 @@ import (
|
|||
|
||||
// Repository contains information about a GitHub repo
|
||||
type Repository struct {
|
||||
ID string
|
||||
Name string
|
||||
Description string
|
||||
URL string
|
||||
CloneURL string
|
||||
CreatedAt time.Time
|
||||
Owner RepositoryOwner
|
||||
ID string
|
||||
Name string
|
||||
NameWithOwner string
|
||||
Owner RepositoryOwner
|
||||
Parent *Repository
|
||||
TemplateRepository *Repository
|
||||
Description string
|
||||
HomepageURL string
|
||||
OpenGraphImageURL string
|
||||
UsesCustomOpenGraphImage bool
|
||||
URL string
|
||||
SSHURL string
|
||||
MirrorURL string
|
||||
SecurityPolicyURL string
|
||||
|
||||
IsPrivate bool
|
||||
HasIssuesEnabled bool
|
||||
HasWikiEnabled bool
|
||||
ViewerPermission string
|
||||
DefaultBranchRef BranchRef
|
||||
CreatedAt time.Time
|
||||
PushedAt *time.Time
|
||||
UpdatedAt time.Time
|
||||
|
||||
Parent *Repository
|
||||
IsBlankIssuesEnabled bool
|
||||
IsSecurityPolicyEnabled bool
|
||||
HasIssuesEnabled bool
|
||||
HasProjectsEnabled bool
|
||||
HasWikiEnabled bool
|
||||
MergeCommitAllowed bool
|
||||
SquashMergeAllowed bool
|
||||
RebaseMergeAllowed bool
|
||||
|
||||
MergeCommitAllowed bool
|
||||
RebaseMergeAllowed bool
|
||||
SquashMergeAllowed bool
|
||||
ForkCount int
|
||||
StargazerCount int
|
||||
Watchers struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
Issues struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
PullRequests struct {
|
||||
TotalCount int `json:"totalCount"`
|
||||
}
|
||||
|
||||
CodeOfConduct *CodeOfConduct
|
||||
ContactLinks []ContactLink
|
||||
DefaultBranchRef BranchRef
|
||||
DeleteBranchOnMerge bool
|
||||
DiskUsage int
|
||||
FundingLinks []FundingLink
|
||||
IsArchived bool
|
||||
IsEmpty bool
|
||||
IsFork bool
|
||||
IsInOrganization bool
|
||||
IsMirror bool
|
||||
IsPrivate bool
|
||||
IsTemplate bool
|
||||
IsUserConfigurationRepository bool
|
||||
LicenseInfo *RepositoryLicense
|
||||
ViewerCanAdminister bool
|
||||
ViewerDefaultCommitEmail string
|
||||
ViewerDefaultMergeMethod string
|
||||
ViewerHasStarred bool
|
||||
ViewerPermission string
|
||||
ViewerPossibleCommitEmails []string
|
||||
ViewerSubscription string
|
||||
|
||||
RepositoryTopics struct {
|
||||
Nodes []struct {
|
||||
Topic RepositoryTopic
|
||||
}
|
||||
}
|
||||
PrimaryLanguage *CodingLanguage
|
||||
Languages struct {
|
||||
Edges []struct {
|
||||
Size int `json:"size"`
|
||||
Node CodingLanguage `json:"node"`
|
||||
}
|
||||
}
|
||||
IssueTemplates []IssueTemplate
|
||||
PullRequestTemplates []PullRequestTemplate
|
||||
Labels struct {
|
||||
Nodes []IssueLabel
|
||||
}
|
||||
Milestones struct {
|
||||
Nodes []Milestone
|
||||
}
|
||||
LatestRelease *RepositoryRelease
|
||||
|
||||
AssignableUsers struct {
|
||||
Nodes []GitHubUser
|
||||
}
|
||||
MentionableUsers struct {
|
||||
Nodes []GitHubUser
|
||||
}
|
||||
Projects struct {
|
||||
Nodes []RepoProject
|
||||
}
|
||||
|
||||
// pseudo-field that keeps track of host name of this repo
|
||||
hostname string
|
||||
|
|
@ -42,12 +117,76 @@ type Repository struct {
|
|||
|
||||
// RepositoryOwner is the owner of a GitHub repository
|
||||
type RepositoryOwner struct {
|
||||
Login string
|
||||
ID string `json:"id"`
|
||||
Login string `json:"login"`
|
||||
}
|
||||
|
||||
type GitHubUser struct {
|
||||
ID string `json:"id"`
|
||||
Login string `json:"login"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
// BranchRef is the branch name in a GitHub repository
|
||||
type BranchRef struct {
|
||||
Name string
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type CodeOfConduct struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type RepositoryLicense struct {
|
||||
Key string `json:"key"`
|
||||
Name string `json:"name"`
|
||||
Nickname string `json:"nickname"`
|
||||
}
|
||||
|
||||
type ContactLink struct {
|
||||
About string `json:"about"`
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type FundingLink struct {
|
||||
Platform string `json:"platform"`
|
||||
URL string `json:"url"`
|
||||
}
|
||||
|
||||
type CodingLanguage struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type IssueTemplate struct {
|
||||
Name string `json:"name"`
|
||||
Title string `json:"title"`
|
||||
Body string `json:"body"`
|
||||
About string `json:"about"`
|
||||
}
|
||||
|
||||
type PullRequestTemplate struct {
|
||||
Filename string `json:"filename"`
|
||||
Body string `json:"body"`
|
||||
}
|
||||
|
||||
type RepositoryTopic struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
type RepositoryRelease struct {
|
||||
Name string `json:"name"`
|
||||
TagName string `json:"tagName"`
|
||||
URL string `json:"url"`
|
||||
PublishedAt time.Time `json:"publishedAt"`
|
||||
}
|
||||
|
||||
type IssueLabel struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Color string `json:"color"`
|
||||
}
|
||||
|
||||
// RepoOwner is the login name of the owner
|
||||
|
|
@ -65,11 +204,6 @@ func (r Repository) RepoHost() string {
|
|||
return r.hostname
|
||||
}
|
||||
|
||||
// IsFork is true when this repository has a parent repository
|
||||
func (r Repository) IsFork() bool {
|
||||
return r.Parent != nil
|
||||
}
|
||||
|
||||
// ViewerCanPush is true when the requesting user has push access
|
||||
func (r Repository) ViewerCanPush() bool {
|
||||
switch r.ViewerPermission {
|
||||
|
|
@ -305,7 +439,6 @@ type repositoryV3 struct {
|
|||
NodeID string
|
||||
Name string
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
CloneURL string `json:"clone_url"`
|
||||
Owner struct {
|
||||
Login string
|
||||
}
|
||||
|
|
@ -324,7 +457,6 @@ func ForkRepo(client *Client, repo ghrepo.Interface) (*Repository, error) {
|
|||
return &Repository{
|
||||
ID: result.NodeID,
|
||||
Name: result.Name,
|
||||
CloneURL: result.CloneURL,
|
||||
CreatedAt: result.CreatedAt,
|
||||
Owner: RepositoryOwner{
|
||||
Login: result.Owner.Login,
|
||||
|
|
@ -707,9 +839,10 @@ func RepoResolveMetadataIDs(client *Client, repo ghrepo.Interface, input RepoRes
|
|||
}
|
||||
|
||||
type RepoProject struct {
|
||||
ID string
|
||||
Name string
|
||||
ResourcePath string
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Number int `json:"number"`
|
||||
ResourcePath string `json:"resourcePath"`
|
||||
}
|
||||
|
||||
// RepoProjects fetches all open projects for a repository
|
||||
|
|
|
|||
|
|
@ -144,9 +144,9 @@ func Test_RepoMetadata(t *testing.T) {
|
|||
func Test_ProjectsToPaths(t *testing.T) {
|
||||
expectedProjectPaths := []string{"OWNER/REPO/PROJECT_NUMBER", "ORG/PROJECT_NUMBER"}
|
||||
projects := []RepoProject{
|
||||
{"id1", "My Project", "/OWNER/REPO/projects/PROJECT_NUMBER"},
|
||||
{"id2", "Org Project", "/orgs/ORG/projects/PROJECT_NUMBER"},
|
||||
{"id3", "Project", "/orgs/ORG/projects/PROJECT_NUMBER_2"},
|
||||
{ID: "id1", Name: "My Project", ResourcePath: "/OWNER/REPO/projects/PROJECT_NUMBER"},
|
||||
{ID: "id2", Name: "Org Project", ResourcePath: "/orgs/ORG/projects/PROJECT_NUMBER"},
|
||||
{ID: "id3", Name: "Project", ResourcePath: "/orgs/ORG/projects/PROJECT_NUMBER_2"},
|
||||
}
|
||||
projectNames := []string{"My Project", "Org Project"}
|
||||
|
||||
|
|
|
|||
|
|
@ -186,3 +186,133 @@ func PullRequestGraphQL(fields []string) string {
|
|||
}
|
||||
return strings.Join(q, ",")
|
||||
}
|
||||
|
||||
var RepositoryFields = []string{
|
||||
"id",
|
||||
"name",
|
||||
"nameWithOwner",
|
||||
"owner",
|
||||
"parent",
|
||||
"templateRepository",
|
||||
"description",
|
||||
"homepageUrl",
|
||||
"openGraphImageUrl",
|
||||
"usesCustomOpenGraphImage",
|
||||
"url",
|
||||
"sshUrl",
|
||||
"mirrorUrl",
|
||||
"securityPolicyUrl",
|
||||
|
||||
"createdAt",
|
||||
"pushedAt",
|
||||
"updatedAt",
|
||||
|
||||
"isBlankIssuesEnabled",
|
||||
"isSecurityPolicyEnabled",
|
||||
"hasIssuesEnabled",
|
||||
"hasProjectsEnabled",
|
||||
"hasWikiEnabled",
|
||||
"mergeCommitAllowed",
|
||||
"squashMergeAllowed",
|
||||
"rebaseMergeAllowed",
|
||||
|
||||
"forkCount",
|
||||
"stargazerCount",
|
||||
"watchers",
|
||||
"issues",
|
||||
"pullRequests",
|
||||
|
||||
"codeOfConduct",
|
||||
"contactLinks",
|
||||
"defaultBranchRef",
|
||||
"deleteBranchOnMerge",
|
||||
"diskUsage",
|
||||
"fundingLinks",
|
||||
"isArchived",
|
||||
"isEmpty",
|
||||
"isFork",
|
||||
"isInOrganization",
|
||||
"isMirror",
|
||||
"isPrivate",
|
||||
"isTemplate",
|
||||
"isUserConfigurationRepository",
|
||||
"licenseInfo",
|
||||
"viewerCanAdminister",
|
||||
"viewerDefaultCommitEmail",
|
||||
"viewerDefaultMergeMethod",
|
||||
"viewerHasStarred",
|
||||
"viewerPermission",
|
||||
"viewerPossibleCommitEmails",
|
||||
"viewerSubscription",
|
||||
|
||||
"repositoryTopics",
|
||||
"primaryLanguage",
|
||||
"languages",
|
||||
"issueTemplates",
|
||||
"pullRequestTemplates",
|
||||
"labels",
|
||||
"milestones",
|
||||
"latestRelease",
|
||||
|
||||
"assignableUsers",
|
||||
"mentionableUsers",
|
||||
"projects",
|
||||
|
||||
// "branchProtectionRules", // too complex to expose
|
||||
// "collaborators", // does it make sense to expose without affiliation filter?
|
||||
}
|
||||
|
||||
func RepositoryGraphQL(fields []string) string {
|
||||
var q []string
|
||||
for _, field := range fields {
|
||||
switch field {
|
||||
case "codeOfConduct":
|
||||
q = append(q, "codeOfConduct{key,name,url}")
|
||||
case "contactLinks":
|
||||
q = append(q, "contactLinks{about,name,url}")
|
||||
case "fundingLinks":
|
||||
q = append(q, "fundingLinks{platform,url}")
|
||||
case "licenseInfo":
|
||||
q = append(q, "licenseInfo{key,name,nickname}")
|
||||
case "owner":
|
||||
q = append(q, "owner{id,login}")
|
||||
case "parent":
|
||||
q = append(q, "parent{id,name,owner{id,login}}")
|
||||
case "templateRepository":
|
||||
q = append(q, "templateRepository{id,name,owner{id,login}}")
|
||||
case "repositoryTopics":
|
||||
q = append(q, "repositoryTopics(first:100){nodes{topic{name}}}")
|
||||
case "issueTemplates":
|
||||
q = append(q, "issueTemplates{name,title,body,about}")
|
||||
case "pullRequestTemplates":
|
||||
q = append(q, "pullRequestTemplates{body,filename}")
|
||||
case "labels":
|
||||
q = append(q, "labels(first:100){nodes{id,color,name,description}}")
|
||||
case "languages":
|
||||
q = append(q, "languages(first:100){edges{size,node{name}}}")
|
||||
case "primaryLanguage":
|
||||
q = append(q, "primaryLanguage{name}")
|
||||
case "latestRelease":
|
||||
q = append(q, "latestRelease{publishedAt,tagName,name,url}")
|
||||
case "milestones":
|
||||
q = append(q, "milestones(first:100,states:OPEN){nodes{number,title,description,dueOn}}")
|
||||
case "assignableUsers":
|
||||
q = append(q, "assignableUsers(first:100){nodes{id,login,name}}")
|
||||
case "mentionableUsers":
|
||||
q = append(q, "mentionableUsers(first:100){nodes{id,login,name}}")
|
||||
case "projects":
|
||||
q = append(q, "projects(first:100,states:OPEN){nodes{id,name,number,body,resourcePath}}")
|
||||
case "watchers":
|
||||
q = append(q, "watchers{totalCount}")
|
||||
case "issues":
|
||||
q = append(q, "issues(states:OPEN){totalCount}")
|
||||
case "pullRequests":
|
||||
q = append(q, "pullRequests(states:OPEN){totalCount}")
|
||||
case "defaultBranchRef":
|
||||
q = append(q, "defaultBranchRef{name}")
|
||||
default:
|
||||
q = append(q, field)
|
||||
}
|
||||
}
|
||||
return strings.Join(q, ",")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,7 +104,7 @@ func (r *ResolvedRemotes) BaseRepo(io *iostreams.IOStreams) (ghrepo.Interface, e
|
|||
if repo == nil {
|
||||
continue
|
||||
}
|
||||
if repo.IsFork() {
|
||||
if repo.Parent != nil {
|
||||
add(repo.Parent)
|
||||
}
|
||||
add(repo)
|
||||
|
|
|
|||
|
|
@ -12,6 +12,25 @@ import (
|
|||
|
||||
var NotFoundError = errors.New("not found")
|
||||
|
||||
func fetchRepository(apiClient *api.Client, repo ghrepo.Interface, fields []string) (*api.Repository, error) {
|
||||
query := fmt.Sprintf(`query RepositoryInfo($owner: String!, $name: String!) {
|
||||
repository(owner: $owner, name: $name) {%s}
|
||||
}`, api.RepositoryGraphQL(fields))
|
||||
|
||||
variables := map[string]interface{}{
|
||||
"owner": repo.RepoOwner(),
|
||||
"name": repo.RepoName(),
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Repository api.Repository
|
||||
}
|
||||
if err := apiClient.GraphQL(repo.RepoHost(), query, variables, &result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return api.InitRepoHostname(&result.Repository, repo.RepoHost()), nil
|
||||
}
|
||||
|
||||
type RepoReadme struct {
|
||||
Filename string
|
||||
Content string
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ type ViewOptions struct {
|
|||
IO *iostreams.IOStreams
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Browser browser
|
||||
Exporter cmdutil.Exporter
|
||||
|
||||
RepoArg string
|
||||
Web bool
|
||||
|
|
@ -67,10 +68,13 @@ With '--branch', view a specific branch of the repository.`,
|
|||
|
||||
cmd.Flags().BoolVarP(&opts.Web, "web", "w", false, "Open a repository in the browser")
|
||||
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "View a specific branch of the repository")
|
||||
cmdutil.AddJSONFlags(cmd, &opts.Exporter, api.RepositoryFields)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
var defaultFields = []string{"name", "owner", "description"}
|
||||
|
||||
func viewRun(opts *ViewOptions) error {
|
||||
httpClient, err := opts.HttpClient()
|
||||
if err != nil {
|
||||
|
|
@ -101,11 +105,24 @@ func viewRun(opts *ViewOptions) error {
|
|||
}
|
||||
}
|
||||
|
||||
repo, err := api.GitHubRepo(apiClient, toView)
|
||||
var readme *RepoReadme
|
||||
fields := defaultFields
|
||||
if opts.Exporter != nil {
|
||||
fields = opts.Exporter.Fields()
|
||||
}
|
||||
|
||||
repo, err := fetchRepository(apiClient, toView, fields)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !opts.Web && opts.Exporter == nil {
|
||||
readme, err = RepositoryReadme(httpClient, toView, opts.Branch)
|
||||
if err != nil && !errors.Is(err, NotFoundError) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
openURL := generateBranchURL(toView, opts.Branch)
|
||||
if opts.Web {
|
||||
if opts.IO.IsStdoutTTY() {
|
||||
|
|
@ -114,21 +131,17 @@ func viewRun(opts *ViewOptions) error {
|
|||
return opts.Browser.Browse(openURL)
|
||||
}
|
||||
|
||||
fullName := ghrepo.FullName(toView)
|
||||
|
||||
readme, err := RepositoryReadme(httpClient, toView, opts.Branch)
|
||||
if err != nil && err != NotFoundError {
|
||||
return err
|
||||
}
|
||||
|
||||
opts.IO.DetectTerminalTheme()
|
||||
|
||||
err = opts.IO.StartPager()
|
||||
if err != nil {
|
||||
if err := opts.IO.StartPager(); err != nil {
|
||||
return err
|
||||
}
|
||||
defer opts.IO.StopPager()
|
||||
|
||||
if opts.Exporter != nil {
|
||||
return opts.Exporter.Write(opts.IO.Out, repo, opts.IO.ColorEnabled())
|
||||
}
|
||||
|
||||
fullName := ghrepo.FullName(toView)
|
||||
stdout := opts.IO.Out
|
||||
|
||||
if !opts.IO.IsStdoutTTY() {
|
||||
|
|
|
|||
|
|
@ -3,10 +3,12 @@ package view
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/api"
|
||||
"github.com/cli/cli/internal/ghrepo"
|
||||
"github.com/cli/cli/internal/run"
|
||||
"github.com/cli/cli/pkg/cmdutil"
|
||||
|
|
@ -625,3 +627,51 @@ func Test_ViewRun_HandlesSpecialCharacters(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_viewRun_json(t *testing.T) {
|
||||
io, _, stdout, stderr := iostreams.Test()
|
||||
io.SetStdoutTTY(false)
|
||||
|
||||
reg := &httpmock.Registry{}
|
||||
defer reg.Verify(t)
|
||||
reg.StubRepoInfoResponse("OWNER", "REPO", "main")
|
||||
|
||||
opts := &ViewOptions{
|
||||
IO: io,
|
||||
HttpClient: func() (*http.Client, error) {
|
||||
return &http.Client{Transport: reg}, nil
|
||||
},
|
||||
BaseRepo: func() (ghrepo.Interface, error) {
|
||||
return ghrepo.New("OWNER", "REPO"), nil
|
||||
},
|
||||
Exporter: &testExporter{
|
||||
fields: []string{"name", "defaultBranchRef"},
|
||||
},
|
||||
}
|
||||
|
||||
_, teardown := run.Stub()
|
||||
defer teardown(t)
|
||||
|
||||
err := viewRun(opts)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, heredoc.Doc(`
|
||||
name: REPO
|
||||
defaultBranchRef: main
|
||||
`), stdout.String())
|
||||
assert.Equal(t, "", stderr.String())
|
||||
}
|
||||
|
||||
type testExporter struct {
|
||||
fields []string
|
||||
}
|
||||
|
||||
func (e *testExporter) Fields() []string {
|
||||
return e.fields
|
||||
}
|
||||
|
||||
func (e *testExporter) Write(w io.Writer, data interface{}, colorize bool) error {
|
||||
r := data.(*api.Repository)
|
||||
fmt.Fprintf(w, "name: %s\n", r.Name)
|
||||
fmt.Fprintf(w, "defaultBranchRef: %s\n", r.DefaultBranchRef.Name)
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue