diff --git a/cmd/gogitlabber/git.go b/cmd/gogitlabber/git.go index 1c3c709..7ebc508 100644 --- a/cmd/gogitlabber/git.go +++ b/cmd/gogitlabber/git.go @@ -41,8 +41,8 @@ func checkoutRepositories(repositories []Repository, concurrency int) { // log activity logger.Print("Starting on repository: "+repoName, nil) - // make gitlab url - url := fmt.Sprintf("https://gitlab-token:%s@%s/%s.git", gitlabToken, gitlabHost, repoName) + // make git url + url := fmt.Sprintf("https://%s-token:%s@%s/%s.git", gitBackend, gitToken, gitHost, repoName) // check current status of repoDestination checkRepo := func(repoDestination string) string { diff --git a/cmd/gogitlabber/gitea.go b/cmd/gogitlabber/gitea.go new file mode 100644 index 0000000..51006ee --- /dev/null +++ b/cmd/gogitlabber/gitea.go @@ -0,0 +1,99 @@ +package main + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/scornet256/go-logger" +) + +func fetchRepositoriesGitea() ([]Repository, error) { + + type GiteaRepository struct { + Name string `json:"name"` + FullName string `json:"full_name"` + } + + // default options + visibility := "visibility=all" + perpage := "limit=100" + sort := "sort=alpha" + + // configure archived options + var archived string + switch includeArchived { + case "excluded": + archived = "&archived=false" + case "only": + archived = "&archived=true" + default: + archived = "" + } + + url := fmt.Sprintf("https://%s/api/v1/user/repos?%s&%s&%s%s", + gitHost, visibility, sort, perpage, archived) + + logger.Print("HTTP: Creating API request", nil) + req, err := http.NewRequest("GET", url, nil) + if err != nil { + return nil, fmt.Errorf("ERROR: creating request: %v", err) + } + + logger.Print("HTTP: Adding Authorization header to API request", nil) + req.Header.Set("Authorization", fmt.Sprintf("token %s", gitToken)) + + logger.Print("HTTP: Making request", nil) + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, fmt.Errorf("ERROR: making request: %v", err) + } + + defer func() { + if err := resp.Body.Close(); err != nil { + logger.Fatal("HTTP: Error closing response body", err) + } + }() + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("ERROR: API request failed with status: %d", resp.StatusCode) + } + logger.Print("HTTP: Decoding JSON response", nil) + + // first decode into gitearepository slice + var giteaRepos []GiteaRepository + if err := json.NewDecoder(resp.Body).Decode(&giteaRepos); err != nil { + return nil, fmt.Errorf("ERROR: decoding response: %v", err) + } + + // convert to repository slice + repositories := make([]Repository, len(giteaRepos)) + for repo, giteaRepo := range giteaRepos { + repositories[repo] = Repository{ + Name: giteaRepo.Name, + PathWithNamespace: giteaRepo.FullName, + } + } + + if len(repositories) < 1 { + return repositories, fmt.Errorf("ERROR: no repositories found") + } + repoCount := len(repositories) + + logger.Print("BAR: Resetting the progressbar", nil) + if !debug { + err = bar.Set(0) + if err != nil { + logger.Fatal("Could not reset the progressbar", err) + } + } + + logger.Print("BAR: Increasing the max value of the progressbar", nil) + if !debug { + bar.ChangeMax(repoCount) + } + + logger.Print("HTTP: Returning repositories found", nil) + return repositories, nil +} diff --git a/cmd/gogitlabber/gitlab.go b/cmd/gogitlabber/gitlab.go index e7bfd74..0a72ef4 100644 --- a/cmd/gogitlabber/gitlab.go +++ b/cmd/gogitlabber/gitlab.go @@ -27,7 +27,7 @@ func fetchRepositoriesGitlab() ([]Repository, error) { } url := fmt.Sprintf("https://%s/api/v4/projects?%s&%s&%s%s", - gitlabHost, membership, order, perpage, archived) + gitHost, membership, order, perpage, archived) logger.Print("HTTP: Creating API request", nil) req, err := http.NewRequest("GET", url, nil) @@ -36,7 +36,7 @@ func fetchRepositoriesGitlab() ([]Repository, error) { } logger.Print("HTTP: Adding PRIVATE-TOKEN header to API request", nil) - req.Header.Set("PRIVATE-TOKEN", gitlabToken) + req.Header.Set("PRIVATE-TOKEN", gitToken) logger.Print("HTTP: Making request", nil) client := &http.Client{} diff --git a/cmd/gogitlabber/input.go b/cmd/gogitlabber/input.go index 5c073eb..072fd28 100644 --- a/cmd/gogitlabber/input.go +++ b/cmd/gogitlabber/input.go @@ -16,8 +16,8 @@ func setDefaultsFromEnv() { // set default values debug = false concurrency = 15 - gitlabHost = "gitlab.com" - gitlabToken = "" + gitHost = "gitlab.com" + gitToken = "" includeArchived = "excluded" repoDestinationPre = "$HOME/Documents" @@ -30,12 +30,16 @@ func setDefaultsFromEnv() { } } - if envToken := os.Getenv("GITLAB_API_TOKEN"); envToken != "" { - gitlabToken = envToken + if envBackend := os.Getenv("GOGITLABBER_BACKEND"); envBackend != "" { + gitBackend = envBackend } - if envHost := os.Getenv("GITLAB_URL"); envHost != "" { - gitlabHost = envHost + if envToken := os.Getenv("GIT_API_TOKEN"); envToken != "" { + gitToken = envToken + } + + if envHost := os.Getenv("GIT_URL"); envHost != "" { + gitHost = envHost } if envRepoDest := os.Getenv("GOGITLABBER_DESTINATION"); envRepoDest != "" { @@ -81,15 +85,20 @@ func manageArguments() { repoDestinationPre, "Specify where to check the repositories out\n example: -destination=$HOME/repos\nenv = GOGITLABBER_DESTINATION\n") + var backendFlag = flag.String( + "backend", + gitBackend, + "Specify git backend\n example -backend=gitlab\nenv = GOGITLABBER_BACKEND\n") + var hostFlag = flag.String( - "gitlab-url", - gitlabHost, - "Specify GitLab host\n example: -gitlab-url=gitlab.com\nenv = GITLAB_URL\n") + "git-url", + gitHost, + "Specify GitLab/Gitea host\n example: -git-url=gitlab.com\nenv = GIT_URL\n") var tokenFlag = flag.String( - "gitlab-api-token", - gitlabToken, - "Specify GitLab API token\n example: -gitlab-api=glpat-xxxx\nenv = GITLAB_API_TOKEN\n") + "git-api-token", + gitToken, + "Specify GitLab/Gitea API token\n example: -git-api=glpat-xxxx\nenv = GIT_API_TOKEN\n") var debugFlag = flag.Bool( "debug", @@ -109,8 +118,9 @@ func manageArguments() { // override with flag values (higher precedence) concurrency = *concurrencyFlag debug = *debugFlag - gitlabHost = *hostFlag - gitlabToken = *tokenFlag + gitHost = *hostFlag + gitToken = *tokenFlag + gitBackend = *backendFlag includeArchived = *archivedFlag repoDestinationPre = *destinationFlag @@ -120,9 +130,9 @@ func manageArguments() { } // validate required parameters - if gitlabToken == "" { + if gitToken == "" { flag.Usage() - logger.Fatal("Configuration: Gitlab API Token not found", nil) + logger.Fatal("Configuration: API Token not found", nil) } // validate archived option @@ -134,7 +144,7 @@ func manageArguments() { } // log configuration - logger.Print("Configuration: Using GitLab host: "+gitlabHost, nil) + logger.Print("Configuration: Using host: "+gitHost, nil) logger.Print("Configuration: Using destination: "+repoDestinationPre, nil) logger.Print("Configuration: Using concurrency: "+strconv.Itoa(concurrency), nil) logger.Print("Configuration: Using archived option: "+includeArchived, nil) diff --git a/cmd/gogitlabber/main.go b/cmd/gogitlabber/main.go index 8de152f..5d43689 100644 --- a/cmd/gogitlabber/main.go +++ b/cmd/gogitlabber/main.go @@ -10,11 +10,14 @@ var version string // userdata var concurrency int var debug bool -var gitlabHost string -var gitlabToken string var includeArchived string var repoDestinationPre string +// git +var gitHost string +var gitToken string +var gitBackend string + // keep count 🧛 var clonedCount int var errorCount int @@ -30,7 +33,7 @@ type Repository struct { func main() { // set app version - version = "0.0.9" + version = "1.0.0" // set appname for logger logger.SetAppName("gogitlabber") @@ -53,9 +56,20 @@ func main() { progressBar() } - // fetch repository information from gitlab - repositories, err := fetchRepositoriesGitlab() - if err != nil { + // fetch repository information + var repositories []Repository + switch gitBackend { + case "gitea": + repositories, err = fetchRepositoriesGitea() + if err != nil { + logger.Fatal("Fetching repositories failed", err) + } + case "gitlab": + repositories, err = fetchRepositoriesGitlab() + if err != nil { + logger.Fatal("Fetching repositories failed", err) + } + default: logger.Fatal("Fetching repositories failed", err) } diff --git a/cmd/gogitlabber/output.go b/cmd/gogitlabber/output.go index 189fb02..070c153 100644 --- a/cmd/gogitlabber/output.go +++ b/cmd/gogitlabber/output.go @@ -15,7 +15,7 @@ func progressBar() { // configure progressbar bar = progressbar.NewOptions(2, progressbar.OptionEnableColorCodes(true), - progressbar.OptionSetDescription("Logging into Gitlab..."), + progressbar.OptionSetDescription("Logging into Git..."), progressbar.OptionSetElapsedTime(false), progressbar.OptionSetPredictTime(false), progressbar.OptionSetWidth(20), diff --git a/readme.md b/readme.md index ae73379..aa1e47d 100644 --- a/readme.md +++ b/readme.md @@ -6,7 +6,7 @@ solves my problem. 😆 It is definitely not as feature-rich as the original project... 😬 -The program can clone and pull all repositories you have access to on a selfhosted or SaaS provided Gitlab server. +The program can clone and pull all repositories you have access to on a selfhosted or SaaS provided Gitlab or Gitea server. It only supports the HTTP access method. It will pull the repositories in a tree like structure same as on Gitlab. @@ -32,6 +32,11 @@ Usage of gogitlabber: env = GOGITLABBER_ARCHIVED (default "excluded") + -backend string + Specify git backend + example: -backend=gitlab + env = GOGITLABBER_BACKEND + -concurrency int Specify repository concurrency example: -concurrency=15 @@ -50,15 +55,15 @@ Usage of gogitlabber: env = GOGITLABBER_DESTINATION (default "$HOME/Documents") - -gitlab-api-token string - Specify GitLab API token - example: -gitlab-api=glpat-xxxx - env = GITLAB_API_TOKEN + -git-api-token string + Specify API token + example: -git-api=glpat-xxxx + env = GIT_API_TOKEN (default "") - -gitlab-url string - Specify GitLab host - example: -gitlab-url=gitlab.example.com - env = GITLAB_URL + -git-url string + Specify Git host + example: -git-url=gitlab.example.com + env = GIT_URL (default "gitlab.com") ```