package main import ( "bytes" "encoding/json" "errors" "flag" "fmt" "io/ioutil" "log" "net/http" "os" "sync" ) // GetReposFromGitHub get starred repositories from github func GetReposFromGitHub(config *Config) ([]GitHubRepo, error) { var repopartiallist []GitHubRepo var repofulllist []GitHubRepo fmt.Println("Getting GitHub starred repos") 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) fmt.Println(url) resp, err := GetGitHubRepos(config, url) if err != nil { return nil, err } respbody, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } err = json.Unmarshal(respbody, &repopartiallist) if err != nil { return nil, err } for _, elem := range repopartiallist { repofulllist = append(repofulllist, elem) } } fmt.Println(fmt.Sprintf("%d repositories from Github fetched", len(repofulllist))) return repofulllist, nil } // GetGitHubRepos fetchs starred repositories on GitHub func GetGitHubRepos(config *Config, url string) (*http.Response, error) { req, err := http.NewRequest("GET", url, nil) if err != nil { return nil, err } req.Header.Add("Content-Type", "application/x-www-form-urlencoded") req.SetBasicAuth(config.GitHubAuthUsername, config.GitHubAuthPassword) client := &http.Client{} resp, err := client.Do(req) if err != nil { return nil, err } if resp.StatusCode != http.StatusOK { return nil, fmt.Errorf("Error on status code %s", resp.Status) } return resp, nil } // CheckGiteaExistingRepo checks if there's an existing repository in gitea func CheckGiteaExistingRepo(config *Config, repo GitHubRepo) (bool, error) { var isExists bool gitearepourl := fmt.Sprintf(config.GiteaRepoURLTmpl, config.GiteaDestUsername, repo.Name) req, err := http.NewRequest("GET", gitearepourl, nil) req.Header.Set("Authorization", config.GiteaAuthToken) client := &http.Client{} resp, err := client.Do(req) if err != nil { return false, err } if resp.StatusCode == http.StatusOK { isExists = true } else if resp.StatusCode == http.StatusNotFound { isExists = false } else { return false, fmt.Errorf("Can't determine error, cancelling, error %s in gitea webservice", resp.Status) } return isExists, nil } // GetGiteaUserUID get the logued user identifier func (config *Config) GetGiteaUserUID() error { var giteaorg GiteaOrg gitearepourl := fmt.Sprintf(config.GiteaOrgsURLTmpl, config.GiteaDestUsername) req, err := http.NewRequest("GET", gitearepourl, nil) if err != nil { return err } req.Header.Set("Authorization", config.GiteaAuthToken) client := &http.Client{} resp, err := client.Do(req) if err != nil { return err } if resp.StatusCode != 200 { err = errors.New("Error invoking gitea webservice") return err } respbody, err := ioutil.ReadAll(resp.Body) err = json.Unmarshal(respbody, &giteaorg) if err != nil { err = errors.New("Failed to parse user ID from gitea webservice, check auth") return err } config.GiteaUID = giteaorg.ID return nil } // RunMigration run threads for migration func RunMigration(config *Config, repolist []GitHubRepo) { repochan := make(chan GitHubRepo) done := make(chan bool) var wg sync.WaitGroup for thr := range make([]int, config.G2gThreads) { go MigrateReposToGitea(config, &wg, repochan, done, thr) } for _, repo := range repolist { repochan <- repo } close(repochan) <-done wg.Wait() } // MigrateReposToGitea migrates input repositories to gitea func MigrateReposToGitea(config *Config, wg *sync.WaitGroup, jobs chan GitHubRepo, done chan bool, thr int) error { wg.Add(1) for { elem, more := <-jobs if more { client := &http.Client{} existingrepo, err := CheckGiteaExistingRepo(config, elem) if err != nil { return err } if !existingrepo { jsondata := fmt.Sprintf(`{"uid" : %d, "repo_name" : "%s" , "mirror" : %v, "clone_addr" : "%s"}`, config.GiteaUID, elem.Name, true, elem.CloneURL) req, err := http.NewRequest("POST", config.GiteaMigrateURL, bytes.NewBufferString(jsondata)) if err != nil { return err } req.Header.Add("Content-Type", "application/json") req.Header.Set("Authorization", config.GiteaAuthToken) client.Timeout = config.G2gRequestTimeout fmt.Println(fmt.Sprintf("Migrating repo %s to gitea rest api", elem.Name)) resp, err := client.Do(req) if err != nil { return err } if resp.StatusCode != 201 { err = fmt.Errorf("Error when migrating repo %s to gitea with status code %d on gitea webservice", elem.Name, resp.StatusCode) log.Println(err) } } else { fmt.Println(fmt.Sprintf("Not migrating, %s exists in gitea", elem.Name)) } } else { fmt.Println(fmt.Sprintf("All repo migrated on thread num %d", thr)) wg.Done() done <- true return nil } } } // Usage displays possible arguments func Usage() { flag.PrintDefaults() os.Exit(1) } // 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 }