mirror of
https://github.com/gabrie30/ghorg.git
synced 2025-08-06 06:17:09 +02:00
741 lines
20 KiB
Go
741 lines
20 KiB
Go
// Package cmd encapsulates the logic for all cli commands
|
|
package cmd
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"log"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gabrie30/ghorg/colorlog"
|
|
"github.com/gabrie30/ghorg/configs"
|
|
"github.com/gabrie30/ghorg/git"
|
|
"github.com/gabrie30/ghorg/scm"
|
|
"github.com/korovkin/limiter"
|
|
"github.com/spf13/cobra"
|
|
)
|
|
|
|
var cloneCmd = &cobra.Command{
|
|
Use: "clone",
|
|
Short: "Clone user or org repos from GitHub, GitLab, Gitea or Bitbucket",
|
|
Long: `Clone user or org repos from GitHub, GitLab, Gitea or Bitbucket. See $HOME/ghorg/conf.yaml for defaults, its likely you will need to update some of these values of use the flags to overwrite them. Values are set first by a default value, then based off what is set in $HOME/ghorg/conf.yaml, finally the cli flags, which have the highest level of precedence.`,
|
|
Run: cloneFunc,
|
|
}
|
|
|
|
func cloneFunc(cmd *cobra.Command, argz []string) {
|
|
if cmd.Flags().Changed("path") {
|
|
absolutePath := configs.EnsureTrailingSlashOnFilePath((cmd.Flag("path").Value.String()))
|
|
os.Setenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO", absolutePath)
|
|
}
|
|
|
|
if cmd.Flags().Changed("protocol") {
|
|
protocol := cmd.Flag("protocol").Value.String()
|
|
os.Setenv("GHORG_CLONE_PROTOCOL", protocol)
|
|
}
|
|
|
|
if cmd.Flags().Changed("branch") {
|
|
os.Setenv("GHORG_BRANCH", cmd.Flag("branch").Value.String())
|
|
}
|
|
|
|
if cmd.Flags().Changed("bitbucket-username") {
|
|
os.Setenv("GHORG_BITBUCKET_USERNAME", cmd.Flag("bitbucket-username").Value.String())
|
|
}
|
|
|
|
if cmd.Flags().Changed("clone-type") {
|
|
cloneType := strings.ToLower(cmd.Flag("clone-type").Value.String())
|
|
os.Setenv("GHORG_CLONE_TYPE", cloneType)
|
|
}
|
|
|
|
if cmd.Flags().Changed("scm") {
|
|
scmType := strings.ToLower(cmd.Flag("scm").Value.String())
|
|
os.Setenv("GHORG_SCM_TYPE", scmType)
|
|
}
|
|
|
|
if cmd.Flags().Changed("base-url") {
|
|
url := cmd.Flag("base-url").Value.String()
|
|
os.Setenv("GHORG_SCM_BASE_URL", url)
|
|
}
|
|
|
|
if cmd.Flags().Changed("concurrency") {
|
|
g := cmd.Flag("concurrency").Value.String()
|
|
os.Setenv("GHORG_CONCURRENCY", g)
|
|
}
|
|
|
|
if cmd.Flags().Changed("topics") {
|
|
topics := cmd.Flag("topics").Value.String()
|
|
os.Setenv("GHORG_TOPICS", topics)
|
|
}
|
|
|
|
if cmd.Flags().Changed("match-prefix") {
|
|
prefix := cmd.Flag("match-prefix").Value.String()
|
|
os.Setenv("GHORG_MATCH_PREFIX", prefix)
|
|
}
|
|
|
|
if cmd.Flags().Changed("exclude-match-prefix") {
|
|
prefix := cmd.Flag("exclude-match-prefix").Value.String()
|
|
os.Setenv("GHORG_EXCLUDE_MATCH_PREFIX", prefix)
|
|
}
|
|
|
|
if cmd.Flags().Changed("gitlab-group-exclude-match-regex") {
|
|
prefix := cmd.Flag("gitlab-group-exclude-match-regex").Value.String()
|
|
os.Setenv("GHORG_GITLAB_GROUP_EXCLUDE_MATCH_REGEX", prefix)
|
|
}
|
|
|
|
if cmd.Flags().Changed("match-regex") {
|
|
regex := cmd.Flag("match-regex").Value.String()
|
|
os.Setenv("GHORG_MATCH_REGEX", regex)
|
|
}
|
|
|
|
if cmd.Flags().Changed("exclude-match-regex") {
|
|
regex := cmd.Flag("exclude-match-regex").Value.String()
|
|
os.Setenv("GHORG_EXCLUDE_MATCH_REGEX", regex)
|
|
}
|
|
|
|
if cmd.Flags().Changed("ghorgignore-path") {
|
|
path := cmd.Flag("ghorgignore-path").Value.String()
|
|
os.Setenv("GHORG_IGNORE_PATH", path)
|
|
}
|
|
|
|
if cmd.Flags().Changed("skip-archived") {
|
|
os.Setenv("GHORG_SKIP_ARCHIVED", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("no-clean") {
|
|
os.Setenv("GHORG_NO_CLEAN", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("fetch-all") {
|
|
os.Setenv("GHORG_FETCH_ALL", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("dry-run") {
|
|
os.Setenv("GHORG_DRY_RUN", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("clone-wiki") {
|
|
os.Setenv("GHORG_CLONE_WIKI", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("insecure-gitlab-client") {
|
|
os.Setenv("GHORG_INSECURE_GITLAB_CLIENT", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("skip-forks") {
|
|
os.Setenv("GHORG_SKIP_FORKS", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("quiet") {
|
|
os.Setenv("GHORG_QUIET", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("preserve-dir") {
|
|
os.Setenv("GHORG_PRESERVE_DIRECTORY_STRUCTURE", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("backup") {
|
|
os.Setenv("GHORG_BACKUP", "true")
|
|
}
|
|
|
|
if cmd.Flags().Changed("output-dir") {
|
|
d := cmd.Flag("output-dir").Value.String()
|
|
os.Setenv("GHORG_OUTPUT_DIR", d)
|
|
}
|
|
|
|
if len(argz) < 1 {
|
|
if os.Getenv("GHORG_SCM_TYPE") == "github" && os.Getenv("GHORG_CLONE_TYPE") == "user" {
|
|
argz = append(argz, "")
|
|
} else {
|
|
colorlog.PrintError("You must provide an org or user to clone")
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
configs.GetOrSetToken()
|
|
|
|
if cmd.Flags().Changed("token") {
|
|
if os.Getenv("GHORG_SCM_TYPE") == "github" {
|
|
os.Setenv("GHORG_GITHUB_TOKEN", cmd.Flag("token").Value.String())
|
|
} else if os.Getenv("GHORG_SCM_TYPE") == "gitlab" {
|
|
os.Setenv("GHORG_GITLAB_TOKEN", cmd.Flag("token").Value.String())
|
|
} else if os.Getenv("GHORG_SCM_TYPE") == "bitbucket" {
|
|
if cmd.Flags().Changed("bitbucket-username") {
|
|
os.Setenv("GHORG_BITBUCKET_APP_PASSWORD", cmd.Flag("token").Value.String())
|
|
} else {
|
|
os.Setenv("GHORG_BITBUCKET_OAUTH_TOKEN", cmd.Flag("token").Value.String())
|
|
}
|
|
} else if os.Getenv("GHORG_SCM_TYPE") == "gitea" {
|
|
os.Setenv("GHORG_GITEA_TOKEN", cmd.Flag("token").Value.String())
|
|
}
|
|
}
|
|
|
|
err := configs.VerifyTokenSet()
|
|
if err != nil {
|
|
colorlog.PrintError(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
err = configs.VerifyConfigsSetCorrectly()
|
|
if err != nil {
|
|
colorlog.PrintError(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
parseParentFolder(argz)
|
|
args = argz
|
|
targetCloneSource = argz[0]
|
|
setupRepoClone()
|
|
}
|
|
|
|
func setupRepoClone() {
|
|
var cloneTargets []scm.Repo
|
|
var err error
|
|
|
|
if os.Getenv("GHORG_CLONE_TYPE") == "org" {
|
|
cloneTargets, err = getAllOrgCloneUrls()
|
|
} else if os.Getenv("GHORG_CLONE_TYPE") == "user" {
|
|
cloneTargets, err = getAllUserCloneUrls()
|
|
} else {
|
|
colorlog.PrintError("GHORG_CLONE_TYPE not set or unsupported")
|
|
os.Exit(1)
|
|
}
|
|
|
|
if err != nil {
|
|
colorlog.PrintError("Encountered an error, aborting")
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if len(cloneTargets) == 0 {
|
|
colorlog.PrintInfo("No repos found for " + os.Getenv("GHORG_SCM_TYPE") + " " + os.Getenv("GHORG_CLONE_TYPE") + ": " + targetCloneSource + ", please verify you have sufficient permissions to clone target repos, double check spelling and try again.")
|
|
os.Exit(0)
|
|
}
|
|
git := git.NewGit()
|
|
CloneAllRepos(git, cloneTargets)
|
|
}
|
|
|
|
func getAllOrgCloneUrls() ([]scm.Repo, error) {
|
|
return getCloneUrls(true)
|
|
}
|
|
|
|
func getAllUserCloneUrls() ([]scm.Repo, error) {
|
|
return getCloneUrls(false)
|
|
}
|
|
|
|
func getCloneUrls(isOrg bool) ([]scm.Repo, error) {
|
|
asciiTime()
|
|
PrintConfigs()
|
|
scmType := strings.ToLower(os.Getenv("GHORG_SCM_TYPE"))
|
|
if len(scmType) == 0 {
|
|
colorlog.PrintError("GHORG_SCM_TYPE not set")
|
|
os.Exit(1)
|
|
}
|
|
client, err := scm.GetClient(scmType)
|
|
if err != nil {
|
|
colorlog.PrintError(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
if isOrg {
|
|
return client.GetOrgRepos(targetCloneSource)
|
|
}
|
|
return client.GetUserRepos(targetCloneSource)
|
|
}
|
|
|
|
func createDirIfNotExist() {
|
|
if _, err := os.Stat(os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO") + parentFolder); os.IsNotExist(err) {
|
|
err = os.MkdirAll(os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"), 0o700)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func repoExistsLocally(repo scm.Repo) bool {
|
|
if _, err := os.Stat(repo.HostPath); os.IsNotExist(err) {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
func getAppNameFromURL(url string) string {
|
|
withGit := strings.Split(url, "/")
|
|
appName := withGit[len(withGit)-1]
|
|
split := strings.Split(appName, ".")
|
|
return strings.Join(split[0:len(split)-1], ".")
|
|
}
|
|
|
|
func printRemainingMessages() {
|
|
if len(cloneInfos) > 0 {
|
|
colorlog.PrintInfo("\n============ Info ============\n")
|
|
for _, i := range cloneInfos {
|
|
colorlog.PrintInfo(i + "\n")
|
|
}
|
|
}
|
|
|
|
if len(cloneErrors) > 0 {
|
|
colorlog.PrintError("\n============ Issues ============\n")
|
|
for _, e := range cloneErrors {
|
|
colorlog.PrintError(e + "\n")
|
|
}
|
|
}
|
|
}
|
|
|
|
func readGhorgIgnore() ([]string, error) {
|
|
file, err := os.Open(configs.GhorgIgnoreLocation())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer file.Close()
|
|
|
|
var lines []string
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
if scanner.Text() != "" {
|
|
lines = append(lines, scanner.Text())
|
|
}
|
|
}
|
|
return lines, scanner.Err()
|
|
}
|
|
|
|
func filterByRegexMatch(repos []scm.Repo) []scm.Repo {
|
|
filteredRepos := []scm.Repo{}
|
|
regex := fmt.Sprint(os.Getenv("GHORG_MATCH_REGEX"))
|
|
|
|
for i, r := range repos {
|
|
re := regexp.MustCompile(regex)
|
|
match := re.FindString(r.Name)
|
|
if match != "" {
|
|
filteredRepos = append(filteredRepos, repos[i])
|
|
}
|
|
}
|
|
|
|
return filteredRepos
|
|
}
|
|
|
|
func filterByExcludeRegexMatch(repos []scm.Repo) []scm.Repo {
|
|
filteredRepos := []scm.Repo{}
|
|
regex := fmt.Sprint(os.Getenv("GHORG_EXCLUDE_MATCH_REGEX"))
|
|
|
|
for i, r := range repos {
|
|
exclude := false
|
|
re := regexp.MustCompile(regex)
|
|
match := re.FindString(r.Name)
|
|
if match != "" {
|
|
exclude = true
|
|
}
|
|
|
|
if !exclude {
|
|
filteredRepos = append(filteredRepos, repos[i])
|
|
}
|
|
}
|
|
|
|
return filteredRepos
|
|
}
|
|
|
|
func filterByMatchPrefix(repos []scm.Repo) []scm.Repo {
|
|
filteredRepos := []scm.Repo{}
|
|
for i, r := range repos {
|
|
pfs := strings.Split(os.Getenv("GHORG_MATCH_PREFIX"), ",")
|
|
for _, p := range pfs {
|
|
if strings.HasPrefix(strings.ToLower(r.Name), strings.ToLower(p)) {
|
|
filteredRepos = append(filteredRepos, repos[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
return filteredRepos
|
|
}
|
|
|
|
func filterByExcludeMatchPrefix(repos []scm.Repo) []scm.Repo {
|
|
filteredRepos := []scm.Repo{}
|
|
for i, r := range repos {
|
|
var exclude bool
|
|
pfs := strings.Split(os.Getenv("GHORG_EXCLUDE_MATCH_PREFIX"), ",")
|
|
for _, p := range pfs {
|
|
if strings.HasPrefix(strings.ToLower(r.Name), strings.ToLower(p)) {
|
|
exclude = true
|
|
}
|
|
}
|
|
|
|
if !exclude {
|
|
filteredRepos = append(filteredRepos, repos[i])
|
|
}
|
|
}
|
|
|
|
return filteredRepos
|
|
}
|
|
|
|
// exclude wikis from repo count
|
|
func getRepoCountOnly(targets []scm.Repo) int {
|
|
count := 0
|
|
for _, t := range targets {
|
|
if !t.IsWiki {
|
|
count++
|
|
}
|
|
}
|
|
|
|
return count
|
|
}
|
|
|
|
func printDryRun(repos []scm.Repo) {
|
|
for _, repo := range repos {
|
|
colorlog.PrintSubtleInfo(repo.URL + "\n")
|
|
}
|
|
count := len(repos)
|
|
colorlog.PrintSuccess(fmt.Sprintf("%v repos to be cloned into: %s%s", count, os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"), parentFolder))
|
|
}
|
|
|
|
// CloneAllRepos clones all repos
|
|
func CloneAllRepos(git git.Gitter, cloneTargets []scm.Repo) {
|
|
// Filter repos that have attributes that don't need specific scm api calls
|
|
if os.Getenv("GHORG_MATCH_REGEX") != "" {
|
|
colorlog.PrintInfo("Filtering repos down by including regex matches...\n")
|
|
cloneTargets = filterByRegexMatch(cloneTargets)
|
|
}
|
|
if os.Getenv("GHORG_EXCLUDE_MATCH_REGEX") != "" {
|
|
colorlog.PrintInfo("Filtering repos down by excluding regex matches...\n")
|
|
cloneTargets = filterByExcludeRegexMatch(cloneTargets)
|
|
}
|
|
if os.Getenv("GHORG_MATCH_PREFIX") != "" {
|
|
colorlog.PrintInfo("Filtering repos down by including prefix matches...\n")
|
|
cloneTargets = filterByMatchPrefix(cloneTargets)
|
|
}
|
|
if os.Getenv("GHORG_EXCLUDE_MATCH_PREFIX") != "" {
|
|
colorlog.PrintInfo("Filtering repos down by excluding prefix matches...\n")
|
|
cloneTargets = filterByExcludeMatchPrefix(cloneTargets)
|
|
}
|
|
|
|
// filter repos down based on ghorgignore if one exists
|
|
_, err := os.Stat(configs.GhorgIgnoreLocation())
|
|
if !os.IsNotExist(err) {
|
|
// Open the file parse each line and remove cloneTargets containing
|
|
toIgnore, err := readGhorgIgnore()
|
|
if err != nil {
|
|
colorlog.PrintError("Error parsing your ghorgignore, aborting")
|
|
fmt.Println(err)
|
|
os.Exit(1)
|
|
}
|
|
|
|
colorlog.PrintInfo("\nUsing ghorgignore, filtering repos down...\n")
|
|
|
|
filteredCloneTargets := []scm.Repo{}
|
|
var flag bool
|
|
for _, cloned := range cloneTargets {
|
|
flag = false
|
|
for _, ignore := range toIgnore {
|
|
if strings.Contains(cloned.URL, ignore) {
|
|
flag = true
|
|
}
|
|
}
|
|
|
|
if !flag {
|
|
filteredCloneTargets = append(filteredCloneTargets, cloned)
|
|
}
|
|
}
|
|
|
|
cloneTargets = filteredCloneTargets
|
|
|
|
}
|
|
|
|
repoCount := getRepoCountOnly(cloneTargets)
|
|
|
|
if os.Getenv("GHORG_CLONE_WIKI") == "true" {
|
|
wikiCount := strconv.Itoa(len(cloneTargets) - repoCount)
|
|
colorlog.PrintInfo(strconv.Itoa(repoCount) + " repos found in " + targetCloneSource + ", including " + wikiCount + " enabled wikis\n")
|
|
} else {
|
|
colorlog.PrintInfo(strconv.Itoa(repoCount) + " repos found in " + targetCloneSource + "\n")
|
|
}
|
|
|
|
if os.Getenv("GHORG_DRY_RUN") == "true" {
|
|
printDryRun(cloneTargets)
|
|
return
|
|
}
|
|
|
|
createDirIfNotExist()
|
|
|
|
l, err := strconv.Atoi(os.Getenv("GHORG_CONCURRENCY"))
|
|
if err != nil {
|
|
log.Fatal("Could not determine GHORG_CONCURRENCY")
|
|
}
|
|
|
|
limit := limiter.NewConcurrencyLimiter(l)
|
|
|
|
var cloneCount, pulledCount int
|
|
|
|
for i := range cloneTargets {
|
|
repo := cloneTargets[i]
|
|
repoSlug := getAppNameFromURL(repo.URL)
|
|
limit.Execute(func() {
|
|
if repo.Path != "" && os.Getenv("GHORG_PRESERVE_DIRECTORY_STRUCTURE") == "true" {
|
|
repoSlug = repo.Path
|
|
}
|
|
|
|
repo.HostPath = filepath.Join(os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"), parentFolder, configs.GetCorrectFilePathSeparator(), repoSlug)
|
|
|
|
if repo.IsWiki {
|
|
if !strings.HasSuffix(repo.HostPath, ".wiki") {
|
|
repo.HostPath = repo.HostPath + ".wiki"
|
|
}
|
|
}
|
|
|
|
if os.Getenv("GHORG_BACKUP") == "true" {
|
|
repo.HostPath = filepath.Join(os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"), parentFolder+"_backup", configs.GetCorrectFilePathSeparator(), repoSlug)
|
|
}
|
|
|
|
action := "cloning"
|
|
|
|
if repoExistsLocally(repo) {
|
|
if os.Getenv("GHORG_BACKUP") == "true" {
|
|
err := git.UpdateRemote(repo)
|
|
|
|
// Theres no way to tell if a github repo has a wiki to clone
|
|
if err != nil && repo.IsWiki {
|
|
e := fmt.Sprintf("Wiki may be enabled but there was no content to clone on Repo: %s Error: %v", repo.URL, err)
|
|
cloneInfos = append(cloneInfos, e)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Could not update remotes in Repo: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
} else if os.Getenv("GHORG_NO_CLEAN") == "true" {
|
|
action = "fetching"
|
|
err := git.FetchAll(repo)
|
|
|
|
// Theres no way to tell if a github repo has a wiki to clone
|
|
if err != nil && repo.IsWiki {
|
|
e := fmt.Sprintf("Wiki may be enabled but there was no content to clone on Repo: %s Error: %v", repo.URL, err)
|
|
cloneInfos = append(cloneInfos, e)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Could not fetch remotes in Repo: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
|
|
} else {
|
|
err := git.Checkout(repo)
|
|
if err != nil {
|
|
e := fmt.Sprintf("Could not checkout out %s, branch may not exist, no changes made Repo: %s Error: %v", repo.CloneBranch, repo.URL, err)
|
|
cloneInfos = append(cloneInfos, e)
|
|
return
|
|
}
|
|
|
|
err = git.Clean(repo)
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Problem running git clean: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
|
|
err = git.Reset(repo)
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Problem resetting %s Repo: %s Error: %v", repo.CloneBranch, repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
|
|
err = git.Pull(repo)
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Problem trying to pull %v Repo: %s Error: %v", repo.CloneBranch, repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
|
|
action = "pulling"
|
|
pulledCount++
|
|
|
|
if os.Getenv("GHORG_FETCH_ALL") == "true" {
|
|
err = git.FetchAll(repo)
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Could not fetch remotes in Repo: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
// if https clone and github/gitlab add personal access token to url
|
|
|
|
err = git.Clone(repo)
|
|
|
|
// Theres no way to tell if a github repo has a wiki to clone
|
|
if err != nil && repo.IsWiki {
|
|
e := fmt.Sprintf("Wiki may be enabled but there was no content to clone on Repo: %s Error: %v", repo.URL, err)
|
|
cloneInfos = append(cloneInfos, e)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Problem trying to clone Repo: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
|
|
if os.Getenv("GHORG_BRANCH") != "" {
|
|
err := git.Checkout(repo)
|
|
if err != nil {
|
|
e := fmt.Sprintf("Could not checkout out %s, branch may not exist, no changes made Repo: %s Error: %v", repo.CloneBranch, repo.URL, err)
|
|
cloneInfos = append(cloneInfos, e)
|
|
return
|
|
}
|
|
}
|
|
|
|
cloneCount++
|
|
|
|
// TODO: make configs around remote name
|
|
// we clone with api-key in clone url
|
|
err = git.SetOrigin(repo)
|
|
|
|
// if repo has wiki, but content does not exist this is going to error
|
|
if err != nil {
|
|
e := fmt.Sprintf("Problem trying to set remote on Repo: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
|
|
if os.Getenv("GHORG_FETCH_ALL") == "true" {
|
|
err = git.FetchAll(repo)
|
|
|
|
if err != nil {
|
|
e := fmt.Sprintf("Could not fetch remotes in Repo: %s Error: %v", repo.URL, err)
|
|
cloneErrors = append(cloneErrors, e)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
colorlog.PrintSuccess("Success " + action + " repo: " + repo.URL + " -> branch: " + repo.CloneBranch)
|
|
})
|
|
|
|
}
|
|
|
|
limit.WaitAndClose()
|
|
|
|
printRemainingMessages()
|
|
|
|
colorlog.PrintSuccess(fmt.Sprintf("New repos cloned: %v, existing repos pulled: %v", cloneCount, pulledCount))
|
|
|
|
// TODO: fix all these if else checks with ghorg_backups
|
|
if os.Getenv("GHORG_BACKUP") == "true" {
|
|
colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s%s_backup", os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"), parentFolder))
|
|
} else if os.Getenv("GHORG_QUIET") != "true" {
|
|
colorlog.PrintSuccess(fmt.Sprintf("\nFinished! %s%s", os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"), parentFolder))
|
|
}
|
|
}
|
|
|
|
func asciiTime() {
|
|
colorlog.PrintInfo(
|
|
`
|
|
+-+-+-+-+ +-+-+ +-+-+-+-+-+
|
|
|T|I|M|E| |T|O| |G|H|O|R|G|
|
|
+-+-+-+-+ +-+-+ +-+-+-+-+-+
|
|
`)
|
|
}
|
|
|
|
// PrintConfigs shows the user what is set before cloning
|
|
func PrintConfigs() {
|
|
if os.Getenv("GHORG_QUIET") == "true" {
|
|
return
|
|
}
|
|
|
|
colorlog.PrintInfo("*************************************")
|
|
colorlog.PrintInfo("* SCM : " + os.Getenv("GHORG_SCM_TYPE"))
|
|
colorlog.PrintInfo("* Type : " + os.Getenv("GHORG_CLONE_TYPE"))
|
|
colorlog.PrintInfo("* Protocol : " + os.Getenv("GHORG_CLONE_PROTOCOL"))
|
|
colorlog.PrintInfo("* Location : " + os.Getenv("GHORG_ABSOLUTE_PATH_TO_CLONE_TO"))
|
|
colorlog.PrintInfo("* Concurrency : " + os.Getenv("GHORG_CONCURRENCY"))
|
|
|
|
if os.Getenv("GHORG_BRANCH") != "" {
|
|
colorlog.PrintInfo("* Branch : " + getGhorgBranch())
|
|
}
|
|
if os.Getenv("GHORG_SCM_BASE_URL") != "" {
|
|
colorlog.PrintInfo("* Base URL : " + os.Getenv("GHORG_SCM_BASE_URL"))
|
|
}
|
|
if os.Getenv("GHORG_SKIP_ARCHIVED") == "true" {
|
|
colorlog.PrintInfo("* Skip Archived : " + os.Getenv("GHORG_SKIP_ARCHIVED"))
|
|
}
|
|
if os.Getenv("GHORG_SKIP_FORKS") == "true" {
|
|
colorlog.PrintInfo("* Skip Forks : " + os.Getenv("GHORG_SKIP_FORKS"))
|
|
}
|
|
if os.Getenv("GHORG_BACKUP") == "true" {
|
|
colorlog.PrintInfo("* Backup : " + os.Getenv("GHORG_BACKUP"))
|
|
}
|
|
if os.Getenv("GHORG_CLONE_WIKI") == "true" {
|
|
colorlog.PrintInfo("* Wikis : " + os.Getenv("GHORG_CLONE_WIKI"))
|
|
}
|
|
if configs.GhorgIgnoreDetected() {
|
|
colorlog.PrintInfo("* Ghorgignore : " + configs.GhorgIgnoreLocation())
|
|
}
|
|
if os.Getenv("GHORG_MATCH_REGEX") != "" {
|
|
colorlog.PrintInfo("* Regex Match : " + os.Getenv("GHORG_MATCH_REGEX"))
|
|
}
|
|
if os.Getenv("GHORG_EXCLUDE_MATCH_REGEX") != "" {
|
|
colorlog.PrintInfo("* Exclude Regex : " + os.Getenv("GHORG_EXCLUDE_MATCH_REGEX"))
|
|
}
|
|
if os.Getenv("GHORG_MATCH_PREFIX") != "" {
|
|
colorlog.PrintInfo("* Prefix Match: " + os.Getenv("GHORG_MATCH_PREFIX"))
|
|
}
|
|
if os.Getenv("GHORG_EXCLUDE_MATCH_PREFIX") != "" {
|
|
colorlog.PrintInfo("* Exclude Prefix: " + os.Getenv("GHORG_EXCLUDE_MATCH_PREFIX"))
|
|
}
|
|
if os.Getenv("GHORG_OUTPUT_DIR") != "" {
|
|
colorlog.PrintInfo("* Output Dir : " + parentFolder)
|
|
}
|
|
if os.Getenv("GHORG_NO_CLEAN") == "true" {
|
|
colorlog.PrintInfo("* No Clean : " + "true")
|
|
}
|
|
if os.Getenv("GHORG_FETCH_ALL") == "true" {
|
|
colorlog.PrintInfo("* Fetch All : " + "true")
|
|
}
|
|
if os.Getenv("GHORG_DRY_RUN") == "true" {
|
|
colorlog.PrintInfo("* Dry Run : " + "true")
|
|
}
|
|
|
|
colorlog.PrintInfo("* Config Used : " + os.Getenv("GHORG_CONFIG"))
|
|
colorlog.PrintInfo("* Ghorg version : " + GetVersion())
|
|
|
|
colorlog.PrintInfo("*************************************")
|
|
}
|
|
|
|
func getGhorgBranch() string {
|
|
if os.Getenv("GHORG_BRANCH") == "" {
|
|
return "default branch"
|
|
}
|
|
|
|
return os.Getenv("GHORG_BRANCH")
|
|
}
|
|
|
|
func parseParentFolder(argz []string) {
|
|
if os.Getenv("GHORG_OUTPUT_DIR") != "" {
|
|
parentFolder = os.Getenv("GHORG_OUTPUT_DIR")
|
|
return
|
|
}
|
|
|
|
parentFolder = strings.ToLower(argz[0])
|
|
|
|
// If all-group is used set the parent folder to the name of the baseurl
|
|
if argz[0] == "all-groups" && os.Getenv("GHORG_SCM_BASE_URL") != "" {
|
|
u, err := url.Parse(os.Getenv("GHORG_SCM_BASE_URL"))
|
|
if err != nil {
|
|
return
|
|
}
|
|
parentFolder = strings.TrimSuffix(strings.TrimPrefix(u.Host, "www."), ".com")
|
|
fmt.Println(parentFolder)
|
|
}
|
|
}
|