From 81a0b34c2834701c1842daa02e5c58886897e2fd Mon Sep 17 00:00:00 2001
From: Benedikt Bongartz <bongartz@klimlive.de>
Date: Thu, 5 Oct 2023 09:22:23 +0200
Subject: [PATCH] otelcol: carry factory func instead of object in settings

Signed-off-by: Benedikt Bongartz <bongartz@klimlive.de>
---
 .../internal/builder/templates/main.go.tmpl   | 11 +---
 cmd/otelcorecol/main.go                       | 11 +---
 otelcol/collector.go                          | 24 ++++---
 otelcol/collector_test.go                     | 64 ++++---------------
 otelcol/collector_windows_test.go             |  6 +-
 otelcol/command.go                            | 14 ----
 otelcol/command_components.go                 | 53 ++++++++-------
 otelcol/command_components_test.go            |  5 +-
 otelcol/command_test.go                       | 10 +--
 otelcol/command_validate_test.go              | 12 +---
 otelcol/flags.go                              |  8 +--
 11 files changed, 69 insertions(+), 149 deletions(-)

diff --git a/cmd/builder/internal/builder/templates/main.go.tmpl b/cmd/builder/internal/builder/templates/main.go.tmpl
index bc73cc5582be..64a81295bcbc 100644
--- a/cmd/builder/internal/builder/templates/main.go.tmpl
+++ b/cmd/builder/internal/builder/templates/main.go.tmpl
@@ -11,22 +11,13 @@ import (
 )
 
 func main() {
-	if err := otelcol.NewCommandFeatureGate().Execute(); err != nil {
-		log.Fatalf("failed to validate featuregates: %v", err)
-	}
-
-	factories, err := components()
-	if err != nil {
-		log.Fatalf("failed to build components: %v", err)
-	}
-
 	info := component.BuildInfo{
 		Command:     "{{ .Distribution.Name }}",
 		Description: "{{ .Distribution.Description }}",
 		Version:     "{{ .Distribution.Version }}",
 	}
 
-	if err := run(otelcol.CollectorSettings{BuildInfo: info, Factories: factories}); err != nil {
+	if err := run(otelcol.CollectorSettings{BuildInfo: info, Factories: components}); err != nil {
 		log.Fatal(err)
 	}
 }
diff --git a/cmd/otelcorecol/main.go b/cmd/otelcorecol/main.go
index f58f5779fa60..154adfddeeb1 100644
--- a/cmd/otelcorecol/main.go
+++ b/cmd/otelcorecol/main.go
@@ -11,22 +11,13 @@ import (
 )
 
 func main() {
-	if err := otelcol.NewCommandFeatureGate().Execute(); err != nil {
-		log.Fatalf("failed to validate featuregates: %v", err)
-	}
-
-	factories, err := components()
-	if err != nil {
-		log.Fatalf("failed to build components: %v", err)
-	}
-
 	info := component.BuildInfo{
 		Command:     "otelcorecol",
 		Description: "Local OpenTelemetry Collector binary, testing only.",
 		Version:     "0.86.0-dev",
 	}
 
-	if err := run(otelcol.CollectorSettings{BuildInfo: info, Factories: factories}); err != nil {
+	if err := run(otelcol.CollectorSettings{BuildInfo: info, Factories: components}); err != nil {
 		log.Fatal(err)
 	}
 }
diff --git a/otelcol/collector.go b/otelcol/collector.go
index 557ff6f18aaf..1e369bdaad31 100644
--- a/otelcol/collector.go
+++ b/otelcol/collector.go
@@ -55,7 +55,7 @@ func (s State) String() string {
 // CollectorSettings holds configuration for creating a new Collector.
 type CollectorSettings struct {
 	// Factories service factories.
-	Factories Factories
+	Factories func() (Factories, error)
 
 	// BuildInfo provides collector start information.
 	BuildInfo component.BuildInfo
@@ -155,7 +155,11 @@ func (col *Collector) setupConfigurationComponents(ctx context.Context) error {
 		}
 	}
 
-	cfg, err := col.set.ConfigProvider.Get(ctx, col.set.Factories)
+	factories, err := col.set.Factories()
+	if err != nil {
+		return fmt.Errorf("failed to initialize factories: %w", err)
+	}
+	cfg, err := col.set.ConfigProvider.Get(ctx, factories)
 	if err != nil {
 		return fmt.Errorf("failed to get config: %w", err)
 	}
@@ -167,11 +171,11 @@ func (col *Collector) setupConfigurationComponents(ctx context.Context) error {
 	col.service, err = service.New(ctx, service.Settings{
 		BuildInfo:         col.set.BuildInfo,
 		CollectorConf:     conf,
-		Receivers:         receiver.NewBuilder(cfg.Receivers, col.set.Factories.Receivers),
-		Processors:        processor.NewBuilder(cfg.Processors, col.set.Factories.Processors),
-		Exporters:         exporter.NewBuilder(cfg.Exporters, col.set.Factories.Exporters),
-		Connectors:        connector.NewBuilder(cfg.Connectors, col.set.Factories.Connectors),
-		Extensions:        extension.NewBuilder(cfg.Extensions, col.set.Factories.Extensions),
+		Receivers:         receiver.NewBuilder(cfg.Receivers, factories.Receivers),
+		Processors:        processor.NewBuilder(cfg.Processors, factories.Processors),
+		Exporters:         exporter.NewBuilder(cfg.Exporters, factories.Exporters),
+		Connectors:        connector.NewBuilder(cfg.Connectors, factories.Connectors),
+		Extensions:        extension.NewBuilder(cfg.Extensions, factories.Extensions),
 		AsyncErrorChannel: col.asyncErrorChannel,
 		LoggingOptions:    col.set.LoggingOptions,
 	}, cfg.Service)
@@ -207,7 +211,11 @@ func (col *Collector) reloadConfiguration(ctx context.Context) error {
 }
 
 func (col *Collector) DryRun(ctx context.Context) error {
-	cfg, err := col.set.ConfigProvider.Get(ctx, col.set.Factories)
+	factories, err := col.set.Factories()
+	if err != nil {
+		return fmt.Errorf("failed to initialize factories: %w", err)
+	}
+	cfg, err := col.set.ConfigProvider.Get(ctx, factories)
 	if err != nil {
 		return fmt.Errorf("failed to get config: %w", err)
 	}
diff --git a/otelcol/collector_test.go b/otelcol/collector_test.go
index 1a0ad8d06078..d2fca3cce8fc 100644
--- a/otelcol/collector_test.go
+++ b/otelcol/collector_test.go
@@ -30,15 +30,12 @@ func TestStateString(t *testing.T) {
 }
 
 func TestCollectorStartAsGoRoutine(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	col, err := NewCollector(set)
@@ -57,15 +54,12 @@ func TestCollectorStartAsGoRoutine(t *testing.T) {
 }
 
 func TestCollectorCancelContext(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	col, err := NewCollector(set)
@@ -93,16 +87,13 @@ func (p mockCfgProvider) Watch() <-chan error {
 }
 
 func TestCollectorStateAfterConfigChange(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	provider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	watcher := make(chan error, 1)
 	col, err := NewCollector(CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: &mockCfgProvider{ConfigProvider: provider, watcher: watcher},
 	})
 	require.NoError(t, err)
@@ -126,15 +117,12 @@ func TestCollectorStateAfterConfigChange(t *testing.T) {
 }
 
 func TestCollectorReportError(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	col, err := NewCollector(CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	})
 	require.NoError(t, err)
@@ -152,15 +140,12 @@ func TestCollectorReportError(t *testing.T) {
 }
 
 func TestCollectorSendSignal(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	col, err := NewCollector(CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	})
 	require.NoError(t, err)
@@ -185,15 +170,13 @@ func TestCollectorSendSignal(t *testing.T) {
 
 func TestCollectorFailedShutdown(t *testing.T) {
 	t.Skip("This test was using telemetry shutdown failure, switch to use a component that errors on shutdown.")
-	factories, err := nopFactories()
-	require.NoError(t, err)
 
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	col, err := NewCollector(CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	})
 	require.NoError(t, err)
@@ -216,15 +199,12 @@ func TestCollectorFailedShutdown(t *testing.T) {
 }
 
 func TestCollectorStartInvalidConfig(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid.yaml")}))
 	require.NoError(t, err)
 
 	col, err := NewCollector(CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	})
 	require.NoError(t, err)
@@ -243,15 +223,12 @@ func TestCollectorStartWithTraceContextPropagation(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.file, func(t *testing.T) {
-			factories, err := nopFactories()
-			require.NoError(t, err)
-
 			cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", tt.file)}))
 			require.NoError(t, err)
 
 			set := CollectorSettings{
 				BuildInfo:      component.NewDefaultBuildInfo(),
-				Factories:      factories,
+				Factories:      nopFactories,
 				ConfigProvider: cfgProvider,
 			}
 
@@ -281,15 +258,12 @@ func TestCollectorRun(t *testing.T) {
 
 	for _, tt := range tests {
 		t.Run(tt.file, func(t *testing.T) {
-			factories, err := nopFactories()
-			require.NoError(t, err)
-
 			cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", tt.file)}))
 			require.NoError(t, err)
 
 			set := CollectorSettings{
 				BuildInfo:      component.NewDefaultBuildInfo(),
-				Factories:      factories,
+				Factories:      nopFactories,
 				ConfigProvider: cfgProvider,
 			}
 			col, err := NewCollector(set)
@@ -305,15 +279,12 @@ func TestCollectorRun(t *testing.T) {
 }
 
 func TestCollectorShutdownBeforeRun(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	col, err := NewCollector(set)
@@ -330,16 +301,13 @@ func TestCollectorShutdownBeforeRun(t *testing.T) {
 }
 
 func TestCollectorClosedStateOnStartUpError(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid.yaml")}))
 	require.NoError(t, err)
 
 	// Load a bad config causing startup to fail
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	col, err := NewCollector(set)
@@ -353,16 +321,13 @@ func TestCollectorClosedStateOnStartUpError(t *testing.T) {
 }
 
 func TestCollectorDryRun(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-invalid.yaml")}))
 	require.NoError(t, err)
 
 	// Load a bad config causing startup to fail
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	col, err := NewCollector(set)
@@ -372,9 +337,6 @@ func TestCollectorDryRun(t *testing.T) {
 }
 
 func TestPassConfmapToServiceFailure(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(ConfigProviderSettings{
 		ResolverSettings: confmap.ResolverSettings{
 			URIs:       []string{filepath.Join("testdata", "otelcol-invalid.yaml")},
@@ -386,7 +348,7 @@ func TestPassConfmapToServiceFailure(t *testing.T) {
 
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	col, err := NewCollector(set)
diff --git a/otelcol/collector_windows_test.go b/otelcol/collector_windows_test.go
index fb12df6d11b1..a9aaf6bf9221 100644
--- a/otelcol/collector_windows_test.go
+++ b/otelcol/collector_windows_test.go
@@ -12,7 +12,6 @@ import (
 	"testing"
 
 	"github.com/stretchr/testify/assert"
-	"github.com/stretchr/testify/require"
 	"golang.org/x/sys/windows/svc"
 
 	"go.opentelemetry.io/collector/component"
@@ -23,10 +22,7 @@ func TestNewSvcHandler(t *testing.T) {
 	defer func() { os.Args = oldArgs }()
 	os.Args = []string{"otelcol", "--config", filepath.Join("testdata", "otelcol-nop.yaml")}
 
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
-	s := NewSvcHandler(CollectorSettings{BuildInfo: component.NewDefaultBuildInfo(), Factories: factories})
+	s := NewSvcHandler(CollectorSettings{BuildInfo: component.NewDefaultBuildInfo(), Factories: nopFactories})
 
 	colDone := make(chan struct{})
 	requests := make(chan svc.ChangeRequest)
diff --git a/otelcol/command.go b/otelcol/command.go
index fed69df2d18f..a9baff305f31 100644
--- a/otelcol/command.go
+++ b/otelcol/command.go
@@ -12,20 +12,6 @@ import (
 	"go.opentelemetry.io/collector/featuregate"
 )
 
-// NewCommandFeatureGate constructs a new cobra.Command used to parse given FeatureGates.
-func NewCommandFeatureGate() *cobra.Command {
-	flagSet := new(flag.FlagSet)
-	flagFeatureGate(flagSet, featuregate.GlobalRegistry())
-	rootCmd := &cobra.Command{
-		SilenceUsage: true,
-		FParseErrWhitelist: cobra.FParseErrWhitelist{
-			UnknownFlags: true,
-		},
-	}
-	rootCmd.Flags().AddGoFlagSet(flagSet)
-	return rootCmd
-}
-
 // NewCommand constructs a new cobra.Command using the given CollectorSettings.
 func NewCommand(set CollectorSettings) *cobra.Command {
 	flagSet := flags(featuregate.GlobalRegistry())
diff --git a/otelcol/command_components.go b/otelcol/command_components.go
index f63fce8e55f0..4bf18103d05d 100644
--- a/otelcol/command_components.go
+++ b/otelcol/command_components.go
@@ -35,60 +35,65 @@ func newComponentsCommand(set CollectorSettings) *cobra.Command {
 		Args:  cobra.ExactArgs(0),
 		RunE: func(cmd *cobra.Command, args []string) error {
 
+			factories, err := set.Factories()
+			if err != nil {
+				return fmt.Errorf("failed to initialize factories: %w", err)
+			}
+
 			components := componentsOutput{}
-			for con := range set.Factories.Connectors {
+			for con := range factories.Connectors {
 				components.Connectors = append(components.Connectors, componentWithStability{
 					Name: con,
 					Stability: map[string]string{
-						"logs-to-logs":    set.Factories.Connectors[con].LogsToLogsStability().String(),
-						"logs-to-metrics": set.Factories.Connectors[con].LogsToMetricsStability().String(),
-						"logs-to-traces":  set.Factories.Connectors[con].LogsToTracesStability().String(),
+						"logs-to-logs":    factories.Connectors[con].LogsToLogsStability().String(),
+						"logs-to-metrics": factories.Connectors[con].LogsToMetricsStability().String(),
+						"logs-to-traces":  factories.Connectors[con].LogsToTracesStability().String(),
 
-						"metrics-to-logs":    set.Factories.Connectors[con].MetricsToLogsStability().String(),
-						"metrics-to-metrics": set.Factories.Connectors[con].MetricsToMetricsStability().String(),
-						"metrics-to-traces":  set.Factories.Connectors[con].MetricsToTracesStability().String(),
+						"metrics-to-logs":    factories.Connectors[con].MetricsToLogsStability().String(),
+						"metrics-to-metrics": factories.Connectors[con].MetricsToMetricsStability().String(),
+						"metrics-to-traces":  factories.Connectors[con].MetricsToTracesStability().String(),
 
-						"traces-to-logs":    set.Factories.Connectors[con].TracesToLogsStability().String(),
-						"traces-to-metrics": set.Factories.Connectors[con].TracesToMetricsStability().String(),
-						"traces-to-traces":  set.Factories.Connectors[con].TracesToTracesStability().String(),
+						"traces-to-logs":    factories.Connectors[con].TracesToLogsStability().String(),
+						"traces-to-metrics": factories.Connectors[con].TracesToMetricsStability().String(),
+						"traces-to-traces":  factories.Connectors[con].TracesToTracesStability().String(),
 					},
 				})
 			}
-			for ext := range set.Factories.Extensions {
+			for ext := range factories.Extensions {
 				components.Extensions = append(components.Extensions, componentWithStability{
 					Name: ext,
 					Stability: map[string]string{
-						"extension": set.Factories.Extensions[ext].ExtensionStability().String(),
+						"extension": factories.Extensions[ext].ExtensionStability().String(),
 					},
 				})
 			}
-			for prs := range set.Factories.Processors {
+			for prs := range factories.Processors {
 				components.Processors = append(components.Processors, componentWithStability{
 					Name: prs,
 					Stability: map[string]string{
-						"logs":    set.Factories.Processors[prs].LogsProcessorStability().String(),
-						"metrics": set.Factories.Processors[prs].MetricsProcessorStability().String(),
-						"traces":  set.Factories.Processors[prs].TracesProcessorStability().String(),
+						"logs":    factories.Processors[prs].LogsProcessorStability().String(),
+						"metrics": factories.Processors[prs].MetricsProcessorStability().String(),
+						"traces":  factories.Processors[prs].TracesProcessorStability().String(),
 					},
 				})
 			}
-			for rcv := range set.Factories.Receivers {
+			for rcv := range factories.Receivers {
 				components.Receivers = append(components.Receivers, componentWithStability{
 					Name: rcv,
 					Stability: map[string]string{
-						"logs":    set.Factories.Receivers[rcv].LogsReceiverStability().String(),
-						"metrics": set.Factories.Receivers[rcv].MetricsReceiverStability().String(),
-						"traces":  set.Factories.Receivers[rcv].TracesReceiverStability().String(),
+						"logs":    factories.Receivers[rcv].LogsReceiverStability().String(),
+						"metrics": factories.Receivers[rcv].MetricsReceiverStability().String(),
+						"traces":  factories.Receivers[rcv].TracesReceiverStability().String(),
 					},
 				})
 			}
-			for exp := range set.Factories.Exporters {
+			for exp := range factories.Exporters {
 				components.Exporters = append(components.Exporters, componentWithStability{
 					Name: exp,
 					Stability: map[string]string{
-						"logs":    set.Factories.Exporters[exp].LogsExporterStability().String(),
-						"metrics": set.Factories.Exporters[exp].MetricsExporterStability().String(),
-						"traces":  set.Factories.Exporters[exp].TracesExporterStability().String(),
+						"logs":    factories.Exporters[exp].LogsExporterStability().String(),
+						"metrics": factories.Exporters[exp].MetricsExporterStability().String(),
+						"traces":  factories.Exporters[exp].TracesExporterStability().String(),
 					},
 				})
 			}
diff --git a/otelcol/command_components_test.go b/otelcol/command_components_test.go
index b143023eb5c9..3fe9a2cdd51e 100644
--- a/otelcol/command_components_test.go
+++ b/otelcol/command_components_test.go
@@ -17,15 +17,12 @@ import (
 )
 
 func TestNewBuildSubCommand(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(newDefaultConfigProviderSettings([]string{filepath.Join("testdata", "otelcol-nop.yaml")}))
 	require.NoError(t, err)
 
 	set := CollectorSettings{
 		BuildInfo:      component.NewDefaultBuildInfo(),
-		Factories:      factories,
+		Factories:      nopFactories,
 		ConfigProvider: cfgProvider,
 	}
 	cmd := NewCommand(set)
diff --git a/otelcol/command_test.go b/otelcol/command_test.go
index fdf2885dc1ec..ef9220494700 100644
--- a/otelcol/command_test.go
+++ b/otelcol/command_test.go
@@ -22,17 +22,11 @@ func TestNewCommandVersion(t *testing.T) {
 }
 
 func TestNewCommandNoConfigURI(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
-	cmd := NewCommand(CollectorSettings{Factories: factories})
+	cmd := NewCommand(CollectorSettings{Factories: nopFactories})
 	require.Error(t, cmd.Execute())
 }
 
 func TestNewCommandInvalidComponent(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(
 		ConfigProviderSettings{
 			ResolverSettings: confmap.ResolverSettings{
@@ -43,6 +37,6 @@ func TestNewCommandInvalidComponent(t *testing.T) {
 		})
 	require.NoError(t, err)
 
-	cmd := NewCommand(CollectorSettings{Factories: factories, ConfigProvider: cfgProvider})
+	cmd := NewCommand(CollectorSettings{Factories: nopFactories, ConfigProvider: cfgProvider})
 	require.Error(t, cmd.Execute())
 }
diff --git a/otelcol/command_validate_test.go b/otelcol/command_validate_test.go
index 4511eb730979..ffc47b5d71f1 100644
--- a/otelcol/command_validate_test.go
+++ b/otelcol/command_validate_test.go
@@ -16,19 +16,13 @@ import (
 )
 
 func TestValidateSubCommandNoConfig(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
-	cmd := newValidateSubCommand(CollectorSettings{Factories: factories}, flags(featuregate.GlobalRegistry()))
-	err = cmd.Execute()
+	cmd := newValidateSubCommand(CollectorSettings{Factories: nopFactories}, flags(featuregate.GlobalRegistry()))
+	err := cmd.Execute()
 	require.Error(t, err)
 	require.Contains(t, err.Error(), "at least one config flag must be provided")
 }
 
 func TestValidateSubCommandInvalidComponents(t *testing.T) {
-	factories, err := nopFactories()
-	require.NoError(t, err)
-
 	cfgProvider, err := NewConfigProvider(
 		ConfigProviderSettings{
 			ResolverSettings: confmap.ResolverSettings{
@@ -39,7 +33,7 @@ func TestValidateSubCommandInvalidComponents(t *testing.T) {
 		})
 	require.NoError(t, err)
 
-	cmd := newValidateSubCommand(CollectorSettings{Factories: factories, ConfigProvider: cfgProvider}, flags(featuregate.GlobalRegistry()))
+	cmd := newValidateSubCommand(CollectorSettings{Factories: nopFactories, ConfigProvider: cfgProvider}, flags(featuregate.GlobalRegistry()))
 	err = cmd.Execute()
 	require.Error(t, err)
 	require.Contains(t, err.Error(), "unknown type: \"nosuchprocessor\"")
diff --git a/otelcol/flags.go b/otelcol/flags.go
index c41467ebf48f..a2d0885f53e6 100644
--- a/otelcol/flags.go
+++ b/otelcol/flags.go
@@ -50,14 +50,10 @@ func flags(reg *featuregate.Registry) *flag.FlagSet {
 			return nil
 		})
 
-	flagFeatureGate(flagSet, reg)
-
-	return flagSet
-}
-
-func flagFeatureGate(flagSet *flag.FlagSet, reg *featuregate.Registry) {
 	flagSet.Var(featuregate.NewFlag(reg), featureGatesFlag,
 		"Comma-delimited list of feature gate identifiers. Prefix with '-' to disable the feature. '+' or no prefix will enable the feature.")
+
+	return flagSet
 }
 
 func getConfigFlag(flagSet *flag.FlagSet) []string {