feat: Add support for creating autolink references

This commit is contained in:
Michael Hoffman 2025-01-03 11:14:33 -05:00
parent d6dba93586
commit 6cf2e9ee3e
11 changed files with 616 additions and 29 deletions

View file

@ -2,6 +2,7 @@ package autolink
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"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/spf13/cobra"
@ -24,6 +25,7 @@ func NewCmdAutolink(f *cmdutil.Factory) *cobra.Command {
cmdutil.EnableRepoOverride(cmd, f)
cmd.AddCommand(cmdList.NewCmdList(f, nil))
cmd.AddCommand(cmdCreate.NewCmdCreate(f, nil))
return cmd
}

View file

@ -0,0 +1,139 @@
package create
import (
"fmt"
"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/domain"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/spf13/cobra"
)
type createOptions struct {
BaseRepo func() (ghrepo.Interface, error)
Browser browser.Browser
AutolinkClient AutolinkCreateClient
IO *iostreams.IOStreams
Exporter cmdutil.Exporter
KeyPrefix string
URLTemplate string
Numeric bool
}
type AutolinkCreateClient interface {
Create(repo ghrepo.Interface, request AutolinkCreateRequest) (*domain.Autolink, error)
}
func NewCmdCreate(f *cmdutil.Factory, runF func(*createOptions) error) *cobra.Command {
opts := &createOptions{
Browser: f.Browser,
IO: f.IOStreams,
}
cmd := &cobra.Command{
Use: "create <keyPrefix> <urlTemplate>",
Short: "Create a new autolink reference",
Long: heredoc.Docf(`
Create a new autolink reference for a repository.
Autolinks automatically generate links to external resources when they appear in an issue, pull request, or commit.
The %[1]skeyPrefix%[1]s specifies the prefix that will generate a link when it is appended by certain characters.
The %[1]surlTemplate%[1]s specifies the target URL that will be generated when the keyPrefix is found. The urlTemplate must contain %[1]s<num>%[1]s for the reference number. %[1]s<num>%[1]s matches different characters depending on the whether the autolink is specified as numeric or alphanumeric.
By default, the command will create an alphanumeric autolink. This means that the %[1]s<num>%[1]s in the %[1]surlTemplate%[1]s will match alphanumeric characters %[1]sA-Z%[1]s (case insensitive), %[1]s0-9%[1]s, and %[1]s-%[1]s. To create a numeric autolink, use the %[1]s--numeric%[1]s flag. Numeric autolinks only match against numeric characters. If the template contains multiple instances of %[1]s<num>%[1]s, only the first will be replaced.
If you are using a shell that applies special meaning to angle brackets, you you will need to need to escape these characters in the %[1]surlTemplate%[1]s or place quotation marks around this argument.
Only repository administrators can create autolinks.
`, "`"),
Example: heredoc.Doc(`
# Create an alphanumeric autolink to example.com for the key prefix "TICKET-". This will generate a link to https://example.com/TICKET?query=123abc when "TICKET-123abc" appears.
$ gh repo autolink create TICKET- https://example.com/TICKET?query=<num>
# Create a numeric autolink to example.com for the key prefix "STORY-". This will generate a link to https://example.com/STORY?id=123 when "STORY-123" appears.
$ gh repo autolink create STORY- https://example.com/STORY?id=<num> --numeric
`),
Args: cmdutil.ExactArgs(2, "Cannot create autolink: keyPrefix and urlTemplate arguments are both required"),
Aliases: []string{"new"},
RunE: func(c *cobra.Command, args []string) error {
opts.BaseRepo = f.BaseRepo
httpClient, err := f.HttpClient()
if err != nil {
return err
}
opts.AutolinkClient = &AutolinkCreator{HTTPClient: httpClient}
opts.KeyPrefix = args[0]
opts.URLTemplate = args[1]
if runF != nil {
return runF(opts)
}
return createRun(opts)
},
}
cmd.Flags().BoolVarP(&opts.Numeric, "numeric", "n", false, "Mark autolink as non-alphanumeric")
return cmd
}
func createRun(opts *createOptions) error {
repo, err := opts.BaseRepo()
if err != nil {
return err
}
cs := opts.IO.ColorScheme()
isAlphanumeric := !opts.Numeric
request := AutolinkCreateRequest{
KeyPrefix: opts.KeyPrefix,
URLTemplate: opts.URLTemplate,
IsAlphanumeric: isAlphanumeric,
}
autolink, err := opts.AutolinkClient.Create(repo, request)
if err != nil {
return fmt.Errorf("%s %w", cs.Red("error creating autolink:"), err)
}
msg := successMsg(autolink, repo, cs)
fmt.Fprint(opts.IO.Out, msg)
return nil
}
func successMsg(autolink *domain.Autolink, repo ghrepo.Interface, cs *iostreams.ColorScheme) string {
autolinkType := "Numeric"
if autolink.IsAlphanumeric {
autolinkType = "Alphanumeric"
}
createdMsg := fmt.Sprintf(
"%s %s autolink created in %s (id: %d)",
cs.SuccessIconWithColor(cs.Green),
autolinkType,
ghrepo.FullName(repo),
autolink.ID,
)
autolinkMapMsg := cs.Bluef(
" %s%s → %s",
autolink.KeyPrefix,
"<num>",
autolink.URLTemplate,
)
return fmt.Sprintf("%s\n%s\n", createdMsg, autolinkMapMsg)
}

