Skip to content

Commit 3459dfa

Browse files
committed
add viewing repo in terminal
1 parent ff96f48 commit 3459dfa

File tree

3 files changed

+177
-19
lines changed

3 files changed

+177
-19
lines changed

api/queries_repo.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,13 @@ import (
1313

1414
// Repository contains information about a GitHub repo
1515
type Repository struct {
16-
ID string
17-
Name string
18-
URL string
19-
CloneURL string
20-
CreatedAt time.Time
21-
Owner RepositoryOwner
16+
ID string
17+
Name string
18+
Description string
19+
URL string
20+
CloneURL string
21+
CreatedAt time.Time
22+
Owner RepositoryOwner
2223

2324
IsPrivate bool
2425
HasIssuesEnabled bool
@@ -69,6 +70,7 @@ func GitHubRepo(client *Client, repo ghrepo.Interface) (*Repository, error) {
6970
repository(owner: $owner, name: $name) {
7071
id
7172
hasIssuesEnabled
73+
description
7274
}
7375
}`
7476
variables := map[string]interface{}{

command/repo.go

Lines changed: 89 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package command
22

33
import (
4+
"encoding/base64"
45
"fmt"
56
"net/url"
67
"os"
78
"path"
89
"strings"
10+
"text/template"
911
"time"
1012

1113
"github.com/AlecAivazis/survey/v2"
@@ -35,6 +37,7 @@ func init() {
3537
repoForkCmd.Flags().Lookup("remote").NoOptDefVal = "true"
3638

3739
repoCmd.AddCommand(repoViewCmd)
40+
repoViewCmd.Flags().BoolP("web", "w", false, "Open repository in browser")
3841
}
3942

4043
var repoCmd = &cobra.Command{
@@ -78,9 +81,9 @@ With no argument, creates a fork of the current repository. Otherwise, forks the
7881
var repoViewCmd = &cobra.Command{
7982
Use: "view [<repository>]",
8083
Short: "View a repository in the browser",
81-
Long: `View a GitHub repository in the browser.
84+
Long: `View a GitHub repository.
8285
83-
With no argument, the repository for the current directory is opened.`,
86+
With no argument, the repository for the current directory is displayed.`,
8487
RunE: repoView,
8588
}
8689

@@ -386,6 +389,7 @@ var Confirm = func(prompt string, result *bool) error {
386389

387390
func repoView(cmd *cobra.Command, args []string) error {
388391
ctx := contextForCommand(cmd)
392+
389393
var toView ghrepo.Interface
390394
if len(args) == 0 {
391395
var err error
@@ -414,12 +418,91 @@ func repoView(cmd *cobra.Command, args []string) error {
414418
if err != nil {
415419
return err
416420
}
417-
_, err = api.GitHubRepo(apiClient, toView)
421+
repo, err := api.GitHubRepo(apiClient, toView)
422+
if err != nil {
423+
return err
424+
}
425+
426+
web, err := cmd.Flags().GetBool("web")
418427
if err != nil {
419428
return err
420429
}
421430

422-
openURL := fmt.Sprintf("https://github.com/%s", ghrepo.FullName(toView))
423-
fmt.Fprintf(cmd.ErrOrStderr(), "Opening %s in your browser.\n", displayURL(openURL))
424-
return utils.OpenInBrowser(openURL)
431+
fullName := ghrepo.FullName(toView)
432+
433+
openURL := fmt.Sprintf("https://github.com/%s", fullName)
434+
if web {
435+
fmt.Fprintf(cmd.ErrOrStderr(), "Opening %s in your browser.\n", displayURL(openURL))
436+
return utils.OpenInBrowser(openURL)
437+
}
438+
439+
repoTmpl := `
440+
{{.FullName}}
441+
{{.Description}}
442+
443+
{{.Readme}}
444+
445+
{{.View}}
446+
`
447+
448+
tmpl, err := template.New("repo").Parse(repoTmpl)
449+
if err != nil {
450+
return err
451+
}
452+
453+
type readmeResponse struct {
454+
Name string
455+
Content string
456+
}
457+
458+
var readme readmeResponse
459+
460+
err = apiClient.REST("GET", fmt.Sprintf("repos/%s/readme", fullName), nil, &readme)
461+
if err != nil && !strings.HasSuffix(err.Error(), "'Not Found'") {
462+
return fmt.Errorf("could not get readme for repo: %w", err)
463+
}
464+
465+
decoded, err := base64.StdEncoding.DecodeString(readme.Content)
466+
if err != nil {
467+
return fmt.Errorf("failed to decode readme: %w", err)
468+
}
469+
470+
readmeContent := string(decoded)
471+
472+
if strings.HasSuffix(readme.Name, ".md") {
473+
readmeContent, err = utils.RenderMarkdown(readmeContent)
474+
if err != nil {
475+
return fmt.Errorf("failed to render readme as markdown: %w", err)
476+
}
477+
}
478+
479+
if readmeContent == "" {
480+
readmeContent = utils.Gray("No README provided")
481+
}
482+
483+
description := repo.Description
484+
if description == "" {
485+
description = utils.Gray("No description provided")
486+
}
487+
488+
repoData := struct {
489+
FullName string
490+
Description string
491+
Readme string
492+
View string
493+
}{
494+
FullName: utils.Bold(fullName),
495+
Description: description,
496+
Readme: readmeContent,
497+
View: utils.Gray(fmt.Sprintf("View this repository on GitHub: %s", openURL)),
498+
}
499+
500+
out := colorableOut(cmd)
501+
502+
err = tmpl.Execute(out, repoData)
503+
if err != nil {
504+
return err
505+
}
506+
507+
return nil
425508
}

command/repo_test.go

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -552,8 +552,7 @@ func TestRepoCreate_orgWithTeam(t *testing.T) {
552552
}
553553
}
554554

555-
556-
func TestRepoView(t *testing.T) {
555+
func TestRepoView_web(t *testing.T) {
557556
initBlankContext("OWNER/REPO", "master")
558557
http := initFakeHTTP()
559558
http.StubRepoResponse("OWNER", "REPO")
@@ -568,7 +567,7 @@ func TestRepoView(t *testing.T) {
568567
})
569568
defer restoreCmd()
570569

571-
output, err := RunCommand(repoViewCmd, "repo view")
570+
output, err := RunCommand(repoViewCmd, "repo view -w")
572571
if err != nil {
573572
t.Errorf("error running command `repo view`: %v", err)
574573
}
@@ -583,7 +582,7 @@ func TestRepoView(t *testing.T) {
583582
eq(t, url, "https://github.com/OWNER/REPO")
584583
}
585584

586-
func TestRepoView_ownerRepo(t *testing.T) {
585+
func TestRepoView_web_ownerRepo(t *testing.T) {
587586
ctx := context.NewBlank()
588587
ctx.SetBranch("master")
589588
initContext = func() context.Context {
@@ -601,7 +600,7 @@ func TestRepoView_ownerRepo(t *testing.T) {
601600
})
602601
defer restoreCmd()
603602

604-
output, err := RunCommand(repoViewCmd, "repo view cli/cli")
603+
output, err := RunCommand(repoViewCmd, "repo view -w cli/cli")
605604
if err != nil {
606605
t.Errorf("error running command `repo view`: %v", err)
607606
}
@@ -616,7 +615,7 @@ func TestRepoView_ownerRepo(t *testing.T) {
616615
eq(t, url, "https://github.com/cli/cli")
617616
}
618617

619-
func TestRepoView_fullURL(t *testing.T) {
618+
func TestRepoView_web_fullURL(t *testing.T) {
620619
ctx := context.NewBlank()
621620
ctx.SetBranch("master")
622621
initContext = func() context.Context {
@@ -633,7 +632,7 @@ func TestRepoView_fullURL(t *testing.T) {
633632
})
634633
defer restoreCmd()
635634

636-
output, err := RunCommand(repoViewCmd, "repo view https://github.com/cli/cli")
635+
output, err := RunCommand(repoViewCmd, "repo view -w https://github.com/cli/cli")
637636
if err != nil {
638637
t.Errorf("error running command `repo view`: %v", err)
639638
}
@@ -647,3 +646,77 @@ func TestRepoView_fullURL(t *testing.T) {
647646
url := seenCmd.Args[len(seenCmd.Args)-1]
648647
eq(t, url, "https://github.com/cli/cli")
649648
}
649+
650+
func TestRepoView(t *testing.T) {
651+
initBlankContext("OWNER/REPO", "master")
652+
http := initFakeHTTP()
653+
http.StubRepoResponse("OWNER", "REPO")
654+
http.StubResponse(200, bytes.NewBufferString(`
655+
{ "data": {
656+
"repository": {
657+
"description": "social distancing"
658+
}}}
659+
`))
660+
http.StubResponse(200, bytes.NewBufferString(`
661+
{ "name": "readme.md",
662+
"content": "IyB0cnVseSBjb29sIHJlYWRtZSBjaGVjayBpdCBvdXQ="}
663+
`))
664+
665+
output, err := RunCommand(repoViewCmd, "repo view")
666+
if err != nil {
667+
t.Errorf("error running command `repo view`: %v", err)
668+
}
669+
670+
test.ExpectLines(t, output.String(),
671+
"OWNER/REPO",
672+
"social distancing",
673+
"truly cool readme",
674+
"View this repository on GitHub: https://github.com/OWNER/REPO")
675+
676+
}
677+
678+
func TestRepoView_nonmarkdown_readme(t *testing.T) {
679+
initBlankContext("OWNER/REPO", "master")
680+
http := initFakeHTTP()
681+
http.StubRepoResponse("OWNER", "REPO")
682+
http.StubResponse(200, bytes.NewBufferString(`
683+
{ "data": {
684+
"repository": {
685+
"description": "social distancing"
686+
}}}
687+
`))
688+
http.StubResponse(200, bytes.NewBufferString(`
689+
{ "name": "readme.org",
690+
"content": "IyB0cnVseSBjb29sIHJlYWRtZSBjaGVjayBpdCBvdXQ="}
691+
`))
692+
693+
output, err := RunCommand(repoViewCmd, "repo view")
694+
if err != nil {
695+
t.Errorf("error running command `repo view`: %v", err)
696+
}
697+
698+
test.ExpectLines(t, output.String(),
699+
"OWNER/REPO",
700+
"social distancing",
701+
"# truly cool readme",
702+
"View this repository on GitHub: https://github.com/OWNER/REPO")
703+
}
704+
705+
func TestRepoView_blanks(t *testing.T) {
706+
initBlankContext("OWNER/REPO", "master")
707+
http := initFakeHTTP()
708+
http.StubRepoResponse("OWNER", "REPO")
709+
http.StubResponse(200, bytes.NewBufferString("{}"))
710+
http.StubResponse(200, bytes.NewBufferString("{}"))
711+
712+
output, err := RunCommand(repoViewCmd, "repo view")
713+
if err != nil {
714+
t.Errorf("error running command `repo view`: %v", err)
715+
}
716+
717+
test.ExpectLines(t, output.String(),
718+
"OWNER/REPO",
719+
"No description provided",
720+
"No README provided",
721+
"View this repository on GitHub: https://github.com/OWNER/REPO")
722+
}

0 commit comments

Comments
 (0)