initial commit
This commit is contained in:
34
.gitignore
vendored
Normal file
34
.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
.env
|
||||||
|
debug
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/visualstudiocode
|
||||||
|
|
||||||
|
### VisualStudioCode ###
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.history
|
||||||
|
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/visualstudiocode
|
||||||
|
|
||||||
|
# Created by https://www.gitignore.io/api/go
|
||||||
|
|
||||||
|
### Go ###
|
||||||
|
# Binaries for programs and plugins
|
||||||
|
*.exe
|
||||||
|
*.exe~
|
||||||
|
*.dll
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
|
||||||
|
# Test binary, build with `go test -c`
|
||||||
|
*.test
|
||||||
|
|
||||||
|
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||||
|
*.out
|
||||||
|
|
||||||
|
|
||||||
|
# End of https://www.gitignore.io/api/go
|
||||||
21
.vscode/launch.json
vendored
Normal file
21
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Launch",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "debug",
|
||||||
|
"remotePath": "",
|
||||||
|
"port": 2345,
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"program": "${workspaceFolder}/main.go",
|
||||||
|
"env": {},
|
||||||
|
"args": [],
|
||||||
|
"showLog": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
69
main.go
Normal file
69
main.go
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.gyulakerezsi.ro/migrate-github/migration"
|
||||||
|
"git.gyulakerezsi.ro/migrate-github/utils"
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ghRepo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
FullName string `json:"full_name"`
|
||||||
|
CloneURL string `json:"clone_url"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
godotenv.Load()
|
||||||
|
|
||||||
|
gogsTrgt := os.Getenv("TARGET_GOGS")
|
||||||
|
gogsPat := os.Getenv("GOGS_PAT")
|
||||||
|
user := os.Getenv("GH_USER")
|
||||||
|
|
||||||
|
response, err := http.Get("https://api.github.com/users/" + user + "/repos")
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
|
||||||
|
migrationClient := migration.NewClient(gogsTrgt, gogsPat)
|
||||||
|
|
||||||
|
repos := make([]ghRepo, 0)
|
||||||
|
utils.UnmarshalFromResponse(response, &repos)
|
||||||
|
|
||||||
|
migrated := make([]string, 0)
|
||||||
|
for _, el := range repos {
|
||||||
|
fmt.Printf("Migrate %s to your git? [Y/n] > ", el.FullName)
|
||||||
|
resp := utils.ReadLine()
|
||||||
|
|
||||||
|
switch resp = strings.ToLower(strings.TrimSpace(resp)); resp {
|
||||||
|
case "n":
|
||||||
|
fmt.Println("skipping")
|
||||||
|
default:
|
||||||
|
fmt.Print("Target repo name [leave blank to use the curent one] > ")
|
||||||
|
|
||||||
|
newName := utils.ReadLine()
|
||||||
|
if newName == "" {
|
||||||
|
newName = el.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("migrating %s ==> %s/%s\n", el.CloneURL, migrationClient.User.Username, newName)
|
||||||
|
err := migrationClient.Migrate(el.CloneURL, el.Description, newName)
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
|
||||||
|
migrated = append(migrated, el.FullName+" -> "+migrationClient.User.Username+"/"+newName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("\n\n================================================")
|
||||||
|
if len(migrated) > 0 {
|
||||||
|
fmt.Println("Migrated:")
|
||||||
|
for _, el := range migrated {
|
||||||
|
fmt.Printf("\t%s\n", el)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fmt.Println("Nothing migrated")
|
||||||
|
}
|
||||||
|
}
|
||||||
83
migration/client.go
Normal file
83
migration/client.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package migration
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.gyulakerezsi.ro/migrate-github/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
apiURL string
|
||||||
|
pat string
|
||||||
|
httpClient *http.Client
|
||||||
|
User *userResponse
|
||||||
|
}
|
||||||
|
|
||||||
|
type userResponse struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
ID int `json:"id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type migrateRequest struct {
|
||||||
|
CloneAddr string `json:"clone_addr"`
|
||||||
|
UID int `json:"uid"`
|
||||||
|
RepoName string `json:"repo_name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Migrate will send a migrate request to the gogs server
|
||||||
|
func (c *client) Migrate(cloneURL, description, targetName string) error {
|
||||||
|
jsonBody, err := json.Marshal(&migrateRequest{cloneURL, c.User.ID, targetName, description})
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodPost, c.apiURL+"repos/migrate", bytes.NewReader(jsonBody))
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
|
||||||
|
c.setHeadersOnRequest(req)
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
return fmt.Errorf("got non-success status code: %s\n==========request=========\n%+v\n=================response=============\n%+v", resp.Status, req, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) setHeadersOnRequest(req *http.Request) {
|
||||||
|
req.Header.Set("Authorization", "token "+c.pat)
|
||||||
|
req.Header.Set("Accept", "application/json")
|
||||||
|
|
||||||
|
if req.Method == http.MethodPost {
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *client) getUIDFromGogs() {
|
||||||
|
req, err := http.NewRequest(http.MethodGet, c.apiURL+"user", http.NoBody)
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
c.setHeadersOnRequest(req)
|
||||||
|
|
||||||
|
response, err := c.httpClient.Do(req)
|
||||||
|
utils.PanicOnError(err)
|
||||||
|
|
||||||
|
user := userResponse{}
|
||||||
|
utils.UnmarshalFromResponse(response, &user)
|
||||||
|
c.User = &user
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClient creates new migrationClient
|
||||||
|
func NewClient(baseURL, pat string) *client {
|
||||||
|
client := &client{}
|
||||||
|
client.apiURL = strings.TrimRight(baseURL, "/") + "/api/v1/"
|
||||||
|
client.pat = pat
|
||||||
|
client.httpClient = &http.Client{}
|
||||||
|
client.getUIDFromGogs()
|
||||||
|
|
||||||
|
return client
|
||||||
|
}
|
||||||
8
utils/panicOnError.go
Normal file
8
utils/panicOnError.go
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
// PanicOnError will panic if err goven is not nil
|
||||||
|
func PanicOnError(err error) {
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
21
utils/readLine.go
Normal file
21
utils/readLine.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var rd *bufio.Reader
|
||||||
|
|
||||||
|
// ReadLine reads a line from stdin and strips newline from the end
|
||||||
|
func ReadLine() string {
|
||||||
|
if rd == nil {
|
||||||
|
rd = bufio.NewReader(os.Stdin)
|
||||||
|
}
|
||||||
|
|
||||||
|
str, err := rd.ReadString('\n')
|
||||||
|
PanicOnError(err)
|
||||||
|
|
||||||
|
return strings.TrimRight(str, "\r\n")
|
||||||
|
}
|
||||||
16
utils/unmarshalFromResponse.go
Normal file
16
utils/unmarshalFromResponse.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UnmarshalFromResponse will unmarshal json from response body
|
||||||
|
func UnmarshalFromResponse(response *http.Response, v interface{}) {
|
||||||
|
responseBody, err := ioutil.ReadAll(response.Body)
|
||||||
|
PanicOnError(err)
|
||||||
|
|
||||||
|
err = json.Unmarshal(responseBody, &v)
|
||||||
|
PanicOnError(err)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user