Skip to content

Commit 80e63ee

Browse files
Remove interactive prompts and clean up command output
- Strip interactive scope menu, TTY waiting, and alternative scope prompting from issues command - Remove --default-branch flag from report-card command - Simplify WaitOrFallback to always fall back to last completed run - Add in-progress run handling and local changes warnings to metrics and vulns commands - Add output indentation for tables and Pluralize helper for footer counts - Move golang.org/x/term to indirect dependency - Remove unused interactive deps from cmddeps (SelectFromOptionsFunc, GetSingleLineInputFunc, IsInteractiveFunc) - Delete orphaned golden files and related tests
1 parent f47a980 commit 80e63ee

15 files changed

Lines changed: 225 additions & 625 deletions

File tree

command/cmddeps/deps.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,4 @@ type Deps struct {
2222
RemoteFunc func() (*vcs.RemoteData, error)
2323
HasUnpushedCommitsFunc func() bool
2424
HasUncommittedChangesFunc func() bool
25-
SelectFromOptionsFunc func(msg, help string, opts []string) (string, error)
26-
GetSingleLineInputFunc func(msg, help string) (string, error)
27-
IsInteractiveFunc func() bool
2825
}

command/cmdutil/resolve_run.go

Lines changed: 9 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@ import (
55
"context"
66
"fmt"
77
"io"
8-
"os"
98
"os/exec"
109
"strings"
1110
"time"
1211

13-
"golang.org/x/term"
14-
1512
"github.com/deepsourcelabs/cli/deepsource"
1613
"github.com/deepsourcelabs/cli/deepsource/runs"
17-
"github.com/deepsourcelabs/cli/internal/cli/prompt"
18-
"github.com/deepsourcelabs/cli/internal/cli/style"
1914
"github.com/deepsourcelabs/cli/internal/debug"
2015
"github.com/deepsourcelabs/cli/internal/vcs"
2116
)
@@ -88,67 +83,23 @@ func IsRunTimedOut(status string) bool {
8883
return status == "TIMEOUT"
8984
}
9085

91-
// WaitOrFallback handles in-progress analysis runs by either waiting for
92-
// completion (interactive TTY) or falling back to the last completed run
93-
// (non-interactive). Returns the final run status, or "FALLBACK" if the
86+
// WaitOrFallback handles in-progress analysis runs by falling back to the
87+
// last completed run. Returns the final run status, or "FALLBACK" if the
9488
// caller should fetch the last completed run instead.
9589
func WaitOrFallback(
96-
ctx context.Context,
97-
w io.Writer,
90+
_ context.Context,
91+
_ io.Writer,
9892
initialStatus string,
99-
commitShort string,
100-
branchName string,
101-
pollInterval time.Duration,
102-
check func(ctx context.Context) (status string, err error),
93+
_ string,
94+
_ string,
95+
_ time.Duration,
96+
_ func(ctx context.Context) (status string, err error),
10397
) (string, error) {
10498
if !IsRunInProgress(initialStatus) {
10599
return initialStatus, nil
106100
}
107101

108-
if !term.IsTerminal(int(os.Stdout.Fd())) {
109-
return "FALLBACK", nil
110-
}
111-
112-
fmt.Fprintf(w, "\nAnalysis is still running on branch %q (latest commit %s).\n\n", branchName, commitShort)
113-
114-
choice, err := prompt.SelectFromOptions(
115-
"What would you like to do?",
116-
"",
117-
[]string{
118-
"Wait for the current analysis to finish",
119-
"Show results from the last completed analysis",
120-
},
121-
)
122-
if err != nil {
123-
return "", err
124-
}
125-
126-
if choice == "Show results from the last completed analysis" {
127-
return "FALLBACK", nil
128-
}
129-
130-
pollCtx, cancel := context.WithTimeout(ctx, 10*time.Minute)
131-
defer cancel()
132-
133-
style.Infof(w, "Waiting for analysis to complete...")
134-
135-
ticker := time.NewTicker(pollInterval)
136-
defer ticker.Stop()
137-
138-
for {
139-
select {
140-
case <-pollCtx.Done():
141-
return "", pollCtx.Err()
142-
case <-ticker.C:
143-
status, checkErr := check(pollCtx)
144-
if checkErr != nil {
145-
return "", checkErr
146-
}
147-
if !IsRunInProgress(status) {
148-
return status, nil
149-
}
150-
}
151-
}
102+
return "FALLBACK", nil
152103
}
153104

154105
// ResolveLatestCompletedRun finds the most recent completed analysis run on

command/issues/issues.go

Lines changed: 2 additions & 189 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import (
77
"io"
88
"os"
99
"slices"
10-
"strconv"
1110
"strings"
1211
"time"
1312

@@ -19,14 +18,12 @@ import (
1918
"github.com/deepsourcelabs/cli/deepsource/issues"
2019
issuesQuery "github.com/deepsourcelabs/cli/deepsource/issues/queries"
2120
"github.com/deepsourcelabs/cli/internal/cli/completion"
22-
"github.com/deepsourcelabs/cli/internal/cli/prompt"
2321
"github.com/deepsourcelabs/cli/internal/cli/style"
2422
clierrors "github.com/deepsourcelabs/cli/internal/errors"
2523
"github.com/deepsourcelabs/cli/internal/vcs"
2624
"github.com/pterm/pterm"
2725
"github.com/spf13/cobra"
2826
"github.com/spf13/pflag"
29-
"golang.org/x/term"
3027
)
3128

3229
type IssuesOptions struct {
@@ -46,7 +43,6 @@ type IssuesOptions struct {
4643
autoDetectedBranch string
4744
issues []issues.Issue
4845
deps *cmddeps.Deps
49-
explicitScope bool
5046
client *deepsource.Client
5147
remote *vcs.RemoteData
5248
}
@@ -254,8 +250,6 @@ func (opts *IssuesOptions) Run(ctx context.Context) error {
254250
}
255251
}
256252

257-
opts.explicitScope = opts.CommitOid != "" || opts.PRNumber > 0 || opts.DefaultBranch
258-
259253
if opts.CommitOid != "" {
260254
opts.CommitOid = cmdutil.ResolveCommitOid(opts.CommitOid)
261255
}
@@ -598,41 +592,13 @@ func groupIssuesByCategory(issuesList []issues.Issue) map[string][]issues.Issue
598592
return grouped
599593
}
600594

601-
func (opts *IssuesOptions) outputHuman(ctx context.Context) error {
595+
func (opts *IssuesOptions) outputHuman(_ context.Context) error {
602596
if len(opts.issues) == 0 {
603-
// Safety net: check for in-progress run before scope menu.
604-
// This catches cases where resolveIssues bypassed WaitOrFallback
605-
// (e.g. PR path ignoring FALLBACK status).
606-
if opts.autoDetectedBranch != "" && !opts.explicitScope {
607-
handled, err := opts.checkInProgressAndRetry(ctx)
608-
if err != nil {
609-
return err
610-
}
611-
if handled {
612-
return nil
613-
}
614-
}
615-
616597
if opts.hasFilters() {
617598
style.Infof(opts.stdout(), "No issues matched the provided filters in %s on %s.", opts.repoSlug, opts.scopeLabel())
618599
} else {
619600
style.Infof(opts.stdout(), "No issues found in %s on %s.", opts.repoSlug, opts.scopeLabel())
620601
}
621-
622-
if opts.shouldPromptAlternativeScope() {
623-
newIssues, err := opts.promptAlternativeScope(ctx)
624-
if err != nil {
625-
return err
626-
}
627-
if newIssues != nil {
628-
opts.issues = newIssues
629-
if len(opts.issues) == 0 {
630-
style.Infof(opts.stdout(), "No issues found in %s on %s.", opts.repoSlug, opts.scopeLabel())
631-
return nil
632-
}
633-
return opts.renderHumanIssues()
634-
}
635-
}
636602
return nil
637603
}
638604

@@ -695,164 +661,11 @@ func (opts *IssuesOptions) renderHumanIssues() error {
695661
}
696662
}
697663

698-
fmt.Fprintf(w, "\nShowing %d issue(s) in %s from %s\n", len(opts.issues), opts.repoSlug, scopeLabel)
664+
fmt.Fprintf(w, "\nShowing %d %s in %s from %s\n", len(opts.issues), style.Pluralize(len(opts.issues), "issue", "issues"), opts.repoSlug, scopeLabel)
699665

700666
return nil
701667
}
702668

703-
// --- Safety-net: in-progress check before scope menu ---
704-
705-
// checkInProgressAndRetry makes an extra API call to see if the latest run is
706-
// in-progress when we got 0 issues on an auto-detected branch. This catches
707-
// cases where resolveIssues bypassed or ignored the WaitOrFallback result
708-
// (e.g. the PR path). Returns (true, nil) if it handled the situation and
709-
// the scope menu should be skipped.
710-
func (opts *IssuesOptions) checkInProgressAndRetry(ctx context.Context) (bool, error) {
711-
run, err := cmdutil.ResolveLatestRunForBranch(ctx, opts.client, opts.autoDetectedBranch, opts.remote)
712-
if err != nil || !cmdutil.IsRunInProgress(run.Status) {
713-
return false, nil
714-
}
715-
716-
commitShort := run.CommitOid
717-
if len(commitShort) > 8 {
718-
commitShort = commitShort[:8]
719-
}
720-
721-
return opts.refetchAfterFallback(ctx, commitShort)
722-
}
723-
724-
// refetchAfterFallback finds the last completed run on the branch and
725-
// re-fetches issues from it. If no completed run exists, prints a message
726-
// and returns (true, nil) so the scope menu is skipped.
727-
func (opts *IssuesOptions) refetchAfterFallback(ctx context.Context, inProgressCommitShort string) (bool, error) {
728-
run, err := cmdutil.ResolveLatestCompletedRun(ctx, opts.client, opts.autoDetectedBranch, opts.remote)
729-
if err != nil {
730-
return false, err
731-
}
732-
if run == nil {
733-
style.Infof(opts.stdout(), "Analysis is in progress on branch %q (commit %s). Try again in a few minutes.", opts.autoDetectedBranch, inProgressCommitShort)
734-
return true, nil
735-
}
736-
737-
completedShort := run.CommitOid
738-
if len(completedShort) > 8 {
739-
completedShort = completedShort[:8]
740-
}
741-
style.Infof(opts.stdout(), "Analysis is running on commit %s. Showing results from the last analyzed commit (%s).", inProgressCommitShort, completedShort)
742-
opts.CommitOid = run.CommitOid
743-
return opts.refetchIssuesAndRender(ctx)
744-
}
745-
746-
// refetchIssuesAndRender re-fetches issues based on the current scope
747-
// (PR or commit), filters them, and renders the result.
748-
func (opts *IssuesOptions) refetchIssuesAndRender(ctx context.Context) (bool, error) {
749-
serverFilters := opts.buildServerFilters()
750-
751-
var issuesList []issues.Issue
752-
var err error
753-
if opts.PRNumber > 0 {
754-
issuesList, err = opts.client.GetPRIssues(ctx, opts.remote.Owner, opts.remote.RepoName, opts.remote.VCSProvider, opts.PRNumber, opts.LimitArg)
755-
} else if opts.CommitOid != "" {
756-
issuesList, err = opts.client.GetRunIssuesFlat(ctx, opts.CommitOid, opts.LimitArg, serverFilters)
757-
}
758-
if err != nil {
759-
return false, err
760-
}
761-
762-
issuesList = opts.filterIssues(issuesList)
763-
opts.issues = issuesList
764-
765-
if len(opts.issues) == 0 {
766-
style.Infof(opts.stdout(), "No issues found in %s on %s.", opts.repoSlug, opts.scopeLabel())
767-
return true, nil
768-
}
769-
return true, opts.renderHumanIssues()
770-
}
771-
772-
// --- Interactive scope menu ---
773-
774-
func (opts *IssuesOptions) selectFromOptions(msg, help string, options []string) (string, error) {
775-
if opts.deps != nil && opts.deps.SelectFromOptionsFunc != nil {
776-
return opts.deps.SelectFromOptionsFunc(msg, help, options)
777-
}
778-
return prompt.SelectFromOptions(msg, help, options)
779-
}
780-
781-
func (opts *IssuesOptions) getSingleLineInput(msg, help string) (string, error) {
782-
if opts.deps != nil && opts.deps.GetSingleLineInputFunc != nil {
783-
return opts.deps.GetSingleLineInputFunc(msg, help)
784-
}
785-
return prompt.GetSingleLineInput(msg, help)
786-
}
787-
788-
func (opts *IssuesOptions) isInteractive() bool {
789-
if opts.deps != nil && opts.deps.IsInteractiveFunc != nil {
790-
return opts.deps.IsInteractiveFunc()
791-
}
792-
return term.IsTerminal(int(os.Stdout.Fd()))
793-
}
794-
795-
func (opts *IssuesOptions) shouldPromptAlternativeScope() bool {
796-
return !opts.explicitScope &&
797-
!opts.hasFilters() &&
798-
opts.OutputFormat == "pretty" &&
799-
opts.isInteractive()
800-
}
801-
802-
const (
803-
scopeOptionDefaultBranch = "View issues on default branch"
804-
scopeOptionPR = "View issues for a pull request"
805-
scopeOptionCommit = "View issues for a specific commit"
806-
scopeOptionExit = "Exit"
807-
)
808-
809-
func (opts *IssuesOptions) promptAlternativeScope(ctx context.Context) ([]issues.Issue, error) {
810-
fmt.Fprintln(opts.stdout())
811-
choice, err := opts.selectFromOptions(
812-
"Try a different scope?",
813-
"",
814-
[]string{scopeOptionDefaultBranch, scopeOptionPR, scopeOptionCommit, scopeOptionExit},
815-
)
816-
if err != nil {
817-
return nil, err
818-
}
819-
820-
// Reset scope fields
821-
opts.CommitOid = ""
822-
opts.PRNumber = 0
823-
opts.DefaultBranch = false
824-
opts.autoDetectedBranch = ""
825-
826-
switch choice {
827-
case scopeOptionDefaultBranch:
828-
opts.DefaultBranch = true
829-
case scopeOptionPR:
830-
prStr, inputErr := opts.getSingleLineInput("Pull request number:", "")
831-
if inputErr != nil {
832-
return nil, inputErr
833-
}
834-
prNum, parseErr := strconv.Atoi(strings.TrimSpace(prStr))
835-
if parseErr != nil {
836-
return nil, fmt.Errorf("invalid PR number: %s", prStr)
837-
}
838-
opts.PRNumber = prNum
839-
case scopeOptionCommit:
840-
sha, inputErr := opts.getSingleLineInput("Commit SHA:", "")
841-
if inputErr != nil {
842-
return nil, inputErr
843-
}
844-
opts.CommitOid = cmdutil.ResolveCommitOid(strings.TrimSpace(sha))
845-
case scopeOptionExit:
846-
return nil, nil
847-
}
848-
849-
issuesList, err := opts.resolveIssues(ctx, opts.client, opts.remote)
850-
if err != nil {
851-
return nil, err
852-
}
853-
return opts.filterIssues(issuesList), nil
854-
}
855-
856669
// --- JSON output ---
857670

858671
type IssueJSON struct {

command/issues/tests/golden_files/commit_scope_empty_response.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

command/issues/tests/golden_files/get_analysis_runs_empty_issues_response.json

Lines changed: 0 additions & 29 deletions
This file was deleted.

command/issues/tests/golden_files/pr_scope_empty_response.json

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)