feat: improve logging and added verbose output

This commit is contained in:
Simon Cornet 2025-03-05 08:45:55 +01:00
commit e0f87d7ef9
6 changed files with 104 additions and 46 deletions

View file

@ -2,7 +2,6 @@ package main
import ( import (
"fmt" "fmt"
"log"
"os/exec" "os/exec"
"strings" "strings"
"sync" "sync"
@ -54,10 +53,6 @@ func checkoutRepositories(repositories []Repository, concurrency int) {
switch { switch {
case strings.Contains(string(repoStatus), "No such file or directory"): case strings.Contains(string(repoStatus), "No such file or directory"):
// update the progress bar
descriptionPrefixPre := "Cloning repository "
descriptionPrefix := descriptionPrefixPre + repoName + " ..."
// clone the repo // clone the repo
cloneRepository := func(repoDestination string, url string) (string, error) { cloneRepository := func(repoDestination string, url string) (string, error) {
cloneCmd := exec.Command("git", "clone", url, repoDestination) cloneCmd := exec.Command("git", "clone", url, repoDestination)
@ -67,29 +62,41 @@ func checkoutRepositories(repositories []Repository, concurrency int) {
} }
_, err := cloneRepository(repoDestination, url) _, err := cloneRepository(repoDestination, url)
if err != nil { if err != nil {
log.Printf("ERROR: %v\n", err) logPrint("ERROR: %v\n", err)
} }
// set a lock, increment counters and unlock // set a lock, increment counters, update progressbar and unlock
mu.Lock() mu.Lock()
clonedCount++ clonedCount++
bar.Describe(descriptionPrefix) if !verbose {
progressBarAdd(1) // update the progress bar
descriptionPrefixPre := "Cloning repository "
descriptionPrefix := descriptionPrefixPre + repoName + " ..."
bar.Describe(descriptionPrefix)
progressBarAdd(1)
}
mu.Unlock() mu.Unlock()
// pull the latest // pull the latest
case strings.Contains(string(repoStatus), url): case strings.Contains(string(repoStatus), url):
pullRepository(repoName, repoDestination) pullRepository(repoName, repoDestination)
progressBarAdd(1) if !verbose {
descriptionPrefixPre := "Pulling repository "
descriptionPrefix := descriptionPrefixPre + repoName + " ..."
bar.Describe(descriptionPrefix)
progressBarAdd(1)
}
default: default:
log.Printf("ERROR: decided not to clone or pull repository %v\n", repoName) logPrint("ERROR: decided not to clone or pull repository" + repoName, nil)
log.Printf("ERROR: this is why: %v\n", repoStatus) logPrint("ERROR: this is why: " + repoStatus, nil)
// set a lock, increment counters and unlock // set a lock, increment counters and unlock
mu.Lock() mu.Lock()
errorCount++ errorCount++
progressBarAdd(1) if !verbose {
progressBarAdd(1)
}
mu.Unlock() mu.Unlock()
} }
}(repo) }(repo)
@ -101,10 +108,6 @@ func checkoutRepositories(repositories []Repository, concurrency int) {
func pullRepository(repoName string, repoDestination string) { func pullRepository(repoName string, repoDestination string) {
// update the progress bar
descriptionPrefixPre := "Pulling repository "
descriptionPrefix := descriptionPrefixPre + repoName + " ..."
// find remote // find remote
findRemote := func(repoDestination string) (string, error) { findRemote := func(repoDestination string) (string, error) {
remoteCmd := exec.Command("git", "-C", repoDestination, "remote", "show") remoteCmd := exec.Command("git", "-C", repoDestination, "remote", "show")
@ -124,7 +127,6 @@ func pullRepository(repoName string, repoDestination string) {
// set a lock, increment counters and unlock // set a lock, increment counters and unlock
mu.Lock() mu.Lock()
bar.Describe(descriptionPrefix)
pulledCount++ pulledCount++
mu.Unlock() mu.Unlock()
@ -141,7 +143,7 @@ func pullRepository(repoName string, repoDestination string) {
pullErrorMsg = append(pullErrorMsg, repoDestination) pullErrorMsg = append(pullErrorMsg, repoDestination)
default: default:
log.Printf("ERROR: pulling %v\n", err) logPrint("ERROR: pulling " + repoName, nil)
} }
} }
} }

View file

@ -29,7 +29,7 @@ func fetchRepositoriesGitlab() ([]Repository, error) {
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
return nil, fmt.Errorf("creating request: %v\n", err) return nil, fmt.Errorf("ERROR: creating request: %v\n", err)
} }
req.Header.Set("PRIVATE-TOKEN", gitlabToken) req.Header.Set("PRIVATE-TOKEN", gitlabToken)
@ -37,21 +37,21 @@ func fetchRepositoriesGitlab() ([]Repository, error) {
client := &http.Client{} client := &http.Client{}
resp, err := client.Do(req) resp, err := client.Do(req)
if err != nil { if err != nil {
return nil, fmt.Errorf("making request: %v\n", err) return nil, fmt.Errorf("ERROR: making request: %v\n", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("API request failed with status: %d\n", resp.StatusCode) return nil, fmt.Errorf("ERROR: API request failed with status: %d\n", resp.StatusCode)
} }
var repositories []Repository var repositories []Repository
if err := json.NewDecoder(resp.Body).Decode(&repositories); err != nil { if err := json.NewDecoder(resp.Body).Decode(&repositories); err != nil {
return nil, fmt.Errorf("decoding response: %v\n", err) return nil, fmt.Errorf("ERROR: decoding response: %v\n", err)
} }
if len(repositories) < 1 { if len(repositories) < 1 {
return repositories, fmt.Errorf("no repositories found\n") return repositories, fmt.Errorf("ERROR: no repositories found\n")
} }
return repositories, nil return repositories, nil

View file

@ -16,6 +16,7 @@ func manageArguments() {
var destinationFlag = flag.String("destination", "$HOME/Documents", "Specify where to check the repositories out\n example: -destination=$HOME/repos\nenv = GOGITLABBER_DESTINATION\n") var destinationFlag = flag.String("destination", "$HOME/Documents", "Specify where to check the repositories out\n example: -destination=$HOME/repos\nenv = GOGITLABBER_DESTINATION\n")
var hostFlag = flag.String("gitlab-url", "gitlab.com", "Specify GitLab host\n example: -gitlab-url=gitlab.com\nenv = GITLAB_URL\n") var hostFlag = flag.String("gitlab-url", "gitlab.com", "Specify GitLab host\n example: -gitlab-url=gitlab.com\nenv = GITLAB_URL\n")
var tokenFlag = flag.String("gitlab-api-token", "", "Specify GitLab API token\n example: -gitlab-api=glpat-xxxx\nenv = GITLAB_API_TOKEN\n") var tokenFlag = flag.String("gitlab-api-token", "", "Specify GitLab API token\n example: -gitlab-api=glpat-xxxx\nenv = GITLAB_API_TOKEN\n")
var verboseFlag = flag.Bool("verbose", false, "Specify verbosity\n example: -verbose=true\nenv = GOGITLABBER_VERBOSE\n")
flag.Parse() flag.Parse()
@ -25,32 +26,50 @@ func manageArguments() {
gitlabToken = *tokenFlag gitlabToken = *tokenFlag
includeArchived = *archivedFlag includeArchived = *archivedFlag
repoDestinationPre = *destinationFlag repoDestinationPre = *destinationFlag
verbose = *verboseFlag
// manage verbosity option
switch envVerbose := os.Getenv("GOGITLABBER_VERBOSE"); {
case envVerbose != "":
var err error
verbose, err = strconv.ParseBool(envVerbose)
logPrint("CONFIG: verbose option found", nil)
if err != nil {
logFatal("FATAL: config; not a valid bool", nil)
}
default:
flag.Usage()
logFatal("FATAL: config; no verbose option found", nil)
}
// manage gitlab api option // manage gitlab api option
switch envToken := os.Getenv("GITLAB_API_TOKEN"); { switch envToken := os.Getenv("GITLAB_API_TOKEN"); {
case envToken != "": case envToken != "":
gitlabToken = envToken gitlabToken = envToken
logPrint("CONFIG: Gitlab API Token found", nil)
default: default:
flag.Usage() flag.Usage()
log.Printf("FATAL: config; gitlab api token not found\n") logFatal("CONFIG: Giltab API Token not found", nil)
} }
// manage gitlab url option // manage gitlab url option
switch envHost := os.Getenv("GITLAB_URL"); { switch envHost := os.Getenv("GITLAB_URL"); {
case envHost != "": case envHost != "":
gitlabHost = envHost gitlabHost = envHost
logPrint("CONFIG: Gitlab host found", nil)
default: default:
flag.Usage() flag.Usage()
log.Fatalf("FATAL: config; gitlab host not found\n") logFatal("CONFIG: Gitlab host not found", nil)
} }
// manage destination option // manage destination option
switch envRepoDest := os.Getenv("GOGITLABBER_DESTINATION"); { switch envRepoDest := os.Getenv("GOGITLABBER_DESTINATION"); {
case envRepoDest != "": case envRepoDest != "":
repoDestinationPre = envRepoDest repoDestinationPre = envRepoDest
logPrint("CONFIG: destination found", nil)
default: default:
flag.Usage() flag.Usage()
log.Fatalf("FATAL: config; destination not found\n") logFatal("CONFIG: destination not found", nil)
} }
// add slash 🎩🎸 if not provided // add slash 🎩🎸 if not provided
@ -60,36 +79,41 @@ func manageArguments() {
} }
// manage concurrency option // manage concurrency option
switch envConcurrency := os.Getenv("GOGITLABBER_CONCURRENCY"); { switch envConcurrency := os.Getenv("GOGITLABBER_CONCURRENCY"); {
case envConcurrency == "": case envConcurrency == "":
concurrency = 15 concurrency = 15
case envConcurrency != "": case envConcurrency != "":
concurrencyValue, err := strconv.Atoi(envConcurrency) concurrencyValue, err := strconv.Atoi(envConcurrency)
if err != nil { if err != nil {
log.Fatalf("FATAL: invalid concurrency value in environment: %v", err) logFatal("invalid concurrency value in environment: %v", err)
} }
concurrency = concurrencyValue concurrency = concurrencyValue
default: logPrint("CONFIG: concurrency option found", nil)
flag.Usage() default:
log.Fatalf("FATAL: config; concurrency not found\n") flag.Usage()
} log.Fatalln("FATAL: config; concurrency not found")
}
// manage archived option // manage archived option
switch envArchived := os.Getenv("GOGITLABBER_ARCHIVED"); { switch envArchived := os.Getenv("GOGITLABBER_ARCHIVED"); {
case envArchived == "": case envArchived == "":
includeArchived = "excluded" includeArchived = "excluded"
logPrint("CONFIG: archive option found", nil)
case envArchived == "any": case envArchived == "any":
includeArchived = envArchived includeArchived = envArchived
logPrint("CONFIG: archive option found", nil)
case envArchived == "exclusive": case envArchived == "exclusive":
includeArchived = envArchived includeArchived = envArchived
logPrint("CONFIG: archive option found", nil)
case envArchived == "excluded": case envArchived == "excluded":
includeArchived = envArchived includeArchived = envArchived
logPrint("CONFIG: archive option found", nil)
default: default:
flag.Usage() flag.Usage()
log.Fatalf("FATAL: config; no or wrong archive option found\n") logFatal("FATAL: config; no or wrong archive option found", nil)
} }
} }

View file

@ -1,6 +1,9 @@
package main package main
import "log" import (
"io"
"log"
)
// userdata // userdata
var concurrency int var concurrency int
@ -8,6 +11,7 @@ var gitlabHost string
var gitlabToken string var gitlabToken string
var includeArchived string var includeArchived string
var repoDestinationPre string var repoDestinationPre string
var verbose bool
// keep count 🧛 // keep count 🧛
var clonedCount int var clonedCount int
@ -27,16 +31,26 @@ func main() {
manageArguments() manageArguments()
// check for git // check for git
verifyGitAvailable() err := verifyGitAvailable()
if err != nil {
logFatal("FATAL: git not found in path: %v", err)
}
logPrint("Git is available. Proceeding with the program.", nil)
// fetch repository information from gitlab // fetch repository information from gitlab
repositories, err := fetchRepositoriesGitlab() repositories, err := fetchRepositoriesGitlab()
if err != nil { if err != nil {
log.Fatalf("FATAL: %v", err) logFatal("FATAL: %v", err)
}
logPrint("Logged into GitLab, Repositories found. Proceeding with the program.", nil)
// print progressbar ony if not in verbose mode
if !verbose {
progressBar(repositories)
log.SetOutput(io.Discard)
} }
// manage found repositories // manage found repositories
progressBar(repositories)
checkoutRepositories(repositories, concurrency) checkoutRepositories(repositories, concurrency)
printSummary() printSummary()
printPullError(pullErrorMsg) printPullError(pullErrorMsg)

View file

@ -41,7 +41,7 @@ func progressBar(repositories []Repository) {
func progressBarAdd(amount int) { func progressBarAdd(amount int) {
if err := bar.Add(amount); err != nil { if err := bar.Add(amount); err != nil {
log.Printf("ERROR: Progress bar update error: %v\n", err) logPrint("ERROR: Progress bar update error: %v\n", err)
} }
} }
@ -66,3 +66,21 @@ func printPullError(pullErrorMsg []string) {
} }
} }
} }
func logPrint(message string, err error) {
if verbose == true {
if err != nil {
log.Printf("gogitlabber | %v error: %v\n", message, err)
}
if err == nil {
log.Printf("gogitlabber | %v\n", message)
}
}
}
func logFatal(message string, err error) {
if err != nil {
log.Fatalf("gogitlabber | FATAL: %v error: %v\n", message, err)
}
log.Fatalf("gogitlabber | FATAL: %v\n", message)
}

View file

@ -1,13 +1,13 @@
package main package main
import ( import (
"log"
"os/exec" "os/exec"
) )
func verifyGitAvailable() { func verifyGitAvailable() error {
_, err := exec.LookPath("git") _, err := exec.LookPath("git")
if err != nil { if err != nil {
log.Fatal("could not find git in path") return err
} }
return nil
} }