From bc771c1b4dcff66d2f3165a82279764e59301fb2 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Mon, 6 Jul 2026 23:06:18 -0400 Subject: [PATCH] Initial code commit --- .gitignore | 4 +++ README.md | 9 ++++++ go.mod | 5 +++ go.sum | 2 ++ main.go | 94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 114 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1601855 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/repos +/repos.bak +/repos-new +/go-gitea-vendor diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea1c710 --- /dev/null +++ b/README.md @@ -0,0 +1,9 @@ +# go-gitea-vendor +Want to vendor all your Go projects on your personal Gitea instance? +Don't want to bloat your git history? +Use `go-gitea-vendor` to maintain a separate repo that is only the latest vendoring! + +## Usage +`echo 'EXAMPLE_API_TOKEN' | go-gitea-vendor https://gitea.example.com` + +I recommend setting up a chron job or some form of automation for this. diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..494baeb --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module go-gitea-vendor + +go 1.26.4 + +require github.com/rwinkhart/go-boilerplate v0.3.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..969f986 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/rwinkhart/go-boilerplate v0.3.1 h1:vkVRuptO2s1yPzzwpvtiiB0c/hPB6yr0p1mzZ2Myb9E= +github.com/rwinkhart/go-boilerplate v0.3.1/go.mod h1:ES13A2r9fnCVfyezwMBgY/RgA4pOIudOUXz3Jk/ikes= diff --git a/main.go b/main.go new file mode 100644 index 0000000..587143b --- /dev/null +++ b/main.go @@ -0,0 +1,94 @@ +package main + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "os" + "os/exec" + + "github.com/rwinkhart/go-boilerplate/back" + "github.com/rwinkhart/go-boilerplate/other" +) + +type giteaRespT struct { + Data []struct { + Language string `json:"language"` + MasterURL string `json:"original_url"` + Name string `json:"name"` + } +} + +func main() { + if len(os.Args) != 2 { + fmt.Println("Usage: " + os.Args[0] + " \n\nAPI token can be piped into stdin to run non-interactively!") + os.Exit(0) + } + + url := os.Args[1] + "/api/v1/repos/search?sort=updated&order=desc&limit=999" + fmt.Print("Input token: ") + token := back.ReadFromStdin() + if len(token) == 0 { + other.PrintError("No token provided; API token must be provided via stdin!", 1) + } + fmt.Print("\r \r") + + req, err := http.NewRequest("GET", url, nil) + if err != nil { + other.PrintError("Failed to create request: "+err.Error(), 2) + } + + req.Header.Set("Accept", "application/json") + req.Header.Set("Authorization", "token "+string(token)) + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + other.PrintError("Failed to make request: "+err.Error(), 3) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + other.PrintError("Failed to read response body: "+err.Error(), 4) + } + + var giteaResp giteaRespT + if err = json.Unmarshal(body, &giteaResp); err != nil { + other.PrintError("Failed to unmarshal response: "+err.Error(), 5) + } + + const workingDir = "repos-new" + const finishedDir = "repos" + os.Mkdir(workingDir, 0755) + for _, repo := range giteaResp.Data { + if repo.Language == "Go" { + cloneCmd := exec.Command("git", "clone", "--depth=1", repo.MasterURL) + cloneCmd.Dir = workingDir + if err = cloneCmd.Run(); err != nil { + other.PrintError("Failed to clone "+repo.MasterURL+": "+err.Error(), 6) + } + vendorCmd := exec.Command("go", "mod", "vendor") + vendorCmd.Dir = workingDir + "/" + repo.Name + if err = vendorCmd.Run(); err != nil { + other.PrintError("Failed to vendor "+repo.MasterURL+": "+err.Error(), 7) + } + if err = os.RemoveAll(workingDir + "/" + repo.Name + "/.git"); err != nil { + other.PrintError("Failed to remove .git directory for "+repo.MasterURL, 8) + } + } + } + isAccessible, err := back.TargetIsFile(finishedDir, false) + if isAccessible && err == nil { + if err = os.RemoveAll(finishedDir + ".bak"); err != nil { + other.PrintError("Failed to remove old backup dir", 9) + } + if err = os.Rename(finishedDir, finishedDir+".bak"); err != nil { + other.PrintError("Failed to backup old repos dir", 10) + } + } + if err = os.Rename(workingDir, finishedDir); err != nil { + other.PrintError("Failed to rename new repos dir", 11) + } +}