Repository: urfave/cli
Pull request #1630 (2022-12-19 03:01:17)

Allow `any` instead of custom `*Author` type
## What type of PR is this?

- cleanup

## What this PR does / why we need it:

Drop the custom `*Author` type and allow `any` with the assumption that it either implements `fmt.Stringer` or can otherwise be safely `Sprintf`'d via `%s`.

## Which issue(s) this PR fixes:

Supports #1586 given the `*Author` type was defined in `app.go` which is slated for removal.


Patch:
diff --git a/app.go b/app.go
index 98a629d..60eeb72 100644
--- a/app.go
+++ b/app.go
@@ -78,8 +78,8 @@ type App struct {
 	OnUsageError OnUsageErrorFunc
 	// Execute this function when an invalid flag is accessed from the context
 	InvalidFlagAccessHandler InvalidFlagAccessFunc
-	// List of all authors who contributed
-	Authors []*Author
+	// List of all authors who contributed (string or fmt.Stringer)
+	Authors []any // TODO: ~string | fmt.Stringer when interface unions are available
 	// Copyright of the binary if any
 	Copyright string
 	// Reader reader to write input to (useful for tests)
@@ -434,22 +434,6 @@ func runFlagActions(c *Context, fs []Flag) error {
 	return nil
 }
 
-// Author represents someone who has contributed to a cli project.
-type Author struct {
-	Name  string // The Authors name
-	Email string // The Authors email
-}
-
-// String makes Author comply to the Stringer interface, to allow an easy print in the templating process
-func (a *Author) String() string {
-	e := ""
-	if a.Email != "" {
-		e = " <" + a.Email + ">"
-	}
-
-	return fmt.Sprintf("%v%v", a.Name, e)
-}
-
 func checkStringSliceIncludes(want string, sSlice []string) bool {
 	found := false
 	for _, s := range sSlice {
diff --git a/godoc-current.txt b/godoc-current.txt
index 43add56..91a4c94 100644
--- a/godoc-current.txt
+++ b/godoc-current.txt
@@ -293,8 +293,8 @@ type App struct {
 	OnUsageError OnUsageErrorFunc
 	// Execute this function when an invalid flag is accessed from the context
 	InvalidFlagAccessHandler InvalidFlagAccessFunc
-	// List of all authors who contributed
-	Authors []*Author
+	// List of all authors who contributed (string or fmt.Stringer)
+	Authors []any // TODO: ~string | fmt.Stringer when interface unions are available
 	// Copyright of the binary if any
 	Copyright string
 	// Reader reader to write input to (useful for tests)
@@ -399,16 +399,6 @@ type Args interface {
 	Slice() []string
 }
 
-type Author struct {
-	Name  string // The Authors name
-	Email string // The Authors email
-}
-    Author represents someone who has contributed to a cli project.
-
-func (a *Author) String() string
-    String makes Author comply to the Stringer interface, to allow an easy print
-    in the templating process
-
 type BeforeFunc func(*Context) error
     BeforeFunc is an action to execute before any subcommands are run, but after
     the context is ready if a non-nil error is returned, no subcommands are run


Test patch:
diff --git a/app_test.go b/app_test.go
index a720bdc..00e980d 100644
--- a/app_test.go
+++ b/app_test.go
@@ -6,6 +6,7 @@ import (
 	"flag"
 	"fmt"
 	"io"
+	"net/mail"
 	"os"
 	"reflect"
 	"strconv"
@@ -45,7 +46,7 @@ func ExampleApp_Run() {
 			return nil
 		},
 		UsageText: "app [first_arg] [second_arg]",
-		Authors:   []*Author{{Name: "Oliver Allen", Email: "oliver@toyshop.example.com"}},
+		Authors:   []any{&mail.Address{Name: "Oliver Allen", Address: "oliver@toyshop.example.com"}, "gruffalo@soup-world.example.org"},
 	}
 
 	app.Run(os.Args)
@@ -100,9 +101,9 @@ func ExampleApp_Run_appHelp() {
 		Name:        "greet",
 		Version:     "0.1.0",
 		Description: "This is how we describe greet the app",
-		Authors: []*Author{
-			{Name: "Harrison", Email: "harrison@lolwut.com"},
-			{Name: "Oliver Allen", Email: "oliver@toyshop.com"},
+		Authors: []any{
+			&mail.Address{Name: "Harrison", Address: "harrison@lolwut.example.com"},
+			"Oliver Allen  <oliver@toyshop.example.com>",
 		},
 		Flags: []Flag{
 			&StringFlag{Name: "name", Value: "bob", Usage: "a name to say"},
@@ -135,8 +136,8 @@ func ExampleApp_Run_appHelp() {
 	//    This is how we describe greet the app
 	//
 	// AUTHORS:
-	//    Harrison <harrison@lolwut.com>
-	//    Oliver Allen <oliver@toyshop.com>
+	//    "Harrison" <harrison@lolwut.example.com>
+	//    Oliver Allen  <oliver@toyshop.example.com>
 	//
 	// COMMANDS:
 	//    describeit, d  use it to see a description
diff --git a/docs_test.go b/docs_test.go
index 12d5d3c..e4ae2fe 100644
--- a/docs_test.go
+++ b/docs_test.go
@@ -49,7 +49,7 @@ func TestToMarkdownNoCommands(t *testing.T) {
 func TestToMarkdownNoAuthors(t *testing.T) {
 	// Given
 	app := testApp()
-	app.Authors = []*Author{}
+	app.Authors = []any{}
 
 	// When
 	res, err := app.ToMarkdown()
diff --git a/fish_test.go b/fish_test.go
index 10a0a16..de75939 100644
--- a/fish_test.go
+++ b/fish_test.go
@@ -2,6 +2,7 @@ package cli
 
 import (
 	"bytes"
+	"net/mail"
 	"os"
 	"testing"
 )
@@ -127,9 +128,9 @@ Should be a part of the same code block
 	app.UsageText = "app [first_arg] [second_arg]"
 	app.Description = `Description of the application.`
 	app.Usage = "Some app"
-	app.Authors = []*Author{
-		{Name: "Harrison", Email: "harrison@lolwut.com"},
-		{Name: "Oliver Allen", Email: "oliver@toyshop.com"},
+	app.Authors = []any{
+		"Harrison <harrison@lolwut.example.com>",
+		&mail.Address{Name: "Oliver Allen", Address: "oliver@toyshop.com"},
 	}
 	return app
 }
diff --git a/testdata/godoc-v3.x.txt b/testdata/godoc-v3.x.txt
index 43add56..91a4c94 100644
--- a/testdata/godoc-v3.x.txt
+++ b/testdata/godoc-v3.x.txt
@@ -293,8 +293,8 @@ type App struct {
 	OnUsageError OnUsageErrorFunc
 	// Execute this function when an invalid flag is accessed from the context
 	InvalidFlagAccessHandler InvalidFlagAccessFunc
-	// List of all authors who contributed
-	Authors []*Author
+	// List of all authors who contributed (string or fmt.Stringer)
+	Authors []any // TODO: ~string | fmt.Stringer when interface unions are available
 	// Copyright of the binary if any
 	Copyright string
 	// Reader reader to write input to (useful for tests)
@@ -399,16 +399,6 @@ type Args interface {
 	Slice() []string
 }
 
-type Author struct {
-	Name  string // The Authors name
-	Email string // The Authors email
-}
-    Author represents someone who has contributed to a cli project.
-
-func (a *Author) String() string
-    String makes Author comply to the Stringer interface, to allow an easy print
-    in the templating process
-
 type BeforeFunc func(*Context) error
     BeforeFunc is an action to execute before any subcommands are run, but after
     the context is ready if a non-nil error is returned, no subcommands are run