Repository: cli/cli
Pull request #7850 (2023-08-17 02:52:52)

update more prompts
This PR:

- use new prompter in repo fork
- fix RegisterPassword
- use prompter in secret set
- use prompter in issue delete

The only prompts that remain to be fixed are in the shared pr package.

Part of #6255



Patch:
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 10f17a2fc..eed468389 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -23,7 +23,7 @@ Please avoid:
 ## Building the project
 
 Prerequisites:
-- Go 1.21+
+- Go 1.19+
 
 Build with:
 * Unix-like systems: `make`
diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml
index b15b23806..3974737aa 100644
--- a/.github/workflows/deployment.yml
+++ b/.github/workflows/deployment.yml
@@ -1,6 +1,6 @@
 name: Deployment
 
-concurrency:
+concurrency: 
   group: ${{ github.workflow }}-${{ github.ref_name }}
   cancel-in-progress: true
 
@@ -17,7 +17,7 @@ on:
         default: production
         type: environment
       go_version:
-        default: "1.21"
+        default: "1.19"
         type: string
       platforms:
         default: "linux,macos,windows"
@@ -61,7 +61,7 @@ jobs:
             dist/*.tar.gz
             dist/*.rpm
             dist/*.deb
-
+  
   macos:
     runs-on: macos-latest
     environment: ${{ inputs.environment }}
@@ -118,7 +118,7 @@ jobs:
           path: |
             dist/*.tar.gz
             dist/*.zip
-
+  
   windows:
     runs-on: windows-latest
     environment: ${{ inputs.environment }}
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index a375e2d8f..1a3a33318 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -13,10 +13,10 @@ jobs:
     runs-on: ${{ matrix.os }}
 
     steps:
-      - name: Set up Go 1.21
+      - name: Set up Go 1.19
         uses: actions/setup-go@v4
         with:
-          go-version: 1.21
+          go-version: 1.19
 
       - name: Check out code
         uses: actions/checkout@v3
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index c8defbf3a..dd1fede0d 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -19,10 +19,10 @@ jobs:
     runs-on: ubuntu-latest
 
     steps:
-      - name: Set up Go 1.21
+      - name: Set up Go 1.19
         uses: actions/setup-go@v4
         with:
-          go-version: 1.21
+          go-version: 1.19
 
       - name: Check out code
         uses: actions/checkout@v3
@@ -40,7 +40,7 @@ jobs:
           go mod verify
           go mod download
 
-          LINT_VERSION=1.54.1
+          LINT_VERSION=1.50.1
           curl -fsSL https://github.com/golangci/golangci-lint/releases/download/v${LINT_VERSION}/golangci-lint-${LINT_VERSION}-linux-amd64.tar.gz | \
             tar xz --strip-components 1 --wildcards \*/golangci-lint
           mkdir -p bin && mv golangci-lint bin/
diff --git a/docs/source.md b/docs/source.md
index cc1605b8c..9034e9de5 100644
--- a/docs/source.md
+++ b/docs/source.md
@@ -1,6 +1,6 @@
 # Installation from source
 
-1. Verify that you have Go 1.21+ installed
+1. Verify that you have Go 1.19+ installed
 
    ```sh
    $ go version
diff --git a/go.mod b/go.mod
index 48632a1e3..2602fc496 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/cli/cli/v2
 
-go 1.21
+go 1.19
 
 require (
 	github.com/AlecAivazis/survey/v2 v2.3.7
diff --git a/go.sum b/go.sum
index 14af85480..47e5159ae 100644
--- a/go.sum
+++ b/go.sum
@@ -91,7 +91,6 @@ github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwA
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
 github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
-github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
@@ -183,7 +182,6 @@ golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfS
 golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
 golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M=
-golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -223,13 +221,11 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
 golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
-google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
 google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f h1:BWUVssLB0HVOSY78gIdvk1dTVYtT1y8SBWtPYuTJ/6w=
 google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f/go.mod h1:RGgjbofJ8xD9Sq1VVhDM1Vok1vRONV+rg+CjzG4SZKM=
 google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
diff --git a/pkg/cmd/issue/delete/delete.go b/pkg/cmd/issue/delete/delete.go
index f0c68de42..cee367cb8 100644
--- a/pkg/cmd/issue/delete/delete.go
+++ b/pkg/cmd/issue/delete/delete.go
@@ -3,16 +3,13 @@ package delete
 import (
 	"fmt"
 	"net/http"
-	"strconv"
 
-	"github.com/AlecAivazis/survey/v2"
 	"github.com/cli/cli/v2/api"
 	"github.com/cli/cli/v2/internal/config"
 	"github.com/cli/cli/v2/internal/ghrepo"
 	"github.com/cli/cli/v2/pkg/cmd/issue/shared"
 	"github.com/cli/cli/v2/pkg/cmdutil"
 	"github.com/cli/cli/v2/pkg/iostreams"
-	"github.com/cli/cli/v2/pkg/prompt"
 	"github.com/shurcooL/githubv4"
 	"github.com/spf13/cobra"
 )
@@ -22,16 +19,22 @@ type DeleteOptions struct {
 	Config     func() (config.Config, error)
 	IO         *iostreams.IOStreams
 	BaseRepo   func() (ghrepo.Interface, error)
+	Prompter   iprompter
 
 	SelectorArg string
 	Confirmed   bool
 }
 
+type iprompter interface {
+	ConfirmDeletion(string) error
+}
+
 func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Command {
 	opts := &DeleteOptions{
 		IO:         f.IOStreams,
 		HttpClient: f.HttpClient,
 		Config:     f.Config,
+		Prompter:   f.Prompter,
 	}
 
 	cmd := &cobra.Command{
@@ -79,22 +82,12 @@ func deleteRun(opts *DeleteOptions) error {
 	// When executed in an interactive shell, require confirmation, unless
 	// already provided. Otherwise skip confirmation.
 	if opts.IO.CanPrompt() && !opts.Confirmed {
-		answer := ""
-		//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
-		err = prompt.SurveyAskOne(
-			&survey.Input{
-				Message: fmt.Sprintf("You're going to delete issue #%d. This action cannot be reversed. To confirm, type the issue number:", issue.Number),
-			},
-			&answer,
-		)
+		cs := opts.IO.ColorScheme()
+		fmt.Printf("%s Deleted issues cannot be recovered.\n", cs.WarningIcon())
+		err := opts.Prompter.ConfirmDeletion(fmt.Sprintf("%d", issue.Number))
 		if err != nil {
 			return err
 		}
-		answerInt, err := strconv.Atoi(answer)
-		if err != nil || answerInt != issue.Number {
-			fmt.Fprintf(opts.IO.Out, "Issue #%d was not deleted.\n", issue.Number)
-			return nil
-		}
 	}
 
 	if err := apiDelete(httpClient, baseRepo, issue.ID); err != nil {
diff --git a/pkg/cmd/label/create.go b/pkg/cmd/label/create.go
index 0a88fbcab..f9c63f6e6 100644
--- a/pkg/cmd/label/create.go
+++ b/pkg/cmd/label/create.go
@@ -102,8 +102,8 @@ func createRun(opts *createOptions) error {
 	}
 
 	if opts.Color == "" {
-		r := rand.New(rand.NewSource(time.Now().UnixNano()))
-		opts.Color = randomColors[r.Intn(len(randomColors)-1)]
+		rand.Seed(time.Now().UnixNano())
+		opts.Color = randomColors[rand.Intn(len(randomColors)-1)]
 	}
 
 	opts.IO.StartProgressIndicator()
diff --git a/pkg/cmd/repo/credits/credits.go b/pkg/cmd/repo/credits/credits.go
index 4b7b9fb28..37390bcb1 100644
--- a/pkg/cmd/repo/credits/credits.go
+++ b/pkg/cmd/repo/credits/credits.go
@@ -178,7 +178,7 @@ func creditsRun(opts *CreditsOptions) error {
 		return nil
 	}
 
-	r := rand.New(rand.NewSource(time.Now().UnixNano()))
+	rand.Seed(time.Now().UnixNano())
 
 	lines := []string{}
 
@@ -199,13 +199,13 @@ func creditsRun(opts *CreditsOptions) error {
 
 	starLinesLeft := []string{}
 	for x := 0; x < len(lines); x++ {
-		starLinesLeft = append(starLinesLeft, starLine(r, margin))
+		starLinesLeft = append(starLinesLeft, starLine(margin))
 	}
 
 	starLinesRight := []string{}
 	for x := 0; x < len(lines); x++ {
 		lineWidth := termWidth - (margin + len(lines[x]))
-		starLinesRight = append(starLinesRight, starLine(r, lineWidth))
+		starLinesRight = append(starLinesRight, starLine(lineWidth))
 	}
 
 	loop := true
@@ -245,13 +245,13 @@ func creditsRun(opts *CreditsOptions) error {
 	return nil
 }
 
-func starLine(r *rand.Rand, width int) string {
+func starLine(width int) string {
 	line := ""
 	starChance := 0.1
 	for y := 0; y < width; y++ {
-		chance := r.Float64()
+		chance := rand.Float64()
 		if chance <= starChance {
-			charRoll := r.Float64()
+			charRoll := rand.Float64()
 			switch {
 			case charRoll < 0.3:
 				line += "."
diff --git a/pkg/cmd/repo/fork/fork.go b/pkg/cmd/repo/fork/fork.go
index 087d7219e..0d2d1da69 100644
--- a/pkg/cmd/repo/fork/fork.go
+++ b/pkg/cmd/repo/fork/fork.go
@@ -19,13 +19,16 @@ import (
 	"github.com/cli/cli/v2/pkg/cmd/repo/shared"
 	"github.com/cli/cli/v2/pkg/cmdutil"
 	"github.com/cli/cli/v2/pkg/iostreams"
-	"github.com/cli/cli/v2/pkg/prompt"
 	"github.com/spf13/cobra"
 	"github.com/spf13/pflag"
 )
 
 const defaultRemoteName = "origin"
 
+type iprompter interface {
+	Confirm(string, bool) (bool, error)
+}
+
 type ForkOptions struct {
 	HttpClient func() (*http.Client, error)
 	GitClient  *git.Client
@@ -35,6 +38,7 @@ type ForkOptions struct {
 	Remotes    func() (ghContext.Remotes, error)
 	Since      func(time.Time) time.Duration
 	BackOff    backoff.BackOff
+	Prompter   iprompter
 
 	GitArgs           []string
 	Repository        string
@@ -65,6 +69,7 @@ func NewCmdFork(f *cmdutil.Factory, runF func(*ForkOptions) error) *cobra.Comman
 		Config:     f.Config,
 		BaseRepo:   f.BaseRepo,
 		Remotes:    f.Remotes,
+		Prompter:   f.Prompter,
 		Since:      time.Since,
 	}
 
@@ -273,10 +278,9 @@ func forkRun(opts *ForkOptions) error {
 
 		remoteDesired := opts.Remote
 		if opts.PromptRemote {
-			//nolint:staticcheck // SA1019: prompt.Confirm is deprecated: use Prompter
-			err = prompt.Confirm("Would you like to add a remote for the fork?", &remoteDesired)
+			remoteDesired, err = opts.Prompter.Confirm("Would you like to add a remote for the fork?", false)
 			if err != nil {
-				return fmt.Errorf("failed to prompt: %w", err)
+				return err
 			}
 		}
 
@@ -317,10 +321,9 @@ func forkRun(opts *ForkOptions) error {
 	} else {
 		cloneDesired := opts.Clone
 		if opts.PromptClone {
-			//nolint:staticcheck // SA1019: prompt.Confirm is deprecated: use Prompter
-			err = prompt.Confirm("Would you like to clone the fork?", &cloneDesired)
+			cloneDesired, err = opts.Prompter.Confirm("Would you like to clone the fork?", false)
 			if err != nil {
-				return fmt.Errorf("failed to prompt: %w", err)
+				return err
 			}
 		}
 		if cloneDesired {
diff --git a/pkg/cmd/repo/garden/garden.go b/pkg/cmd/repo/garden/garden.go
index 840d5adca..c9c59d420 100644
--- a/pkg/cmd/repo/garden/garden.go
+++ b/pkg/cmd/repo/garden/garden.go
@@ -169,7 +169,7 @@ func gardenRun(opts *GardenOptions) error {
 	}
 
 	seed := computeSeed(ghrepo.FullName(toView))
-	r := rand.New(rand.NewSource(seed))
+	rand.Seed(seed)
 
 	termWidth, termHeight, err := utils.TerminalSize(out)
 	if err != nil {
@@ -198,7 +198,7 @@ func gardenRun(opts *GardenOptions) error {
 	}
 	player := &Player{0, 0, cs.Bold("@"), geo, 0}
 
-	garden := plantGarden(r, commits, geo)
+	garden := plantGarden(commits, geo)
 	if len(garden) < geo.Height {
 		geo.Height = len(garden)
 	}
@@ -334,11 +334,11 @@ func isQuit(b []byte) bool {
 	return rune(b[0]) == 'q' || bytes.Equal(b, ctrlC)
 }
 
-func plantGarden(r *rand.Rand, commits []*Commit, geo *Geometry) [][]*Cell {
+func plantGarden(commits []*Commit, geo *Geometry) [][]*Cell {
 	cellIx := 0
 	grassCell := &Cell{RGB(0, 200, 0, ","), "You're standing on a patch of grass in a field of wildflowers."}
 	garden := [][]*Cell{}
-	streamIx := r.Intn(geo.Width - 1)
+	streamIx := rand.Intn(geo.Width - 1)
 	if streamIx == geo.Width/2 {
 		streamIx--
 	}
@@ -363,7 +363,7 @@ func plantGarden(r *rand.Rand, commits []*Commit, geo *Geometry) [][]*Cell {
 				})
 				tint += 15
 				streamIx--
-				if r.Float64() < 0.5 {
+				if rand.Float64() < 0.5 {
 					streamIx++
 				}
 				if streamIx < 0 {
@@ -393,7 +393,7 @@ func plantGarden(r *rand.Rand, commits []*Commit, geo *Geometry) [][]*Cell {
 				continue
 			}
 
-			chance := r.Float64()
+			chance := rand.Float64()
 			if chance <= geo.Density {
 				commit := commits[cellIx]
 				garden[y] = append(garden[y], &Cell{
diff --git a/pkg/cmd/secret/set/set.go b/pkg/cmd/secret/set/set.go
index 86dd35258..95f80f8b1 100644
--- a/pkg/cmd/secret/set/set.go
+++ b/pkg/cmd/secret/set/set.go
@@ -9,7 +9,6 @@ import (
 	"os"
 	"strings"
 
-	"github.com/AlecAivazis/survey/v2"
 	"github.com/MakeNowJust/heredoc"
 	"github.com/cli/cli/v2/api"
 	"github.com/cli/cli/v2/internal/config"
@@ -17,7 +16,6 @@ import (
 	"github.com/cli/cli/v2/pkg/cmd/secret/shared"
 	"github.com/cli/cli/v2/pkg/cmdutil"
 	"github.com/cli/cli/v2/pkg/iostreams"
-	"github.com/cli/cli/v2/pkg/prompt"
 	"github.com/hashicorp/go-multierror"
 	"github.com/joho/godotenv"
 	"github.com/spf13/cobra"
@@ -29,6 +27,7 @@ type SetOptions struct {
 	IO         *iostreams.IOStreams
 	Config     func() (config.Config, error)
 	BaseRepo   func() (ghrepo.Interface, error)
+	Prompter   iprompter
 
 	RandomOverride func() io.Reader
 
@@ -44,11 +43,16 @@ type SetOptions struct {
 	Application     string
 }
 
+type iprompter interface {
+	Password(string) (string, error)
+}
+
 func NewCmdSet(f *cmdutil.Factory, runF func(*SetOptions) error) *cobra.Command {
 	opts := &SetOptions{
 		IO:         f.IOStreams,
 		Config:     f.Config,
 		HttpClient: f.HttpClient,
+		Prompter:   f.Prompter,
 	}
 
 	cmd := &cobra.Command{
@@ -375,11 +379,7 @@ func getBody(opts *SetOptions) ([]byte, error) {
 	}
 
 	if opts.IO.CanPrompt() {
-		var bodyInput string
-		//nolint:staticcheck // SA1019: prompt.SurveyAskOne is deprecated: use Prompter
-		err := prompt.SurveyAskOne(&survey.Password{
-			Message: "Paste your secret",
-		}, &bodyInput)
+		bodyInput, err := opts.Prompter.Password("Paste your secret")
 		if err != nil {
 			return nil, err
 		}


Test patch:
diff --git a/internal/codespaces/api/api_test.go b/internal/codespaces/api/api_test.go
index 65852cc79..75f82c39e 100644
--- a/internal/codespaces/api/api_test.go
+++ b/internal/codespaces/api/api_test.go
@@ -136,7 +136,6 @@ func createHttpClient() (*http.Client, error) {
 
 func TestNew_APIURL_dotcomConfig(t *testing.T) {
 	t.Setenv("GITHUB_API_URL", "")
-	t.Setenv("GITHUB_SERVER_URL", "https://github.com")
 	cfg := &config.ConfigMock{
 		AuthenticationFunc: func() *config.AuthConfig {
 			return &config.AuthConfig{}
@@ -159,7 +158,6 @@ func TestNew_APIURL_dotcomConfig(t *testing.T) {
 
 func TestNew_APIURL_customConfig(t *testing.T) {
 	t.Setenv("GITHUB_API_URL", "")
-	t.Setenv("GITHUB_SERVER_URL", "https://github.mycompany.com")
 	cfg := &config.ConfigMock{
 		AuthenticationFunc: func() *config.AuthConfig {
 			authCfg := &config.AuthConfig{}
@@ -184,7 +182,6 @@ func TestNew_APIURL_customConfig(t *testing.T) {
 
 func TestNew_APIURL_env(t *testing.T) {
 	t.Setenv("GITHUB_API_URL", "https://api.mycompany.com")
-	t.Setenv("GITHUB_SERVER_URL", "https://mycompany.com")
 	cfg := &config.ConfigMock{
 		AuthenticationFunc: func() *config.AuthConfig {
 			return &config.AuthConfig{}
@@ -221,7 +218,6 @@ func TestNew_APIURL_dotcomFallback(t *testing.T) {
 
 func TestNew_ServerURL_dotcomConfig(t *testing.T) {
 	t.Setenv("GITHUB_SERVER_URL", "")
-	t.Setenv("GITHUB_API_URL", "https://api.github.com")
 	cfg := &config.ConfigMock{
 		AuthenticationFunc: func() *config.AuthConfig {
 			return &config.AuthConfig{}
@@ -244,7 +240,6 @@ func TestNew_ServerURL_dotcomConfig(t *testing.T) {
 
 func TestNew_ServerURL_customConfig(t *testing.T) {
 	t.Setenv("GITHUB_SERVER_URL", "")
-	t.Setenv("GITHUB_API_URL", "https://github.mycompany.com/api/v3")
 	cfg := &config.ConfigMock{
 		AuthenticationFunc: func() *config.AuthConfig {
 			authCfg := &config.AuthConfig{}
@@ -269,7 +264,6 @@ func TestNew_ServerURL_customConfig(t *testing.T) {
 
 func TestNew_ServerURL_env(t *testing.T) {
 	t.Setenv("GITHUB_SERVER_URL", "https://mycompany.com")
-	t.Setenv("GITHUB_API_URL", "https://api.mycompany.com")
 	cfg := &config.ConfigMock{
 		AuthenticationFunc: func() *config.AuthConfig {
 			return &config.AuthConfig{}
diff --git a/internal/prompter/test.go b/internal/prompter/test.go
index c376e9c83..0dea18e5a 100644
--- a/internal/prompter/test.go
+++ b/internal/prompter/test.go
@@ -258,7 +258,7 @@ func (m *MockPrompter) RegisterInputHostname(stub func() (string, error)) {
 }
 
 func (m *MockPrompter) RegisterPassword(prompt string, stub func(string) (string, error)) {
-	m.PasswordStubs = append(m.PasswordStubs, PasswordStub{Fn: stub})
+	m.PasswordStubs = append(m.PasswordStubs, PasswordStub{Prompt: prompt, Fn: stub})
 }
 
 func (m *MockPrompter) RegisterConfirmDeletion(prompt string, stub func(string) error) {
diff --git a/pkg/cmd/issue/delete/delete_test.go b/pkg/cmd/issue/delete/delete_test.go
index e3b2613ce..acc52af65 100644
--- a/pkg/cmd/issue/delete/delete_test.go
+++ b/pkg/cmd/issue/delete/delete_test.go
@@ -2,6 +2,7 @@ package delete
 
 import (
 	"bytes"
+	"errors"
 	"io"
 	"net/http"
 	"regexp"
@@ -9,16 +10,16 @@ import (
 
 	"github.com/cli/cli/v2/internal/config"
 	"github.com/cli/cli/v2/internal/ghrepo"
+	"github.com/cli/cli/v2/internal/prompter"
 	"github.com/cli/cli/v2/pkg/cmdutil"
 	"github.com/cli/cli/v2/pkg/httpmock"
 	"github.com/cli/cli/v2/pkg/iostreams"
-	"github.com/cli/cli/v2/pkg/prompt"
 	"github.com/cli/cli/v2/test"
 	"github.com/google/shlex"
 	"github.com/stretchr/testify/assert"
 )
 
-func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, error) {
+func runCommand(rt http.RoundTripper, pm *prompter.MockPrompter, isTTY bool, cli string) (*test.CmdOut, error) {
 	ios, _, stdout, stderr := iostreams.Test()
 	ios.SetStdoutTTY(isTTY)
 	ios.SetStdinTTY(isTTY)
@@ -26,6 +27,7 @@ func runCommand(rt http.RoundTripper, isTTY bool, cli string) (*test.CmdOut, err
 
 	factory := &cmdutil.Factory{
 		IOStreams: ios,
+		Prompter:  pm,
 		HttpClient: func() (*http.Client, error) {
 			return &http.Client{Transport: rt}, nil
 		},
@@ -76,11 +78,10 @@ func TestIssueDelete(t *testing.T) {
 			}),
 	)
 
-	//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
-	as := prompt.NewAskStubber(t)
-	as.StubPrompt("You're going to delete issue #13. This action cannot be reversed. To confirm, type the issue number:").AnswerWith("13")
+	pm := prompter.NewMockPrompter(t)
+	pm.RegisterConfirmDeletion("13", func(_ string) error { return nil })
 
-	output, err := runCommand(httpRegistry, true, "13")
+	output, err := runCommand(httpRegistry, pm, true, "13")
 	if err != nil {
 		t.Fatalf("error running command `issue delete`: %v", err)
 	}
@@ -112,7 +113,7 @@ func TestIssueDelete_confirm(t *testing.T) {
 			}),
 	)
 
-	output, err := runCommand(httpRegistry, true, "13 --confirm")
+	output, err := runCommand(httpRegistry, nil, true, "13 --confirm")
 	if err != nil {
 		t.Fatalf("error running command `issue delete`: %v", err)
 	}
@@ -137,19 +138,17 @@ func TestIssueDelete_cancel(t *testing.T) {
 			} } }`),
 	)
 
