Repository: kyverno/chainsaw
Pull request #231 (2023-10-27 12:23:38)

fix: improve kuttl migrate command
Improve kuttl migrate command.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/kyverno/chainsaw/pull/231?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) Report
> Merging [#231](https://app.codecov.io/gh/kyverno/chainsaw/pull/231?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) (8bb8b76) into [main](https://app.codecov.io/gh/kyverno/chainsaw/commit/0483dce330832911c58644e6a20b16d23cc05f1a?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) (0483dce) will **decrease** coverage by `1.52%`.
> The diff coverage is `7.69%`.

```diff
@@            Coverage Diff             @@
##             main     #231      +/-   ##
==========================================
- Coverage   56.43%   54.92%   -1.52%     
==========================================
  Files          15       15              
  Lines         629      650      +21     
==========================================
+ Hits          355      357       +2     
- Misses        238      257      +19     
  Partials       36       36              
```


| [Files](https://app.codecov.io/gh/kyverno/chainsaw/pull/231?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno) | Coverage Δ | |
|---|---|---|
| [pkg/commands/kuttl/migrate/command.go](https://app.codecov.io/gh/kyverno/chainsaw/pull/231?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno#diff-cGtnL2NvbW1hbmRzL2t1dHRsL21pZ3JhdGUvY29tbWFuZC5nbw==) | `10.24% <7.69%> (-0.11%)` | :arrow_down: |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=kyverno)


Patch:
diff --git a/.crds/chainsaw.kyverno.io_configurations.yaml b/.crds/chainsaw.kyverno.io_configurations.yaml
index 05013f7d..03b1f92d 100644
--- a/.crds/chainsaw.kyverno.io_configurations.yaml
+++ b/.crds/chainsaw.kyverno.io_configurations.yaml
@@ -57,9 +57,9 @@ spec:
                   unless the namespace is overridden in a the test spec.
                 type: string
               parallel:
-                default: 8
                 description: The maximum number of tests to run at once.
                 format: int
+                minimum: 1
                 type: integer
               repeatCount:
                 description: RepeatCount indicates how many times the tests should
diff --git a/.release-notes/main.md b/.release-notes/main.md
index c9743c4a..b7f53eb5 100644
--- a/.release-notes/main.md
+++ b/.release-notes/main.md
@@ -24,6 +24,7 @@ Release notes for `TODO`.
 
 - Improved logging of running tests
 - Added coloured logs
+- Made `Parallel` in `Configuration` optional (delegates default to the testing package)
 
 ## :books: Docs :books:
 
diff --git a/pkg/apis/v1alpha1/configuration_spec.go b/pkg/apis/v1alpha1/configuration_spec.go
index 289fae79..dc9fa8e9 100644
--- a/pkg/apis/v1alpha1/configuration_spec.go
+++ b/pkg/apis/v1alpha1/configuration_spec.go
@@ -32,9 +32,10 @@ type ConfigurationSpec struct {
 	FailFast bool `json:"failFast,omitempty"`
 
 	// The maximum number of tests to run at once.
-	// +kubebuilder:default:=8
 	// +kubebuilder:validation:Format:=int
-	Parallel int `json:"parallel,omitempty"`
+	// +kubebuilder:validation:Minimum:=1
+	// +optional
+	Parallel *int `json:"parallel,omitempty"`
 
 	// ReportFormat determines test report format (JSON|XML|nil) nil == no report.
 	// maps to report.Type, however we don't want generated.deepcopy to have reference to it.
diff --git a/pkg/apis/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/v1alpha1/zz_generated.deepcopy.go
index c36bf3a1..87b30e1e 100644
--- a/pkg/apis/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/v1alpha1/zz_generated.deepcopy.go
@@ -157,6 +157,11 @@ func (in *ConfigurationSpec) DeepCopyInto(out *ConfigurationSpec) {
 		*out = make([]string, len(*in))
 		copy(*out, *in)
 	}
+	if in.Parallel != nil {
+		in, out := &in.Parallel, &out.Parallel
+		*out = new(int)
+		**out = **in
+	}
 	if in.RepeatCount != nil {
 		in, out := &in.RepeatCount, &out.RepeatCount
 		*out = new(int)
diff --git a/pkg/commands/kuttl/migrate/command.go b/pkg/commands/kuttl/migrate/command.go
index e88b94de..4dee7d6f 100644
--- a/pkg/commands/kuttl/migrate/command.go
+++ b/pkg/commands/kuttl/migrate/command.go
@@ -10,6 +10,7 @@ import (
 
 	kuttlapi "github.com/kudobuilder/kuttl/pkg/apis/testharness/v1beta1"
 	"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
+	"github.com/kyverno/chainsaw/pkg/discovery"
 	"github.com/kyverno/chainsaw/pkg/resource"
 	"github.com/kyverno/chainsaw/pkg/utils/convert"
 	fileutils "github.com/kyverno/chainsaw/pkg/utils/file"
@@ -22,20 +23,22 @@ import (
 
 func Command() *cobra.Command {
 	save := false
+	overwrite := false
 	cmd := &cobra.Command{
 		Use:          "migrate",
 		Short:        "Migrate KUTTL tests to Chainsaw",
 		SilenceUsage: true,
 		Args:         cobra.MinimumNArgs(1),
 		RunE: func(cmd *cobra.Command, args []string) error {
-			return execute(cmd.OutOrStdout(), save, args...)
+			return execute(cmd.OutOrStdout(), save, overwrite, args...)
 		},
 	}
 	cmd.Flags().BoolVar(&save, "save", false, "If set, converted files will be saved.")
+	cmd.Flags().BoolVar(&overwrite, "overwrite", false, "If set, overwrites original file.")
 	return cmd
 }
 
-func execute(out io.Writer, save bool, paths ...string) error {
+func execute(out io.Writer, save, overwrite bool, paths ...string) error {
 	folders, err := fsutils.DiscoverFolders(paths...)
 	if err != nil {
 		fmt.Fprintf(out, "  ERROR: failed to discover folders: %s\n", err)
@@ -62,40 +65,23 @@ func execute(out io.Writer, save bool, paths ...string) error {
 			var converted []interface{}
 			needsSave := false
 			for _, resource := range resources {
-				if resource.GetAPIVersion() == "kuttl.dev/v1beta1" {
-					switch resource.GetKind() {
-					case "TestSuite":
-						fmt.Fprintf(out, "Converting %s in %s...\n", "TestSuite", path)
-						configuration, err := testSuite(resource)
-						if err != nil {
-							fmt.Fprintf(out, "  ERROR: failed to convert %s (%s): %s\n", "TestSuite", path, err)
-							return err
-						}
-						needsSave = true
-						converted = append(converted, configuration)
-					case "TestStep":
-						fmt.Fprintf(out, "Converting %s in %s...\n", "TestStep", path)
-						step, err := testStep(resource)
-						if err != nil {
-							fmt.Fprintf(out, "  ERROR: failed to convert %s (%s): %s\n", "TestStep", path, err)
-							return err
-						}
-						needsSave = true
-						converted = append(converted, step)
-					case "TestAssert":
-						fmt.Fprintf(out, "Converting %s in %s...\n", "TestAssert", path)
-						fmt.Fprintf(out, "  ERROR: not supported (%s)\n", path)
-						return fmt.Errorf("conversion not supported %s", resource.GetKind())
-					default:
-						fmt.Fprintf(out, "  ERROR: unknown kuttl resource (%s): %s\n", path, err)
-						return fmt.Errorf("unknown kuttl resource %s", resource.GetKind())
-					}
-				} else {
+				migrated, err := migrate(out, path, resource)
+				if err != nil {
+					needsSave = false
+					break
+				}
+				if migrated == nil {
 					converted = append(converted, resource)
+				} else {
+					converted = append(converted, migrated)
+					needsSave = true
 				}
 			}
 			if save && needsSave {
-				savePath := strings.TrimRight(path, filepath.Ext(path)) + ".chainsaw.yaml"
+				savePath := path
+				if !overwrite {
+					savePath = strings.TrimRight(path, filepath.Ext(path)) + ".chainsaw.yaml"
+				}
 				fmt.Fprintf(out, "Saving converted file %s to %s...\n", path, savePath)
 				var yamlBytes []byte
 				for _, resource := range converted {
@@ -117,6 +103,45 @@ func execute(out io.Writer, save bool, paths ...string) error {
 	return nil
 }
 
+func migrate(out io.Writer, path string, resource unstructured.Unstructured) (metav1.Object, error) {
+	if resource.GetAPIVersion() == "kuttl.dev/v1beta1" {
+		switch resource.GetKind() {
+		case "TestSuite":
+			fmt.Fprintf(out, "Converting %s in %s...\n", "TestSuite", path)
+			configuration, err := testSuite(resource)
+			if err != nil {
+				fmt.Fprintf(out, "  ERROR: failed to convert %s (%s): %s\n", "TestSuite", path, err)
+				return nil, err
+			}
+			if configuration.GetName() == "" {
+				configuration.SetName("configuration")
+			}
+			return configuration, nil
+		case "TestStep":
+			fmt.Fprintf(out, "Converting %s in %s...\n", "TestStep", path)
+			step, err := testStep(resource)
+			if err != nil {
+				fmt.Fprintf(out, "  ERROR: failed to convert %s (%s): %s\n", "TestStep", path, err)
+				return nil, err
+			}
+			if step.GetName() == "" {
+				groups := discovery.StepFileName.FindStringSubmatch(filepath.Base(path))
+				step.SetName(groups[2])
+			}
+			return step, nil
+		case "TestAssert":
+			fmt.Fprintf(out, "Converting %s in %s...\n", "TestAssert", path)
+			fmt.Fprintf(out, "  ERROR: not supported (%s)\n", path)
+			return nil, fmt.Errorf("conversion not supported %s", resource.GetKind())
+		default:
+			fmt.Fprintf(out, "  ERROR: unknown kuttl resource (%s): %s\n", path, resource.GetKind())
+			return nil, fmt.Errorf("unknown kuttl resource %s", resource.GetKind())
+		}
+	} else {
+		return nil, nil
+	}
+}
+
 func testSuite(in unstructured.Unstructured) (*v1alpha1.Configuration, error) {
 	from, err := convert.To[kuttlapi.TestSuite](in)
 	if err != nil {
@@ -138,12 +163,14 @@ func testSuite(in unstructured.Unstructured) (*v1alpha1.Configuration, error) {
 			Timeout:      timeout,
 			TestDirs:     from.TestDirs,
 			SkipDelete:   from.SkipDelete,
-			Parallel:     from.Parallel,
 			ReportFormat: v1alpha1.ReportFormatType(from.ReportFormat),
 			ReportName:   from.ReportName,
 			Namespace:    from.Namespace,
 		},
 	}
+	if from.Parallel != 0 {
+		to.Spec.Parallel = &from.Parallel
+	}
 	return to, nil
 }
 
diff --git a/pkg/data/crds/chainsaw.kyverno.io_configurations.yaml b/pkg/data/crds/chainsaw.kyverno.io_configurations.yaml
index 05013f7d..03b1f92d 100644
--- a/pkg/data/crds/chainsaw.kyverno.io_configurations.yaml
+++ b/pkg/data/crds/chainsaw.kyverno.io_configurations.yaml
@@ -57,9 +57,9 @@ spec:
                   unless the namespace is overridden in a the test spec.
                 type: string
               parallel:
-                default: 8
                 description: The maximum number of tests to run at once.
                 format: int
+                minimum: 1
                 type: integer
               repeatCount:
                 description: RepeatCount indicates how many times the tests should
diff --git a/pkg/runner/flags.go b/pkg/runner/flags.go
index 892a21b9..70dbfda5 100644
--- a/pkg/runner/flags.go
+++ b/pkg/runner/flags.go
@@ -14,8 +14,10 @@ func setupFlags(config v1alpha1.ConfigurationSpec) error {
 	if err := flag.Set("test.v", "true"); err != nil {
 		return err
 	}
-	if err := flag.Set("test.parallel", strconv.Itoa(config.Parallel)); err != nil {
-		return err
+	if config.Parallel != nil {
+		if err := flag.Set("test.parallel", strconv.Itoa(*config.Parallel)); err != nil {
+			return err
+		}
 	}
 	if err := flag.Set("test.failfast", fmt.Sprint(config.FailFast)); err != nil {
 		return err
diff --git a/website/docs/apis/chainsaw.v1alpha1.md b/website/docs/apis/chainsaw.v1alpha1.md
index d3fc3019..3c11e3bb 100644
--- a/website/docs/apis/chainsaw.v1alpha1.md
+++ b/website/docs/apis/chainsaw.v1alpha1.md
@@ -123,7 +123,7 @@ during the testing process.</p>
 | `testDirs` | `[]string` |  |  | <p>Directories containing test cases to run.</p> |
 | `skipDelete` | `bool` |  |  | <p>If set, do not delete the resources after running the tests (implies SkipClusterDelete).</p> |
 | `failFast` | `bool` |  |  | <p>FailFast determines whether the test should stop upon encountering the first failure.</p> |
-| `parallel` | `int` | :white_check_mark: |  | <p>The maximum number of tests to run at once.</p> |
+| `parallel` | `int` |  |  | <p>The maximum number of tests to run at once.</p> |
 | `reportFormat` | [`ReportFormatType`](#chainsaw-kyverno-io-v1alpha1-ReportFormatType) |  |  | <p>ReportFormat determines test report format (JSON|XML|nil) nil == no report. maps to report.Type, however we don't want generated.deepcopy to have reference to it.</p> |
 | `reportName` | `string` |  |  | <p>ReportName defines the name of report to create. It defaults to "chainsaw-report".</p> |
 | `namespace` | `string` |  |  | <p>Namespace defines the namespace to use for tests. If not specified, every test will execute in a random ephemeral namespace unless the namespace is overridden in a the test spec.</p> |
diff --git a/website/docs/commands/chainsaw_kuttl_migrate.md b/website/docs/commands/chainsaw_kuttl_migrate.md
index 0c33e64b..c18700e4 100644
--- a/website/docs/commands/chainsaw_kuttl_migrate.md
+++ b/website/docs/commands/chainsaw_kuttl_migrate.md
@@ -9,8 +9,9 @@ chainsaw kuttl migrate [flags]
 ### Options
 
 ```
-  -h, --help   help for migrate
-      --save   If set, converted files will be saved.
+  -h, --help        help for migrate
+      --overwrite   If set, overwrites original file.
+      --save        If set, converted files will be saved.
 ```
 
 ### SEE ALSO


Test patch:
diff --git a/pkg/commands/test/command.go b/pkg/commands/test/command.go
index 55feb3f3..e47ad913 100644
--- a/pkg/commands/test/command.go
+++ b/pkg/commands/test/command.go
@@ -93,7 +93,7 @@ func Command() *cobra.Command {
 				configuration.Spec.FailFast = options.failFast
 			}
 			if flagutils.IsSet(flags, "parallel") {
-				configuration.Spec.Parallel = options.parallel
+				configuration.Spec.Parallel = &options.parallel
 			}
 			if flagutils.IsSet(flags, "repeat-count") {
 				configuration.Spec.RepeatCount = &options.repeatCount
@@ -120,16 +120,18 @@ func Command() *cobra.Command {
 			fmt.Fprintf(out, "- TestDirs %v\n", configuration.Spec.TestDirs)
 			fmt.Fprintf(out, "- SkipDelete %v\n", configuration.Spec.SkipDelete)
 			fmt.Fprintf(out, "- FailFast %v\n", configuration.Spec.FailFast)
-			fmt.Fprintf(out, "- Parallel %v\n", configuration.Spec.Parallel)
-			if configuration.Spec.RepeatCount != nil {
-				fmt.Fprintf(out, "- RepeatCount %v\n", *configuration.Spec.RepeatCount)
-			}
 			fmt.Fprintf(out, "- ReportFormat '%v'\n", configuration.Spec.ReportFormat)
 			fmt.Fprintf(out, "- ReportName '%v'\n", configuration.Spec.ReportName)
 			fmt.Fprintf(out, "- Namespace '%v'\n", configuration.Spec.Namespace)
 			fmt.Fprintf(out, "- FullName %v\n", configuration.Spec.FullName)
 			fmt.Fprintf(out, "- IncludeTestRegex '%v'\n", configuration.Spec.IncludeTestRegex)
 			fmt.Fprintf(out, "- ExcludeTestRegex '%v'\n", configuration.Spec.ExcludeTestRegex)
+			if configuration.Spec.Parallel != nil && *configuration.Spec.Parallel > 0 {
+				fmt.Fprintf(out, "- Parallel %d\n", *configuration.Spec.Parallel)
+			}
+			if configuration.Spec.RepeatCount != nil {
+				fmt.Fprintf(out, "- RepeatCount %v\n", *configuration.Spec.RepeatCount)
+			}
 			// loading tests
 			fmt.Fprintln(out, "Loading tests...")
 			tests, err := discovery.DiscoverTests("chainsaw-test.yaml", configuration.Spec.TestDirs...)
@@ -168,7 +170,7 @@ func Command() *cobra.Command {
 	cmd.Flags().StringArrayVar(&options.testDirs, "test-dir", []string{}, "Directories containing test cases to run.")
 	cmd.Flags().BoolVar(&options.skipDelete, "skip-delete", false, "If set, do not delete the resources after running the tests.")
 	cmd.Flags().BoolVar(&options.failFast, "stop-on-first-failure", false, "Stop the test upon encountering the first failure.")
-	cmd.Flags().IntVar(&options.parallel, "parallel", 8, "The maximum number of tests to run at once.")
+	cmd.Flags().IntVar(&options.parallel, "parallel", 0, "The maximum number of tests to run at once.")
 	cmd.Flags().IntVar(&options.repeatCount, "repeat-count", 1, "Number of times to repeat each test.")
 	cmd.Flags().StringVar(&options.reportFormat, "report-format", "", "Test report format (JSON|XML|nil).")
 	cmd.Flags().StringVar(&options.reportName, "report-name", "chainsaw-report", "The name of the report to create.")
diff --git a/pkg/config/load_test.go b/pkg/config/load_test.go
index 2bfcd7b2..e924a3a8 100644
--- a/pkg/config/load_test.go
+++ b/pkg/config/load_test.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/kyverno/chainsaw/pkg/apis/v1alpha1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/utils/ptr"
 )
 
 func TestLoad(t *testing.T) {
@@ -48,7 +49,6 @@ func TestLoad(t *testing.T) {
 					},
 					SkipDelete:       false,
 					FailFast:         false,
-					Parallel:         8,
 					ReportFormat:     "",
 					ReportName:       "chainsaw-report",
 					FullName:         false,
@@ -74,7 +74,7 @@ func TestLoad(t *testing.T) {
 					},
 					SkipDelete:       true,
 					FailFast:         true,
-					Parallel:         4,
+					Parallel:         ptr.To(4),
 					ReportFormat:     "JSON",
 					ReportName:       "custom-report",
 					FullName:         true,
diff --git a/testdata/commands/test/config_all_fields.txt b/testdata/commands/test/config_all_fields.txt
index 02d2972f..b0ffbc65 100644
--- a/testdata/commands/test/config_all_fields.txt
+++ b/testdata/commands/test/config_all_fields.txt
@@ -3,13 +3,13 @@ Loading config (../../../testdata/commands/test/config/config_all_fields.yaml)..
 - TestDirs [/path/to/testdir1 /path/to/testdir2]
 - SkipDelete true
 - FailFast true
-- Parallel 5
 - ReportFormat 'JSON'
 - ReportName 'custom-chainsaw-report'
 - Namespace 'test-namespace'
 - FullName true
 - IncludeTestRegex '^include-.*'
 - ExcludeTestRegex '^exclude-.*'
+- Parallel 5
 Loading tests...
 Running tests...
 Tests Summary...
diff --git a/testdata/commands/test/default.txt b/testdata/commands/test/default.txt
index cef1f433..b4d40a02 100644
--- a/testdata/commands/test/default.txt
+++ b/testdata/commands/test/default.txt
@@ -3,7 +3,6 @@ Loading default configuration...
 - TestDirs []
 - SkipDelete false
 - FailFast false
-- Parallel 8
 - ReportFormat ''
 - ReportName 'chainsaw-report'
 - Namespace ''
diff --git a/testdata/commands/test/with_regex.txt b/testdata/commands/test/with_regex.txt
index 9e9143d9..74992370 100644
--- a/testdata/commands/test/with_regex.txt
+++ b/testdata/commands/test/with_regex.txt
@@ -3,7 +3,6 @@ Loading default configuration...
 - TestDirs []
 - SkipDelete false
 - FailFast false
-- Parallel 8
 - ReportFormat ''
 - ReportName 'chainsaw-report'
 - Namespace ''
diff --git a/testdata/commands/test/with_repeat_count.txt b/testdata/commands/test/with_repeat_count.txt
index d8c93fa1..e4456e8f 100644
--- a/testdata/commands/test/with_repeat_count.txt
+++ b/testdata/commands/test/with_repeat_count.txt
@@ -3,14 +3,13 @@ Loading default configuration...
 - TestDirs []
 - SkipDelete false
 - FailFast false
-- Parallel 8
-- RepeatCount 3
 - ReportFormat ''
 - ReportName 'chainsaw-report'
 - Namespace ''
 - FullName false
 - IncludeTestRegex ''
 - ExcludeTestRegex ''
+- RepeatCount 3
 Loading tests...
 Running tests...
 Tests Summary...
diff --git a/testdata/commands/test/with_suppress.txt b/testdata/commands/test/with_suppress.txt
index cef1f433..b4d40a02 100644
--- a/testdata/commands/test/with_suppress.txt
+++ b/testdata/commands/test/with_suppress.txt
@@ -3,7 +3,6 @@ Loading default configuration...
 - TestDirs []
 - SkipDelete false
 - FailFast false
-- Parallel 8
 - ReportFormat ''
 - ReportName 'chainsaw-report'
 - Namespace ''
diff --git a/testdata/commands/test/with_test_dirs.txt b/testdata/commands/test/with_test_dirs.txt
index 4aa17c38..df915a1b 100644
--- a/testdata/commands/test/with_test_dirs.txt
+++ b/testdata/commands/test/with_test_dirs.txt
@@ -3,7 +3,6 @@ Loading default configuration...
 - TestDirs [dir1,dir2,dir3]
 - SkipDelete false
 - FailFast false
-- Parallel 8
 - ReportFormat ''
 - ReportName 'chainsaw-report'
 - Namespace ''
diff --git a/testdata/commands/test/with_timeout.txt b/testdata/commands/test/with_timeout.txt
index 64c38ad7..c89d9e1d 100644
--- a/testdata/commands/test/with_timeout.txt
+++ b/testdata/commands/test/with_timeout.txt
@@ -3,7 +3,6 @@ Loading default configuration...
 - TestDirs []
 - SkipDelete false
 - FailFast false
-- Parallel 8
 - ReportFormat ''
 - ReportName 'chainsaw-report'
 - Namespace ''
diff --git a/website/docs/commands/chainsaw_test.md b/website/docs/commands/chainsaw_test.md
index 8d87cc14..4cfa9813 100644
--- a/website/docs/commands/chainsaw_test.md
+++ b/website/docs/commands/chainsaw_test.md
@@ -35,7 +35,7 @@ chainsaw test [flags]... [test directories]...
       --kube-username string                Username for basic authentication to the API server
       --namespace string                    Namespace to use for tests.
       --no-color                            Removes output colors.
-      --parallel int                        The maximum number of tests to run at once. (default 8)
+      --parallel int                        The maximum number of tests to run at once.
       --repeat-count int                    Number of times to repeat each test. (default 1)
       --report-format string                Test report format (JSON|XML|nil).
       --report-name string                  The name of the report to create. (default "chainsaw-report")