Repository: urfave/cli
Pull request #1459 (2022-08-19 22:43:52)

Fix:(issue_1094) Dont execute Before/After during shell completions
<!--
  This template provides some ideas of things to include in your PR description.
  To start, try providing a short summary of your changes in the Title above.
  If a section of the PR template does not apply to this PR, then delete that section.
 -->

## What type of PR is this?

_(REQUIRED)_

<!--
  Delete any of the following that do not apply:
 -->

- bug

## What this PR does / why we need it:

_(REQUIRED)_

<!--
  What goal is this change working towards?
  Provide a bullet pointed summary of how each file was changed.
  Briefly explain any decisions you made with respect to the changes.
  Include anything here that you didn't include in *Release Notes*
  above, such as changes to CI or changes to internal methods.
-->
Before/After handlers shouldnt be invoked during shell completion

## Which issue(s) this PR fixes:

_(REQUIRED)_

<!--
If this PR fixes one of more issues, list them here.
One line each, like so:

Fixes #1094 
-->

## Special notes for your reviewer:

_(fill-in or delete this section)_

<!--
   Is there any particular feedback you would / wouldn't like?
   Which parts of the code should reviewers focus on?
-->

## Testing

_(fill-in or delete this section)_

<!--
  Describe how you tested this change.
-->

go test -run=TestApp_BeforeAfterFuncShellCompletion

## Release Notes

_(REQUIRED)_
<!--
  If this PR makes user facing changes, please describe them here. This
  description will be copied into the release notes/changelog, whenever the
  next version is released. Keep this section short, and focus on high level
  changes.

  Put your text between the block. To omit notes, use NONE within the block.
-->

```release-note

```


VirrageS: @dearchap LGTM. Tested and works :)
talarian1: @dearchap, @Dokiys  We will be happy to see this improvement as well  :) 

Patch:
diff --git a/app.go b/app.go
index 382f238..df5a9a9 100644
--- a/app.go
+++ b/app.go
@@ -248,7 +248,7 @@ func (a *App) Run(arguments []string) (err error) {
 		return cerr
 	}
 
-	if a.After != nil {
+	if a.After != nil && !context.shellComplete {
 		defer func() {
 			if afterErr := a.After(context); afterErr != nil {
 				if err != nil {
@@ -260,7 +260,7 @@ func (a *App) Run(arguments []string) (err error) {
 		}()
 	}
 
-	if a.Before != nil {
+	if a.Before != nil && !context.shellComplete {
 		beforeErr := a.Before(context)
 		if beforeErr != nil {
 			a.handleExitCoder(context, beforeErr)
@@ -374,7 +374,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
 		return cerr
 	}
 
-	if a.After != nil {
+	if a.After != nil && !context.shellComplete {
 		defer func() {
 			afterErr := a.After(context)
 			if afterErr != nil {
@@ -388,7 +388,7 @@ func (a *App) RunAsSubcommand(ctx *Context) (err error) {
 		}()
 	}
 
-	if a.Before != nil {
+	if a.Before != nil && !context.shellComplete {
 		beforeErr := a.Before(context)
 		if beforeErr != nil {
 			a.handleExitCoder(context, beforeErr)


Test patch:
diff --git a/app_test.go b/app_test.go
index 4dc43ba..e18a9f0 100644
--- a/app_test.go
+++ b/app_test.go
@@ -986,6 +986,58 @@ func TestApp_BeforeFunc(t *testing.T) {
 	}
 }
 
+func TestApp_BeforeAfterFuncShellCompletion(t *testing.T) {
+	counts := &opCounts{}
+	var err error
+
+	app := &App{
+		EnableBashCompletion: true,
+		Before: func(c *Context) error {
+			counts.Total++
+			counts.Before = counts.Total
+			return nil
+		},
+		After: func(c *Context) error {
+			counts.Total++
+			counts.After = counts.Total
+			return nil
+		},
+		Commands: []Command{
+			{
+				Name: "sub",
+				Action: func(c *Context) error {
+					counts.Total++
+					counts.SubCommand = counts.Total
+					return nil
+				},
+			},
+		},
+		Flags: []Flag{
+			&StringFlag{Name: "opt"},
+		},
+		Writer: ioutil.Discard,
+	}
+
+	// run with the Before() func succeeding
+	err = app.Run([]string{"command", "--opt", "succeed", "sub", "--generate-bash-completion"})
+
+	if err != nil {
+		t.Fatalf("Run error: %s", err)
+	}
+
+	if counts.Before != 0 {
+		t.Errorf("Before() executed when not expected")
+	}
+
+	if counts.After != 0 {
+		t.Errorf("After() executed when not expected")
+	}
+
+	if counts.SubCommand != 0 {
+		t.Errorf("Subcommand executed more than expected")
+	}
+}
+
 func TestApp_AfterFunc(t *testing.T) {
 	counts := &opCounts{}
 	afterError := fmt.Errorf("fail")