Repository: rancher/fleet
Pull request #2361 (2024-04-23 12:59:27)

Merge binaries
<!-- Specify the issue ID that this pull request is solving -->
Refers to #2342 



This is a follow up to previous redesigns.


Patch:
diff --git a/.github/scripts/build-fleet-binaries.sh b/.github/scripts/build-fleet-binaries.sh
index a4158c74..4b914f23 100755
--- a/.github/scripts/build-fleet-binaries.sh
+++ b/.github/scripts/build-fleet-binaries.sh
@@ -13,7 +13,3 @@ go build -gcflags='all=-N -l' -o bin/fleetcontroller-linux-"$GOARCH" ./cmd/fleet
 # fleet agent
 go build -gcflags='all=-N -l' -o "bin/fleet-linux-$GOARCH" ./cmd/fleetcli
 go build -gcflags='all=-N -l' -o "bin/fleetagent-linux-$GOARCH" ./cmd/fleetagent
-
-# gitjob
-go build -gcflags='all=-N -l' -o "bin/gitcloner-linux-$GOARCH" ./cmd/gitcloner
-go build -gcflags='all=-N -l' -o "bin/gitjob-linux-$GOARCH" ./cmd/gitjob
diff --git a/.goreleaser.yml b/.goreleaser.yml
index 836632dc..e8109875 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -20,18 +20,6 @@ archives:
     builds:
       - fleet-agent
 
-  - id: fleet-gitcloner
-    format: binary
-    name_template: "{{ .Binary }}"
-    builds:
-      - fleet-gitcloner
-
-  - id: fleet-gitjob
-    format: binary
-    name_template: "{{ .Binary }}"
-    builds:
-      - fleet-gitjob
-
   - id: fleet-cli
     format: binary
     name_template: "{{ .Binary }}"
@@ -66,30 +54,6 @@ builds:
     - linux_amd64_v1
     - linux_arm64
     - windows_amd64
-  -
-    id: fleet-gitcloner
-    main: ./cmd/gitcloner
-    binary: gitcloner-{{ .Os }}-{{ .Arch }}{{ if .Arm }}64{{ end }}
-    no_unique_dist_dir: true
-    ldflags:
-      - -w -s
-      - -X github.com/rancher/fleet/pkg/version.GitCommit={{ .Commit }}
-      - -X github.com/rancher/fleet/pkg/version.Version={{ .Tag }}
-    targets:
-    - linux_amd64_v1
-    - linux_arm64
-  -
-    id: fleet-gitjob
-    main: ./cmd/gitjob
-    binary: gitjob-{{ .Os }}-{{ .Arch }}{{ if .Arm }}64{{ end }}
-    no_unique_dist_dir: true
-    ldflags:
-      - -w -s
-      - -X github.com/rancher/fleet/pkg/version.GitCommit={{ .Commit }}
-      - -X github.com/rancher/fleet/pkg/version.Version={{ .Tag }}
-    targets:
-    - linux_amd64_v1
-    - linux_arm64
   -
     id: fleet-cli
     main: ./cmd/fleetcli
@@ -130,8 +94,6 @@ dockers:
     ids:
     - fleet-controller
     - fleet-cli
-    - fleet-gitcloner
-    - fleet-gitjob
 
     # Templates of the Docker image names.
     image_templates:
@@ -159,8 +121,6 @@ dockers:
     ids:
     - fleet-controller
     - fleet-cli
-    - fleet-gitcloner
-    - fleet-gitjob
     image_templates:
     - "docker.io/rancher/fleet:{{ .Tag }}-linux-arm64"
     dockerfile: package/Dockerfile
diff --git a/charts/fleet/templates/deployment_gitjob.yaml b/charts/fleet/templates/deployment_gitjob.yaml
index 699b9997..135a213e 100644
--- a/charts/fleet/templates/deployment_gitjob.yaml
+++ b/charts/fleet/templates/deployment_gitjob.yaml
@@ -17,6 +17,7 @@ spec:
         - image: "{{ template "system_default_registry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag }}"
           name: gitjob
           args:
+          - fleetcontroller
           - gitjob
           - --gitjob-image
           - "{{ template "system_default_registry" . }}{{ .Values.image.repository }}:{{ .Values.image.tag }}"
diff --git a/cmd/gitcloner/main.go b/cmd/gitcloner/main.go
deleted file mode 100644
index 09d48e29..00000000
--- a/cmd/gitcloner/main.go
+++ /dev/null
@@ -1,18 +0,0 @@
-package main
-
-import (
-	"os"
-
-	"github.com/rancher/fleet/cmd/gitcloner/cmd"
-	"github.com/rancher/fleet/cmd/gitcloner/gogit"
-	"github.com/sirupsen/logrus"
-)
-
-func main() {
-	logrus.Info("Starting to clone git repository")
-	cmd := cmd.New(gogit.NewCloner())
-	if err := cmd.Execute(); err != nil {
-		logrus.Errorf("Error cloning repository: %v", err)
-		os.Exit(1)
-	}
-}
diff --git a/dev/build-fleet b/dev/build-fleet
index c8ea1cb5..c5eaa3f2 100755
--- a/dev/build-fleet
+++ b/dev/build-fleet
@@ -17,9 +17,6 @@ if ! git diff --quiet HEAD origin/main --  pkg/apis/fleet.cattle.io/v1alpha1; th
 fi
 
 export GOOS=linux
