feat: many improvements

This commit is contained in:
Simon Cornet 2025-01-01 22:50:18 +01:00
commit 23652f5a04

145
main.go
View file

@ -3,13 +3,13 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/k0kubun/go-ansi"
"github.com/schollz/progressbar/v3"
"log" "log"
"strings"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"github.com/k0kubun/go-ansi" "strings"
"github.com/schollz/progressbar/v3"
) )
type Repository struct { type Repository struct {
@ -21,6 +21,7 @@ var repoDestinationPre string
var includeArchived string var includeArchived string
var gitlabToken string var gitlabToken string
var gitlabHost string var gitlabHost string
var pullError []string
func main() { func main() {
@ -30,42 +31,10 @@ func main() {
log.Fatalf("Error loading environment variables: %v", err) log.Fatalf("Error loading environment variables: %v", err)
} }
// require at least the destination argument // manage all argument magic
if len(os.Args) <= 1 { manageArguments()
fmt.Println("Usage: gogitlabber --destination=<directory>")
fmt.Println("Example: gogitlabber --destination=/tmp/repos")
os.Exit(1)
}
// parse arguments // fetch repository information from gitlab
for _, arg := range os.Args[1:] {
switch {
case strings.HasPrefix(arg, "--destination="):
repoDestinationPre = strings.TrimPrefix(arg, "--destination=")
case strings.HasPrefix(arg, "--gitlab-api-token="):
gitlabToken = strings.TrimPrefix(arg, "--gitlab-api-token=")
case strings.HasPrefix(arg, "--gitlab-url="):
gitlabHost = strings.TrimPrefix(arg, "--gitlab-url=")
default:
fmt.Println("Usage: gogitlabber --destination=<directory>")
fmt.Println("Example: gogitlabber --destination=/tmp/repos")
os.Exit(1)
}
}
// fail if destination is unknown
if repoDestinationPre == "" {
fmt.Println("Fatal: No destination found.")
fmt.Println("Example: gogitlabber --destination=/tmp/repos")
fmt.Println("Usage: gogitlabber --destination=/tmp/repos")
os.Exit(1)
}
// fetch repository information
repositories, err := fetchRepositories() repositories, err := fetchRepositories()
if err != nil { if err != nil {
log.Fatalf("Error fetching repositories: %v", err) log.Fatalf("Error fetching repositories: %v", err)
@ -73,9 +42,9 @@ func main() {
// manage found repositories // manage found repositories
checkoutRepositories(repositories) checkoutRepositories(repositories)
printPullerror(pullError)
} }
func loadEnvironmentVariables() error { func loadEnvironmentVariables() error {
gitlabToken = os.Getenv("GITLAB_API_KEY") gitlabToken = os.Getenv("GITLAB_API_KEY")
if gitlabToken == "" { if gitlabToken == "" {
@ -89,16 +58,87 @@ func loadEnvironmentVariables() error {
return nil return nil
} }
func manageArguments() {
// require at least the destination argument
if len(os.Args) <= 1 {
fmt.Println("Usage: gogitlabber --destination=<directory>")
fmt.Println("Example: gogitlabber --destination=$HOME/repos")
os.Exit(1)
}
// parse arguments
for _, arg := range os.Args[1:] {
switch {
case strings.HasPrefix(arg, "--archived="):
includeArchived = strings.TrimPrefix(arg, "--archived=")
case strings.HasPrefix(arg, "--destination="):
repoDestinationPre = strings.TrimPrefix(arg, "--destination=")
case strings.HasPrefix(arg, "--gitlab-api-token="):
gitlabToken = strings.TrimPrefix(arg, "--gitlab-api-token=")
case strings.HasPrefix(arg, "--gitlab-url="):
gitlabHost = strings.TrimPrefix(arg, "--gitlab-url=")
default:
fmt.Println("Usage: gogitlabber --destination=<directory>")
fmt.Println("Example: gogitlabber --destination=$HOME/repos")
os.Exit(1)
}
}
// --archive options:
// - any (fetch both)
// - only (fetch archived only)
// - excluded (fetch non-archived only - default)
if includeArchived == "" {
includeArchived = "excluded"
}
if includeArchived != "any" &&
includeArchived != "only" &&
includeArchived != "excluded" {
fmt.Println("Usage: gogitlabber --archived=(any|excluded|only)")
os.Exit(1)
}
// fail if destination is unknown
if repoDestinationPre == "" {
fmt.Println("Fatal: No destination found.")
fmt.Println("Example: gogitlabber --destination=$HOME/repos")
fmt.Println("Usage: gogitlabber --destination=$HOME/repos")
os.Exit(1)
}
// add slash if not provided to directory
if !strings.HasSuffix(repoDestinationPre, "/") {
repoDestinationPre += "/"
}
}
func fetchRepositories() ([]Repository, error) { func fetchRepositories() ([]Repository, error) {
archived := "archived=false" // default options
membership := "membership=true" membership := "membership=true"
perpage := "per_page=100" perpage := "per_page=100"
order := "order_by=name" order := "order_by=name"
url := fmt.Sprintf("https://%s/api/v4/projects?%s&%s&%s&%s", // configure archived options
gitlabHost, membership, order, archived, perpage) var archived string
switch {
case includeArchived == "excluded":
archived = "&archived=false"
case includeArchived == "only":
archived = "&archived=true"
default:
archived = ""
}
url := fmt.Sprintf("https://%s/api/v4/projects?%s&%s&%s%s",
gitlabHost, membership, order, perpage, archived)
req, err := http.NewRequest("GET", url, nil) req, err := http.NewRequest("GET", url, nil)
if err != nil { if err != nil {
@ -126,7 +166,6 @@ func fetchRepositories() ([]Repository, error) {
return repositories, nil return repositories, nil
} }
func checkoutRepositories(repositories []Repository) { func checkoutRepositories(repositories []Repository) {
repoCount := len(repositories) repoCount := len(repositories)
@ -179,14 +218,28 @@ func checkoutRepositories(repositories []Repository) {
} }
bar.Add(1) bar.Add(1)
} }
}
// print empty line as the bar does not do that
fmt.Println("")
}
func pullRepositories(repoDestination string) { func pullRepositories(repoDestination string) {
pullCmd := exec.Command("git", "-C", repoDestination, "pull", "origin") pullCmd := exec.Command("git", "-C", repoDestination, "pull", "origin")
output, err := pullCmd.CombinedOutput() pullOutput, err := pullCmd.CombinedOutput()
if err != nil { if err != nil {
log.Printf("❌ Error pulling %s: %v\n%s", repoDestination, err, string(output)) if strings.Contains(string(pullOutput),
"You have unstaged changes") {
pullError = append(pullError, repoDestination)
}
}
}
func printPullerror(pullError []string) {
if len(pullError) > 0 {
for _, repo := range pullError {
fmt.Printf("❕%s has unstaged changes.\n", repo)
}
} }
} }