initial commit

This commit is contained in:
Gardient
2018-06-07 22:50:47 +03:00
commit 926aeb4eee
7 changed files with 252 additions and 0 deletions

34
.gitignore vendored Normal file
View 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
View 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
View 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
View 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
View 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
View 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")
}

View 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)
}