-	//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
-	as := prompt.NewAskStubber(t)
-	as.StubPrompt("You're going to delete issue #13. This action cannot be reversed. To confirm, type the issue number:").AnswerWith("14")
+	pm := prompter.NewMockPrompter(t)
+	pm.RegisterConfirmDeletion("13", func(_ string) error {
+		return errors.New("You entered 14")
+	})
 
-	output, err := runCommand(httpRegistry, true, "13")
-	if err != nil {
-		t.Fatalf("error running command `issue delete`: %v", err)
+	_, err := runCommand(httpRegistry, pm, true, "13")
+	if err == nil {
+		t.Fatalf("expected error")
 	}
-
-	r := regexp.MustCompile(`Issue #13 was not deleted`)
-
-	if !r.MatchString(output.String()) {
-		t.Fatalf("output did not match regexp /%s/\n> output\n%q\n", r, output.String())
+	if err.Error() != "You entered 14" {
+		t.Fatalf("got unexpected error '%s'", err)
 	}
 }
 
@@ -166,7 +165,7 @@ func TestIssueDelete_doesNotExist(t *testing.T) {
 			`),
 	)
 
-	_, err := runCommand(httpRegistry, true, "13")
+	_, err := runCommand(httpRegistry, nil, true, "13")
 	if err == nil || err.Error() != "GraphQL: Could not resolve to an Issue with the number of 13." {
 		t.Errorf("error running command `issue delete`: %v", err)
 	}
@@ -199,7 +198,7 @@ func TestIssueDelete_issuesDisabled(t *testing.T) {
 		}`),
 	)
 
