func InGitHubActions() bool {
	return os.Getenv("GITHUB_ACTIONS") == "true"
}
InGitHubActions returns true if we are running inside a github action
package setup
import (
	"bytes"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	jxcore "github.com/jenkins-x/jx-api/v4/pkg/apis/core/v4beta1"
	"github.com/jenkins-x/jx-helpers/v3/pkg/boot"
	"github.com/jenkins-x/jx-helpers/v3/pkg/files"
	"github.com/jenkins-x/jx-helpers/v3/pkg/gitclient"
	"github.com/jenkins-x/jx-helpers/v3/pkg/gitclient/cli"
	"github.com/jenkins-x/jx-helpers/v3/pkg/gitclient/credentialhelper"
	"github.com/jenkins-x/jx-helpers/v3/pkg/gitclient/giturl"
	"github.com/jenkins-x/jx-helpers/v3/pkg/homedir"
	"github.com/jenkins-x/jx-helpers/v3/pkg/kube"
	"github.com/jenkins-x/jx-helpers/v3/pkg/options"
	"github.com/jenkins-x/jx-helpers/v3/pkg/termcolor"
	"github.com/jenkins-x/jx-logging/v3/pkg/log"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"github.com/jenkins-x-plugins/jx-gitops/pkg/rootcmd"
	"github.com/jenkins-x/jx-helpers/v3/pkg/cmdrunner"
	"github.com/jenkins-x/jx-helpers/v3/pkg/cobras/helper"
	"github.com/jenkins-x/jx-helpers/v3/pkg/cobras/templates"
	"github.com/pkg/errors"
	"github.com/spf13/cobra"
)
var (
	info = termcolor.ColorInfo
	cmdLong = templates.LongDesc(`
		Sets up git to ensure the git user name and email is setup. This is typically used in a pipeline to ensure git can do commits.
		The jx gitops git setup command ensures that we can authenticate with configured Git server by configuring the local
		credentials file in the home directory. This command tries to ensure the following things:
		- The user can be authenticated with Git provider (for example Github)
		- An email is associated with each automated commit message
		These credentials are written to ${HOME}/git/credentials file, where the ${HOME} directory is determined as:
		- value stored in XGD_CONFIG_HOME environment variable or
		- value stored in HOME environment variable or
		- value stored in USERPROFILE environment variable or
		- as current directory ./
		The credentials are determined by reading out the jx-requirements.yaml from the cluster repository and jx-boot
		Secret resource provisioned together with jx-git-operator in your Kubernetes namespace.
		The Git username and email are preferentially determined from PipelineUser field from jx-requirements.yaml, but if
		they are not available there then default email address jenkins-x@googlegroups.com is used . If the username could not be determined
		from jx-requirements.yaml, then it is determined from:
		- GIT_USERNAME environment variable or
		- GITHUB_ACTOR environment variable
		- In case that we are running in Kubernetes cluster from "username" field of the "jx-boot" Secret provisioned with
		"jx-git-operator"
		The password for Github user (or a token for the robot account, depending on which you configued) is determined in
		similar fashion. Namely the token is first determined from environment variable GITHUB_TOKEN, but if that fails, then
		further determination is dependent on execution environment of the command. Namely if it is running within Github
		actions, then the GITHUB_TOKEN environment variable is our last stop. Otherwise if the command is executed within
		Kubernetes cluster, then the secret is determined by reading the password field of the "jx-boot" Secret provisioned
		with the "jx-git-operator".
`)
	cmdExample = templates.Examples(`
		%s git setup 
	`)
)
type Options struct {
	Dir                  string
	UserName             string
	UserEmail            string
	Password             string
	OutputFile           string
	Namespace            string
	OperatorNamespace    string
	SecretName           string
	GitURL               string
	GitProviderURL       string
	GitInitCommands      string
	DisableInClusterTest bool
	KubeClient           kubernetes.Interface
	CommandRunner        cmdrunner.CommandRunner
	gitClient            gitclient.Interface
	Requirements         *jxcore.Requirements
}
func NewCmdGitSetup() (*cobra.Command, *Options) {
	o := &Options{}
	cmd := &cobra.Command{
		Use:     "setup",
		Short:   "Sets up git to ensure the git user name and email is setup",
		Long:    cmdLong,
		Example: fmt.Sprintf(cmdExample, rootcmd.BinaryName),
		Run: func(cmd *cobra.Command, args []string) {
			err := o.Run()
			helper.CheckErr(err)
		},
	}
	o.AddFlags(cmd)
	return cmd, o
}
func (o *Options) AddFlags(cmd *cobra.Command) {
	cmd.Flags().StringVarP(&o.Dir, "dir", "d", "", "the directory to run the git setup command from")
	cmd.Flags().StringVarP(&o.UserName, "name", "n", "", "the git user name to use if one is not setup")
	cmd.Flags().StringVarP(&o.Password, "password", "", "", "the git password/token to use. if not specified it is detected from the git operator Secret")
	cmd.Flags().StringVarP(&o.UserEmail, "email", "e", "", "the git user email to use if one is not setup. Default value is jenkins-x@googlegroups.com, if none other is provided")
	cmd.Flags().StringVarP(&o.GitProviderURL, "git-provider", "", "", "the git provider URL. If not specified its detected from the git operator jx-boot Secret or defaults to https://github.com")
	cmd.Flags().StringVarP(&o.OutputFile, "credentials-file", "", "", "The destination of the git credentials file to generate. If not specified uses $XDG_CONFIG_HOME/git/credentials or $HOME/git/credentials")
	cmd.Flags().StringVarP(&o.OperatorNamespace, "operator-namespace", "", "jx-git-operator", "the namespace used by the git operator to find the secret for the git repository if running in cluster")
	cmd.Flags().StringVarP(&o.Namespace, "namespace", "", "", "the namespace used to find the git operator secret for the git repository if running in cluster. Defaults to the current namespace")
	cmd.Flags().StringVarP(&o.SecretName, "secret", "", "jx-boot", "the name of the Secret to find the git URL, username and password for creating a git credential if running inside the cluster")
	cmd.Flags().BoolVarP(&o.DisableInClusterTest, "fake-in-cluster", "", false, "for testing: lets you fake running this command inside a kubernetes cluster so that it can create the file: $XDG_CONFIG_HOME/git/credentials or $HOME/git/credentials")
}
func (o *Options) Run() error {
	gitClient := o.GitClient()
	homeDir := GetConfigHome()
	err := os.MkdirAll(homeDir, files.DefaultDirWritePermissions)
	if err != nil {
		return errors.Wrapf(err, "failed to ensure git config home directory exists %s", homeDir)
	}
	err = o.findCredentialsFromRequirements()
	if err != nil {
		return errors.Wrapf(err, "failed to find credentials from requirements")
	}
	credentials, err := o.findCredentials()
	if err != nil {
		return errors.Wrap(err, "creating git credentials")
	}
	_, _, err = gitclient.SetUserAndEmail(gitClient, o.Dir, o.UserName, o.UserEmail, o.DisableInClusterTest)
	if err != nil {
		return errors.Wrapf(err, "failed to setup git user and email")
	}
	err = gitclient.SetCredentialHelper(gitClient, "")
	if err != nil {
		return errors.Wrapf(err, "failed to setup credential store")
	}
	if o.DisableInClusterTest || InGitHubActions() || IsInCluster() {
		outFile, err := o.determineOutputFile()
		if err != nil {
			return errors.Wrap(err, "unable to determine for git credentials")
		}
		err = o.createGitCredentialsFile(outFile, credentials)
		if err != nil {
			return errors.Wrapf(err, "failed to generate credentials file %s", outFile)
		}
		log.Logger().Infof("generated Git credentials file: %s with username: %s email: %s", info(outFile), info(o.UserName), info(o.UserEmail))
	}
	return nil
}