feat: added gitea backend support

This commit is contained in:
Simon Cornet 2025-04-09 16:54:02 +02:00
commit 5ddc973a3d
7 changed files with 165 additions and 37 deletions

View file

@ -41,8 +41,8 @@ func checkoutRepositories(repositories []Repository, concurrency int) {
// log activity // log activity
logger.Print("Starting on repository: "+repoName, nil) logger.Print("Starting on repository: "+repoName, nil)
// make gitlab url // make git url
url := fmt.Sprintf("https://gitlab-token:%s@%s/%s.git", gitlabToken, gitlabHost, repoName) url := fmt.Sprintf("https://%s-token:%s@%s/%s.git", gitBackend, gitToken, gitHost, repoName)
// check current status of repoDestination // check current status of repoDestination
checkRepo := func(repoDestination string) string { checkRepo := func(repoDestination string) string {

99
cmd/gogitlabber/gitea.go Normal file
View file

@ -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
}

View file

@ -27,7 +27,7 @@ func fetchRepositoriesGitlab() ([]Repository, error) {
} }
url := fmt.Sprintf("https://%s/api/v4/projects?%s&%s&%s%s", 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) logger.Print("HTTP: Creating API request", nil)
req, err := http.NewRequest("GET", url, 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) 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) logger.Print("HTTP: Making request", nil)
client := &http.Client{} client := &http.Client{}

View file

