2019-06-09 14:44:07 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
2019-07-09 16:42:04 +02:00
|
|
|
"errors"
|
2019-06-09 14:44:07 +02:00
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"os"
|
2019-07-10 15:07:41 +02:00
|
|
|
"sync"
|
2019-06-09 14:44:07 +02:00
|
|
|
)
|
|
|
|
|
2019-07-07 12:47:28 +02:00
|
|
|
// GetReposFromGitHub get starred repositories from github
|
2019-07-09 16:42:04 +02:00
|
|
|
func GetReposFromGitHub(config *Config) ([]GitHubRepo, error) {
|
2019-07-23 22:02:18 +02:00
|
|
|
var repopartiallist []GitHubRepo
|
|
|
|
var repofulllist []GitHubRepo
|
2019-07-07 12:47:28 +02:00
|
|
|
|
2019-07-14 19:32:47 +02:00
|
|
|
fmt.Println("Getting GitHub starred repos")
|
2019-08-24 21:53:02 +02:00
|
|
|
for num := 1; num <= config.GitHubPageNum; num++ {
|
|
|
|
url := fmt.Sprintf("https://api.github.com/users/%s/starred?per_page=%d&page=%d", config.GitHubAuthUsername, config.GitHubMaxPerPage, num)
|
2019-07-10 15:07:41 +02:00
|
|
|
fmt.Println(url)
|
2019-07-07 12:47:28 +02:00
|
|
|
|
2019-10-12 10:08:05 +02:00
|
|
|
resp, err := GetGitHubRepos(config, url)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2019-07-24 00:27:41 +02:00
|
|
|
respbody, err := ioutil.ReadAll(resp.Body)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-07-07 12:47:28 +02:00
|
|
|
|
2019-07-24 00:27:41 +02:00
|
|
|
err = json.Unmarshal(respbody, &repopartiallist)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-07-24 00:27:41 +02:00
|
|
|
|
2019-07-23 22:02:18 +02:00
|
|
|
for _, elem := range repopartiallist {
|
|
|
|
repofulllist = append(repofulllist, elem)
|
2019-07-07 12:47:28 +02:00
|
|
|
}
|
|
|
|
}
|
2019-07-10 15:07:41 +02:00
|
|
|
|
2019-07-23 22:02:18 +02:00
|
|
|
fmt.Println(fmt.Sprintf("%d repositories from Github fetched", len(repofulllist)))
|
|
|
|
return repofulllist, nil
|
2019-07-07 12:47:28 +02:00
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-10-12 10:08:05 +02:00
|
|
|
// GetGitHubRepos fetchs starred repositories on GitHub
|
|
|
|
func GetGitHubRepos(config *Config, url string) (*http.Response, error) {
|
2019-07-07 12:47:28 +02:00
|
|
|
req, err := http.NewRequest("GET", url, nil)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
|
|
|
req.SetBasicAuth(config.GitHubAuthUsername, config.GitHubAuthPassword)
|
2019-07-07 12:47:28 +02:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
resp, err := client.Do(req)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2019-07-07 12:47:28 +02:00
|
|
|
|
2019-10-12 10:08:05 +02:00
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
return nil, fmt.Errorf("Error on status code %s", resp.Status)
|
|
|
|
}
|
|
|
|
|
2019-07-09 16:42:04 +02:00
|
|
|
return resp, nil
|
2019-07-07 12:47:28 +02:00
|
|
|
}
|
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
// CheckGiteaExistingRepo checks if there's an existing repository in gitea
|
|
|
|
func CheckGiteaExistingRepo(config *Config, repo GitHubRepo) (bool, error) {
|
2019-10-12 10:08:05 +02:00
|
|
|
var isExists bool
|
2019-07-07 12:47:28 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
gitearepourl := fmt.Sprintf(config.GiteaRepoURLTmpl, config.GiteaDestUsername, repo.Name)
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
req, err := http.NewRequest("GET", gitearepourl, nil)
|
|
|
|
req.Header.Set("Authorization", config.GiteaAuthToken)
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-07-07 12:47:28 +02:00
|
|
|
client := &http.Client{}
|
|
|
|
resp, err := client.Do(req)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return false, err
|
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-10-12 10:08:05 +02:00
|
|
|
if resp.StatusCode == http.StatusOK {
|
|
|
|
isExists = true
|
|
|
|
} else if resp.StatusCode == http.StatusNotFound {
|
|
|
|
isExists = false
|
2019-06-09 14:44:07 +02:00
|
|
|
} else {
|
2019-10-12 10:08:05 +02:00
|
|
|
return false, fmt.Errorf("Can't determine error, cancelling, error %s in gitea webservice", resp.Status)
|
2019-06-09 14:44:07 +02:00
|
|
|
}
|
|
|
|
|
2019-10-12 10:08:05 +02:00
|
|
|
return isExists, nil
|
2019-06-09 14:44:07 +02:00
|
|
|
}
|
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
// GetGiteaUserUID get the logued user identifier
|
|
|
|
func (config *Config) GetGiteaUserUID() error {
|
|
|
|
var giteaorg GiteaOrg
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
gitearepourl := fmt.Sprintf(config.GiteaOrgsURLTmpl, config.GiteaDestUsername)
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
req, err := http.NewRequest("GET", gitearepourl, nil)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
req.Header.Set("Authorization", config.GiteaAuthToken)
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-07-07 12:47:28 +02:00
|
|
|
client := &http.Client{}
|
|
|
|
resp, err := client.Do(req)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode != 200 {
|
2019-08-24 21:53:02 +02:00
|
|
|
err = errors.New("Error invoking gitea webservice")
|
2019-07-09 16:42:04 +02:00
|
|
|
return err
|
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-07-24 00:27:41 +02:00
|
|
|
respbody, err := ioutil.ReadAll(resp.Body)
|
2019-07-09 16:42:04 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
err = json.Unmarshal(respbody, &giteaorg)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
2019-08-24 21:53:02 +02:00
|
|
|
err = errors.New("Failed to parse user ID from gitea webservice, check auth")
|
2019-07-09 16:42:04 +02:00
|
|
|
return err
|
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
config.GiteaUID = giteaorg.ID
|
2019-07-09 16:42:04 +02:00
|
|
|
|
|
|
|
return nil
|
2019-06-09 14:44:07 +02:00
|
|
|
}
|
|
|
|
|
2019-07-10 15:07:41 +02:00
|
|
|
// RunMigration run threads for migration
|
|
|
|
func RunMigration(config *Config, repolist []GitHubRepo) {
|
2019-07-14 19:32:47 +02:00
|
|
|
repochan := make(chan GitHubRepo)
|
2019-07-10 15:07:41 +02:00
|
|
|
done := make(chan bool)
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-07-10 15:07:41 +02:00
|
|
|
var wg sync.WaitGroup
|
2019-10-12 10:08:05 +02:00
|
|
|
for thr := range make([]int, config.G2gThreads) {
|
2019-08-24 21:53:02 +02:00
|
|
|
go MigrateReposToGitea(config, &wg, repochan, done, thr)
|
2019-07-10 15:07:41 +02:00
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-07-10 15:07:41 +02:00
|
|
|
for _, repo := range repolist {
|
2019-07-14 19:32:47 +02:00
|
|
|
repochan <- repo
|
2019-07-10 15:07:41 +02:00
|
|
|
}
|
2019-07-14 19:32:47 +02:00
|
|
|
close(repochan)
|
2019-07-10 15:07:41 +02:00
|
|
|
<-done
|
|
|
|
wg.Wait()
|
|
|
|
}
|
2019-06-09 14:44:07 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
// MigrateReposToGitea migrates input repositories to gitea
|
|
|
|
func MigrateReposToGitea(config *Config, wg *sync.WaitGroup, jobs chan GitHubRepo, done chan bool, thr int) error {
|
2019-07-10 15:07:41 +02:00
|
|
|
wg.Add(1)
|
|
|
|
for {
|
|
|
|
elem, more := <-jobs
|
|
|
|
if more {
|
|
|
|
client := &http.Client{}
|
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
existingrepo, err := CheckGiteaExistingRepo(config, elem)
|
2019-07-09 16:42:04 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-07-10 15:07:41 +02:00
|
|
|
if !existingrepo {
|
2019-08-24 21:53:02 +02:00
|
|
|
jsondata := fmt.Sprintf(`{"uid" : %d, "repo_name" : "%s" , "mirror" : %v, "clone_addr" : "%s"}`, config.GiteaUID, elem.Name, true, elem.CloneURL)
|
2019-07-10 15:07:41 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
req, err := http.NewRequest("POST", config.GiteaMigrateURL, bytes.NewBufferString(jsondata))
|
2019-07-10 15:07:41 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
req.Header.Set("Authorization", config.GiteaAuthToken)
|
2019-07-10 15:07:41 +02:00
|
|
|
|
2019-10-12 10:08:05 +02:00
|
|
|
client.Timeout = config.G2gRequestTimeout
|
2019-07-10 15:07:41 +02:00
|
|
|
|
2019-08-24 21:53:02 +02:00
|
|
|
fmt.Println(fmt.Sprintf("Migrating repo %s to gitea rest api", elem.Name))
|
2019-07-24 00:27:41 +02:00
|
|
|
|
|
|
|
resp, err := client.Do(req)
|
2019-07-10 15:07:41 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-07-24 00:27:41 +02:00
|
|
|
|
2019-07-10 15:07:41 +02:00
|
|
|
if resp.StatusCode != 201 {
|
2019-08-24 21:53:02 +02:00
|
|
|
err = fmt.Errorf("Error when migrating repo %s to gitea with status code %d on gitea webservice", elem.Name, resp.StatusCode)
|
2019-07-10 15:07:41 +02:00
|
|
|
log.Println(err)
|
|
|
|
}
|
|
|
|
} else {
|
2019-08-24 21:53:02 +02:00
|
|
|
fmt.Println(fmt.Sprintf("Not migrating, %s exists in gitea", elem.Name))
|
2019-07-09 16:42:04 +02:00
|
|
|
}
|
2019-07-07 12:47:28 +02:00
|
|
|
} else {
|
2019-07-10 15:07:41 +02:00
|
|
|
fmt.Println(fmt.Sprintf("All repo migrated on thread num %d", thr))
|
|
|
|
wg.Done()
|
|
|
|
done <- true
|
|
|
|
return nil
|
2019-06-09 14:44:07 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Usage displays possible arguments
|
|
|
|
func Usage() {
|
|
|
|
flag.PrintDefaults()
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
2019-10-12 10:08:05 +02:00
|
|
|
|
|
|
|
// GitHubRepo githubrepo struct
|
|
|
|
type GitHubRepo struct {
|
|
|
|
Name string `json:"name"`
|
|
|
|
CloneURL string `json:"clone_url"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GiteaOrg gitearepo struct
|
|
|
|
type GiteaOrg struct {
|
|
|
|
ID int `json:"id"`
|
|
|
|
Username string `json:"username"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// GiteaMigrateRepo defines the repo to migrate
|
|
|
|
type GiteaMigrateRepo struct {
|
|
|
|
Name string
|
|
|
|
CloneURL string
|
|
|
|
UID int
|
|
|
|
Mirror bool
|
|
|
|
}
|