View file

@ -0,0 +1,197 @@
package create
import (
"bytes"
"fmt"
"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/domain"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestNewCmdCreate(t *testing.T) {
tests := []struct {
name string
input string
output createOptions
wantErr bool
errMsg string
}{
{
name: "no argument",
input: "",
wantErr: true,
errMsg: "Cannot create autolink: keyPrefix and urlTemplate arguments are both required",
},
{
name: "one argument",
input: "TEST-",
wantErr: true,
errMsg: "Cannot create autolink: keyPrefix and urlTemplate arguments are both required",
},
{
name: "two argument",
input: "TICKET- https://example.com/TICKET?query=<num>",
output: createOptions{
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
},
},
{
name: "numeric flag",
input: "TICKET- https://example.com/TICKET?query=<num> --numeric",
output: createOptions{
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
Numeric: true,
},
},
}
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 *createOptions
cmd := NewCmdCreate(f, func(opts *createOptions) 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.output.KeyPrefix, gotOpts.KeyPrefix)
assert.Equal(t, tt.output.URLTemplate, gotOpts.URLTemplate)
assert.Equal(t, tt.output.Numeric, gotOpts.Numeric)
}
})
}
}
type stubAutoLinkCreator struct {
err error
}
func (g stubAutoLinkCreator) Create(repo ghrepo.Interface, request AutolinkCreateRequest) (*domain.Autolink, error) {
if g.err != nil {
return nil, g.err
}
return &domain.Autolink{
ID: 1,
KeyPrefix: request.KeyPrefix,
URLTemplate: request.URLTemplate,
IsAlphanumeric: request.IsAlphanumeric,
}, nil
}
type testAutolinkClientCreateError struct{}
func (e testAutolinkClientCreateError) Error() string {
return "autolink client create error"
}
func TestCreateRun(t *testing.T) {
tests := []struct {
name string
opts *createOptions
stubCreator stubAutoLinkCreator
expectedErr error
errMsg string
wantStdout string
wantStderr string
}{
{
name: "success, alphanumeric",
opts: &createOptions{
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
},
stubCreator: stubAutoLinkCreator{},
wantStdout: heredoc.Doc(`
Alphanumeric autolink created in OWNER/REPO (id: 1)
TICKET-<num> https://example.com/TICKET?query=<num>
`),
},
{
name: "success, numeric",
opts: &createOptions{
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
Numeric: true,
},
stubCreator: stubAutoLinkCreator{},
wantStdout: heredoc.Doc(`
Numeric autolink created in OWNER/REPO (id: 1)
TICKET-<num> https://example.com/TICKET?query=<num>
`),
},
{
name: "client error",
opts: &createOptions{
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
},
stubCreator: stubAutoLinkCreator{err: testAutolinkClientCreateError{}},
expectedErr: testAutolinkClientCreateError{},
errMsg: fmt.Sprint("error creating autolink: ", testAutolinkClientCreateError{}.Error()),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ios, _, stdout, stderr := 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.stubCreator
err := createRun(opts)
if tt.expectedErr != nil {
require.Error(t, err)
assert.ErrorIs(t, err, tt.expectedErr)
assert.Equal(t, err.Error(), tt.errMsg)
} else {
require.NoError(t, err)
}
if tt.wantStdout != "" {
assert.Equal(t, tt.wantStdout, stdout.String())
}
if tt.wantStderr != "" {
assert.Equal(t, tt.wantStderr, stderr.String())
}
})
}
}

View file

@ -0,0 +1,83 @@
package create
import (
"bytes"
"encoding/json"
"errors"
"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/domain"
)
type AutolinkCreator struct {
HTTPClient *http.Client
}
type AutolinkCreateRequest struct {
IsAlphanumeric bool `json:"is_alphanumeric"`
KeyPrefix string `json:"key_prefix"`
URLTemplate string `json:"url_template"`
}
func (a *AutolinkCreator) Create(repo ghrepo.Interface, request AutolinkCreateRequest) (*domain.Autolink, error) {
path := fmt.Sprintf("repos/%s/%s/autolinks", repo.RepoOwner(), repo.RepoName())
url := ghinstance.RESTPrefix(repo.RepoHost()) + path
requestByte, err := json.Marshal(request)
if err != nil {
return nil, err
}
requestBody := bytes.NewReader(requestByte)
req, err := http.NewRequest(http.MethodPost, url, requestBody)
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.StatusCreated {
// return nil, api.HandleHTTPError(resp)
// }
err = handleAutolinkCreateError(resp)
if err != nil {
return nil, err
}
var autolink domain.Autolink
err = json.NewDecoder(resp.Body).Decode(&autolink)
if err != nil {
return nil, err
}
return &autolink, nil
}
func handleAutolinkCreateError(resp *http.Response) error {
switch resp.StatusCode {
case http.StatusCreated:
return nil
case http.StatusNotFound:
err := api.HandleHTTPError(resp)
var httpErr api.HTTPError
if errors.As(err, &httpErr) {
httpErr.Message = "Must have admin rights to Repository."
return httpErr
}
return err
default:
return api.HandleHTTPError(resp)
}
}

View file

@ -0,0 +1,155 @@
package create
import (
"fmt"
"net/http"
"testing"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/domain"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestAutoLinkCreator_Create(t *testing.T) {
repo := ghrepo.New("OWNER", "REPO")
tests := []struct {
name string
req AutolinkCreateRequest
stubStatus int
stubRespJSON string
expectedAutolink *domain.Autolink
expectErr bool
expectedErrMsg string
}{
{
name: "201 successful creation",
req: AutolinkCreateRequest{
IsAlphanumeric: true,
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
},
stubStatus: http.StatusCreated,
stubRespJSON: `{
"id": 1,
"is_alphanumeric": true,
"key_prefix": "TICKET-",
"url_template": "https://example.com/TICKET?query=<num>"
}`,
expectedAutolink: &domain.Autolink{
ID: 1,
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
IsAlphanumeric: true,
},
},
{
name: "422 URL template not valid URL",
req: AutolinkCreateRequest{
IsAlphanumeric: true,
KeyPrefix: "TICKET-",
URLTemplate: "foo/<num>",
},
stubStatus: http.StatusUnprocessableEntity,
stubRespJSON: `{
"message": "Validation Failed",
"errors": [
{
"resource": "KeyLink",
"code": "custom",
"field": "url_template",
"message": "url_template must be an absolute URL"
}
],
"documentation_url": "https://docs.github.com/rest/repos/autolinks#create-an-autolink-reference-for-a-repository",
"status": "422"
}`,
expectErr: true,
expectedErrMsg: heredoc.Doc(`
HTTP 422: Validation Failed (https://api.github.com/repos/OWNER/REPO/autolinks)
url_template must be an absolute URL`),
},
{
name: "404 repo not found",
req: AutolinkCreateRequest{
IsAlphanumeric: true,
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
},
stubStatus: http.StatusNotFound,
stubRespJSON: `{
"message": "Not Found",
"documentation_url": "https://docs.github.com/rest/repos/autolinks#create-an-autolink-reference-for-a-repository",
"status": "404"
}`,
expectErr: true,
expectedErrMsg: "HTTP 404: Must have admin rights to Repository. (https://api.github.com/repos/OWNER/REPO/autolinks)",
},
{
name: "422 URL template missing <num>",
req: AutolinkCreateRequest{
IsAlphanumeric: true,
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET",
},
stubStatus: http.StatusUnprocessableEntity,
stubRespJSON: `{"message":"Validation Failed","errors":[{"resource":"KeyLink","code":"custom","field":"url_template","message":"url_template is missing a <num> token"}],"documentation_url":"https://docs.github.com/rest/repos/autolinks#create-an-autolink-reference-for-a-repository","status":"422"}`,
expectErr: true,
expectedErrMsg: heredoc.Doc(`
HTTP 422: Validation Failed (https://api.github.com/repos/OWNER/REPO/autolinks)
url_template is missing a <num> token`),
},
{
name: "422 already exists",
req: AutolinkCreateRequest{
IsAlphanumeric: true,
KeyPrefix: "TICKET-",
URLTemplate: "https://example.com/TICKET?query=<num>",
},
stubStatus: http.StatusUnprocessableEntity,
stubRespJSON: `{"message":"Validation Failed","errors":[{"resource":"KeyLink","code":"already_exists","field":"key_prefix"}],"documentation_url":"https://docs.github.com/rest/repos/autolinks#create-an-autolink-reference-for-a-repository","status":"422"}`,
expectErr: true,
expectedErrMsg: heredoc.Doc(`
HTTP 422: Validation Failed (https://api.github.com/repos/OWNER/REPO/autolinks)
KeyLink.key_prefix already exists`),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
reg.Register(
httpmock.REST(
http.MethodPost,
fmt.Sprintf("repos/%s/%s/autolinks", repo.RepoOwner(), repo.RepoName())),
httpmock.RESTPayload(tt.stubStatus, tt.stubRespJSON,
func(payload map[string]interface{}) {
require.Equal(t, map[string]interface{}{
"is_alphanumeric": tt.req.IsAlphanumeric,
"key_prefix": tt.req.KeyPrefix,
"url_template": tt.req.URLTemplate,
}, payload)
},
),
)
defer reg.Verify(t)
autolinkCreator := &AutolinkCreator{
HTTPClient: &http.Client{Transport: reg},
}
autolink, err := autolinkCreator.Create(repo, tt.req)
if tt.expectErr {
require.EqualError(t, err, tt.expectedErrMsg)
} else {
require.NoError(t, err)
assert.Equal(t, tt.expectedAutolink, autolink)
}
})
}
}

View file

@ -0,0 +1,14 @@
package domain
import "github.com/cli/cli/v2/pkg/cmdutil"
type Autolink struct {
ID int `json:"id"`
IsAlphanumeric bool `json:"is_alphanumeric"`
KeyPrefix string `json:"key_prefix"`
URLTemplate string `json:"url_template"`
}
func (a *Autolink) ExportData(fields []string) map[string]interface{} {
return cmdutil.StructExportData(a, fields)
}

View file

@ -8,16 +8,17 @@ import (
"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/domain"
)
type AutolinkLister struct {
HTTPClient *http.Client
}
func (a *AutolinkLister) List(repo ghrepo.Interface) ([]autolink, error) {
func (a *AutolinkLister) List(repo ghrepo.Interface) ([]domain.Autolink, error) {
path := fmt.Sprintf("repos/%s/%s/autolinks", repo.RepoOwner(), repo.RepoName())
url := ghinstance.RESTPrefix(repo.RepoHost()) + path
req, err := http.NewRequest("GET", url, nil)
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, err
}
@ -33,7 +34,7 @@ func (a *AutolinkLister) List(repo ghrepo.Interface) ([]autolink, error) {
} else if resp.StatusCode > 299 {
return nil, api.HandleHTTPError(resp)
}
var autolinks []autolink
var autolinks []domain.Autolink
err = json.NewDecoder(resp.Body).Decode(&autolinks)
if err != nil {
return nil, err

View file

@ -6,6 +6,7 @@ import (
"testing"
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/domain"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -15,19 +16,19 @@ func TestAutoLinkLister_List(t *testing.T) {
tests := []struct {
name string
repo ghrepo.Interface
resp []autolink
resp []domain.Autolink
status int
}{
{
name: "no autolinks",
repo: ghrepo.New("OWNER", "REPO"),
resp: []autolink{},
resp: []domain.Autolink{},
status: 200,
},
{
name: "two autolinks",
repo: ghrepo.New("OWNER", "REPO"),
resp: []autolink{
resp: []domain.Autolink{
{
ID: 1,
IsAlphanumeric: true,
@ -54,7 +55,7 @@ func TestAutoLinkLister_List(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
reg.Register(
httpmock.REST("GET", fmt.Sprintf("repos/%s/%s/autolinks", tt.repo.RepoOwner(), tt.repo.RepoName())),
httpmock.REST(http.MethodGet, fmt.Sprintf("repos/%s/%s/autolinks", tt.repo.RepoOwner(), tt.repo.RepoName())),
httpmock.StatusJSONResponse(tt.status, tt.resp),
)
defer reg.Verify(t)

View file

@ -9,6 +9,7 @@ import (
"github.com/cli/cli/v2/internal/ghrepo"
"github.com/cli/cli/v2/internal/tableprinter"
"github.com/cli/cli/v2/internal/text"
"github.com/cli/cli/v2/pkg/cmd/repo/autolink/domain"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/spf13/cobra"
@ -21,29 +22,18 @@ var autolinkFields = []string{
"urlTemplate",
}
type autolink struct {
ID int `json:"id"`
IsAlphanumeric bool `json:"is_alphanumeric"`
KeyPrefix string `json:"key_prefix"`
URLTemplate string `json:"url_template"`
}
func (s *autolink) ExportData(fields []string) map[string]interface{} {
return cmdutil.StructExportData(s, fields)
}
type listOptions struct {
BaseRepo func() (ghrepo.Interface, error)
Browser browser.Browser
AutolinkClient AutolinkClient
AutolinkClient AutolinkListClient
IO *iostreams.IOStreams
Exporter cmdutil.Exporter
WebMode bool
}
type AutolinkClient interface {
List(repo ghrepo.Interface) ([]autolink, error)
type AutolinkListClient interface {
List(repo ghrepo.Interface) ([]domain.Autolink, error)
}
func NewCmdList(f *cmdutil.Factory, runF func(*listOptions) error) *cobra.Command {

View file

@ -8,6 +8,7 @@ import (
"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/domain"
"github.com/cli/cli/v2/pkg/cmdutil"
"github.com/cli/cli/v2/pkg/iostreams"
"github.com/cli/cli/v2/pkg/jsonfieldstest"
@ -96,11 +97,11 @@ func TestNewCmdList(t *testing.T) {
}
type stubAutoLinkLister struct {
autolinks []autolink
autolinks []domain.Autolink
err error
}
func (g stubAutoLinkLister) List(repo ghrepo.Interface) ([]autolink, error) {
func (g stubAutoLinkLister) List(repo ghrepo.Interface) ([]domain.Autolink, error) {
return g.autolinks, g.err
}
@ -125,7 +126,7 @@ func TestListRun(t *testing.T) {
opts: &listOptions{},
isTTY: true,
stubLister: stubAutoLinkLister{
autolinks: []autolink{
autolinks: []domain.Autolink{
{
ID: 1,
KeyPrefix: "TICKET-",
@ -161,7 +162,7 @@ func TestListRun(t *testing.T) {
},
isTTY: true,
stubLister: stubAutoLinkLister{
autolinks: []autolink{
autolinks: []domain.Autolink{
{
ID: 1,
KeyPrefix: "TICKET-",
@ -184,7 +185,7 @@ func TestListRun(t *testing.T) {
opts: &listOptions{},
isTTY: false,
stubLister: stubAutoLinkLister{
autolinks: []autolink{
autolinks: []domain.Autolink{
{
ID: 1,
KeyPrefix: "TICKET-",
@ -210,7 +211,7 @@ func TestListRun(t *testing.T) {
opts: &listOptions{},
isTTY: true,
stubLister: stubAutoLinkLister{
autolinks: []autolink{},
autolinks: []domain.Autolink{},
},
expectedErr: cmdutil.NewNoResultsError("no autolinks found in OWNER/REPO"),
wantStderr: "",
@ -220,7 +221,7 @@ func TestListRun(t *testing.T) {
opts: &listOptions{},
isTTY: true,
stubLister: stubAutoLinkLister{
autolinks: []autolink{},
autolinks: []domain.Autolink{},
err: testAutolinkClientListError{},
},
expectedErr: testAutolinkClientListError{},

View file

@ -188,7 +188,11 @@ func RESTPayload(responseStatus int, responseBody string, cb func(payload map[st
return nil, err
}
cb(bodyData)
return httpResponse(responseStatus, req, bytes.NewBufferString(responseBody)), nil
header := http.Header{
"Content-Type": []string{"application/json"},
}
return httpResponseWithHeader(responseStatus, req, bytes.NewBufferString(responseBody), header), nil
}
}