@ -16,8 +16,8 @@ func setDefaultsFromEnv() {
// set default values // set default values
debug = false debug = false
concurrency = 15 concurrency = 15
gitlabHost = "gitlab.com" gitHost = "gitlab.com"
gitlabToken = "" gitToken = ""
includeArchived = "excluded" includeArchived = "excluded"
repoDestinationPre = "$HOME/Documents" repoDestinationPre = "$HOME/Documents"
@ -30,12 +30,16 @@ func setDefaultsFromEnv() {
} }
} }
if envToken := os.Getenv("GITLAB_API_TOKEN"); envToken != "" { if envBackend := os.Getenv("GOGITLABBER_BACKEND"); envBackend != "" {
gitlabToken = envToken gitBackend = envBackend
} }
if envHost := os.Getenv("GITLAB_URL"); envHost != "" { if envToken := os.Getenv("GIT_API_TOKEN"); envToken != "" {
gitlabHost = envHost gitToken = envToken
}
if envHost := os.Getenv("GIT_URL"); envHost != "" {
gitHost = envHost
} }
if envRepoDest := os.Getenv("GOGITLABBER_DESTINATION"); envRepoDest != "" { if envRepoDest := os.Getenv("GOGITLABBER_DESTINATION"); envRepoDest != "" {
@ -81,15 +85,20 @@ func manageArguments() {
repoDestinationPre, repoDestinationPre,
"Specify where to check the repositories out\n example: -destination=$HOME/repos\nenv = GOGITLABBER_DESTINATION\n") "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( var hostFlag = flag.String(
"gitlab-url", "git-url",
gitlabHost, gitHost,
"Specify GitLab host\n example: -gitlab-url=gitlab.com\nenv = GITLAB_URL\n") "Specify GitLab/Gitea host\n example: -git-url=gitlab.com\nenv = GIT_URL\n")
var tokenFlag = flag.String( var tokenFlag = flag.String(
"gitlab-api-token", "git-api-token",
gitlabToken, gitToken,
"Specify GitLab API token\n example: -gitlab-api=glpat-xxxx\nenv = GITLAB_API_TOKEN\n") "Specify GitLab/Gitea API token\n example: -git-api=glpat-xxxx\nenv = GIT_API_TOKEN\n")
var debugFlag = flag.Bool( var debugFlag = flag.Bool(
"debug", "debug",
@ -109,8 +118,9 @@ func manageArguments() {
// override with flag values (higher precedence) // override with flag values (higher precedence)
concurrency = *concurrencyFlag concurrency = *concurrencyFlag
debug = *debugFlag debug = *debugFlag
gitlabHost = *hostFlag gitHost = *hostFlag
gitlabToken = *tokenFlag gitToken = *tokenFlag
gitBackend = *backendFlag
includeArchived = *archivedFlag includeArchived = *archivedFlag
repoDestinationPre = *destinationFlag repoDestinationPre = *destinationFlag
@ -120,9 +130,9 @@ func manageArguments() {
} }
// validate required parameters // validate required parameters
if gitlabToken == "" { if gitToken == "" {
flag.Usage() flag.Usage()
logger.Fatal("Configuration: Gitlab API Token not found", nil) logger.Fatal("Configuration: API Token not found", nil)
} }
// validate archived option // validate archived option
@ -134,7 +144,7 @@ func manageArguments() {
} }
// log configuration // 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 destination: "+repoDestinationPre, nil)
logger.Print("Configuration: Using concurrency: "+strconv.Itoa(concurrency), nil) logger.Print("Configuration: Using concurrency: "+strconv.Itoa(concurrency), nil)
logger.Print("Configuration: Using archived option: "+includeArchived, nil) logger.Print("Configuration: Using archived option: "+includeArchived, nil)

View file

@ -10,11 +10,14 @@ var version string
// userdata // userdata
var concurrency int var concurrency int
var debug bool var debug bool
var gitlabHost string
var gitlabToken string
var includeArchived string var includeArchived string
var repoDestinationPre string var repoDestinationPre string
// git
var gitHost string
var gitToken string
var gitBackend string
// keep count 🧛 // keep count 🧛
var clonedCount int var clonedCount int
var errorCount int var errorCount int
@ -30,7 +33,7 @@ type Repository struct {
func main() { func main() {
// set app version // set app version
version = "0.0.9" version = "1.0.0"
// set appname for logger // set appname for logger
logger.SetAppName("gogitlabber") logger.SetAppName("gogitlabber")
@ -53,9 +56,20 @@ func main() {
progressBar() progressBar()
} }
// fetch repository information from gitlab // fetch repository information
repositories, err := fetchRepositoriesGitlab() var repositories []Repository
if err != nil { 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) logger.Fatal("Fetching repositories failed", err)
} }

View file

@ -15,7 +15,7 @@ func progressBar() {
// configure progressbar // configure progressbar
bar = progressbar.NewOptions(2, bar = progressbar.NewOptions(2,
progressbar.OptionEnableColorCodes(true), progressbar.OptionEnableColorCodes(true),
progressbar.OptionSetDescription("Logging into Gitlab..."), progressbar.OptionSetDescription("Logging into Git..."),
progressbar.OptionSetElapsedTime(false), progressbar.OptionSetElapsedTime(false),
progressbar.OptionSetPredictTime(false), progressbar.OptionSetPredictTime(false),
progressbar.OptionSetWidth(20), progressbar.OptionSetWidth(20),

View file

@ -6,7 +6,7 @@ solves my problem. 😆
It is definitely not as feature-rich as the original project... 😬 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 only supports the HTTP access method.
It will pull the repositories in a tree like structure same as on Gitlab. It will pull the repositories in a tree like structure same as on Gitlab.
@ -32,6 +32,11 @@ Usage of gogitlabber:
env = GOGITLABBER_ARCHIVED env = GOGITLABBER_ARCHIVED
(default "excluded") (default "excluded")
-backend string
Specify git backend
example: -backend=gitlab
env = GOGITLABBER_BACKEND
-concurrency int -concurrency int
Specify repository concurrency Specify repository concurrency
example: -concurrency=15 example: -concurrency=15
@ -50,15 +55,15 @@ Usage of gogitlabber:
env = GOGITLABBER_DESTINATION env = GOGITLABBER_DESTINATION
(default "$HOME/Documents") (default "$HOME/Documents")
-gitlab-api-token string -git-api-token string
Specify GitLab API token Specify API token
example: -gitlab-api=glpat-xxxx example: -git-api=glpat-xxxx
env = GITLAB_API_TOKEN env = GIT_API_TOKEN
(default "") (default "")
-gitlab-url string -git-url string
Specify GitLab host Specify Git host
example: -gitlab-url=gitlab.example.com example: -git-url=gitlab.example.com
env = GITLAB_URL env = GIT_URL
(default "gitlab.com") (default "gitlab.com")
``` ```