-	_, err := runCommand(httpRegistry, true, "13")
+	_, err := runCommand(httpRegistry, nil, true, "13")
 	if err == nil || err.Error() != "the 'OWNER/REPO' repository has disabled issues" {
 		t.Fatalf("got error: %v", err)
 	}
diff --git a/pkg/cmd/repo/fork/fork_test.go b/pkg/cmd/repo/fork/fork_test.go
index 5833acb5d..f59fba1b7 100644
--- a/pkg/cmd/repo/fork/fork_test.go
+++ b/pkg/cmd/repo/fork/fork_test.go
@@ -14,11 +14,11 @@ import (
 	"github.com/cli/cli/v2/git"
 	"github.com/cli/cli/v2/internal/config"
 	"github.com/cli/cli/v2/internal/ghrepo"
+	"github.com/cli/cli/v2/internal/prompter"
 	"github.com/cli/cli/v2/internal/run"
 	"github.com/cli/cli/v2/pkg/cmdutil"
 	"github.com/cli/cli/v2/pkg/httpmock"
 	"github.com/cli/cli/v2/pkg/iostreams"
-	"github.com/cli/cli/v2/pkg/prompt"
 	"github.com/google/shlex"
 	"github.com/stretchr/testify/assert"
 )
@@ -205,18 +205,18 @@ func TestRepoFork(t *testing.T) {
 	}
 
 	tests := []struct {
-		name       string
-		opts       *ForkOptions
-		tty        bool
-		httpStubs  func(*httpmock.Registry)
-		execStubs  func(*run.CommandStubber)
-		askStubs   func(*prompt.AskStubber)
-		cfgStubs   func(*config.ConfigMock)
-		remotes    []*context.Remote
-		wantOut    string
-		wantErrOut string
-		wantErr    bool
-		errMsg     string
+		name        string
+		opts        *ForkOptions
+		tty         bool
+		httpStubs   func(*httpmock.Registry)
+		execStubs   func(*run.CommandStubber)
+		promptStubs func(*prompter.MockPrompter)
+		cfgStubs    func(*config.ConfigMock)
+		remotes     []*context.Remote
+		wantOut     string
+		wantErrOut  string
+		wantErr     bool
+		errMsg      string
 	}{
 		{
 			name: "implicit match, configured protocol overrides provided",
@@ -272,9 +272,10 @@ func TestRepoFork(t *testing.T) {
 				RemoteName:   defaultRemoteName,
 			},
 			httpStubs: forkPost,
-			askStubs: func(as *prompt.AskStubber) {
-				//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
-				as.StubOne(false)
+			promptStubs: func(pm *prompter.MockPrompter) {
+				pm.RegisterConfirm("Would you like to add a remote for the fork?", func(_ string, _ bool) (bool, error) {
+					return false, nil
+				})
 			},
 			wantErrOut: "✓ Created fork someone/REPO\n",
 		},
@@ -291,9 +292,10 @@ func TestRepoFork(t *testing.T) {
 				cs.Register("git remote rename origin upstream", 0, "")
 				cs.Register(`git remote add origin https://github.com/someone/REPO.git`, 0, "")
 			},
-			askStubs: func(as *prompt.AskStubber) {
-				//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
-				as.StubOne(true)
+			promptStubs: func(pm *prompter.MockPrompter) {
+				pm.RegisterConfirm("Would you like to add a remote for the fork?", func(_ string, _ bool) (bool, error) {
+					return true, nil
+				})
 			},
 			wantErrOut: "✓ Created fork someone/REPO\n✓ Added remote origin\n",
 		},
@@ -497,9 +499,10 @@ func TestRepoFork(t *testing.T) {
 				PromptClone: true,
 			},
 			httpStubs: forkPost,
-			askStubs: func(as *prompt.AskStubber) {
-				//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
-				as.StubOne(false)
+			promptStubs: func(pm *prompter.MockPrompter) {
+				pm.RegisterConfirm("Would you like to clone the fork?", func(_ string, _ bool) (bool, error) {
+					return false, nil
+				})
 			},
 			wantErrOut: "✓ Created fork someone/REPO\n",
 		},
@@ -511,9 +514,10 @@ func TestRepoFork(t *testing.T) {
 				PromptClone: true,
 			},
 			httpStubs: forkPost,
-			askStubs: func(as *prompt.AskStubber) {
-				//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
-				as.StubOne(true)
+			promptStubs: func(pm *prompter.MockPrompter) {
+				pm.RegisterConfirm("Would you like to clone the fork?", func(_ string, _ bool) (bool, error) {
+					return true, nil
+				})
 			},
 			execStubs: func(cs *run.CommandStubber) {
 				cs.Register(`git clone https://github.com/someone/REPO\.git`, 0, "")
@@ -533,9 +537,10 @@ func TestRepoFork(t *testing.T) {
 				},
 			},
 			httpStubs: forkPost,
-			askStubs: func(as *prompt.AskStubber) {
-				//nolint:staticcheck // SA1019: as.StubOne is deprecated: use StubPrompt
-				as.StubOne(true)
+			promptStubs: func(pm *prompter.MockPrompter) {
+				pm.RegisterConfirm("Would you like to clone the fork?", func(_ string, _ bool) (bool, error) {
+					return true, nil
+				})
 			},
 			execStubs: func(cs *run.CommandStubber) {
 				cs.Register(`git clone https://github.com/someone/REPO\.git`, 0, "")
@@ -746,11 +751,10 @@ func TestRepoFork(t *testing.T) {
 				GitPath: "some/path/git",
 			}
 
-			//nolint:staticcheck // SA1019: prompt.InitAskStubber is deprecated: use NewAskStubber
-			as, teardown := prompt.InitAskStubber()
-			defer teardown()
-			if tt.askStubs != nil {
-				tt.askStubs(as)
+			pm := prompter.NewMockPrompter(t)
+			tt.opts.Prompter = pm
+			if tt.promptStubs != nil {
+				tt.promptStubs(pm)
 			}
 
 			cs, restoreRun := run.Stub()
diff --git a/pkg/cmd/secret/set/set_test.go b/pkg/cmd/secret/set/set_test.go
index 592527c5f..376ef2d53 100644
--- a/pkg/cmd/secret/set/set_test.go
+++ b/pkg/cmd/secret/set/set_test.go
@@ -12,11 +12,11 @@ import (
 	"github.com/MakeNowJust/heredoc"
 	"github.com/cli/cli/v2/internal/config"
 	"github.com/cli/cli/v2/internal/ghrepo"
+	"github.com/cli/cli/v2/internal/prompter"
 	"github.com/cli/cli/v2/pkg/cmd/secret/shared"
 	"github.com/cli/cli/v2/pkg/cmdutil"
 	"github.com/cli/cli/v2/pkg/httpmock"
 	"github.com/cli/cli/v2/pkg/iostreams"
-	"github.com/cli/cli/v2/pkg/prompt"
 	"github.com/google/shlex"
 	"github.com/stretchr/testify/assert"
 )
@@ -595,12 +595,14 @@ func Test_getBodyPrompt(t *testing.T) {
 	ios.SetStdinTTY(true)
 	ios.SetStdoutTTY(true)
 
-	//nolint:staticcheck // SA1019: prompt.NewAskStubber is deprecated: use PrompterMock
-	as := prompt.NewAskStubber(t)
-	as.StubPrompt("Paste your secret").AnswerWith("cool secret")
+	pm := prompter.NewMockPrompter(t)
+	pm.RegisterPassword("Paste your secret", func(_ string) (string, error) {
+		return "cool secret", nil
+	})
 
 	body, err := getBody(&SetOptions{
-		IO: ios,
+		IO:       ios,
+		Prompter: pm,
 	})
 	assert.NoError(t, err)
 	assert.Equal(t, string(body), "cool secret")