Add godoc comments to exported symbols in internal/featuredetection and internal/prompter
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
7367596c83
commit
f9fec823ad
4 changed files with 82 additions and 1 deletions
|
|
@ -2,99 +2,122 @@ package featuredetection
|
||||||
|
|
||||||
import "github.com/cli/cli/v2/internal/gh"
|
import "github.com/cli/cli/v2/internal/gh"
|
||||||
|
|
||||||
|
// DisabledDetectorMock is a mock Detector that returns zero-value features for all queries.
|
||||||
type DisabledDetectorMock struct{}
|
type DisabledDetectorMock struct{}
|
||||||
|
|
||||||
|
// IssueFeatures returns empty issue features.
|
||||||
func (md *DisabledDetectorMock) IssueFeatures() (IssueFeatures, error) {
|
func (md *DisabledDetectorMock) IssueFeatures() (IssueFeatures, error) {
|
||||||
return IssueFeatures{}, nil
|
return IssueFeatures{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PullRequestFeatures returns empty pull request features.
|
||||||
func (md *DisabledDetectorMock) PullRequestFeatures() (PullRequestFeatures, error) {
|
func (md *DisabledDetectorMock) PullRequestFeatures() (PullRequestFeatures, error) {
|
||||||
return PullRequestFeatures{}, nil
|
return PullRequestFeatures{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryFeatures returns empty repository features.
|
||||||
func (md *DisabledDetectorMock) RepositoryFeatures() (RepositoryFeatures, error) {
|
func (md *DisabledDetectorMock) RepositoryFeatures() (RepositoryFeatures, error) {
|
||||||
return RepositoryFeatures{}, nil
|
return RepositoryFeatures{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectsV1 returns unsupported for ProjectsV1.
|
||||||
func (md *DisabledDetectorMock) ProjectsV1() gh.ProjectsV1Support {
|
func (md *DisabledDetectorMock) ProjectsV1() gh.ProjectsV1Support {
|
||||||
return gh.ProjectsV1Unsupported
|
return gh.ProjectsV1Unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectFeatures returns empty project features.
|
||||||
func (md *DisabledDetectorMock) ProjectFeatures() (ProjectFeatures, error) {
|
func (md *DisabledDetectorMock) ProjectFeatures() (ProjectFeatures, error) {
|
||||||
return ProjectFeatures{}, nil
|
return ProjectFeatures{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchFeatures returns search features with advanced issue search disabled.
|
||||||
func (md *DisabledDetectorMock) SearchFeatures() (SearchFeatures, error) {
|
func (md *DisabledDetectorMock) SearchFeatures() (SearchFeatures, error) {
|
||||||
return advancedIssueSearchNotSupported, nil
|
return advancedIssueSearchNotSupported, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReleaseFeatures returns empty release features.
|
||||||
func (md *DisabledDetectorMock) ReleaseFeatures() (ReleaseFeatures, error) {
|
func (md *DisabledDetectorMock) ReleaseFeatures() (ReleaseFeatures, error) {
|
||||||
return ReleaseFeatures{}, nil
|
return ReleaseFeatures{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ActionsFeatures returns empty actions features.
|
||||||
func (md *DisabledDetectorMock) ActionsFeatures() (ActionsFeatures, error) {
|
func (md *DisabledDetectorMock) ActionsFeatures() (ActionsFeatures, error) {
|
||||||
return ActionsFeatures{}, nil
|
return ActionsFeatures{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnabledDetectorMock is a mock Detector that returns all features as enabled.
|
||||||
type EnabledDetectorMock struct{}
|
type EnabledDetectorMock struct{}
|
||||||
|
|
||||||
|
// IssueFeatures returns all issue features enabled.
|
||||||
func (md *EnabledDetectorMock) IssueFeatures() (IssueFeatures, error) {
|
func (md *EnabledDetectorMock) IssueFeatures() (IssueFeatures, error) {
|
||||||
return allIssueFeatures, nil
|
return allIssueFeatures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PullRequestFeatures returns all pull request features enabled.
|
||||||
func (md *EnabledDetectorMock) PullRequestFeatures() (PullRequestFeatures, error) {
|
func (md *EnabledDetectorMock) PullRequestFeatures() (PullRequestFeatures, error) {
|
||||||
return allPullRequestFeatures, nil
|
return allPullRequestFeatures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryFeatures returns all repository features enabled.
|
||||||
func (md *EnabledDetectorMock) RepositoryFeatures() (RepositoryFeatures, error) {
|
func (md *EnabledDetectorMock) RepositoryFeatures() (RepositoryFeatures, error) {
|
||||||
return allRepositoryFeatures, nil
|
return allRepositoryFeatures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectsV1 returns supported for ProjectsV1.
|
||||||
func (md *EnabledDetectorMock) ProjectsV1() gh.ProjectsV1Support {
|
func (md *EnabledDetectorMock) ProjectsV1() gh.ProjectsV1Support {
|
||||||
return gh.ProjectsV1Supported
|
return gh.ProjectsV1Supported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectFeatures returns all project features enabled.
|
||||||
func (md *EnabledDetectorMock) ProjectFeatures() (ProjectFeatures, error) {
|
func (md *EnabledDetectorMock) ProjectFeatures() (ProjectFeatures, error) {
|
||||||
return allProjectFeatures, nil
|
return allProjectFeatures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchFeatures returns search features with advanced issue search disabled.
|
||||||
func (md *EnabledDetectorMock) SearchFeatures() (SearchFeatures, error) {
|
func (md *EnabledDetectorMock) SearchFeatures() (SearchFeatures, error) {
|
||||||
return advancedIssueSearchNotSupported, nil
|
return advancedIssueSearchNotSupported, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReleaseFeatures returns release features with immutable releases enabled.
|
||||||
func (md *EnabledDetectorMock) ReleaseFeatures() (ReleaseFeatures, error) {
|
func (md *EnabledDetectorMock) ReleaseFeatures() (ReleaseFeatures, error) {
|
||||||
return ReleaseFeatures{
|
return ReleaseFeatures{
|
||||||
ImmutableReleases: true,
|
ImmutableReleases: true,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ActionsFeatures returns actions features with dispatch run details enabled.
|
||||||
func (md *EnabledDetectorMock) ActionsFeatures() (ActionsFeatures, error) {
|
func (md *EnabledDetectorMock) ActionsFeatures() (ActionsFeatures, error) {
|
||||||
return ActionsFeatures{
|
return ActionsFeatures{
|
||||||
DispatchRunDetails: true,
|
DispatchRunDetails: true,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdvancedIssueSearchDetectorMock is a mock Detector with configurable search features.
|
||||||
type AdvancedIssueSearchDetectorMock struct {
|
type AdvancedIssueSearchDetectorMock struct {
|
||||||
EnabledDetectorMock
|
EnabledDetectorMock
|
||||||
searchFeatures SearchFeatures
|
searchFeatures SearchFeatures
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchFeatures returns the configured search features.
|
||||||
func (md *AdvancedIssueSearchDetectorMock) SearchFeatures() (SearchFeatures, error) {
|
func (md *AdvancedIssueSearchDetectorMock) SearchFeatures() (SearchFeatures, error) {
|
||||||
return md.searchFeatures, nil
|
return md.searchFeatures, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdvancedIssueSearchUnsupported returns a mock detector where advanced issue search is not supported.
|
||||||
func AdvancedIssueSearchUnsupported() *AdvancedIssueSearchDetectorMock {
|
func AdvancedIssueSearchUnsupported() *AdvancedIssueSearchDetectorMock {
|
||||||
return &AdvancedIssueSearchDetectorMock{
|
return &AdvancedIssueSearchDetectorMock{
|
||||||
searchFeatures: advancedIssueSearchNotSupported,
|
searchFeatures: advancedIssueSearchNotSupported,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdvancedIssueSearchSupportedAsOptIn returns a mock detector where advanced issue search is opt-in.
|
||||||
func AdvancedIssueSearchSupportedAsOptIn() *AdvancedIssueSearchDetectorMock {
|
func AdvancedIssueSearchSupportedAsOptIn() *AdvancedIssueSearchDetectorMock {
|
||||||
return &AdvancedIssueSearchDetectorMock{
|
return &AdvancedIssueSearchDetectorMock{
|
||||||
searchFeatures: advancedIssueSearchSupportedAsOptIn,
|
searchFeatures: advancedIssueSearchSupportedAsOptIn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AdvancedIssueSearchSupportedAsOnlyBackend returns a mock detector where advanced issue search is the only backend.
|
||||||
func AdvancedIssueSearchSupportedAsOnlyBackend() *AdvancedIssueSearchDetectorMock {
|
func AdvancedIssueSearchSupportedAsOnlyBackend() *AdvancedIssueSearchDetectorMock {
|
||||||
return &AdvancedIssueSearchDetectorMock{
|
return &AdvancedIssueSearchDetectorMock{
|
||||||
searchFeatures: advancedIssueSearchSupportedAsOnlyBackend,
|
searchFeatures: advancedIssueSearchSupportedAsOnlyBackend,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package featuredetection
|
package featuredetection
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -11,6 +11,7 @@ import (
|
||||||
ghauth "github.com/cli/go-gh/v2/pkg/auth"
|
ghauth "github.com/cli/go-gh/v2/pkg/auth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Detector queries a GitHub host to determine which API features are available.
|
||||||
type Detector interface {
|
type Detector interface {
|
||||||
IssueFeatures() (IssueFeatures, error)
|
IssueFeatures() (IssueFeatures, error)
|
||||||
PullRequestFeatures() (PullRequestFeatures, error)
|
PullRequestFeatures() (PullRequestFeatures, error)
|
||||||
|
|
@ -22,6 +23,7 @@ type Detector interface {
|
||||||
ActionsFeatures() (ActionsFeatures, error)
|
ActionsFeatures() (ActionsFeatures, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IssueFeatures describes the issue-related capabilities of a GitHub host.
|
||||||
type IssueFeatures struct {
|
type IssueFeatures struct {
|
||||||
StateReason bool
|
StateReason bool
|
||||||
StateReasonDuplicate bool
|
StateReasonDuplicate bool
|
||||||
|
|
@ -34,6 +36,7 @@ var allIssueFeatures = IssueFeatures{
|
||||||
ActorIsAssignable: true,
|
ActorIsAssignable: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PullRequestFeatures describes the pull-request-related capabilities of a GitHub host.
|
||||||
type PullRequestFeatures struct {
|
type PullRequestFeatures struct {
|
||||||
MergeQueue bool
|
MergeQueue bool
|
||||||
// CheckRunAndStatusContextCounts indicates whether the API supports
|
// CheckRunAndStatusContextCounts indicates whether the API supports
|
||||||
|
|
@ -49,6 +52,7 @@ var allPullRequestFeatures = PullRequestFeatures{
|
||||||
CheckRunEvent: true,
|
CheckRunEvent: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryFeatures describes the repository-related capabilities of a GitHub host.
|
||||||
type RepositoryFeatures struct {
|
type RepositoryFeatures struct {
|
||||||
PullRequestTemplateQuery bool
|
PullRequestTemplateQuery bool
|
||||||
VisibilityField bool
|
VisibilityField bool
|
||||||
|
|
@ -61,6 +65,7 @@ var allRepositoryFeatures = RepositoryFeatures{
|
||||||
AutoMerge: true,
|
AutoMerge: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectFeatures describes the project-related capabilities of a GitHub host.
|
||||||
type ProjectFeatures struct {
|
type ProjectFeatures struct {
|
||||||
// ProjectItemQuery indicates support for the `query` argument on
|
// ProjectItemQuery indicates support for the `query` argument on
|
||||||
// ProjectV2.items (supported on github.com and GHES 3.20+).
|
// ProjectV2.items (supported on github.com and GHES 3.20+).
|
||||||
|
|
@ -71,6 +76,7 @@ var allProjectFeatures = ProjectFeatures{
|
||||||
ProjectItemQuery: true,
|
ProjectItemQuery: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchFeatures describes the search-related capabilities of a GitHub host.
|
||||||
type SearchFeatures struct {
|
type SearchFeatures struct {
|
||||||
// AdvancedIssueSearch indicates whether the host supports advanced issue
|
// AdvancedIssueSearch indicates whether the host supports advanced issue
|
||||||
// search via API calls.
|
// search via API calls.
|
||||||
|
|
@ -108,10 +114,12 @@ var advancedIssueSearchSupportedAsOnlyBackend = SearchFeatures{
|
||||||
AdvancedIssueSearchAPIOptIn: false,
|
AdvancedIssueSearchAPIOptIn: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReleaseFeatures describes the release-related capabilities of a GitHub host.
|
||||||
type ReleaseFeatures struct {
|
type ReleaseFeatures struct {
|
||||||
ImmutableReleases bool
|
ImmutableReleases bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ActionsFeatures describes the GitHub Actions capabilities of a GitHub host.
|
||||||
type ActionsFeatures struct {
|
type ActionsFeatures struct {
|
||||||
// DispatchRunDetails indicates whether the API supports the `return_run_details`
|
// DispatchRunDetails indicates whether the API supports the `return_run_details`
|
||||||
// field in workflow dispatches that, when set to true, will return the details
|
// field in workflow dispatches that, when set to true, will return the details
|
||||||
|
|
@ -127,6 +135,7 @@ type detector struct {
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewDetector creates a Detector that queries the given host using the provided HTTP client.
|
||||||
func NewDetector(httpClient *http.Client, host string) Detector {
|
func NewDetector(httpClient *http.Client, host string) Detector {
|
||||||
return &detector{
|
return &detector{
|
||||||
httpClient: httpClient,
|
httpClient: httpClient,
|
||||||
|
|
@ -134,6 +143,7 @@ func NewDetector(httpClient *http.Client, host string) Detector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IssueFeatures detects issue-related capabilities of the configured host.
|
||||||
func (d *detector) IssueFeatures() (IssueFeatures, error) {
|
func (d *detector) IssueFeatures() (IssueFeatures, error) {
|
||||||
if !ghauth.IsEnterprise(d.host) {
|
if !ghauth.IsEnterprise(d.host) {
|
||||||
return allIssueFeatures, nil
|
return allIssueFeatures, nil
|
||||||
|
|
@ -182,6 +192,7 @@ func (d *detector) IssueFeatures() (IssueFeatures, error) {
|
||||||
return features, nil
|
return features, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PullRequestFeatures detects pull-request-related capabilities of the configured host.
|
||||||
func (d *detector) PullRequestFeatures() (PullRequestFeatures, error) {
|
func (d *detector) PullRequestFeatures() (PullRequestFeatures, error) {
|
||||||
// TODO: reinstate the short-circuit once the APIs are fully available on github.com
|
// TODO: reinstate the short-circuit once the APIs are fully available on github.com
|
||||||
// https://github.com/cli/cli/issues/5778
|
// https://github.com/cli/cli/issues/5778
|
||||||
|
|
@ -251,6 +262,7 @@ func (d *detector) PullRequestFeatures() (PullRequestFeatures, error) {
|
||||||
return features, nil
|
return features, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RepositoryFeatures detects repository-related capabilities of the configured host.
|
||||||
func (d *detector) RepositoryFeatures() (RepositoryFeatures, error) {
|
func (d *detector) RepositoryFeatures() (RepositoryFeatures, error) {
|
||||||
if !ghauth.IsEnterprise(d.host) {
|
if !ghauth.IsEnterprise(d.host) {
|
||||||
return allRepositoryFeatures, nil
|
return allRepositoryFeatures, nil
|
||||||
|
|
@ -292,6 +304,7 @@ const (
|
||||||
enterpriseProjectsV1Removed = "3.17.0"
|
enterpriseProjectsV1Removed = "3.17.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ProjectsV1 determines whether the configured host supports classic projects (v1).
|
||||||
func (d *detector) ProjectsV1() gh.ProjectsV1Support {
|
func (d *detector) ProjectsV1() gh.ProjectsV1Support {
|
||||||
if !ghauth.IsEnterprise(d.host) {
|
if !ghauth.IsEnterprise(d.host) {
|
||||||
return gh.ProjectsV1Unsupported
|
return gh.ProjectsV1Unsupported
|
||||||
|
|
@ -307,6 +320,7 @@ func (d *detector) ProjectsV1() gh.ProjectsV1Support {
|
||||||
return gh.ProjectsV1Unsupported
|
return gh.ProjectsV1Unsupported
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProjectFeatures detects project-related capabilities of the configured host.
|
||||||
func (d *detector) ProjectFeatures() (ProjectFeatures, error) {
|
func (d *detector) ProjectFeatures() (ProjectFeatures, error) {
|
||||||
if !ghauth.IsEnterprise(d.host) {
|
if !ghauth.IsEnterprise(d.host) {
|
||||||
return allProjectFeatures, nil
|
return allProjectFeatures, nil
|
||||||
|
|
@ -356,6 +370,7 @@ const (
|
||||||
enterpriseAdvancedIssueSearchSupport = "3.18.0"
|
enterpriseAdvancedIssueSearchSupport = "3.18.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SearchFeatures detects search-related capabilities of the configured host.
|
||||||
func (d *detector) SearchFeatures() (SearchFeatures, error) {
|
func (d *detector) SearchFeatures() (SearchFeatures, error) {
|
||||||
// TODO advancedIssueSearchCleanup
|
// TODO advancedIssueSearchCleanup
|
||||||
// Once GHES 3.17 support ends, we don't need this and, probably, the entire search feature detection.
|
// Once GHES 3.17 support ends, we don't need this and, probably, the entire search feature detection.
|
||||||
|
|
@ -441,6 +456,7 @@ func (d *detector) SearchFeatures() (SearchFeatures, error) {
|
||||||
return feature, nil
|
return feature, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReleaseFeatures detects release-related capabilities of the configured host.
|
||||||
func (d *detector) ReleaseFeatures() (ReleaseFeatures, error) {
|
func (d *detector) ReleaseFeatures() (ReleaseFeatures, error) {
|
||||||
// TODO: immutableReleaseFullSupport
|
// TODO: immutableReleaseFullSupport
|
||||||
// Once all supported GHES versions fully support immutable releases, we can
|
// Once all supported GHES versions fully support immutable releases, we can
|
||||||
|
|
@ -475,6 +491,7 @@ const (
|
||||||
enterpriseWorkflowDispatchRunDetailsSupport = "3.21.0"
|
enterpriseWorkflowDispatchRunDetailsSupport = "3.21.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ActionsFeatures detects GitHub Actions capabilities of the configured host.
|
||||||
func (d *detector) ActionsFeatures() (ActionsFeatures, error) {
|
func (d *detector) ActionsFeatures() (ActionsFeatures, error) {
|
||||||
// TODO workflowDispatchRunDetailsCleanup
|
// TODO workflowDispatchRunDetailsCleanup
|
||||||
// Once GHES 3.20 support ends, we don't need feature detection for workflow dispatch (i.e. run details support).
|
// Once GHES 3.20 support ends, we don't need feature detection for workflow dispatch (i.e. run details support).
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate moq -rm -out prompter_mock.go . Prompter
|
//go:generate moq -rm -out prompter_mock.go . Prompter
|
||||||
|
|
||||||
|
// Prompter defines an interface for interactive user prompts.
|
||||||
type Prompter interface {
|
type Prompter interface {
|
||||||
// generic prompts from go-gh
|
// generic prompts from go-gh
|
||||||
|
|
||||||
|
|
@ -52,6 +54,7 @@ type Prompter interface {
|
||||||
MarkdownEditor(prompt string, defaultValue string, blankAllowed bool) (string, error)
|
MarkdownEditor(prompt string, defaultValue string, blankAllowed bool) (string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New creates a Prompter backed by the given editor command and IO streams.
|
||||||
func New(editorCmd string, io *iostreams.IOStreams) Prompter {
|
func New(editorCmd string, io *iostreams.IOStreams) Prompter {
|
||||||
if io.AccessiblePrompterEnabled() {
|
if io.AccessiblePrompterEnabled() {
|
||||||
return &accessiblePrompter{
|
return &accessiblePrompter{
|
||||||
|
|
@ -104,6 +107,7 @@ func (p *accessiblePrompter) addDefaultsToPrompt(prompt string, defaultValues []
|
||||||
return prompt
|
return prompt
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select prompts the user to select an option from a list using accessible forms.
|
||||||
func (p *accessiblePrompter) Select(prompt, defaultValue string, options []string) (int, error) {
|
func (p *accessiblePrompter) Select(prompt, defaultValue string, options []string) (int, error) {
|
||||||
var result int
|
var result int
|
||||||
|
|
||||||
|
|
@ -136,6 +140,7 @@ func (p *accessiblePrompter) Select(prompt, defaultValue string, options []strin
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiSelect prompts the user to select multiple options using accessible forms.
|
||||||
func (p *accessiblePrompter) MultiSelect(prompt string, defaults []string, options []string) ([]int, error) {
|
func (p *accessiblePrompter) MultiSelect(prompt string, defaults []string, options []string) ([]int, error) {
|
||||||
var result []int
|
var result []int
|
||||||
|
|
||||||
|
|
@ -174,6 +179,7 @@ func (p *accessiblePrompter) MultiSelect(prompt string, defaults []string, optio
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Input prompts the user to enter a string value using accessible forms.
|
||||||
func (p *accessiblePrompter) Input(prompt, defaultValue string) (string, error) {
|
func (p *accessiblePrompter) Input(prompt, defaultValue string) (string, error) {
|
||||||
result := defaultValue
|
result := defaultValue
|
||||||
prompt = p.addDefaultsToPrompt(prompt, []string{defaultValue})
|
prompt = p.addDefaultsToPrompt(prompt, []string{defaultValue})
|
||||||
|
|
@ -189,6 +195,7 @@ func (p *accessiblePrompter) Input(prompt, defaultValue string) (string, error)
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Password prompts the user to enter a password using accessible forms.
|
||||||
func (p *accessiblePrompter) Password(prompt string) (string, error) {
|
func (p *accessiblePrompter) Password(prompt string) (string, error) {
|
||||||
var result string
|
var result string
|
||||||
// EchoModePassword is not used as password masking is unsupported in huh.
|
// EchoModePassword is not used as password masking is unsupported in huh.
|
||||||
|
|
@ -210,6 +217,7 @@ func (p *accessiblePrompter) Password(prompt string) (string, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Confirm prompts the user to confirm an action using accessible forms.
|
||||||
func (p *accessiblePrompter) Confirm(prompt string, defaultValue bool) (bool, error) {
|
func (p *accessiblePrompter) Confirm(prompt string, defaultValue bool) (bool, error) {
|
||||||
result := defaultValue
|
result := defaultValue
|
||||||
|
|
||||||
|
|
@ -233,6 +241,7 @@ func (p *accessiblePrompter) Confirm(prompt string, defaultValue bool) (bool, er
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthToken prompts the user to paste an authentication token using accessible forms.
|
||||||
func (p *accessiblePrompter) AuthToken() (string, error) {
|
func (p *accessiblePrompter) AuthToken() (string, error) {
|
||||||
var result string
|
var result string
|
||||||
// EchoModeNone and EchoModePassword both result in disabling echo mode
|
// EchoModeNone and EchoModePassword both result in disabling echo mode
|
||||||
|
|
@ -257,6 +266,7 @@ func (p *accessiblePrompter) AuthToken() (string, error) {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfirmDeletion prompts the user to type a value to confirm deletion using accessible forms.
|
||||||
func (p *accessiblePrompter) ConfirmDeletion(requiredValue string) error {
|
func (p *accessiblePrompter) ConfirmDeletion(requiredValue string) error {
|
||||||
form := p.newForm(
|
form := p.newForm(
|
||||||
huh.NewGroup(
|
huh.NewGroup(
|
||||||
|
|
@ -274,6 +284,7 @@ func (p *accessiblePrompter) ConfirmDeletion(requiredValue string) error {
|
||||||
return form.Run()
|
return form.Run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InputHostname prompts the user to enter a hostname using accessible forms.
|
||||||
func (p *accessiblePrompter) InputHostname() (string, error) {
|
func (p *accessiblePrompter) InputHostname() (string, error) {
|
||||||
var result string
|
var result string
|
||||||
form := p.newForm(
|
form := p.newForm(
|
||||||
|
|
@ -292,6 +303,7 @@ func (p *accessiblePrompter) InputHostname() (string, error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkdownEditor prompts the user to edit markdown in an external editor using accessible forms.
|
||||||
func (p *accessiblePrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
func (p *accessiblePrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
||||||
var result string
|
var result string
|
||||||
skipOption := "skip"
|
skipOption := "skip"
|
||||||
|
|
@ -329,6 +341,7 @@ func (p *accessiblePrompter) MarkdownEditor(prompt, defaultValue string, blankAl
|
||||||
return text, nil
|
return text, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiSelectWithSearch prompts the user to select multiple options with search using accessible forms.
|
||||||
func (p *accessiblePrompter) MultiSelectWithSearch(prompt, searchPrompt string, defaultValues, persistentValues []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
func (p *accessiblePrompter) MultiSelectWithSearch(prompt, searchPrompt string, defaultValues, persistentValues []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
||||||
return multiSelectWithSearch(p, prompt, searchPrompt, defaultValues, persistentValues, searchFunc)
|
return multiSelectWithSearch(p, prompt, searchPrompt, defaultValues, persistentValues, searchFunc)
|
||||||
}
|
}
|
||||||
|
|
@ -341,18 +354,22 @@ type surveyPrompter struct {
|
||||||
editorCmd string
|
editorCmd string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select prompts the user to select an option from a list using survey.
|
||||||
func (p *surveyPrompter) Select(prompt, defaultValue string, options []string) (int, error) {
|
func (p *surveyPrompter) Select(prompt, defaultValue string, options []string) (int, error) {
|
||||||
return p.prompter.Select(prompt, defaultValue, options)
|
return p.prompter.Select(prompt, defaultValue, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiSelect prompts the user to select multiple options using survey.
|
||||||
func (p *surveyPrompter) MultiSelect(prompt string, defaultValues, options []string) ([]int, error) {
|
func (p *surveyPrompter) MultiSelect(prompt string, defaultValues, options []string) ([]int, error) {
|
||||||
return p.prompter.MultiSelect(prompt, defaultValues, options)
|
return p.prompter.MultiSelect(prompt, defaultValues, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiSelectWithSearch prompts the user to select multiple options with search using survey.
|
||||||
func (p *surveyPrompter) MultiSelectWithSearch(prompt string, searchPrompt string, defaultValues, persistentValues []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
func (p *surveyPrompter) MultiSelectWithSearch(prompt string, searchPrompt string, defaultValues, persistentValues []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
||||||
return multiSelectWithSearch(p, prompt, searchPrompt, defaultValues, persistentValues, searchFunc)
|
return multiSelectWithSearch(p, prompt, searchPrompt, defaultValues, persistentValues, searchFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiSelectSearchResult holds the results of a search within MultiSelectWithSearch.
|
||||||
type MultiSelectSearchResult struct {
|
type MultiSelectSearchResult struct {
|
||||||
Keys []string
|
Keys []string
|
||||||
Labels []string
|
Labels []string
|
||||||
|
|
@ -503,18 +520,22 @@ func multiSelectWithSearch(p Prompter, prompt, searchPrompt string, defaultValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Input prompts the user to enter a string value using survey.
|
||||||
func (p *surveyPrompter) Input(prompt, defaultValue string) (string, error) {
|
func (p *surveyPrompter) Input(prompt, defaultValue string) (string, error) {
|
||||||
return p.prompter.Input(prompt, defaultValue)
|
return p.prompter.Input(prompt, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Password prompts the user to enter a password using survey.
|
||||||
func (p *surveyPrompter) Password(prompt string) (string, error) {
|
func (p *surveyPrompter) Password(prompt string) (string, error) {
|
||||||
return p.prompter.Password(prompt)
|
return p.prompter.Password(prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Confirm prompts the user to confirm an action using survey.
|
||||||
func (p *surveyPrompter) Confirm(prompt string, defaultValue bool) (bool, error) {
|
func (p *surveyPrompter) Confirm(prompt string, defaultValue bool) (bool, error) {
|
||||||
return p.prompter.Confirm(prompt, defaultValue)
|
return p.prompter.Confirm(prompt, defaultValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthToken prompts the user to paste an authentication token using survey.
|
||||||
func (p *surveyPrompter) AuthToken() (string, error) {
|
func (p *surveyPrompter) AuthToken() (string, error) {
|
||||||
var result string
|
var result string
|
||||||
err := p.ask(&survey.Password{
|
err := p.ask(&survey.Password{
|
||||||
|
|
@ -523,6 +544,7 @@ func (p *surveyPrompter) AuthToken() (string, error) {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfirmDeletion prompts the user to type a value to confirm deletion using survey.
|
||||||
func (p *surveyPrompter) ConfirmDeletion(requiredValue string) error {
|
func (p *surveyPrompter) ConfirmDeletion(requiredValue string) error {
|
||||||
var result string
|
var result string
|
||||||
return p.ask(
|
return p.ask(
|
||||||
|
|
@ -539,6 +561,7 @@ func (p *surveyPrompter) ConfirmDeletion(requiredValue string) error {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InputHostname prompts the user to enter a hostname using survey.
|
||||||
func (p *surveyPrompter) InputHostname() (string, error) {
|
func (p *surveyPrompter) InputHostname() (string, error) {
|
||||||
var result string
|
var result string
|
||||||
err := p.ask(
|
err := p.ask(
|
||||||
|
|
@ -550,6 +573,7 @@ func (p *surveyPrompter) InputHostname() (string, error) {
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkdownEditor prompts the user to edit markdown in an external editor using survey.
|
||||||
func (p *surveyPrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
func (p *surveyPrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
||||||
var result string
|
var result string
|
||||||
err := p.ask(&surveyext.GhEditor{
|
err := p.ask(&surveyext.GhEditor{
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// NewMockPrompter creates a MockPrompter for use in tests.
|
||||||
func NewMockPrompter(t *testing.T) *MockPrompter {
|
func NewMockPrompter(t *testing.T) *MockPrompter {
|
||||||
m := &MockPrompter{
|
m := &MockPrompter{
|
||||||
t: t,
|
t: t,
|
||||||
|
|
@ -22,6 +23,7 @@ func NewMockPrompter(t *testing.T) *MockPrompter {
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MockPrompter is a test double for Prompter that uses registered stubs for responses.
|
||||||
type MockPrompter struct {
|
type MockPrompter struct {
|
||||||
t *testing.T
|
t *testing.T
|
||||||
ghPrompter.PrompterMock
|
ghPrompter.PrompterMock
|
||||||
|
|
@ -54,6 +56,7 @@ type multiSelectWithSearchStub struct {
|
||||||
fn func(string, string, []string, []string, func(string) MultiSelectSearchResult) ([]string, error)
|
fn func(string, string, []string, []string, func(string) MultiSelectSearchResult) ([]string, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AuthToken returns a stubbed authentication token response.
|
||||||
func (m *MockPrompter) AuthToken() (string, error) {
|
func (m *MockPrompter) AuthToken() (string, error) {
|
||||||
var s authTokenStub
|
var s authTokenStub
|
||||||
if len(m.authTokenStubs) == 0 {
|
if len(m.authTokenStubs) == 0 {
|
||||||
|
|
@ -64,6 +67,7 @@ func (m *MockPrompter) AuthToken() (string, error) {
|
||||||
return s.fn()
|
return s.fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ConfirmDeletion returns a stubbed confirm-deletion response.
|
||||||
func (m *MockPrompter) ConfirmDeletion(prompt string) error {
|
func (m *MockPrompter) ConfirmDeletion(prompt string) error {
|
||||||
var s confirmDeletionStub
|
var s confirmDeletionStub
|
||||||
if len(m.confirmDeletionStubs) == 0 {
|
if len(m.confirmDeletionStubs) == 0 {
|
||||||
|
|
@ -74,6 +78,7 @@ func (m *MockPrompter) ConfirmDeletion(prompt string) error {
|
||||||
return s.fn(prompt)
|
return s.fn(prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InputHostname returns a stubbed hostname input response.
|
||||||
func (m *MockPrompter) InputHostname() (string, error) {
|
func (m *MockPrompter) InputHostname() (string, error) {
|
||||||
var s inputHostnameStub
|
var s inputHostnameStub
|
||||||
if len(m.inputHostnameStubs) == 0 {
|
if len(m.inputHostnameStubs) == 0 {
|
||||||
|
|
@ -84,6 +89,7 @@ func (m *MockPrompter) InputHostname() (string, error) {
|
||||||
return s.fn()
|
return s.fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MarkdownEditor returns a stubbed markdown editor response.
|
||||||
func (m *MockPrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
func (m *MockPrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed bool) (string, error) {
|
||||||
var s markdownEditorStub
|
var s markdownEditorStub
|
||||||
if len(m.markdownEditorStubs) == 0 {
|
if len(m.markdownEditorStubs) == 0 {
|
||||||
|
|
@ -97,6 +103,7 @@ func (m *MockPrompter) MarkdownEditor(prompt, defaultValue string, blankAllowed
|
||||||
return s.fn(prompt, defaultValue, blankAllowed)
|
return s.fn(prompt, defaultValue, blankAllowed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MultiSelectWithSearch returns a stubbed multi-select with search response.
|
||||||
func (m *MockPrompter) MultiSelectWithSearch(prompt, searchPrompt string, defaults []string, persistentOptions []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
func (m *MockPrompter) MultiSelectWithSearch(prompt, searchPrompt string, defaults []string, persistentOptions []string, searchFunc func(string) MultiSelectSearchResult) ([]string, error) {
|
||||||
var s multiSelectWithSearchStub
|
var s multiSelectWithSearchStub
|
||||||
if len(m.multiSelectWithSearchStubs) == 0 {
|
if len(m.multiSelectWithSearchStubs) == 0 {
|
||||||
|
|
@ -107,22 +114,27 @@ func (m *MockPrompter) MultiSelectWithSearch(prompt, searchPrompt string, defaul
|
||||||
return s.fn(prompt, searchPrompt, defaults, persistentOptions, searchFunc)
|
return s.fn(prompt, searchPrompt, defaults, persistentOptions, searchFunc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterAuthToken registers a stub function for the AuthToken prompt.
|
||||||
func (m *MockPrompter) RegisterAuthToken(stub func() (string, error)) {
|
func (m *MockPrompter) RegisterAuthToken(stub func() (string, error)) {
|
||||||
m.authTokenStubs = append(m.authTokenStubs, authTokenStub{fn: stub})
|
m.authTokenStubs = append(m.authTokenStubs, authTokenStub{fn: stub})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterConfirmDeletion registers a stub function for the ConfirmDeletion prompt.
|
||||||
func (m *MockPrompter) RegisterConfirmDeletion(prompt string, stub func(string) error) {
|
func (m *MockPrompter) RegisterConfirmDeletion(prompt string, stub func(string) error) {
|
||||||
m.confirmDeletionStubs = append(m.confirmDeletionStubs, confirmDeletionStub{prompt: prompt, fn: stub})
|
m.confirmDeletionStubs = append(m.confirmDeletionStubs, confirmDeletionStub{prompt: prompt, fn: stub})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterInputHostname registers a stub function for the InputHostname prompt.
|
||||||
func (m *MockPrompter) RegisterInputHostname(stub func() (string, error)) {
|
func (m *MockPrompter) RegisterInputHostname(stub func() (string, error)) {
|
||||||
m.inputHostnameStubs = append(m.inputHostnameStubs, inputHostnameStub{fn: stub})
|
m.inputHostnameStubs = append(m.inputHostnameStubs, inputHostnameStub{fn: stub})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RegisterMarkdownEditor registers a stub function for the MarkdownEditor prompt.
|
||||||
func (m *MockPrompter) RegisterMarkdownEditor(prompt string, stub func(string, string, bool) (string, error)) {
|
func (m *MockPrompter) RegisterMarkdownEditor(prompt string, stub func(string, string, bool) (string, error)) {
|
||||||
m.markdownEditorStubs = append(m.markdownEditorStubs, markdownEditorStub{prompt: prompt, fn: stub})
|
m.markdownEditorStubs = append(m.markdownEditorStubs, markdownEditorStub{prompt: prompt, fn: stub})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verify asserts that all registered stubs have been consumed.
|
||||||
func (m *MockPrompter) Verify() {
|
func (m *MockPrompter) Verify() {
|
||||||
errs := []string{}
|
errs := []string{}
|
||||||
if len(m.authTokenStubs) > 0 {
|
if len(m.authTokenStubs) > 0 {
|
||||||
|
|
@ -143,10 +155,12 @@ func (m *MockPrompter) Verify() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AssertOptions asserts that the expected and actual option slices are equal.
|
||||||
func AssertOptions(t *testing.T, expected, actual []string) {
|
func AssertOptions(t *testing.T, expected, actual []string) {
|
||||||
assert.Equal(t, expected, actual)
|
assert.Equal(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexFor returns the index of the given answer in the options slice.
|
||||||
func IndexFor(options []string, answer string) (int, error) {
|
func IndexFor(options []string, answer string) (int, error) {
|
||||||
for ix, a := range options {
|
for ix, a := range options {
|
||||||
if a == answer {
|
if a == answer {
|
||||||
|
|
@ -156,6 +170,7 @@ func IndexFor(options []string, answer string) (int, error) {
|
||||||
return -1, NoSuchAnswerErr(answer, options)
|
return -1, NoSuchAnswerErr(answer, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IndexesFor returns the indices of the given answers in the options slice.
|
||||||
func IndexesFor(options []string, answers ...string) ([]int, error) {
|
func IndexesFor(options []string, answers ...string) ([]int, error) {
|
||||||
indexes := make([]int, len(answers))
|
indexes := make([]int, len(answers))
|
||||||
for i, answer := range answers {
|
for i, answer := range answers {
|
||||||
|
|
@ -168,10 +183,12 @@ func IndexesFor(options []string, answers ...string) ([]int, error) {
|
||||||
return indexes, nil
|
return indexes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoSuchPromptErr returns an error indicating that no stub was registered for the given prompt.
|
||||||
func NoSuchPromptErr(prompt string) error {
|
func NoSuchPromptErr(prompt string) error {
|
||||||
return fmt.Errorf("no such prompt '%s'", prompt)
|
return fmt.Errorf("no such prompt '%s'", prompt)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NoSuchAnswerErr returns an error indicating that the answer was not found in the options.
|
||||||
func NoSuchAnswerErr(answer string, options []string) error {
|
func NoSuchAnswerErr(answer string, options []string) error {
|
||||||
return fmt.Errorf("no such answer '%s' in [%s]", answer, strings.Join(options, ", "))
|
return fmt.Errorf("no such answer '%s' in [%s]", answer, strings.Join(options, ", "))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue