Merge pull request #13082 from maxbeizer/discussion-cmd
Add `discussion` command group scaffolding
This commit is contained in:
commit
65f5b21121
8 changed files with 1221 additions and 0 deletions
26
pkg/cmd/discussion/client/client.go
Normal file
26
pkg/cmd/discussion/client/client.go
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
// Package client provides an abstraction layer for interacting with the
|
||||
// GitHub Discussions GraphQL API. The DiscussionClient interface defines all
|
||||
// supported operations and can be replaced with a mock in tests.
|
||||
package client
|
||||
|
||||
import "github.com/cli/cli/v2/internal/ghrepo"
|
||||
|
||||
//go:generate moq -rm -out client_mock.go . DiscussionClient
|
||||
|
||||
// DiscussionClient defines operations for interacting with the GitHub Discussions API.
|
||||
type DiscussionClient interface {
|
||||
List(repo ghrepo.Interface, filters ListFilters, limit int) ([]Discussion, int, error)
|
||||
Search(repo ghrepo.Interface, filters SearchFilters, limit int) ([]Discussion, int, error)
|
||||
GetByNumber(repo ghrepo.Interface, number int) (*Discussion, error)
|
||||
GetWithComments(repo ghrepo.Interface, number int, commentLimit int, order string) (*Discussion, error)
|
||||
ListCategories(repo ghrepo.Interface) ([]DiscussionCategory, error)
|
||||
Create(repo ghrepo.Interface, input CreateDiscussionInput) (*Discussion, error)
|
||||
Update(repo ghrepo.Interface, input UpdateDiscussionInput) (*Discussion, error)
|
||||
Close(repo ghrepo.Interface, id string, reason CloseReason) (*Discussion, error)
|
||||
Reopen(repo ghrepo.Interface, id string) (*Discussion, error)
|
||||
AddComment(repo ghrepo.Interface, discussionID string, body string, replyToID string) (*DiscussionComment, error)
|
||||
Lock(repo ghrepo.Interface, id string, reason string) error
|
||||
Unlock(repo ghrepo.Interface, id string) error
|
||||
MarkAnswer(repo ghrepo.Interface, commentID string) error
|
||||
UnmarkAnswer(repo ghrepo.Interface, commentID string) error
|
||||
}
|
||||
76
pkg/cmd/discussion/client/client_impl.go
Normal file
76
pkg/cmd/discussion/client/client_impl.go
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/cli/cli/v2/api"
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
)
|
||||
|
||||
type discussionClient struct {
|
||||
gql *api.Client
|
||||
}
|
||||
|
||||
// NewDiscussionClient creates a DiscussionClient backed by the given HTTP client.
|
||||
func NewDiscussionClient(httpClient *http.Client) DiscussionClient {
|
||||
return &discussionClient{
|
||||
gql: api.NewClientFromHTTP(httpClient),
|
||||
}
|
||||
}
|
||||
|
||||
func (c *discussionClient) List(_ ghrepo.Interface, _ ListFilters, _ int) ([]Discussion, int, error) {
|
||||
return nil, 0, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Search(_ ghrepo.Interface, _ SearchFilters, _ int) ([]Discussion, int, error) {
|
||||
return nil, 0, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) GetByNumber(_ ghrepo.Interface, _ int) (*Discussion, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) GetWithComments(_ ghrepo.Interface, _ int, _ int, _ string) (*Discussion, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) ListCategories(_ ghrepo.Interface) ([]DiscussionCategory, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Create(_ ghrepo.Interface, _ CreateDiscussionInput) (*Discussion, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Update(_ ghrepo.Interface, _ UpdateDiscussionInput) (*Discussion, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Close(_ ghrepo.Interface, _ string, _ CloseReason) (*Discussion, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Reopen(_ ghrepo.Interface, _ string) (*Discussion, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) AddComment(_ ghrepo.Interface, _ string, _ string, _ string) (*DiscussionComment, error) {
|
||||
return nil, fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Lock(_ ghrepo.Interface, _ string, _ string) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) Unlock(_ ghrepo.Interface, _ string) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) MarkAnswer(_ ghrepo.Interface, _ string) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
|
||||
func (c *discussionClient) UnmarkAnswer(_ ghrepo.Interface, _ string) error {
|
||||
return fmt.Errorf("not implemented")
|
||||
}
|
||||
773
pkg/cmd/discussion/client/client_mock.go
Normal file
773
pkg/cmd/discussion/client/client_mock.go
Normal file
|
|
@ -0,0 +1,773 @@
|
|||
// Code generated by moq; DO NOT EDIT.
|
||||
// github.com/matryer/moq
|
||||
|
||||
package client
|
||||
|
||||
import (
|
||||
"github.com/cli/cli/v2/internal/ghrepo"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Ensure, that DiscussionClientMock does implement DiscussionClient.
|
||||
// If this is not the case, regenerate this file with moq.
|
||||
var _ DiscussionClient = &DiscussionClientMock{}
|
||||
|
||||
// DiscussionClientMock is a mock implementation of DiscussionClient.
|
||||
//
|
||||
// func TestSomethingThatUsesDiscussionClient(t *testing.T) {
|
||||
//
|
||||
// // make and configure a mocked DiscussionClient
|
||||
// mockedDiscussionClient := &DiscussionClientMock{
|
||||
// AddCommentFunc: func(repo ghrepo.Interface, discussionID string, body string, replyToID string) (*DiscussionComment, error) {
|
||||
// panic("mock out the AddComment method")
|
||||
// },
|
||||
// CloseFunc: func(repo ghrepo.Interface, id string, reason CloseReason) (*Discussion, error) {
|
||||
// panic("mock out the Close method")
|
||||
// },
|
||||
// CreateFunc: func(repo ghrepo.Interface, input CreateDiscussionInput) (*Discussion, error) {
|
||||
// panic("mock out the Create method")
|
||||
// },
|
||||
// GetByNumberFunc: func(repo ghrepo.Interface, number int) (*Discussion, error) {
|
||||
// panic("mock out the GetByNumber method")
|
||||
// },
|
||||
// GetWithCommentsFunc: func(repo ghrepo.Interface, number int, commentLimit int, order string) (*Discussion, error) {
|
||||
// panic("mock out the GetWithComments method")
|
||||
// },
|
||||
// ListFunc: func(repo ghrepo.Interface, filters ListFilters, limit int) ([]Discussion, int, error) {
|
||||
// panic("mock out the List method")
|
||||
// },
|
||||
// ListCategoriesFunc: func(repo ghrepo.Interface) ([]DiscussionCategory, error) {
|
||||
// panic("mock out the ListCategories method")
|
||||
// },
|
||||
// LockFunc: func(repo ghrepo.Interface, id string, reason string) error {
|
||||
// panic("mock out the Lock method")
|
||||
// },
|
||||
// MarkAnswerFunc: func(repo ghrepo.Interface, commentID string) error {
|
||||
// panic("mock out the MarkAnswer method")
|
||||
// },
|
||||
// ReopenFunc: func(repo ghrepo.Interface, id string) (*Discussion, error) {
|
||||
// panic("mock out the Reopen method")
|
||||
// },
|
||||
// SearchFunc: func(repo ghrepo.Interface, filters SearchFilters, limit int) ([]Discussion, int, error) {
|
||||
// panic("mock out the Search method")
|
||||
// },
|
||||
// UnlockFunc: func(repo ghrepo.Interface, id string) error {
|
||||
// panic("mock out the Unlock method")
|
||||
// },
|
||||
// UnmarkAnswerFunc: func(repo ghrepo.Interface, commentID string) error {
|
||||
// panic("mock out the UnmarkAnswer method")
|
||||
// },
|
||||
// UpdateFunc: func(repo ghrepo.Interface, input UpdateDiscussionInput) (*Discussion, error) {
|
||||
// panic("mock out the Update method")
|
||||
// },
|
||||
// }
|
||||
//
|
||||
// // use mockedDiscussionClient in code that requires DiscussionClient
|
||||
// // and then make assertions.
|
||||
//
|
||||
// }
|
||||
type DiscussionClientMock struct {
|
||||
// AddCommentFunc mocks the AddComment method.
|
||||
AddCommentFunc func(repo ghrepo.Interface, discussionID string, body string, replyToID string) (*DiscussionComment, error)
|
||||
|
||||
// CloseFunc mocks the Close method.
|
||||
CloseFunc func(repo ghrepo.Interface, id string, reason CloseReason) (*Discussion, error)
|
||||
|
||||
// CreateFunc mocks the Create method.
|
||||
CreateFunc func(repo ghrepo.Interface, input CreateDiscussionInput) (*Discussion, error)
|
||||
|
||||
// GetByNumberFunc mocks the GetByNumber method.
|
||||
GetByNumberFunc func(repo ghrepo.Interface, number int) (*Discussion, error)
|
||||
|
||||
// GetWithCommentsFunc mocks the GetWithComments method.
|
||||
GetWithCommentsFunc func(repo ghrepo.Interface, number int, commentLimit int, order string) (*Discussion, error)
|
||||
|
||||
// ListFunc mocks the List method.
|
||||
ListFunc func(repo ghrepo.Interface, filters ListFilters, limit int) ([]Discussion, int, error)
|
||||
|
||||
// ListCategoriesFunc mocks the ListCategories method.
|
||||
ListCategoriesFunc func(repo ghrepo.Interface) ([]DiscussionCategory, error)
|
||||
|
||||
// LockFunc mocks the Lock method.
|
||||
LockFunc func(repo ghrepo.Interface, id string, reason string) error
|
||||
|
||||
// MarkAnswerFunc mocks the MarkAnswer method.
|
||||
MarkAnswerFunc func(repo ghrepo.Interface, commentID string) error
|
||||
|
||||
// ReopenFunc mocks the Reopen method.
|
||||
ReopenFunc func(repo ghrepo.Interface, id string) (*Discussion, error)
|
||||
|
||||
// SearchFunc mocks the Search method.
|
||||
SearchFunc func(repo ghrepo.Interface, filters SearchFilters, limit int) ([]Discussion, int, error)
|
||||
|
||||
// UnlockFunc mocks the Unlock method.
|
||||
UnlockFunc func(repo ghrepo.Interface, id string) error
|
||||
|
||||
// UnmarkAnswerFunc mocks the UnmarkAnswer method.
|
||||
UnmarkAnswerFunc func(repo ghrepo.Interface, commentID string) error
|
||||
|
||||
// UpdateFunc mocks the Update method.
|
||||
UpdateFunc func(repo ghrepo.Interface, input UpdateDiscussionInput) (*Discussion, error)
|
||||
|
||||
// calls tracks calls to the methods.
|
||||
calls struct {
|
||||
// AddComment holds details about calls to the AddComment method.
|
||||
AddComment []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// DiscussionID is the discussionID argument value.
|
||||
DiscussionID string
|
||||
// Body is the body argument value.
|
||||
Body string
|
||||
// ReplyToID is the replyToID argument value.
|
||||
ReplyToID string
|
||||
}
|
||||
// Close holds details about calls to the Close method.
|
||||
Close []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// ID is the id argument value.
|
||||
ID string
|
||||
// Reason is the reason argument value.
|
||||
Reason CloseReason
|
||||
}
|
||||
// Create holds details about calls to the Create method.
|
||||
Create []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// Input is the input argument value.
|
||||
Input CreateDiscussionInput
|
||||
}
|
||||
// GetByNumber holds details about calls to the GetByNumber method.
|
||||
GetByNumber []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// Number is the number argument value.
|
||||
Number int
|
||||
}
|
||||
// GetWithComments holds details about calls to the GetWithComments method.
|
||||
GetWithComments []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// Number is the number argument value.
|
||||
Number int
|
||||
// CommentLimit is the commentLimit argument value.
|
||||
CommentLimit int
|
||||
// Order is the order argument value.
|
||||
Order string
|
||||
}
|
||||
// List holds details about calls to the List method.
|
||||
List []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// Filters is the filters argument value.
|
||||
Filters ListFilters
|
||||
// Limit is the limit argument value.
|
||||
Limit int
|
||||
}
|
||||
// ListCategories holds details about calls to the ListCategories method.
|
||||
ListCategories []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
}
|
||||
// Lock holds details about calls to the Lock method.
|
||||
Lock []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// ID is the id argument value.
|
||||
ID string
|
||||
// Reason is the reason argument value.
|
||||
Reason string
|
||||
}
|
||||
// MarkAnswer holds details about calls to the MarkAnswer method.
|
||||
MarkAnswer []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// CommentID is the commentID argument value.
|
||||
CommentID string
|
||||
}
|
||||
// Reopen holds details about calls to the Reopen method.
|
||||
Reopen []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// ID is the id argument value.
|
||||
ID string
|
||||
}
|
||||
// Search holds details about calls to the Search method.
|
||||
Search []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// Filters is the filters argument value.
|
||||
Filters SearchFilters
|
||||
// Limit is the limit argument value.
|
||||
Limit int
|
||||
}
|
||||
// Unlock holds details about calls to the Unlock method.
|
||||
Unlock []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// ID is the id argument value.
|
||||
ID string
|
||||
}
|
||||
// UnmarkAnswer holds details about calls to the UnmarkAnswer method.
|
||||
UnmarkAnswer []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// CommentID is the commentID argument value.
|
||||
CommentID string
|
||||
}
|
||||
// Update holds details about calls to the Update method.
|
||||
Update []struct {
|
||||
// Repo is the repo argument value.
|
||||
Repo ghrepo.Interface
|
||||
// Input is the input argument value.
|
||||
Input UpdateDiscussionInput
|
||||
}
|
||||
}
|
||||
lockAddComment sync.RWMutex
|
||||
lockClose sync.RWMutex
|
||||
lockCreate sync.RWMutex
|
||||
lockGetByNumber sync.RWMutex
|
||||
lockGetWithComments sync.RWMutex
|
||||
lockList sync.RWMutex
|
||||
lockListCategories sync.RWMutex
|
||||
lockLock sync.RWMutex
|
||||
lockMarkAnswer sync.RWMutex
|
||||
lockReopen sync.RWMutex
|
||||
lockSearch sync.RWMutex
|
||||
lockUnlock sync.RWMutex
|
||||
lockUnmarkAnswer sync.RWMutex
|
||||
lockUpdate sync.RWMutex
|
||||
}
|
||||
|
||||
// AddComment calls AddCommentFunc.
|
||||
func (mock *DiscussionClientMock) AddComment(repo ghrepo.Interface, discussionID string, body string, replyToID string) (*DiscussionComment, error) {
|
||||
if mock.AddCommentFunc == nil {
|
||||
panic("DiscussionClientMock.AddCommentFunc: method is nil but DiscussionClient.AddComment was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
DiscussionID string
|
||||
Body string
|
||||
ReplyToID string
|
||||
}{
|
||||
Repo: repo,
|
||||
DiscussionID: discussionID,
|
||||
Body: body,
|
||||
ReplyToID: replyToID,
|
||||
}
|
||||
mock.lockAddComment.Lock()
|
||||
mock.calls.AddComment = append(mock.calls.AddComment, callInfo)
|
||||
mock.lockAddComment.Unlock()
|
||||
return mock.AddCommentFunc(repo, discussionID, body, replyToID)
|
||||
}
|
||||
|
||||
// AddCommentCalls gets all the calls that were made to AddComment.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.AddCommentCalls())
|
||||
func (mock *DiscussionClientMock) AddCommentCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
DiscussionID string
|
||||
Body string
|
||||
ReplyToID string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
DiscussionID string
|
||||
Body string
|
||||
ReplyToID string
|
||||
}
|
||||
mock.lockAddComment.RLock()
|
||||
calls = mock.calls.AddComment
|
||||
mock.lockAddComment.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Close calls CloseFunc.
|
||||
func (mock *DiscussionClientMock) Close(repo ghrepo.Interface, id string, reason CloseReason) (*Discussion, error) {
|
||||
if mock.CloseFunc == nil {
|
||||
panic("DiscussionClientMock.CloseFunc: method is nil but DiscussionClient.Close was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
Reason CloseReason
|
||||
}{
|
||||
Repo: repo,
|
||||
ID: id,
|
||||
Reason: reason,
|
||||
}
|
||||
mock.lockClose.Lock()
|
||||
mock.calls.Close = append(mock.calls.Close, callInfo)
|
||||
mock.lockClose.Unlock()
|
||||
return mock.CloseFunc(repo, id, reason)
|
||||
}
|
||||
|
||||
// CloseCalls gets all the calls that were made to Close.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.CloseCalls())
|
||||
func (mock *DiscussionClientMock) CloseCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
Reason CloseReason
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
Reason CloseReason
|
||||
}
|
||||
mock.lockClose.RLock()
|
||||
calls = mock.calls.Close
|
||||
mock.lockClose.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Create calls CreateFunc.
|
||||
func (mock *DiscussionClientMock) Create(repo ghrepo.Interface, input CreateDiscussionInput) (*Discussion, error) {
|
||||
if mock.CreateFunc == nil {
|
||||
panic("DiscussionClientMock.CreateFunc: method is nil but DiscussionClient.Create was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
Input CreateDiscussionInput
|
||||
}{
|
||||
Repo: repo,
|
||||
Input: input,
|
||||
}
|
||||
mock.lockCreate.Lock()
|
||||
mock.calls.Create = append(mock.calls.Create, callInfo)
|
||||
mock.lockCreate.Unlock()
|
||||
return mock.CreateFunc(repo, input)
|
||||
}
|
||||
|
||||
// CreateCalls gets all the calls that were made to Create.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.CreateCalls())
|
||||
func (mock *DiscussionClientMock) CreateCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
Input CreateDiscussionInput
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
Input CreateDiscussionInput
|
||||
}
|
||||
mock.lockCreate.RLock()
|
||||
calls = mock.calls.Create
|
||||
mock.lockCreate.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// GetByNumber calls GetByNumberFunc.
|
||||
func (mock *DiscussionClientMock) GetByNumber(repo ghrepo.Interface, number int) (*Discussion, error) {
|
||||
if mock.GetByNumberFunc == nil {
|
||||
panic("DiscussionClientMock.GetByNumberFunc: method is nil but DiscussionClient.GetByNumber was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
Number int
|
||||
}{
|
||||
Repo: repo,
|
||||
Number: number,
|
||||
}
|
||||
mock.lockGetByNumber.Lock()
|
||||
mock.calls.GetByNumber = append(mock.calls.GetByNumber, callInfo)
|
||||
mock.lockGetByNumber.Unlock()
|
||||
return mock.GetByNumberFunc(repo, number)
|
||||
}
|
||||
|
||||
// GetByNumberCalls gets all the calls that were made to GetByNumber.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.GetByNumberCalls())
|
||||
func (mock *DiscussionClientMock) GetByNumberCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
Number int
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
Number int
|
||||
}
|
||||
mock.lockGetByNumber.RLock()
|
||||
calls = mock.calls.GetByNumber
|
||||
mock.lockGetByNumber.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// GetWithComments calls GetWithCommentsFunc.
|
||||
func (mock *DiscussionClientMock) GetWithComments(repo ghrepo.Interface, number int, commentLimit int, order string) (*Discussion, error) {
|
||||
if mock.GetWithCommentsFunc == nil {
|
||||
panic("DiscussionClientMock.GetWithCommentsFunc: method is nil but DiscussionClient.GetWithComments was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
Number int
|
||||
CommentLimit int
|
||||
Order string
|
||||
}{
|
||||
Repo: repo,
|
||||
Number: number,
|
||||
CommentLimit: commentLimit,
|
||||
Order: order,
|
||||
}
|
||||
mock.lockGetWithComments.Lock()
|
||||
mock.calls.GetWithComments = append(mock.calls.GetWithComments, callInfo)
|
||||
mock.lockGetWithComments.Unlock()
|
||||
return mock.GetWithCommentsFunc(repo, number, commentLimit, order)
|
||||
}
|
||||
|
||||
// GetWithCommentsCalls gets all the calls that were made to GetWithComments.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.GetWithCommentsCalls())
|
||||
func (mock *DiscussionClientMock) GetWithCommentsCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
Number int
|
||||
CommentLimit int
|
||||
Order string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
Number int
|
||||
CommentLimit int
|
||||
Order string
|
||||
}
|
||||
mock.lockGetWithComments.RLock()
|
||||
calls = mock.calls.GetWithComments
|
||||
mock.lockGetWithComments.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// List calls ListFunc.
|
||||
func (mock *DiscussionClientMock) List(repo ghrepo.Interface, filters ListFilters, limit int) ([]Discussion, int, error) {
|
||||
if mock.ListFunc == nil {
|
||||
panic("DiscussionClientMock.ListFunc: method is nil but DiscussionClient.List was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
Filters ListFilters
|
||||
Limit int
|
||||
}{
|
||||
Repo: repo,
|
||||
Filters: filters,
|
||||
Limit: limit,
|
||||
}
|
||||
mock.lockList.Lock()
|
||||
mock.calls.List = append(mock.calls.List, callInfo)
|
||||
mock.lockList.Unlock()
|
||||
return mock.ListFunc(repo, filters, limit)
|
||||
}
|
||||
|
||||
// ListCalls gets all the calls that were made to List.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.ListCalls())
|
||||
func (mock *DiscussionClientMock) ListCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
Filters ListFilters
|
||||
Limit int
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
Filters ListFilters
|
||||
Limit int
|
||||
}
|
||||
mock.lockList.RLock()
|
||||
calls = mock.calls.List
|
||||
mock.lockList.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// ListCategories calls ListCategoriesFunc.
|
||||
func (mock *DiscussionClientMock) ListCategories(repo ghrepo.Interface) ([]DiscussionCategory, error) {
|
||||
if mock.ListCategoriesFunc == nil {
|
||||
panic("DiscussionClientMock.ListCategoriesFunc: method is nil but DiscussionClient.ListCategories was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
}{
|
||||
Repo: repo,
|
||||
}
|
||||
mock.lockListCategories.Lock()
|
||||
mock.calls.ListCategories = append(mock.calls.ListCategories, callInfo)
|
||||
mock.lockListCategories.Unlock()
|
||||
return mock.ListCategoriesFunc(repo)
|
||||
}
|
||||
|
||||
// ListCategoriesCalls gets all the calls that were made to ListCategories.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.ListCategoriesCalls())
|
||||
func (mock *DiscussionClientMock) ListCategoriesCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
}
|
||||
mock.lockListCategories.RLock()
|
||||
calls = mock.calls.ListCategories
|
||||
mock.lockListCategories.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Lock calls LockFunc.
|
||||
func (mock *DiscussionClientMock) Lock(repo ghrepo.Interface, id string, reason string) error {
|
||||
if mock.LockFunc == nil {
|
||||
panic("DiscussionClientMock.LockFunc: method is nil but DiscussionClient.Lock was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
Reason string
|
||||
}{
|
||||
Repo: repo,
|
||||
ID: id,
|
||||
Reason: reason,
|
||||
}
|
||||
mock.lockLock.Lock()
|
||||
mock.calls.Lock = append(mock.calls.Lock, callInfo)
|
||||
mock.lockLock.Unlock()
|
||||
return mock.LockFunc(repo, id, reason)
|
||||
}
|
||||
|
||||
// LockCalls gets all the calls that were made to Lock.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.LockCalls())
|
||||
func (mock *DiscussionClientMock) LockCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
Reason string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
Reason string
|
||||
}
|
||||
mock.lockLock.RLock()
|
||||
calls = mock.calls.Lock
|
||||
mock.lockLock.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// MarkAnswer calls MarkAnswerFunc.
|
||||
func (mock *DiscussionClientMock) MarkAnswer(repo ghrepo.Interface, commentID string) error {
|
||||
if mock.MarkAnswerFunc == nil {
|
||||
panic("DiscussionClientMock.MarkAnswerFunc: method is nil but DiscussionClient.MarkAnswer was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
CommentID string
|
||||
}{
|
||||
Repo: repo,
|
||||
CommentID: commentID,
|
||||
}
|
||||
mock.lockMarkAnswer.Lock()
|
||||
mock.calls.MarkAnswer = append(mock.calls.MarkAnswer, callInfo)
|
||||
mock.lockMarkAnswer.Unlock()
|
||||
return mock.MarkAnswerFunc(repo, commentID)
|
||||
}
|
||||
|
||||
// MarkAnswerCalls gets all the calls that were made to MarkAnswer.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.MarkAnswerCalls())
|
||||
func (mock *DiscussionClientMock) MarkAnswerCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
CommentID string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
CommentID string
|
||||
}
|
||||
mock.lockMarkAnswer.RLock()
|
||||
calls = mock.calls.MarkAnswer
|
||||
mock.lockMarkAnswer.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Reopen calls ReopenFunc.
|
||||
func (mock *DiscussionClientMock) Reopen(repo ghrepo.Interface, id string) (*Discussion, error) {
|
||||
if mock.ReopenFunc == nil {
|
||||
panic("DiscussionClientMock.ReopenFunc: method is nil but DiscussionClient.Reopen was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
}{
|
||||
Repo: repo,
|
||||
ID: id,
|
||||
}
|
||||
mock.lockReopen.Lock()
|
||||
mock.calls.Reopen = append(mock.calls.Reopen, callInfo)
|
||||
mock.lockReopen.Unlock()
|
||||
return mock.ReopenFunc(repo, id)
|
||||
}
|
||||
|
||||
// ReopenCalls gets all the calls that were made to Reopen.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.ReopenCalls())
|
||||
func (mock *DiscussionClientMock) ReopenCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
}
|
||||
mock.lockReopen.RLock()
|
||||
calls = mock.calls.Reopen
|
||||
mock.lockReopen.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Search calls SearchFunc.
|
||||
func (mock *DiscussionClientMock) Search(repo ghrepo.Interface, filters SearchFilters, limit int) ([]Discussion, int, error) {
|
||||
if mock.SearchFunc == nil {
|
||||
panic("DiscussionClientMock.SearchFunc: method is nil but DiscussionClient.Search was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
Filters SearchFilters
|
||||
Limit int
|
||||
}{
|
||||
Repo: repo,
|
||||
Filters: filters,
|
||||
Limit: limit,
|
||||
}
|
||||
mock.lockSearch.Lock()
|
||||
mock.calls.Search = append(mock.calls.Search, callInfo)
|
||||
mock.lockSearch.Unlock()
|
||||
return mock.SearchFunc(repo, filters, limit)
|
||||
}
|
||||
|
||||
// SearchCalls gets all the calls that were made to Search.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.SearchCalls())
|
||||
func (mock *DiscussionClientMock) SearchCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
Filters SearchFilters
|
||||
Limit int
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
Filters SearchFilters
|
||||
Limit int
|
||||
}
|
||||
mock.lockSearch.RLock()
|
||||
calls = mock.calls.Search
|
||||
mock.lockSearch.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Unlock calls UnlockFunc.
|
||||
func (mock *DiscussionClientMock) Unlock(repo ghrepo.Interface, id string) error {
|
||||
if mock.UnlockFunc == nil {
|
||||
panic("DiscussionClientMock.UnlockFunc: method is nil but DiscussionClient.Unlock was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
}{
|
||||
Repo: repo,
|
||||
ID: id,
|
||||
}
|
||||
mock.lockUnlock.Lock()
|
||||
mock.calls.Unlock = append(mock.calls.Unlock, callInfo)
|
||||
mock.lockUnlock.Unlock()
|
||||
return mock.UnlockFunc(repo, id)
|
||||
}
|
||||
|
||||
// UnlockCalls gets all the calls that were made to Unlock.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.UnlockCalls())
|
||||
func (mock *DiscussionClientMock) UnlockCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
ID string
|
||||
}
|
||||
mock.lockUnlock.RLock()
|
||||
calls = mock.calls.Unlock
|
||||
mock.lockUnlock.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// UnmarkAnswer calls UnmarkAnswerFunc.
|
||||
func (mock *DiscussionClientMock) UnmarkAnswer(repo ghrepo.Interface, commentID string) error {
|
||||
if mock.UnmarkAnswerFunc == nil {
|
||||
panic("DiscussionClientMock.UnmarkAnswerFunc: method is nil but DiscussionClient.UnmarkAnswer was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
CommentID string
|
||||
}{
|
||||
Repo: repo,
|
||||
CommentID: commentID,
|
||||
}
|
||||
mock.lockUnmarkAnswer.Lock()
|
||||
mock.calls.UnmarkAnswer = append(mock.calls.UnmarkAnswer, callInfo)
|
||||
mock.lockUnmarkAnswer.Unlock()
|
||||
return mock.UnmarkAnswerFunc(repo, commentID)
|
||||
}
|
||||
|
||||
// UnmarkAnswerCalls gets all the calls that were made to UnmarkAnswer.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.UnmarkAnswerCalls())
|
||||
func (mock *DiscussionClientMock) UnmarkAnswerCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
CommentID string
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
CommentID string
|
||||
}
|
||||
mock.lockUnmarkAnswer.RLock()
|
||||
calls = mock.calls.UnmarkAnswer
|
||||
mock.lockUnmarkAnswer.RUnlock()
|
||||
return calls
|
||||
}
|
||||
|
||||
// Update calls UpdateFunc.
|
||||
func (mock *DiscussionClientMock) Update(repo ghrepo.Interface, input UpdateDiscussionInput) (*Discussion, error) {
|
||||
if mock.UpdateFunc == nil {
|
||||
panic("DiscussionClientMock.UpdateFunc: method is nil but DiscussionClient.Update was just called")
|
||||
}
|
||||
callInfo := struct {
|
||||
Repo ghrepo.Interface
|
||||
Input UpdateDiscussionInput
|
||||
}{
|
||||
Repo: repo,
|
||||
Input: input,
|
||||
}
|
||||
mock.lockUpdate.Lock()
|
||||
mock.calls.Update = append(mock.calls.Update, callInfo)
|
||||
mock.lockUpdate.Unlock()
|
||||
return mock.UpdateFunc(repo, input)
|
||||
}
|
||||
|
||||
// UpdateCalls gets all the calls that were made to Update.
|
||||
// Check the length with:
|
||||
//
|
||||
// len(mockedDiscussionClient.UpdateCalls())
|
||||
func (mock *DiscussionClientMock) UpdateCalls() []struct {
|
||||
Repo ghrepo.Interface
|
||||
Input UpdateDiscussionInput
|
||||
} {
|
||||
var calls []struct {
|
||||
Repo ghrepo.Interface
|
||||
Input UpdateDiscussionInput
|
||||
}
|
||||
mock.lockUpdate.RLock()
|
||||
calls = mock.calls.Update
|
||||
mock.lockUpdate.RUnlock()
|
||||
return calls
|
||||
}
|
||||
265
pkg/cmd/discussion/client/types.go
Normal file
265
pkg/cmd/discussion/client/types.go
Normal file
|
|
@ -0,0 +1,265 @@
|
|||
package client
|
||||
|
||||
import "time"
|
||||
|
||||
// Discussion represents a GitHub Discussion as a domain object.
|
||||
// Fields carry no JSON tags; serialization is handled by ExportData.
|
||||
type Discussion struct {
|
||||
ID string
|
||||
Number int
|
||||
Title string
|
||||
Body string
|
||||
URL string
|
||||
State string
|
||||
StateReason string
|
||||
Author DiscussionAuthor
|
||||
Category DiscussionCategory
|
||||
Labels []DiscussionLabel
|
||||
Answered bool
|
||||
AnswerChosenAt time.Time
|
||||
AnswerChosenBy *DiscussionAuthor
|
||||
Comments DiscussionCommentList
|
||||
ReactionGroups []ReactionGroup
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
ClosedAt time.Time
|
||||
Locked bool
|
||||
}
|
||||
|
||||
// ExportData returns a map of the requested fields for JSON output.
|
||||
// Because domain types carry no JSON struct tags, each field is mapped
|
||||
// explicitly rather than using reflection.
|
||||
func (d Discussion) ExportData(fields []string) map[string]interface{} {
|
||||
data := map[string]interface{}{}
|
||||
for _, f := range fields {
|
||||
switch f {
|
||||
case "id":
|
||||
data[f] = d.ID
|
||||
case "number":
|
||||
data[f] = d.Number
|
||||
case "title":
|
||||
data[f] = d.Title
|
||||
case "body":
|
||||
data[f] = d.Body
|
||||
case "url":
|
||||
data[f] = d.URL
|
||||
case "state":
|
||||
data[f] = d.State
|
||||
case "stateReason":
|
||||
data[f] = d.StateReason
|
||||
case "author":
|
||||
data[f] = d.Author.Export()
|
||||
case "category":
|
||||
data[f] = d.Category.Export()
|
||||
case "labels":
|
||||
labels := make([]interface{}, len(d.Labels))
|
||||
for i, l := range d.Labels {
|
||||
labels[i] = l.Export()
|
||||
}
|
||||
data[f] = labels
|
||||
case "answered":
|
||||
data[f] = d.Answered
|
||||
case "answerChosenAt":
|
||||
if d.AnswerChosenAt.IsZero() {
|
||||
data[f] = nil
|
||||
} else {
|
||||
data[f] = d.AnswerChosenAt
|
||||
}
|
||||
case "answerChosenBy":
|
||||
if d.AnswerChosenBy == nil {
|
||||
data[f] = nil
|
||||
} else {
|
||||
data[f] = d.AnswerChosenBy.Export()
|
||||
}
|
||||
case "comments":
|
||||
comments := make([]interface{}, len(d.Comments.Comments))
|
||||
for i, c := range d.Comments.Comments {
|
||||
comments[i] = c.Export()
|
||||
}
|
||||
data[f] = map[string]interface{}{
|
||||
"totalCount": d.Comments.TotalCount,
|
||||
"nodes": comments,
|
||||
}
|
||||
case "reactionGroups":
|
||||
groups := make([]interface{}, len(d.ReactionGroups))
|
||||
for i, rg := range d.ReactionGroups {
|
||||
groups[i] = rg.Export()
|
||||
}
|
||||
data[f] = groups
|
||||
case "createdAt":
|
||||
data[f] = d.CreatedAt
|
||||
case "updatedAt":
|
||||
data[f] = d.UpdatedAt
|
||||
case "closedAt":
|
||||
if d.ClosedAt.IsZero() {
|
||||
data[f] = nil
|
||||
} else {
|
||||
data[f] = d.ClosedAt
|
||||
}
|
||||
case "locked":
|
||||
data[f] = d.Locked
|
||||
}
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
// DiscussionAuthor represents the author of a discussion or comment.
|
||||
type DiscussionAuthor struct {
|
||||
ID string
|
||||
Login string
|
||||
Name string
|
||||
}
|
||||
|
||||
// Export returns the author as a map for JSON output.
|
||||
func (a DiscussionAuthor) Export() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": a.ID,
|
||||
"login": a.Login,
|
||||
"name": a.Name,
|
||||
}
|
||||
}
|
||||
|
||||
// DiscussionCategory represents a discussion category within a repository.
|
||||
type DiscussionCategory struct {
|
||||
ID string
|
||||
Name string
|
||||
Slug string
|
||||
Emoji string
|
||||
IsAnswerable bool
|
||||
}
|
||||
|
||||
// Export returns the category as a map for JSON output.
|
||||
func (c DiscussionCategory) Export() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": c.ID,
|
||||
"name": c.Name,
|
||||
"slug": c.Slug,
|
||||
"emoji": c.Emoji,
|
||||
"isAnswerable": c.IsAnswerable,
|
||||
}
|
||||
}
|
||||
|
||||
// DiscussionLabel represents a label applied to a discussion.
|
||||
type DiscussionLabel struct {
|
||||
ID string
|
||||
Name string
|
||||
Color string
|
||||
}
|
||||
|
||||
// Export returns the label as a map for JSON output.
|
||||
func (l DiscussionLabel) Export() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"id": l.ID,
|
||||
"name": l.Name,
|
||||
"color": l.Color,
|
||||
}
|
||||
}
|
||||
|
||||
// DiscussionComment represents a comment or reply on a discussion.
|
||||
type DiscussionComment struct {
|
||||
ID string
|
||||
URL string
|
||||
Author DiscussionAuthor
|
||||
Body string
|
||||
CreatedAt time.Time
|
||||
IsAnswer bool
|
||||
UpvoteCount int
|
||||
ReactionGroups []ReactionGroup
|
||||
Replies []DiscussionComment
|
||||
TotalReplies int
|
||||
}
|
||||
|
||||
// Export returns the comment as a map for JSON output.
|
||||
func (c DiscussionComment) Export() map[string]interface{} {
|
||||
replies := make([]interface{}, len(c.Replies))
|
||||
for i, r := range c.Replies {
|
||||
replies[i] = r.Export()
|
||||
}
|
||||
reactions := make([]interface{}, len(c.ReactionGroups))
|
||||
for i, rg := range c.ReactionGroups {
|
||||
reactions[i] = rg.Export()
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"id": c.ID,
|
||||
"url": c.URL,
|
||||
"author": c.Author.Export(),
|
||||
"body": c.Body,
|
||||
"createdAt": c.CreatedAt,
|
||||
"isAnswer": c.IsAnswer,
|
||||
"upvoteCount": c.UpvoteCount,
|
||||
"reactionGroups": reactions,
|
||||
"replies": replies,
|
||||
"totalReplies": c.TotalReplies,
|
||||
}
|
||||
}
|
||||
|
||||
// DiscussionCommentList represents a paginated list of comments on a discussion.
|
||||
type DiscussionCommentList struct {
|
||||
Comments []DiscussionComment
|
||||
TotalCount int
|
||||
}
|
||||
|
||||
// ReactionGroup represents a set of reactions of the same type.
|
||||
type ReactionGroup struct {
|
||||
Content string
|
||||
TotalCount int
|
||||
}
|
||||
|
||||
// Export returns the reaction group as a map for JSON output.
|
||||
func (rg ReactionGroup) Export() map[string]interface{} {
|
||||
return map[string]interface{}{
|
||||
"content": rg.Content,
|
||||
"totalCount": rg.TotalCount,
|
||||
}
|
||||
}
|
||||
|
||||
// CloseReason represents the reason for closing a discussion.
|
||||
type CloseReason string
|
||||
|
||||
const (
|
||||
// CloseReasonResolved indicates the discussion topic has been resolved.
|
||||
CloseReasonResolved CloseReason = "RESOLVED"
|
||||
// CloseReasonOutdated indicates the discussion is no longer relevant.
|
||||
CloseReasonOutdated CloseReason = "OUTDATED"
|
||||
// CloseReasonDuplicate indicates the discussion is a duplicate of another.
|
||||
CloseReasonDuplicate CloseReason = "DUPLICATE"
|
||||
)
|
||||
|
||||
// ListFilters holds parameters for the repository.discussions query.
|
||||
// CategoryID must be resolved by the caller before passing to List.
|
||||
type ListFilters struct {
|
||||
State string
|
||||
CategoryID string
|
||||
Answered *bool
|
||||
OrderBy string
|
||||
Direction string
|
||||
}
|
||||
|
||||
// SearchFilters holds parameters for the search query used when
|
||||
// author or label filtering is required.
|
||||
type SearchFilters struct {
|
||||
Author string
|
||||
Labels []string
|
||||
State string
|
||||
Category string
|
||||
Answered *bool
|
||||
OrderBy string
|
||||
Direction string
|
||||
}
|
||||
|
||||
// CreateDiscussionInput holds the parameters for creating a discussion.
|
||||
type CreateDiscussionInput struct {
|
||||
RepositoryID string
|
||||
CategoryID string
|
||||
Title string
|
||||
Body string
|
||||
}
|
||||
|
||||
// UpdateDiscussionInput holds optional parameters for updating a discussion.
|
||||
// Nil pointer fields are left unchanged.
|
||||
type UpdateDiscussionInput struct {
|
||||
DiscussionID string
|
||||
Title *string
|
||||
Body *string
|
||||
CategoryID *string
|
||||
}
|
||||
33
pkg/cmd/discussion/discussion.go
Normal file
33
pkg/cmd/discussion/discussion.go
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
package discussion
|
||||
|
||||
import (
|
||||
"github.com/MakeNowJust/heredoc"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// NewCmdDiscussion returns the top-level "discussion" command.
|
||||
func NewCmdDiscussion(f *cmdutil.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "discussion <command>",
|
||||
Short: "Manage discussions",
|
||||
Long: "Work with GitHub Discussions.",
|
||||
Example: heredoc.Doc(`
|
||||
$ gh discussion list
|
||||
$ gh discussion create --category "General" --title "Hello"
|
||||
$ gh discussion view 123
|
||||
`),
|
||||
Annotations: map[string]string{
|
||||
"help:arguments": heredoc.Doc(`
|
||||
A discussion can be supplied as argument in any of the following formats:
|
||||
- by number, e.g. "123"; or
|
||||
- by URL, e.g. "https://github.com/OWNER/REPO/discussions/123".
|
||||
`),
|
||||
},
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
||||
return cmd
|
||||
}
|
||||
21
pkg/cmd/discussion/shared/client.go
Normal file
21
pkg/cmd/discussion/shared/client.go
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
// Package shared provides factory functions, field definitions, and display
|
||||
// helpers used across discussion subcommands.
|
||||
package shared
|
||||
|
||||
import (
|
||||
"github.com/cli/cli/v2/pkg/cmd/discussion/client"
|
||||
"github.com/cli/cli/v2/pkg/cmdutil"
|
||||
)
|
||||
|
||||
// DiscussionClientFunc returns a factory function that creates a DiscussionClient
|
||||
// from the given Factory. The returned function is intended to be stored in
|
||||
// command Options structs and called lazily inside RunE.
|
||||
func DiscussionClientFunc(f *cmdutil.Factory) func() (client.DiscussionClient, error) {
|
||||
return func() (client.DiscussionClient, error) {
|
||||
httpClient, err := f.HttpClient()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return client.NewDiscussionClient(httpClient), nil
|
||||
}
|
||||
}
|
||||
25
pkg/cmd/discussion/shared/fields.go
Normal file
25
pkg/cmd/discussion/shared/fields.go
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
package shared
|
||||
|
||||
// DiscussionFields lists the field names available for --json output on
|
||||
// discussion commands.
|
||||
var DiscussionFields = []string{
|
||||
"id",
|
||||
"number",
|
||||
"title",
|
||||
"body",
|
||||
"url",
|
||||
"state",
|
||||
"stateReason",
|
||||
"author",
|
||||
"category",
|
||||
"labels",
|
||||
"answered",
|
||||
"answerChosenAt",
|
||||
"answerChosenBy",
|
||||
"comments",
|
||||
"reactionGroups",
|
||||
"createdAt",
|
||||
"updatedAt",
|
||||
"closedAt",
|
||||
"locked",
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import (
|
|||
completionCmd "github.com/cli/cli/v2/pkg/cmd/completion"
|
||||
configCmd "github.com/cli/cli/v2/pkg/cmd/config"
|
||||
copilotCmd "github.com/cli/cli/v2/pkg/cmd/copilot"
|
||||
discussionCmd "github.com/cli/cli/v2/pkg/cmd/discussion"
|
||||
extensionCmd "github.com/cli/cli/v2/pkg/cmd/extension"
|
||||
"github.com/cli/cli/v2/pkg/cmd/factory"
|
||||
gistCmd "github.com/cli/cli/v2/pkg/cmd/gist"
|
||||
|
|
@ -157,6 +158,7 @@ func NewCmdRoot(f *cmdutil.Factory, version, buildDate string) (*cobra.Command,
|
|||
|
||||
cmd.AddCommand(agentTaskCmd.NewCmdAgentTask(&repoResolvingCmdFactory))
|
||||
cmd.AddCommand(browseCmd.NewCmdBrowse(&repoResolvingCmdFactory, nil))
|
||||
cmd.AddCommand(discussionCmd.NewCmdDiscussion(&repoResolvingCmdFactory))
|
||||
cmd.AddCommand(prCmd.NewCmdPR(&repoResolvingCmdFactory))
|
||||
cmd.AddCommand(orgCmd.NewCmdOrg(&repoResolvingCmdFactory))
|
||||
cmd.AddCommand(issueCmd.NewCmdIssue(&repoResolvingCmdFactory))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue