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
3229type 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 , "\n Showing %d issue(s) in %s from %s\n " , len (opts .issues ), opts .repoSlug , scopeLabel )
664+ fmt .Fprintf (w , "\n Showing %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
858671type IssueJSON struct {
0 commit comments