-# gitjob
-go build -gcflags='all=-N -l' -o "bin/gitcloner-linux-$GOARCH" ./cmd/gitcloner
-go build -gcflags='all=-N -l' -o "bin/gitjob-linux-$GOARCH" ./cmd/gitjob
 
 # fleet
 go build -gcflags='all=-N -l' -o "bin/fleet-linux-$GOARCH" ./cmd/fleetcli
diff --git a/cmd/gitcloner/gogit/cloner.go b/internal/cmd/cli/gitcloner/cloner.go
similarity index 91%
rename from cmd/gitcloner/gogit/cloner.go
rename to internal/cmd/cli/gitcloner/cloner.go
index ffe471eb..511c5e32 100644
--- a/cmd/gitcloner/gogit/cloner.go
+++ b/internal/cmd/cli/gitcloner/cloner.go
@@ -1,11 +1,9 @@
-package gogit
+package gitcloner
 
 import (
 	"fmt"
 	"os"
 
-	"github.com/rancher/fleet/cmd/gitcloner/cmd"
-
 	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
@@ -35,11 +33,11 @@ type Options struct {
 	CABundle        []byte
 }
 
-func NewCloner() *Cloner {
+func New() *Cloner {
 	return &Cloner{}
 }
 
-func (c *Cloner) CloneRepo(opts *cmd.Options) error {
+func (c *Cloner) CloneRepo(opts *GitCloner) error {
 	// Azure DevOps requires capabilities multi_ack / multi_ack_detailed,
 	// which are not fully implemented and by default are included in
 	// transport.UnsupportedCapabilities.
@@ -73,7 +71,7 @@ func (c *Cloner) CloneRepo(opts *cmd.Options) error {
 	return cloneRevision(opts, auth, caBundle)
 }
 
-func cloneBranch(opts *cmd.Options, auth transport.AuthMethod, caBundle []byte) error {
+func cloneBranch(opts *GitCloner, auth transport.AuthMethod, caBundle []byte) error {
 	_, err := plainClone(opts.Path, false, &git.CloneOptions{
 		URL:             opts.Repo,
 		Auth:            auth,
@@ -86,7 +84,7 @@ func cloneBranch(opts *cmd.Options, auth transport.AuthMethod, caBundle []byte)
 	return err
 }
 
-func cloneRevision(opts *cmd.Options, auth transport.AuthMethod, caBundle []byte) error {
+func cloneRevision(opts *GitCloner, auth transport.AuthMethod, caBundle []byte) error {
 	r, err := plainClone(opts.Path, false, &git.CloneOptions{
 		URL:             opts.Repo,
 		Auth:            auth,
@@ -118,7 +116,7 @@ func getCABundleFromFile(path string) ([]byte, error) {
 }
 
 // createAuthFromOpts adds auth for cloning git repos based on the parameters provided in opts.
-func createAuthFromOpts(opts *cmd.Options) (transport.AuthMethod, error) {
+func createAuthFromOpts(opts *GitCloner) (transport.AuthMethod, error) {
 	if opts.SSHPrivateKeyFile != "" {
 		privateKey, err := readFile(opts.SSHPrivateKeyFile)
 		if err != nil {
diff --git a/cmd/gitcloner/cmd/cmd.go b/internal/cmd/cli/gitcloner/cmd.go
similarity index 87%
rename from cmd/gitcloner/cmd/cmd.go
rename to internal/cmd/cli/gitcloner/cmd.go
index 4a51fbf5..2d219faf 100644
--- a/cmd/gitcloner/cmd/cmd.go
+++ b/internal/cmd/cli/gitcloner/cmd.go
@@ -1,14 +1,14 @@
-package cmd
+package gitcloner
 
 import (
 	"github.com/spf13/cobra"
 )
 
-type GitCloner interface {
-	CloneRepo(opts *Options) error
+type CloneGit interface {
+	CloneRepo(opts *GitCloner) error
 }
 
-type Options struct {
+type GitCloner struct {
 	Repo              string
 	Path              string
 	Branch            string
@@ -21,9 +21,9 @@ type Options struct {
 	KnownHostsFile    string
 }
 
-var opts *Options
+var opts *GitCloner
 
-func New(gitCloner GitCloner) *cobra.Command {
+func NewCmd(gitCloner CloneGit) *cobra.Command {
 	cmd := &cobra.Command{
 		Use:   "gitcloner [REPO] [PATH]",
 		Short: "Clones a git repository",
@@ -35,7 +35,7 @@ func New(gitCloner GitCloner) *cobra.Command {
 			return gitCloner.CloneRepo(opts)
 		},
 	}
-	opts = &Options{}
+	opts = &GitCloner{}
 	cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "git branch")
 	cmd.Flags().StringVar(&opts.Revision, "revision", "", "git revision")
 	cmd.Flags().StringVar(&opts.CABundleFile, "ca-bundle-file", "", "CA bundle file")
diff --git a/internal/cmd/cli/root.go b/internal/cmd/cli/root.go
index 9c855e47..3c9bb4ea 100644
--- a/internal/cmd/cli/root.go
+++ b/internal/cmd/cli/root.go
@@ -6,6 +6,7 @@ import (
 
 	"github.com/rancher/fleet/internal/client"
 	command "github.com/rancher/fleet/internal/cmd"
+	"github.com/rancher/fleet/internal/cmd/cli/gitcloner"
 	"github.com/rancher/fleet/pkg/version"
 )
 
@@ -32,6 +33,7 @@ func App() *cobra.Command {
 
 		NewTarget(),
 		NewDeploy(),
+		gitcloner.NewCmd(gitcloner.New()),
 	)
 
 	return root
diff --git a/cmd/gitjob/main.go b/internal/cmd/controller/gitops/operator.go
similarity index 55%
rename from cmd/gitjob/main.go
rename to internal/cmd/controller/gitops/operator.go
index 891d52fd..46d89b68 100644
--- a/cmd/gitjob/main.go
+++ b/internal/cmd/controller/gitops/operator.go
@@ -1,19 +1,20 @@
 //go:generate bash ./scripts/controller-gen-generate.sh
 
-package main
+package gitops
 
 import (
 	"context"
-	"flag"
 	"fmt"
 	"net/http"
-	"os"
 	"time"
 
-	controller "github.com/rancher/fleet/internal/cmd/gitjob"
+	command "github.com/rancher/fleet/internal/cmd"
+	"github.com/rancher/fleet/internal/cmd/controller/gitops/reconciler"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	"github.com/rancher/fleet/pkg/git/poll"
+	"github.com/rancher/fleet/pkg/version"
 	"github.com/rancher/fleet/pkg/webhook"
+	"github.com/spf13/cobra"
 
 	"k8s.io/apimachinery/pkg/runtime"
 	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@@ -21,6 +22,7 @@ import (
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/cache"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	clog "sigs.k8s.io/controller-runtime/pkg/log"
 	"sigs.k8s.io/controller-runtime/pkg/log/zap"
 	metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
 
@@ -30,6 +32,7 @@ import (
 var (
 	scheme   = runtime.NewScheme()
 	setupLog = ctrl.Log.WithName("setup")
+	zopts    *zap.Options
 )
 
 func init() {
@@ -37,48 +40,62 @@ func init() {
 	utilruntime.Must(fleet.AddToScheme(scheme))
 }
 
-type flags struct {
-	metricsAddr          string
-	enableLeaderElection bool
-	image                string
-	listen               string
-	debug                bool
+type GitOperator struct {
+	command.DebugConfig
+	Kubeconfig           string `usage:"Kubeconfig file"`
+	Namespace            string `usage:"namespace to watch" default:"cattle-fleet-system" env:"NAMESPACE"`
+	MetricsAddr          string `name:"metrics-bind-address" default:":8081" usage:"The address the metric endpoint binds to."`
+	EnableLeaderElection bool   `name:"leader-elect" default:"true" usage:"Enable leader election for controller manager. Enabling this will ensure there is only one active controller manager."`
+	Image                string `name:"gitjob-image" default:"rancher/fleet:dev" usage:"The gitjob image that will be used in the generated job."`
+	Listen               string `default:":8080" usage:"The port the webhook listens."`
 }
 
-func main() {
-	ctx := ctrl.SetupSignalHandler()
-	if err := run(ctx); err != nil {
-		setupLog.Error(err, "error running gitjob")
-		os.Exit(1)
+func App(zo *zap.Options) *cobra.Command {
+	zopts = zo
+	return command.Command(&GitOperator{}, cobra.Command{
+		Version: version.FriendlyVersion(),
+		Use:     "gitjob",
+	})
+}
+
+func (g *GitOperator) PersistentPre(_ *cobra.Command, _ []string) error {
+	if err := g.SetupDebug(); err != nil {
+		return fmt.Errorf("failed to setup debug logging: %w", err)
 	}
+
+	return nil
 }
 
-func run(ctx context.Context) error {
-	namespace := os.Getenv("NAMESPACE")
-	flags := bindFlags()
+func (g *GitOperator) Run(cmd *cobra.Command, args []string) error {
+	ctx := clog.IntoContext(cmd.Context(), ctrl.Log)
+	// TODO for compatibility, override zap opts with legacy debug opts. remove once manifests are updated.
+	zopts.Development = g.Debug
+	ctrl.SetLogger(zap.New(zap.UseFlagOptions(zopts)))
+
+	namespace := g.Namespace
 	mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
 		Scheme: scheme,
 		Metrics: metricsserver.Options{
-			BindAddress: flags.metricsAddr,
+			BindAddress: g.MetricsAddr,
 		},
-		LeaderElection:          flags.enableLeaderElection,
+		LeaderElection:          g.EnableLeaderElection,
 		LeaderElectionID:        "gitjob-leader",
 		LeaderElectionNamespace: namespace,
 	})
 	if err != nil {
 		return err
 	}
-	reconciler := &controller.GitJobReconciler{
+	reconciler := &reconciler.GitJobReconciler{
 		Client:    mgr.GetClient(),
 		Scheme:    mgr.GetScheme(),
-		Image:     flags.image,
+		Image:     g.Image,
 		GitPoller: poll.NewHandler(ctx, mgr.GetClient()),
 		Log:       ctrl.Log.WithName("gitjob-reconciler"),
 	}
 
 	group := errgroup.Group{}
 	group.Go(func() error {
-		return startWebhook(ctx, namespace, flags.listen, mgr.GetClient(), mgr.GetCache())
+		return startWebhook(ctx, namespace, g.Listen, mgr.GetClient(), mgr.GetCache())
 	})
 	group.Go(func() error {
 		setupLog.Info("starting manager")
@@ -92,40 +109,6 @@ func run(ctx context.Context) error {
 	return group.Wait()
 }
 
-func bindFlags() flags {
-	var metricsAddr string
-	var enableLeaderElection bool
-	var image string
-	var listen string
-	var debug bool
-	flag.StringVar(&metricsAddr, "metrics-bind-address", ":8081", "The address the metric endpoint binds to.")
-	flag.StringVar(
-		&image,
-		"gitjob-image",
-		"rancher/fleet:dev",
-		"The gitjob image that will be used in the generated job.",
-	)
-	flag.StringVar(&listen, "listen", ":8080", "The port the webhook listens.")
-	flag.BoolVar(&enableLeaderElection, "leader-elect", true,
-		"Enable leader election for controller manager. "+
-			"Enabling this will ensure there is only one active controller manager.")
-	flag.BoolVar(&debug, "debug", false, "debug mode.")
-	opts := zap.Options{
-		Development: debug,
-	}
-	opts.BindFlags(flag.CommandLine)
-	ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts)))
-	flag.Parse()
-
-	return flags{
-		metricsAddr:          metricsAddr,
-		enableLeaderElection: enableLeaderElection,
-		image:                image,
-		listen:               listen,
-		debug:                debug,
-	}
-}
-
 func startWebhook(ctx context.Context, namespace string, addr string, client client.Client, cacheClient cache.Cache) error {
 	setupLog.Info("Setting up webhook listener")
 	handler, err := webhook.HandleHooks(ctx, namespace, client, cacheClient)
diff --git a/internal/cmd/gitjob/gitjob.go b/internal/cmd/controller/gitops/reconciler/gitjob_controller.go
similarity index 99%
rename from internal/cmd/gitjob/gitjob.go
rename to internal/cmd/controller/gitops/reconciler/gitjob_controller.go
index 292ae0ce..00d8a32d 100644
--- a/internal/cmd/gitjob/gitjob.go
+++ b/internal/cmd/controller/gitops/reconciler/gitjob_controller.go
@@ -1,4 +1,4 @@
-package gitjob
+package reconciler
 
 import (
 	"context"
@@ -14,9 +14,11 @@ import (
 
 	grutil "github.com/rancher/fleet/internal/cmd/controller/gitrepo"
 	v1alpha1 "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
+
 	"github.com/rancher/wrangler/v2/pkg/condition"
 	"github.com/rancher/wrangler/v2/pkg/kstatus"
 	"github.com/rancher/wrangler/v2/pkg/name"
+
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/api/errors"
@@ -610,7 +612,7 @@ func volumesFromSecret(
 }
 
 func (r *GitJobReconciler) generateInitContainer(ctx context.Context, obj *v1alpha1.GitRepo) (corev1.Container, error) {
-	args := []string{obj.Spec.Repo, "/workspace"}
+	args := []string{"gitcloner", obj.Spec.Repo, "/workspace"}
 	volumeMounts := []corev1.VolumeMount{
 		{
 			Name:      gitClonerVolumeName,
@@ -673,7 +675,7 @@ func (r *GitJobReconciler) generateInitContainer(ctx context.Context, obj *v1alp
 
 	return corev1.Container{
 		Command: []string{
-			"gitcloner",
+			"fleet",
 		},
 		Args:         args,
 		Image:        r.Image,
diff --git a/internal/cmd/controller/root.go b/internal/cmd/controller/root.go
index 2e81d1e8..bb1c19a2 100644
--- a/internal/cmd/controller/root.go
+++ b/internal/cmd/controller/root.go
@@ -15,6 +15,7 @@ import (
 
 	"github.com/rancher/fleet/internal/cmd/controller/agentmanagement"
 	"github.com/rancher/fleet/internal/cmd/controller/agentmanagement/agent"
+	"github.com/rancher/fleet/internal/cmd/controller/gitops"
 
 	"github.com/spf13/cobra"
 
@@ -156,8 +157,11 @@ func App() *cobra.Command {
 	ctrl.RegisterFlags(fs)
 	root.Flags().AddGoFlagSet(fs)
 
-	root.AddCommand(cleanup.App())
-	root.AddCommand(agentmanagement.App())
+	root.AddCommand(
+		cleanup.App(),
+		agentmanagement.App(),
+		gitops.App(&zopts),
+	)
 	return root
 }
 
diff --git a/internal/mocks/client_mock.go b/internal/mocks/client_mock.go
index 4e353f8e..159222f2 100644
--- a/internal/mocks/client_mock.go
+++ b/internal/mocks/client_mock.go
@@ -3,7 +3,7 @@
 //
 // Generated by this command:
 //
-//	mockgen --build_flags=--mod=mod -destination=../../../mocks/client_mock.go -package=mocks sigs.k8s.io/controller-runtime/pkg/client Client,SubResourceWriter
+//	mockgen --build_flags=--mod=mod -destination=../../../../mocks/client_mock.go -package=mocks sigs.k8s.io/controller-runtime/pkg/client Client,SubResourceWriter
 //
 
 // Package mocks is a generated GoMock package.
diff --git a/internal/mocks/poller_mock.go b/internal/mocks/poller_mock.go
index 7ad617b9..6e88fe09 100644
--- a/internal/mocks/poller_mock.go
+++ b/internal/mocks/poller_mock.go
@@ -1,9 +1,9 @@
 // Code generated by MockGen. DO NOT EDIT.
-// Source: github.com/rancher/fleet/internal/cmd/gitjob (interfaces: GitPoller)
+// Source: github.com/rancher/fleet/internal/cmd/controller/gitops/reconciler (interfaces: GitPoller)
 //
 // Generated by this command:
 //
-//	mockgen --build_flags=--mod=mod -destination=../../mocks/poller_mock.go -package=mocks github.com/rancher/fleet/internal/cmd/gitjob GitPoller
+//	mockgen --build_flags=--mod=mod -destination=../../../../mocks/poller_mock.go -package=mocks github.com/rancher/fleet/internal/cmd/controller/gitops/reconciler GitPoller
 //
 
 // Package mocks is a generated GoMock package.
diff --git a/package/Dockerfile b/package/Dockerfile
index 009a650a..d6039647 100644
--- a/package/Dockerfile
+++ b/package/Dockerfile
@@ -11,22 +11,16 @@ FROM base AS copy_dapper
 ONBUILD ARG ARCH
 ONBUILD COPY bin/fleetcontroller-linux-$ARCH /usr/bin/fleetcontroller
 ONBUILD COPY bin/fleet-linux-$ARCH /usr/bin/fleet
-ONBUILD COPY bin/gitjob-linux-$ARCH /usr/bin/gitjob
-ONBUILD COPY bin/gitcloner-linux-$ARCH /usr/bin/gitcloner
 
 FROM base AS copy_buildx
 ONBUILD ARG TARGETARCH
 ONBUILD COPY bin/fleetcontroller-linux-$TARGETARCH /usr/bin/fleetcontroller
 ONBUILD COPY bin/fleet-linux-$TARGETARCH /usr/bin/fleet
-ONBUILD COPY bin/gitjob-linux-$TARGETARCH /usr/bin/gitjob
-ONBUILD COPY bin/gitcloner-linux-$TARGETARCH /usr/bin/gitcloner
 
 FROM base AS copy_goreleaser
 ONBUILD ARG ARCH
 ONBUILD COPY fleetcontroller-linux-$ARCH /usr/bin/fleetcontroller
 ONBUILD COPY fleet-linux-$ARCH /usr/bin/fleet
-ONBUILD COPY gitjob-linux-$ARCH /usr/bin/gitjob
-ONBUILD COPY gitcloner-linux-$ARCH /usr/bin/gitcloner
 
 FROM copy_${BUILD_ENV}
 USER 1000


Test patch:
diff --git a/integrationtests/gitcloner/clone_test.go b/integrationtests/gitcloner/clone_test.go
index a3ee4fcc..592d5f48 100644
--- a/integrationtests/gitcloner/clone_test.go
+++ b/integrationtests/gitcloner/clone_test.go
@@ -14,8 +14,7 @@ import (
 	"strings"
 	"time"
 
-	"github.com/rancher/fleet/cmd/gitcloner/cmd"
-	"github.com/rancher/fleet/cmd/gitcloner/gogit"
+	"github.com/rancher/fleet/internal/cmd/cli/gitcloner"
 
 	dockercontainer "github.com/docker/docker/api/types/container"
 	dockermount "github.com/docker/docker/api/types/mount"
@@ -24,11 +23,12 @@ import (
 	"github.com/go-git/go-git/v5/plumbing/object"
 	httpgit "github.com/go-git/go-git/v5/plumbing/transport/http"
 	"github.com/gogits/go-gogs-client"
-	. "github.com/onsi/ginkgo/v2"
-	. "github.com/onsi/gomega"
 	cp "github.com/otiai10/copy"
 	"github.com/testcontainers/testcontainers-go"
 	"golang.org/x/crypto/ssh"
+
+	. "github.com/onsi/ginkgo/v2"
+	. "github.com/onsi/gomega"
 )
 
 /*
@@ -53,7 +53,7 @@ var (
 var _ = Describe("Applying a git job gets content from git repo", Ordered, func() {
 
 	var (
-		opts          *cmd.Options
+		opts          *gitcloner.GitCloner
 		private       bool
 		cloneErr      error
 		tmp           string
@@ -87,14 +87,14 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 		When("cloning a public repo that contains a README.md file providing a branch", func() {
 			BeforeEach(func() {
 				private = false
-				opts = &cmd.Options{
+				opts = &gitcloner.GitCloner{
 					InsecureSkipTLS: true,
 					Branch:          "master",
 				}
 			})
 
 			JustBeforeEach(func() {
-				c := gogit.NewCloner()
+				c := gitcloner.New()
 				cloneErr = c.CloneRepo(opts)
 				Expect(cloneErr).NotTo(HaveOccurred())
 			})
@@ -108,13 +108,13 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 		When("cloning a public repo that contains a README.md file providing a revision", func() {
 			BeforeEach(func() {
 				private = false
-				opts = &cmd.Options{
+				opts = &gitcloner.GitCloner{
 					InsecureSkipTLS: true,
 				}
 			})
 
 			JustBeforeEach(func() {
-				c := gogit.NewCloner()
+				c := gitcloner.New()
 				opts.Revision = initialCommit
 				cloneErr = c.CloneRepo(opts)
 				Expect(cloneErr).NotTo(HaveOccurred())
@@ -130,13 +130,13 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 			When("No authentication is provided", func() {
 				BeforeEach(func() {
 					private = true
-					opts = &cmd.Options{
+					opts = &gitcloner.GitCloner{
 						InsecureSkipTLS: true,
 					}
 				})
 
 				JustBeforeEach(func() {
-					c := gogit.NewCloner()
+					c := gitcloner.New()
 					cloneErr = c.CloneRepo(opts)
 				})
 
@@ -148,7 +148,7 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 			When("Basic authentication is provided", func() {
 				BeforeEach(func() {
 					private = true
-					opts = &cmd.Options{
+					opts = &gitcloner.GitCloner{
 						InsecureSkipTLS: true,
 						Username:        gogsUser,
 						PasswordFile:    "assets/gogs/password",
@@ -156,7 +156,7 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 				})
 
 				JustBeforeEach(func() {
-					c := gogit.NewCloner()
+					c := gitcloner.New()
 					cloneErr = c.CloneRepo(opts)
 					Expect(cloneErr).NotTo(HaveOccurred())
 				})
@@ -171,11 +171,11 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 		When("Insecure skip tls is not true, and no caBundle is provided", func() {
 			BeforeEach(func() {
 				private = false
-				opts = &cmd.Options{}
+				opts = &gitcloner.GitCloner{}
 			})
 
 			JustBeforeEach(func() {
-				c := gogit.NewCloner()
+				c := gitcloner.New()
 				cloneErr = c.CloneRepo(opts)
 			})
 
@@ -189,7 +189,7 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 
 			BeforeEach(func() {
 				private = false
-				opts = &cmd.Options{}
+				opts = &gitcloner.GitCloner{}
 			})
 
 			AfterEach(func() {
@@ -205,7 +205,7 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 				Expect(err).NotTo(HaveOccurred())
 				opts.CABundleFile = caBundleFile.Name()
 
-				c := gogit.NewCloner()
+				c := gitcloner.New()
 				cloneErr = c.CloneRepo(opts)
 			})
 
@@ -249,7 +249,7 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 		When("the cloned repo is private and contains a README.md file", func() {
 			BeforeEach(func() {
 				private = true
-				opts = &cmd.Options{
+				opts = &gitcloner.GitCloner{
 					InsecureSkipTLS: true,
 				}
 			})
@@ -260,7 +260,7 @@ var _ = Describe("Applying a git job gets content from git repo", Ordered, func(
 			})
 
 			JustBeforeEach(func() {
-				c := gogit.NewCloner()
+				c := gitcloner.New()
 				Eventually(func() error {
 					return c.CloneRepo(opts)
 				}).ShouldNot(HaveOccurred())
diff --git a/integrationtests/gitjob/controller/suite_test.go b/integrationtests/gitjob/controller/suite_test.go
index d7ece82a..a335e236 100644
--- a/integrationtests/gitjob/controller/suite_test.go
+++ b/integrationtests/gitjob/controller/suite_test.go
@@ -11,7 +11,7 @@ import (
 
 	"go.uber.org/mock/gomock"
 
-	"github.com/rancher/fleet/internal/cmd/gitjob"
+	"github.com/rancher/fleet/internal/cmd/controller/gitops/reconciler"
 	"github.com/rancher/fleet/internal/mocks"
 	v1alpha1 "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 
@@ -71,7 +71,7 @@ var _ = BeforeSuite(func() {
 	gitPollerMock.EXPECT().AddOrModifyGitRepoPollJob(gomock.Any(), gomock.Any()).AnyTimes()
 	gitPollerMock.EXPECT().CleanUpGitRepoPollJobs(gomock.Any()).AnyTimes()
 
-	err = (&gitjob.GitJobReconciler{
+	err = (&reconciler.GitJobReconciler{
 		Client:    mgr.GetClient(),
 		Scheme:    mgr.GetScheme(),
 		Image:     "image",
diff --git a/cmd/gitcloner/gogit/cloner_test.go b/internal/cmd/cli/gitcloner/cloner_test.go
similarity index 95%
rename from cmd/gitcloner/gogit/cloner_test.go
rename to internal/cmd/cli/gitcloner/cloner_test.go
index 68e9430d..8ca0e1ae 100644
--- a/cmd/gitcloner/gogit/cloner_test.go
+++ b/internal/cmd/cli/gitcloner/cloner_test.go
@@ -1,18 +1,16 @@
-package gogit
+package gitcloner
 
 import (
 	"errors"
 	"os"
 	"testing"
 
+	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing/protocol/packp/capability"
 	"github.com/go-git/go-git/v5/plumbing/transport"
-
-	"github.com/go-git/go-git/v5"
 	httpgit "github.com/go-git/go-git/v5/plumbing/transport/http"
 	gossh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
 	"github.com/google/go-cmp/cmp"
-	"github.com/rancher/fleet/cmd/gitcloner/cmd"
 )
 
 func TestCloneRepo(t *testing.T) {
@@ -74,12 +72,12 @@ udiSlDctMM/X3ZM2JN5M1rtAJ2WR3ZQtmWbOjZAbG2Eq
 	}()
 
 	tests := map[string]struct {
-		opts              *cmd.Options
+		opts              *GitCloner
 		expectedCloneOpts *git.CloneOptions
 		expectedErr       error
 	}{
 		"branch no auth": {
-			opts: &cmd.Options{
+			opts: &GitCloner{
 				Repo:   "repo",
 				Path:   "path",
 				Branch: "master",
@@ -91,7 +89,7 @@ udiSlDctMM/X3ZM2JN5M1rtAJ2WR3ZQtmWbOjZAbG2Eq
 			},
 		},
 		"branch basic auth": {
-			opts: &cmd.Options{
+			opts: &GitCloner{
 				Repo:         "repo",
 				Path:         "path",
 				Branch:       "master",
@@ -109,7 +107,7 @@ udiSlDctMM/X3ZM2JN5M1rtAJ2WR3ZQtmWbOjZAbG2Eq
 			},
 		},
 		"branch ssh auth": {
-			opts: &cmd.Options{
+			opts: &GitCloner{
 				Repo:              "ssh://git@localhost/test/test-repo",
 				Path:              "path",
 				Branch:            "master",
@@ -123,7 +121,7 @@ udiSlDctMM/X3ZM2JN5M1rtAJ2WR3ZQtmWbOjZAbG2Eq
 			},
 		},
 		"password file does not exist": {
-			opts: &cmd.Options{
+			opts: &GitCloner{
 				Repo:         "repo",
 				Branch:       "master",
 				PasswordFile: "doesntexist",
@@ -133,7 +131,7 @@ udiSlDctMM/X3ZM2JN5M1rtAJ2WR3ZQtmWbOjZAbG2Eq
 			expectedErr:       errors.New("file not found"),
 		},
 		"ca file does not exist": {
-			opts: &cmd.Options{
+			opts: &GitCloner{
 				Repo:         "repo",
 				Branch:       "master",
 				CABundleFile: "doesntexist",
@@ -142,7 +140,7 @@ udiSlDctMM/X3ZM2JN5M1rtAJ2WR3ZQtmWbOjZAbG2Eq
 			expectedErr:       errors.New("file not found"),
 		},
 		"ssh private key file does not exist": {
-			opts: &cmd.Options{
+			opts: &GitCloner{
 				Repo:              "repo",
 				Branch:            "master",
 				SSHPrivateKeyFile: "doesntexist",
diff --git a/cmd/gitcloner/cmd/cmd_test.go b/internal/cmd/cli/gitcloner/cmd_test.go
similarity index 92%
rename from cmd/gitcloner/cmd/cmd_test.go
rename to internal/cmd/cli/gitcloner/cmd_test.go
index 89e3b79d..8d8c7480 100644
--- a/cmd/gitcloner/cmd/cmd_test.go
+++ b/internal/cmd/cli/gitcloner/cmd_test.go
@@ -1,4 +1,4 @@
-package cmd
+package gitcloner
 
 import (
 	"testing"
@@ -6,7 +6,7 @@ import (
 
 func TestArgsAreSet(t *testing.T) {
 	mock := &clonerMock{}
-	cmd := New(mock)
+	cmd := NewCmd(mock)
 	cmd.SetArgs([]string{"test-repo", "test-path", "--branch", "master", "--revision", "v0.1.0", "--ca-bundle-file", "caFile", "--username", "user",
 		"--password-file", "passwordFile", "--ssh-private-key-file", "sshFile", "--insecure-skip-tls", "--known-hosts-file", "knownFile"})
 	err := cmd.Execute()
@@ -43,10 +43,10 @@ func TestArgsAreSet(t *testing.T) {
 }
 
 type clonerMock struct {
-	opts *Options
+	opts *GitCloner
 }
 
-func (m *clonerMock) CloneRepo(opts *Options) error {
+func (m *clonerMock) CloneRepo(opts *GitCloner) error {
 	m.opts = opts
 
 	return nil
diff --git a/internal/cmd/gitjob/gitjob_test.go b/internal/cmd/controller/gitops/reconciler/gitjob_test.go
similarity index 96%
rename from internal/cmd/gitjob/gitjob_test.go
rename to internal/cmd/controller/gitops/reconciler/gitjob_test.go
index cfd0f2ca..68e19782 100644
--- a/internal/cmd/gitjob/gitjob_test.go
+++ b/internal/cmd/controller/gitops/reconciler/gitjob_test.go
@@ -1,7 +1,7 @@
-//go:generate mockgen --build_flags=--mod=mod -destination=../../mocks/poller_mock.go -package=mocks github.com/rancher/fleet/internal/cmd/gitjob GitPoller
-//go:generate mockgen --build_flags=--mod=mod -destination=../../mocks/client_mock.go -package=mocks sigs.k8s.io/controller-runtime/pkg/client Client,SubResourceWriter
+//go:generate mockgen --build_flags=--mod=mod -destination=../../../../mocks/poller_mock.go -package=mocks github.com/rancher/fleet/internal/cmd/controller/gitops/reconciler GitPoller
+//go:generate mockgen --build_flags=--mod=mod -destination=../../../../mocks/client_mock.go -package=mocks sigs.k8s.io/controller-runtime/pkg/client Client,SubResourceWriter
 
-package gitjob
+package reconciler
 
 import (
 	"context"
@@ -120,9 +120,9 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
-					Args:  []string{"repo", "/workspace", "--branch", "master"},
+					Args:  []string{"gitcloner", "repo", "/workspace", "--branch", "master"},
 					Image: "test",
 					Name:  "gitcloner-initializer",
 					VolumeMounts: []corev1.VolumeMount{
@@ -164,9 +164,9 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
-					Args:  []string{"repo", "/workspace", "--branch", "foo"},
+					Args:  []string{"gitcloner", "repo", "/workspace", "--branch", "foo"},
 					Image: "test",
 					Name:  "gitcloner-initializer",
 					VolumeMounts: []corev1.VolumeMount{
@@ -208,9 +208,9 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
-					Args:  []string{"repo", "/workspace", "--revision", "foo"},
+					Args:  []string{"gitcloner", "repo", "/workspace", "--revision", "foo"},
 					Image: "test",
 					Name:  "gitcloner-initializer",
 					VolumeMounts: []corev1.VolumeMount{
@@ -252,9 +252,10 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
 					Args: []string{
+						"gitcloner",
 						"repo",
 						"/workspace",
 						"--branch",
@@ -317,9 +318,10 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
 					Args: []string{
+						"gitcloner",
 						"repo",
 						"/workspace",
 						"--branch",
@@ -380,9 +382,10 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
 					Args: []string{
+						"gitcloner",
 						"repo",
 						"/workspace",
 						"--branch",
@@ -442,9 +445,10 @@ func TestNewJob(t *testing.T) { // nolint:funlen
 			expectedInitContainers: []corev1.Container{
 				{
 					Command: []string{
-						"gitcloner",
+						"fleet",
 					},
 					Args: []string{
+						"gitcloner",
 						"repo",
 						"/workspace",
 						"--branch",
diff --git a/internal/manifest/store_test.go b/internal/manifest/store_test.go
index d4024b68..e012bf54 100644
--- a/internal/manifest/store_test.go
+++ b/internal/manifest/store_test.go
@@ -1,7 +1,5 @@
 package manifest
 
-//go:generate mockgen --build_flags=--mod=mod -destination=../cmd/controller/mocks/client_mock.go -package=mocks sigs.k8s.io/controller-runtime/pkg/client Client
-
 import (
 	"bytes"
 	"context"