feat: Added remote repo pull f38a2ab8
Steve · 2024-08-21 20:40 5 file(s) · +222 −138
RemoteClone.go (added) +83 −0
1 +
package main
2 +
3 +
import (
4 +
	"bufio"
5 +
	"encoding/json"
6 +
	"fmt"
7 +
	"io/ioutil"
8 +
	"net/http"
9 +
	"os"
10 +
	"strings"
11 +
12 +
	"github.com/AlecAivazis/survey/v2"
13 +
)
14 +
15 +
func RemoteClone() error {
16 +
	fmt.Print("Enter the name of GitHub user or org")
17 +
18 +
	reader := bufio.NewReader(os.Stdin)
19 +
	input, err := reader.ReadString('\n')
20 +
	if err != nil {
21 +
		fmt.Println("An error occured while reading the input. Please try again", err)
22 +
		return err
23 +
	}
24 +
	input = strings.TrimSuffix(input, "\n")
25 +
26 +
	apiURL := fmt.Sprintf("https://api.github.com/users/%s/repos?sort=created", input)
27 +
28 +
	response, err := http.Get(apiURL)
29 +
	if err != nil {
30 +
		fmt.Println("Github API request failed with error", err)
31 +
		return err
32 +
	}
33 +
34 +
	body, err := ioutil.ReadAll(response.Body)
35 +
	if err != nil {
36 +
		fmt.Println("Error reading response body:", err)
37 +
		return err
38 +
	}
39 +
40 +
	var repos []Repository
41 +
	err = json.Unmarshal(body, &repos)
42 +
	if err != nil {
43 +
		fmt.Println("Error unmarshalling JSON:", err)
44 +
		return err
45 +
	}
46 +
47 +
	newRepos := selectNewRepos(repos)
48 +
49 +
	for _, repo := range newRepos {
50 +
		fmt.Printf("Repository: %s\n", repo.FullName)
51 +
		fmt.Printf("Description: %s\n", repo.Description)
52 +
		fmt.Printf("URL: %s\n", repo.HTMLURL)
53 +
		fmt.Printf("---\n")
54 +
	}
55 +
56 +
	return nil
57 +
}
58 +
59 +
func selectNewRepos(repos []Repository) []Repository {
60 +
	var options []string
61 +
	for _, repo := range repos {
62 +
		options = append(options, repo.Name)
63 +
	}
64 +
65 +
	var selected []string
66 +
	prompt := &survey.MultiSelect{
67 +
		Message: "Select repositories to initialize:",
68 +
		Options: options,
69 +
	}
70 +
	survey.AskOne(prompt, &selected)
71 +
72 +
	var selectedRepos []Repository
73 +
	for _, name := range selected {
74 +
		for _, repo := range repos {
75 +
			if repo.Name == name {
76 +
				selectedRepos = append(selectedRepos, repo)
77 +
				break
78 +
			}
79 +
		}
80 +
	}
81 +
82 +
	return selectedRepos
83 +
}
go.mod +4 −0
5 5
require (
6 6
	github.com/AlecAivazis/survey/v2 v2.3.7
7 7
	github.com/fatih/color v1.17.0
8 +
	github.com/urfave/cli/v2 v2.27.4
8 9
)
9 10
10 11
require (
12 +
	github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect
11 13
	github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
12 14
	github.com/mattn/go-colorable v0.1.13 // indirect
13 15
	github.com/mattn/go-isatty v0.0.20 // indirect
14 16
	github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
17 +
	github.com/russross/blackfriday/v2 v2.1.0 // indirect
18 +
	github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
15 19
	golang.org/x/sys v0.18.0 // indirect
16 20
	golang.org/x/term v0.1.0 // indirect
17 21
	golang.org/x/text v0.4.0 // indirect
go.sum +8 −0
2 2
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
3 3
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
4 4
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
5 +
github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4=
6 +
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
5 7
github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI=
6 8
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
7 9
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24 26
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
25 27
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
26 28
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
29 +
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
30 +
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
27 31
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
28 32
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
29 33
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
34 +
github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8=
35 +
github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ=
36 +
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
37 +
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
30 38
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
31 39
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
32 40
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
main.go +25 −138
1 1
package main
2 2
3 3
import (
4 -
	"flag"
5 -
	"fmt"
4 +
	"log"
6 5
	"os"
7 -
	"os/exec"
8 -
	"os/signal"
9 -
	"path/filepath"
10 -
	"syscall"
11 6
12 -
	"github.com/AlecAivazis/survey/v2"
13 -
	"github.com/fatih/color"
7 +
	"github.com/urfave/cli/v2"
14 8
)
15 9
16 -
type Repo struct {
17 -
	Path string
18 -
	Name string
19 -
}
20 -
21 -
var isPrivate bool
22 -
23 10
func main() {
24 -
	flag.BoolVar(&isPrivate, "private", false, "Initialize repositories as private")
25 -
	flag.Parse()
26 -
27 -
	repos := findGitRepos(".")
28 -
	selectedRepos := selectRepos(repos)
29 -
	confirmAndInitRepos(selectedRepos)
30 -
}
31 -
32 -
func findGitRepos(root string) []Repo {
33 -
	var repos []Repo
34 -
	var scannedDirs int
35 -
36 -
	entries, err := os.ReadDir(root)
37 -
	if err != nil {
38 -
		fmt.Printf("Error reading directory %v: %v\n", root, err)
39 -
		return repos
11 +
	app := &cli.App{
12 +
		Name:  "radlicalize",
13 +
		Usage: "A CLI tool used to clone either remote or local git repos to Radial.xyz",
14 +
		Commands: []*cli.Command{
15 +
			{
16 +
				Name:    "local",
17 +
				Aliases: []string{"l"},
18 +
				Usage:   "Use to clone any local repos to Racial",
19 +
				Action: func(ctx *cli.Context) error {
20 +
					return LocalClone()
21 +
				},
22 +
			},
23 +
			{
24 +
				Name:    "remote",
25 +
				Aliases: []string{"r"},
26 +
				Usage:   "Use to clone any remote public repos on Github to Racial",
27 +
				Action: func(ctx *cli.Context) error {
28 +
					return RemoteClone()
29 +
				},
30 +
			},
31 +
		},
40 32
	}
41 33
42 -
	for _, entry := range entries {
43 -
		if !entry.IsDir() {
44 -
			continue
45 -
		}
46 -
47 -
		scannedDirs++
48 -
		fmt.Printf("\rScanned %d directories...", scannedDirs)
49 -
50 -
		dirPath := filepath.Join(root, entry.Name())
51 -
		gitDir := filepath.Join(dirPath, ".git")
52 -
53 -
		if _, err := os.Stat(gitDir); err == nil {
54 -
			repos = append(repos, Repo{
55 -
				Path: dirPath,
56 -
				Name: entry.Name(),
57 -
			})
58 -
		}
34 +
	if err := app.Run(os.Args); err != nil {
35 +
		log.Fatal(err)
59 36
	}
60 -
61 -
	// Clear the progress line and print final count
62 -
	fmt.Printf("\rScanned %d directories. Found %d Git repositories.\n", scannedDirs, len(repos))
63 -
64 -
	return repos
65 -
}
66 -
67 -
func selectRepos(repos []Repo) []Repo {
68 -
	var options []string
69 -
	for _, repo := range repos {
70 -
		options = append(options, repo.Name)
71 -
	}
72 -
73 -
	var selected []string
74 -
	prompt := &survey.MultiSelect{
75 -
		Message: "Select repositories to initialize:",
76 -
		Options: options,
77 -
	}
78 -
	survey.AskOne(prompt, &selected)
79 -
80 -
	var selectedRepos []Repo
81 -
	for _, name := range selected {
82 -
		for _, repo := range repos {
83 -
			if repo.Name == name {
84 -
				selectedRepos = append(selectedRepos, repo)
85 -
				break
86 -
			}
87 -
		}
88 -
	}
89 -
90 -
	return selectedRepos
91 -
}
92 -
93 -
func confirmAndInitRepos(repos []Repo) {
94 -
	visibilityStr := "public"
95 -
	if isPrivate {
96 -
		visibilityStr = "private"
97 -
	}
98 -
99 -
	confirm := false
100 -
	prompt := &survey.Confirm{
101 -
		Message: fmt.Sprintf("Initialize %d repositories as %s?", len(repos), visibilityStr),
102 -
	}
103 -
	survey.AskOne(prompt, &confirm)
104 -
105 -
	if !confirm {
106 -
		fmt.Println("Radicalization cancelled.")
107 -
		return
108 -
	}
109 -
110 -
	fmt.Printf("Initializing %d repositories as %s...\n", len(repos), visibilityStr)
111 -
112 -
	interrupt := make(chan os.Signal, 1)
113 -
	signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM)
114 -
115 -
	done := make(chan bool)
116 -
117 -
	go func() {
118 -
		for i, repo := range repos {
119 -
			select {
120 -
			case <-interrupt:
121 -
				fmt.Println("\nInterrupted. Stopping initialization process.")
122 -
				done <- true
123 -
				return
124 -
			default:
125 -
				fmt.Printf("Initializing %s (%d/%d)...\n", repo.Name, i+1, len(repos))
126 -
				err := runRadInit(repo.Path, repo.Name)
127 -
				if err != nil {
128 -
					color.Red("Error initializing %s: %v\n", repo.Name, err)
129 -
				} else {
130 -
					color.Green("Initialized %s as %s\n", repo.Name, visibilityStr)
131 -
				}
132 -
			}
133 -
		}
134 -
		done <- true
135 -
	}()
136 -
137 -
	<-done
138 -
	fmt.Println("Radicalization Complete")
139 -
}
140 -
141 -
func runRadInit(path, name string) error {
142 -
	visibilityFlag := "--public"
143 -
	if isPrivate {
144 -
		visibilityFlag = "--private"
145 -
	}
146 -
147 -
	cmd := exec.Command("rad", "init", "--name", name, "--description", "", visibilityFlag, "--no-confirm")
148 -
	cmd.Dir = path
149 -
	return cmd.Run()
150 37
}
types.go (added) +102 −0
1 +
package main
2 +
3 +
type Repository struct {
4 +
	ID       int    `json:"id"`
5 +
	NodeID   string `json:"node_id"`
6 +
	Name     string `json:"name"`
7 +
	FullName string `json:"full_name"`
8 +
	Private  bool   `json:"private"`
9 +
	Owner    struct {
10 +
		Login             string `json:"login"`
11 +
		ID                int    `json:"id"`
12 +
		NodeID            string `json:"node_id"`
13 +
		AvatarURL         string `json:"avatar_url"`
14 +
		GravatarID        string `json:"gravatar_id"`
15 +
		URL               string `json:"url"`
16 +
		HTMLURL           string `json:"html_url"`
17 +
		FollowersURL      string `json:"followers_url"`
18 +
		FollowingURL      string `json:"following_url"`
19 +
		GistsURL          string `json:"gists_url"`
20 +
		StarredURL        string `json:"starred_url"`
21 +
		SubscriptionsURL  string `json:"subscriptions_url"`
22 +
		OrganizationsURL  string `json:"organizations_url"`
23 +
		ReposURL          string `json:"repos_url"`
24 +
		EventsURL         string `json:"events_url"`
25 +
		ReceivedEventsURL string `json:"received_events_url"`
26 +
		Type              string `json:"type"`
27 +
		SiteAdmin         bool   `json:"site_admin"`
28 +
	} `json:"owner"`
29 +
	HTMLURL                  string      `json:"html_url"`
30 +
	Description              string      `json:"description"`
31 +
	Fork                     bool        `json:"fork"`
32 +
	URL                      string      `json:"url"`
33 +
	ForksURL                 string      `json:"forks_url"`
34 +
	KeysURL                  string      `json:"keys_url"`
35 +
	CollaboratorsURL         string      `json:"collaborators_url"`
36 +
	TeamsURL                 string      `json:"teams_url"`
37 +
	HooksURL                 string      `json:"hooks_url"`
38 +
	IssueEventsURL           string      `json:"issue_events_url"`
39 +
	EventsURL                string      `json:"events_url"`
40 +
	AssigneesURL             string      `json:"assignees_url"`
41 +
	BranchesURL              string      `json:"branches_url"`
42 +
	TagsURL                  string      `json:"tags_url"`
43 +
	BlobsURL                 string      `json:"blobs_url"`
44 +
	GitTagsURL               string      `json:"git_tags_url"`
45 +
	GitRefsURL               string      `json:"git_refs_url"`
46 +
	TreesURL                 string      `json:"trees_url"`
47 +
	StatusesURL              string      `json:"statuses_url"`
48 +
	LanguagesURL             string      `json:"languages_url"`
49 +
	StargazersURL            string      `json:"stargazers_url"`
50 +
	ContributorsURL          string      `json:"contributors_url"`
51 +
	SubscribersURL           string      `json:"subscribers_url"`
52 +
	SubscriptionURL          string      `json:"subscription_url"`
53 +
	CommitsURL               string      `json:"commits_url"`
54 +
	GitCommitsURL            string      `json:"git_commits_url"`
55 +
	CommentsURL              string      `json:"comments_url"`
56 +
	IssueCommentURL          string      `json:"issue_comment_url"`
57 +
	ContentsURL              string      `json:"contents_url"`
58 +
	CompareURL               string      `json:"compare_url"`
59 +
	MergesURL                string      `json:"merges_url"`
60 +
	ArchiveURL               string      `json:"archive_url"`
61 +
	DownloadsURL             string      `json:"downloads_url"`
62 +
	IssuesURL                string      `json:"issues_url"`
63 +
	PullsURL                 string      `json:"pulls_url"`
64 +
	MilestonesURL            string      `json:"milestones_url"`
65 +
	NotificationsURL         string      `json:"notifications_url"`
66 +
	LabelsURL                string      `json:"labels_url"`
67 +
	ReleasesURL              string      `json:"releases_url"`
68 +
	DeploymentsURL           string      `json:"deployments_url"`
69 +
	CreatedAt                string      `json:"created_at"`
70 +
	UpdatedAt                string      `json:"updated_at"`
71 +
	PushedAt                 string      `json:"pushed_at"`
72 +
	GitURL                   string      `json:"git_url"`
73 +
	SSHURL                   string      `json:"ssh_url"`
74 +
	CloneURL                 string      `json:"clone_url"`
75 +
	SvnURL                   string      `json:"svn_url"`
76 +
	Homepage                 interface{} `json:"homepage"`
77 +
	Size                     int         `json:"size"`
78 +
	StargazersCount          int         `json:"stargazers_count"`
79 +
	WatchersCount            int         `json:"watchers_count"`
80 +
	Language                 string      `json:"language"`
81 +
	HasIssues                bool        `json:"has_issues"`
82 +
	HasProjects              bool        `json:"has_projects"`
83 +
	HasDownloads             bool        `json:"has_downloads"`
84 +
	HasWiki                  bool        `json:"has_wiki"`
85 +
	HasPages                 bool        `json:"has_pages"`
86 +
	HasDiscussions           bool        `json:"has_discussions"`
87 +
	ForksCount               int         `json:"forks_count"`
88 +
	MirrorURL                interface{} `json:"mirror_url"`
89 +
	Archived                 bool        `json:"archived"`
90 +
	Disabled                 bool        `json:"disabled"`
91 +
	OpenIssuesCount          int         `json:"open_issues_count"`
92 +
	License                  interface{} `json:"license"`
93 +
	AllowForking             bool        `json:"allow_forking"`
94 +
	IsTemplate               bool        `json:"is_template"`
95 +
	WebCommitSignoffRequired bool        `json:"web_commit_signoff_required"`
96 +
	Topics                   []string    `json:"topics"`
97 +
	Visibility               string      `json:"visibility"`
98 +
	Forks                    int         `json:"forks"`
99 +
	OpenIssues               int         `json:"open_issues"`
100 +
	Watchers                 int         `json:"watchers"`
101 +
	DefaultBranch            string      `json:"default_branch"`
102 +
}