Merge branch 'trunk' into 8386-update-release-doc-with-homebrew-info
This commit is contained in:
commit
0f16c870f3
14 changed files with 483 additions and 29 deletions
2
.github/workflows/deployment.yml
vendored
2
.github/workflows/deployment.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
|||
steps:
|
||||
- name: Validate tag name format
|
||||
run: |
|
||||
if [[ ! "${{ inputs.tag_name }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$]]; then
|
||||
if [[ ! "${{ inputs.tag_name }}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
||||
echo "Invalid tag name format. Must be in the form v1.2.3"
|
||||
exit 1
|
||||
fi
|
||||
|
|
|
|||
2
go.mod
2
go.mod
|
|
@ -29,7 +29,7 @@ require (
|
|||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-version v1.3.0
|
||||
github.com/henvic/httpretty v0.1.4
|
||||
github.com/in-toto/attestation v1.1.0
|
||||
github.com/in-toto/attestation v1.1.1
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
|
||||
github.com/mattn/go-colorable v0.1.14
|
||||
|
|
|
|||
4
go.sum
4
go.sum
|
|
@ -266,8 +266,8 @@ github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u
|
|||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM=
|
||||
github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs=
|
||||
github.com/in-toto/attestation v1.1.0 h1:oRWzfmZPDSctChD0VaQV7MJrywKOzyNrtpENQFq//2Q=
|
||||
github.com/in-toto/attestation v1.1.0/go.mod h1:DB59ytd3z7cIHgXxwpSX2SABrU6WJUKg/grpdgHVgVs=
|
||||
github.com/in-toto/attestation v1.1.1 h1:QD3d+oATQ0dFsWoNh5oT0udQ3tUrOsZZ0Fc3tSgWbzI=
|
||||
github.com/in-toto/attestation v1.1.1/go.mod h1:Dcq1zVwA2V7Qin8I7rgOi+i837wEf/mOZwRm047Sjys=
|
||||
github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU=
|
||||
github.com/in-toto/in-toto-golang v0.9.0/go.mod h1:xsBVrVsHNsB61++S6Dy2vWosKhuA3lUTQd+eF9HdeMo=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
|
|
|
|||
|
|
@ -176,23 +176,25 @@ func (c *LiveClient) fetchBundleFromAttestations(attestations []*Attestation) ([
|
|||
return fmt.Errorf("attestation has no bundle or bundle URL")
|
||||
}
|
||||
|
||||
// for now, we fallback to the bundle field if the bundle URL is empty
|
||||
if a.BundleURL == "" {
|
||||
c.logger.VerbosePrintf("Bundle URL is empty. Falling back to bundle field\n\n")
|
||||
// If the bundle field is nil, try to fetch the bundle with the provided URL
|
||||
if a.Bundle == nil {
|
||||
c.logger.VerbosePrintf("Bundle field is empty. Trying to fetch with bundle URL\n\n")
|
||||
b, err := c.GetBundle(a.BundleURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch bundle with URL: %w", err)
|
||||
}
|
||||
fetched[i] = &Attestation{
|
||||
Bundle: a.Bundle,
|
||||
Bundle: b,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// otherwise fetch the bundle with the provided URL
|
||||
b, err := c.GetBundle(a.BundleURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to fetch bundle with URL: %w", err)
|
||||
}
|
||||
// otherwise fall back to the bundle field
|
||||
c.logger.VerbosePrintf("Fetching bundle from Bundle field\n\n")
|
||||
fetched[i] = &Attestation{
|
||||
Bundle: b,
|
||||
Bundle: a.Bundle,
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ func TestGetByDigest_Error(t *testing.T) {
|
|||
require.Nil(t, attestations)
|
||||
}
|
||||
|
||||
func TestFetchBundleFromAttestations(t *testing.T) {
|
||||
func TestFetchBundleFromAttestations_BundleURL(t *testing.T) {
|
||||
httpClient := &mockHttpClient{}
|
||||
client := LiveClient{
|
||||
httpClient: httpClient,
|
||||
|
|
@ -188,12 +188,15 @@ func TestFetchBundleFromAttestations(t *testing.T) {
|
|||
}
|
||||
|
||||
att1 := makeTestAttestation()
|
||||
att1.Bundle = nil
|
||||
att2 := makeTestAttestation()
|
||||
att2.Bundle = nil
|
||||
// zero out the bundle field so it tries fetching by URL
|
||||
attestations := []*Attestation{&att1, &att2}
|
||||
fetched, err := client.fetchBundleFromAttestations(attestations)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, fetched, 2)
|
||||
require.Equal(t, "application/vnd.dev.sigstore.bundle.v0.3+json", fetched[0].Bundle.GetMediaType())
|
||||
require.NotNil(t, "application/vnd.dev.sigstore.bundle.v0.3+json", fetched[0].Bundle.GetMediaType())
|
||||
httpClient.AssertNumberOfCalls(t, "OnGetSuccess", 2)
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +214,7 @@ func TestFetchBundleFromAttestations_InvalidAttestation(t *testing.T) {
|
|||
require.Nil(t, fetched, 2)
|
||||
}
|
||||
|
||||
func TestFetchBundleFromAttestations_Fail(t *testing.T) {
|
||||
func TestFetchBundleFromAttestations_Fail_BundleURL(t *testing.T) {
|
||||
httpClient := &failAfterOneCallHttpClient{}
|
||||
|
||||
c := &LiveClient{
|
||||
|
|
@ -220,7 +223,10 @@ func TestFetchBundleFromAttestations_Fail(t *testing.T) {
|
|||
}
|
||||
|
||||
att1 := makeTestAttestation()
|
||||
att1.Bundle = nil
|
||||
att2 := makeTestAttestation()
|
||||
att2.Bundle = nil
|
||||
// zero out the bundle field so it tries fetching by URL
|
||||
attestations := []*Attestation{&att1, &att2}
|
||||
fetched, err := c.fetchBundleFromAttestations(attestations)
|
||||
require.Error(t, err)
|
||||
|
|
@ -237,6 +243,7 @@ func TestFetchBundleFromAttestations_FetchByURLFail(t *testing.T) {
|
|||
}
|
||||
|
||||
a := makeTestAttestation()
|
||||
a.Bundle = nil
|
||||
attestations := []*Attestation{&a}
|
||||
bundle, err := c.fetchBundleFromAttestations(attestations)
|
||||
require.Error(t, err)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"github.com/MakeNowJust/heredoc"
|
||||
cmdCreate "github.com/cli/cli/v2/pkg/cmd/repo/autolink/create"
|
||||
cmdList "github.com/cli/cli/v2/pkg/cmd/repo/autolink/list"
|
||||
cmdView "github.com/cli/cli/v2/pkg/cmd/repo/autolink/view"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
|
@ -24,6 +25,7 @@ func NewCmdAutolink(f *cmdutil.Factory) *cobra.Command {
|
|||
|
||||
cmd.AddCommand(cmdList.NewCmdList(f, nil))
|
||||
cmd.AddCommand(cmdCreate.NewCmdCreate(f, nil))
|
||||
cmd.AddCommand(cmdView.NewCmdView(f, nil))
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,9 +109,9 @@ func createRun(opts *createOptions) error {
|
|||
|
||||
cs := opts.IO.ColorScheme()
|
||||
fmt.Fprintf(opts.IO.Out,
|
||||
"%s Created repository autolink %d on %s\n",
|
||||
"%s Created repository autolink %s on %s\n",
|
||||
cs.SuccessIconWithColor(cs.Green),
|
||||
autolink.ID,
|
||||
cs.Cyanf("%d", autolink.ID),
|
||||
ghrepo.FullName(repo))
|
||||
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAutoLinkLister_List(t *testing.T) {
|
||||
func TestAutolinkLister_List(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
repo ghrepo.Interface
|
||||
|
|
|
|||
|
|
@ -15,13 +15,6 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var autolinkFields = []string{
|
||||
"id",
|
||||
"isAlphanumeric",
|
||||
"keyPrefix",
|
||||
"urlTemplate",
|
||||
}
|
||||
|
||||
type listOptions struct {
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Browser browser.Browser
|
||||
|
|
@ -70,7 +63,7 @@ func NewCmdList(f *cmdutil.Factory, runF func(*listOptions) error) *cobra.Comman
|
|||
}
|
||||
|
||||
cmd.Flags().BoolVarP(&opts.WebMode, "web", "w", false, "List autolink references in the web browser")
|
||||
cmdutil.AddJSONFlags(cmd, &opts.Exporter, autolinkFields)
|
||||
cmdutil.AddJSONFlags(cmd, &opts.Exporter, shared.AutolinkFields)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
@ -111,8 +104,10 @@ func listRun(opts *listOptions) error {
|
|||
|
||||
tp := tableprinter.New(opts.IO, tableprinter.WithHeader("ID", "KEY PREFIX", "URL TEMPLATE", "ALPHANUMERIC"))
|
||||
|
||||
cs := opts.IO.ColorScheme()
|
||||
|
||||
for _, autolink := range autolinks {
|
||||
tp.AddField(fmt.Sprintf("%d", autolink.ID))
|
||||
tp.AddField(cs.Cyanf("%d", autolink.ID))
|
||||
tp.AddField(autolink.KeyPrefix)
|
||||
tp.AddField(autolink.URLTemplate)
|
||||
tp.AddField(strconv.FormatBool(autolink.IsAlphanumeric))
|
||||
|
|
|
|||
|
|
@ -9,6 +9,13 @@ type Autolink struct {
|
|||
URLTemplate string `json:"url_template"`
|
||||
}
|
||||
|
||||
var AutolinkFields = []string{
|
||||
"id",
|
||||
"isAlphanumeric",
|
||||
"keyPrefix",
|
||||
"urlTemplate",
|
||||
}
|
||||
|
||||
func (a *Autolink) ExportData(fields []string) map[string]interface{} {
|
||||
return cmdutil.StructExportData(a, fields)
|
||||
}
|
||||
|
|
|
|||
46
pkg/cmd/repo/autolink/view/http.go
Normal file
46
pkg/cmd/repo/autolink/view/http.go
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghinstance"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/shared"
|
||||
)
|
||||
|
||||
type AutolinkViewer struct {
|
||||
HTTPClient *http.Client
|
||||
}
|
||||
|
||||
func (a *AutolinkViewer) View(repo ghrepo.Interface, id string) (*shared.Autolink, error) {
|
||||
path := fmt.Sprintf("repos/%s/%s/autolinks/%s", repo.RepoOwner(), repo.RepoName(), id)
|
||||
url := ghinstance.RESTPrefix(repo.RepoHost()) + path
|
||||
req, err := http.NewRequest(http.MethodGet, url, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
resp, err := a.HTTPClient.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode == http.StatusNotFound {
|
||||
return nil, fmt.Errorf("HTTP 404: Either no autolink with this ID exists for this repository or you are missing admin rights to the repository. (https://api.github.com/%s)", path)
|
||||
} else if resp.StatusCode > 299 {
|
||||
return nil, api.HandleHTTPError(resp)
|
||||
}
|
||||
|
||||
var autolink shared.Autolink
|
||||
err = json.NewDecoder(resp.Body).Decode(&autolink)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &autolink, nil
|
||||
}
|
||||
102
pkg/cmd/repo/autolink/view/http_test.go
Normal file
102
pkg/cmd/repo/autolink/view/http_test.go
Normal file
|
|
@ -0,0 +1,102 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/shared"
|
||||
"github.com/cli/cli/v2/pkg/httpmock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAutolinkViewer_View(t *testing.T) {
|
||||
repo := ghrepo.New("OWNER", "REPO")
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
id string
|
||||
stubStatus int
|
||||
stubRespJSON string
|
||||
|
||||
expectedAutolink *shared.Autolink
|
||||
expectErr bool
|
||||
expectedErrMsg string
|
||||
}{
|
||||
{
|
||||
name: "200 successful alphanumeric view",
|
||||
id: "123",
|
||||
stubStatus: 200,
|
||||
stubRespJSON: `{
|
||||
"id": 123,
|
||||
"key_prefix": "TICKET-",
|
||||
"url_template": "https://example.com/TICKET?query=<num>",
|
||||
"is_alphanumeric": true
|
||||
}`,
|
||||
expectedAutolink: &shared.Autolink{
|
||||
ID: 123,
|
||||
KeyPrefix: "TICKET-",
|
||||
URLTemplate: "https://example.com/TICKET?query=<num>",
|
||||
IsAlphanumeric: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "200 successful numeric view",
|
||||
id: "123",
|
||||
stubStatus: 200,
|
||||
stubRespJSON: `{
|
||||
"id": 123,
|
||||
"key_prefix": "TICKET-",
|
||||
"url_template": "https://example.com/TICKET?query=<num>",
|
||||
"is_alphanumeric": false
|
||||
}`,
|
||||
expectedAutolink: &shared.Autolink{
|
||||
ID: 123,
|
||||
KeyPrefix: "TICKET-",
|
||||
URLTemplate: "https://example.com/TICKET?query=<num>",
|
||||
IsAlphanumeric: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "404 repo or autolink not found",
|
||||
id: "123",
|
||||
stubStatus: 404,
|
||||
stubRespJSON: `{
|
||||
"message": "Not Found",
|
||||
"documentation_url": "https://docs.github.com/rest/repos/autolinks#get-an-autolink-reference-of-a-repository",
|
||||
"status": "404"
|
||||
}`,
|
||||
expectErr: true,
|
||||
expectedErrMsg: "HTTP 404: Either no autolink with this ID exists for this repository or you are missing admin rights to the repository. (https://api.github.com/repos/OWNER/REPO/autolinks/123)",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reg := &httpmock.Registry{}
|
||||
reg.Register(
|
||||
httpmock.REST(
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("repos/%s/%s/autolinks/%s", repo.RepoOwner(), repo.RepoName(), tt.id),
|
||||
),
|
||||
httpmock.StatusStringResponse(tt.stubStatus, tt.stubRespJSON),
|
||||
)
|
||||
defer reg.Verify(t)
|
||||
|
||||
autolinkCreator := &AutolinkViewer{
|
||||
HTTPClient: &http.Client{Transport: reg},
|
||||
}
|
||||
|
||||
autolink, err := autolinkCreator.View(repo, tt.id)
|
||||
|
||||
if tt.expectErr {
|
||||
require.EqualError(t, err, tt.expectedErrMsg)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.expectedAutolink, autolink)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
96
pkg/cmd/repo/autolink/view/view.go
Normal file
96
pkg/cmd/repo/autolink/view/view.go
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cli/cli/v2/internal/browser"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
type viewOptions struct {
|
||||
BaseRepo func() (ghrepo.Interface, error)
|
||||
Browser browser.Browser
|
||||
AutolinkClient AutolinkViewClient
|
||||
IO *iostreams.IOStreams
|
||||
Exporter cmdutil.Exporter
|
||||
|
||||
ID string
|
||||
}
|
||||
|
||||
type AutolinkViewClient interface {
|
||||
View(repo ghrepo.Interface, id string) (*shared.Autolink, error)
|
||||
}
|
||||
|
||||
func NewCmdView(f *cmdutil.Factory, runF func(*viewOptions) error) *cobra.Command {
|
||||
opts := &viewOptions{
|
||||
Browser: f.Browser,
|
||||
IO: f.IOStreams,
|
||||
}
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "view <id>",
|
||||
Short: "View an autolink reference",
|
||||
Long: "View an autolink reference for a repository.",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
httpClient, err := f.HttpClient()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts.BaseRepo = f.BaseRepo
|
||||
opts.ID = args[0]
|
||||
opts.AutolinkClient = &AutolinkViewer{HTTPClient: httpClient}
|
||||
|
||||
if runF != nil {
|
||||
return runF(opts)
|
||||
}
|
||||
|
||||
return viewRun(opts)
|
||||
},
|
||||
}
|
||||
|
||||
cmdutil.AddJSONFlags(cmd, &opts.Exporter, shared.AutolinkFields)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func viewRun(opts *viewOptions) error {
|
||||
repo, err := opts.BaseRepo()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out := opts.IO.Out
|
||||
cs := opts.IO.ColorScheme()
|
||||
|
||||
autolink, err := opts.AutolinkClient.View(repo, opts.ID)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s %w", cs.Red("error viewing autolink:"), err)
|
||||
}
|
||||
|
||||
if opts.Exporter != nil {
|
||||
return opts.Exporter.Write(opts.IO, autolink)
|
||||
}
|
||||
|
||||
fmt.Fprintf(out, "Autolink in %s\n\n", ghrepo.FullName(repo))
|
||||
|
||||
fmt.Fprint(out, cs.Bold("ID: "))
|
||||
fmt.Fprintln(out, cs.Cyanf("%d", autolink.ID))
|
||||
|
||||
fmt.Fprint(out, cs.Bold("Key Prefix: "))
|
||||
fmt.Fprintln(out, autolink.KeyPrefix)
|
||||
|
||||
fmt.Fprint(out, cs.Bold("URL Template: "))
|
||||
fmt.Fprintln(out, autolink.URLTemplate)
|
||||
|
||||
fmt.Fprint(out, cs.Bold("Alphanumeric: "))
|
||||
fmt.Fprintln(out, autolink.IsAlphanumeric)
|
||||
|
||||
return nil
|
||||
}
|
||||
197
pkg/cmd/repo/autolink/view/view_test.go
Normal file
197
pkg/cmd/repo/autolink/view/view_test.go
Normal file
|
|
@ -0,0 +1,197 @@
|
|||
package view
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/internal/browser"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/shared"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/cli/cli/v2/pkg/iostreams"
|
||||
"github.com/cli/cli/v2/pkg/jsonfieldstest"
|
||||
"github.com/google/shlex"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestJSONFields(t *testing.T) {
|
||||
jsonfieldstest.ExpectCommandToSupportJSONFields(t, NewCmdView, []string{
|
||||
"id",
|
||||
"isAlphanumeric",
|
||||
"keyPrefix",
|
||||
"urlTemplate",
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewCmdView(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
output viewOptions
|
||||
wantErr bool
|
||||
wantExporter bool
|
||||
errMsg string
|
||||
}{
|
||||
{
|
||||
name: "no argument",
|
||||
input: "",
|
||||
wantErr: true,
|
||||
errMsg: "accepts 1 arg(s), received 0",
|
||||
},
|
||||
{
|
||||
name: "id provided",
|
||||
input: "123",
|
||||
output: viewOptions{ID: "123"},
|
||||
},
|
||||
{
|
||||
name: "json flag",
|
||||
input: "123 --json id",
|
||||
output: viewOptions{},
|
||||
wantExporter: true,
|
||||
},
|
||||
{
|
||||
name: "invalid json flag",
|
||||
input: "123 --json invalid",
|
||||
output: viewOptions{},
|
||||
wantErr: true,
|
||||
errMsg: "Unknown JSON field: \"invalid\"\nAvailable fields:\n id\n isAlphanumeric\n keyPrefix\n urlTemplate",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ios, _, _, _ := iostreams.Test()
|
||||
f := &cmdutil.Factory{
|
||||
IOStreams: ios,
|
||||
}
|
||||
f.HttpClient = func() (*http.Client, error) {
|
||||
return &http.Client{}, nil
|
||||
}
|
||||
|
||||
argv, err := shlex.Split(tt.input)
|
||||
require.NoError(t, err)
|
||||
|
||||
var gotOpts *viewOptions
|
||||
cmd := NewCmdView(f, func(opts *viewOptions) error {
|
||||
gotOpts = opts
|
||||
return nil
|
||||
})
|
||||
|
||||
cmd.SetArgs(argv)
|
||||
cmd.SetIn(&bytes.Buffer{})
|
||||
cmd.SetOut(&bytes.Buffer{})
|
||||
cmd.SetErr(&bytes.Buffer{})
|
||||
|
||||
_, err = cmd.ExecuteC()
|
||||
if tt.wantErr {
|
||||
require.EqualError(t, err, tt.errMsg)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.wantExporter, gotOpts.Exporter != nil)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type stubAutoLinkViewer struct {
|
||||
autolink *shared.Autolink
|
||||
err error
|
||||
}
|
||||
|
||||
func (g stubAutoLinkViewer) View(repo ghrepo.Interface, id string) (*shared.Autolink, error) {
|
||||
return g.autolink, g.err
|
||||
}
|
||||
|
||||
type testAutolinkClientViewError struct{}
|
||||
|
||||
func (e testAutolinkClientViewError) Error() string {
|
||||
return "autolink client view error"
|
||||
}
|
||||
|
||||
func TestViewRun(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts *viewOptions
|
||||
stubViewer stubAutoLinkViewer
|
||||
expectedErr error
|
||||
wantStdout string
|
||||
}{
|
||||
{
|
||||
name: "view",
|
||||
opts: &viewOptions{
|
||||
ID: "1",
|
||||
},
|
||||
stubViewer: stubAutoLinkViewer{
|
||||
autolink: &shared.Autolink{
|
||||
ID: 1,
|
||||
KeyPrefix: "TICKET-",
|
||||
URLTemplate: "https://example.com/TICKET?query=<num>",
|
||||
IsAlphanumeric: true,
|
||||
},
|
||||
},
|
||||
wantStdout: heredoc.Doc(`
|
||||
Autolink in OWNER/REPO
|
||||
|
||||
ID: 1
|
||||
Key Prefix: TICKET-
|
||||
URL Template: https://example.com/TICKET?query=<num>
|
||||
Alphanumeric: true
|
||||
`),
|
||||
},
|
||||
{
|
||||
name: "view json",
|
||||
opts: &viewOptions{
|
||||
Exporter: func() cmdutil.Exporter {
|
||||
exporter := cmdutil.NewJSONExporter()
|
||||
exporter.SetFields([]string{"id"})
|
||||
return exporter
|
||||
}(),
|
||||
},
|
||||
stubViewer: stubAutoLinkViewer{
|
||||
autolink: &shared.Autolink{
|
||||
ID: 1,
|
||||
KeyPrefix: "TICKET-",
|
||||
URLTemplate: "https://example.com/TICKET?query=<num>",
|
||||
IsAlphanumeric: true,
|
||||
},
|
||||
},
|
||||
wantStdout: "{\"id\":1}\n",
|
||||
},
|
||||
{
|
||||
name: "client error",
|
||||
opts: &viewOptions{},
|
||||
stubViewer: stubAutoLinkViewer{
|
||||
autolink: nil,
|
||||
err: testAutolinkClientViewError{},
|
||||
},
|
||||
expectedErr: testAutolinkClientViewError{},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
ios, _, stdout, _ := iostreams.Test()
|
||||
|
||||
opts := tt.opts
|
||||
opts.IO = ios
|
||||
opts.Browser = &browser.Stub{}
|
||||
|
||||
opts.IO = ios
|
||||
opts.BaseRepo = func() (ghrepo.Interface, error) { return ghrepo.New("OWNER", "REPO"), nil }
|
||||
|
||||
opts.AutolinkClient = &tt.stubViewer
|
||||
err := viewRun(opts)
|
||||
|
||||
if tt.expectedErr != nil {
|
||||
require.Error(t, err)
|
||||
assert.ErrorIs(t, err, tt.expectedErr)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.wantStdout, stdout.String())
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue