Skip to content

Commit 0fb0295

Browse files
authored
GitHub: Add users/orgs whitelist flag (#88)
1 parent 51870a0 commit 0fb0295

File tree

5 files changed

+68
-10
lines changed

5 files changed

+68
-10
lines changed

Diff for: README.md

+8
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,8 @@ Usage of ./gitbackup:
117117
Number of retries to attempt for creating GitHub user migration (default 5)
118118
-github.listUserMigrations
119119
List available user migrations
120+
-github.namespaceWhitelist string
121+
Organizations/Users from where we should clone (separate each value by a comma: 'user1,org2')
120122
-github.repoType string
121123
Repo types to backup (all, owner, member, starred) (default "all")
122124
-github.waitForUserMigration
@@ -161,6 +163,12 @@ Separately, to backup GitHub repositories you have starred:
161163
$ GITHUB_TOKEN=secret$token gitbackup -service github -github.repoType starred
162164
```
163165

166+
Additionally, to backup only the GitHub repositories under 'user1' and 'org3':
167+
168+
```lang=bash
169+
$ GITHUB_TOKEN=secret$token gitbackup -service github -github.namespaceWhitelist "user1,org3"
170+
```
171+
164172
#### Backing up your GitLab repositories
165173

166174
To backup all projects you either own or are a member of which have their [visibility](https://docs.gitlab.com/ce/api/projects.html#project-visibility-level) set to

Diff for: helpers.go

+9
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,12 @@ func validGitlabProjectMembership(membership string) bool {
5252
}
5353
return false
5454
}
55+
56+
func contains(list []string, x string) bool {
57+
for _, item := range list {
58+
if item == x {
59+
return true
60+
}
61+
}
62+
return false
63+
}

Diff for: main.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"fmt"
77
"log"
88
"sync"
9+
"strings"
910
"time"
1011

1112
"github.com/google/go-github/v34/github"
@@ -46,6 +47,7 @@ func main() {
4647

4748
// GitHub specific flags
4849
githubRepoType := flag.String("github.repoType", "all", "Repo types to backup (all, owner, member, starred)")
50+
githubNamespaceWhitelistString := flag.String("github.namespaceWhitelist", "", "Organizations/Users from where we should clone (separate each value by a comma: 'user1,org2')")
4951

5052
githubCreateUserMigration := flag.Bool("github.createUserMigration", false, "Download user data")
5153
githubCreateUserMigrationRetry := flag.Bool("github.createUserMigrationRetry", true, "Retry creating the GitHub user migration if we get an error")
@@ -59,6 +61,13 @@ func main() {
5961

6062
flag.Parse()
6163

64+
// Split namespaces
65+
githubNamespaceWhitelist := []string{}
66+
67+
if len(*githubNamespaceWhitelistString) > 0 {
68+
githubNamespaceWhitelist = strings.Split(*githubNamespaceWhitelistString, ",")
69+
}
70+
6271
if _, ok := knownServices[*service]; !ok {
6372
log.Fatal("Please specify the git service type: github, gitlab, bitbucket")
6473
}
@@ -96,7 +105,7 @@ func main() {
96105

97106
} else if *githubCreateUserMigration {
98107

99-
repos, err := getRepositories(client, *service, *githubRepoType, *gitlabProjectVisibility, *gitlabProjectMembershipType, *ignoreFork)
108+
repos, err := getRepositories(client, *service, *githubRepoType, githubNamespaceWhitelist, *gitlabProjectVisibility, *gitlabProjectMembershipType, *ignoreFork)
100109
if err != nil {
101110
log.Fatalf("Error getting list of repositories: %v", err)
102111
}
@@ -147,7 +156,7 @@ func main() {
147156
log.Fatal("Your Git host's username is needed for backing up private repositories via HTTPS")
148157
}
149158
repos, err := getRepositories(
150-
client, *service, *githubRepoType,
159+
client, *service, *githubRepoType, githubNamespaceWhitelist,
151160
*gitlabProjectVisibility, *gitlabProjectMembershipType, *ignoreFork,
152161
)
153162
if err != nil {

Diff for: repositories.go

+8-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ type Repository struct {
3838
}
3939

4040
func getRepositories(client interface{},
41-
service string, githubRepoType string,
41+
service string, githubRepoType string, githubNamespaceWhitelist []string,
4242
gitlabProjectVisibility string, gitlabProjectMembershipType string,
4343
ignoreFork bool,
4444
) ([]*Repository, error) {
@@ -80,6 +80,8 @@ func getRepositories(client interface{},
8080
}
8181
} else {
8282
options := github.RepositoryListOptions{Type: githubRepoType}
83+
githubNamespaceWhitelistLength := len(githubNamespaceWhitelist)
84+
8385
for {
8486
repos, resp, err := client.(*github.Client).Repositories.List(ctx, "", &options)
8587
if err == nil {
@@ -88,6 +90,11 @@ func getRepositories(client interface{},
8890
continue
8991
}
9092
namespace := strings.Split(*repo.FullName, "/")[0]
93+
94+
if githubNamespaceWhitelistLength > 0 && !contains(githubNamespaceWhitelist, namespace) {
95+
continue
96+
}
97+
9198
if useHTTPSClone != nil && *useHTTPSClone {
9299
cloneURL = *repo.CloneURL
93100
} else {

Diff for: repositories_test.go

+32-7
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func TestGetPublicGitHubRepositories(t *testing.T) {
6767
fmt.Fprint(w, `[{"full_name": "test/r1", "id":1, "ssh_url": "https://github.com/u/r1", "name": "r1", "private": false, "fork": false}]`)
6868
})
6969

70-
repos, err := getRepositories(GitHubClient, "github", "all", "", "", false)
70+
repos, err := getRepositories(GitHubClient, "github", "all", []string{}, "", "", false)
7171
if err != nil {
7272
t.Fatalf("%v", err)
7373
}
@@ -86,7 +86,7 @@ func TestGetPrivateGitHubRepositories(t *testing.T) {
8686
fmt.Fprint(w, `[{"full_name": "test/r1", "id":1, "ssh_url": "https://github.com/u/r1", "name": "r1", "private": true, "fork": false}]`)
8787
})
8888

89-
repos, err := getRepositories(GitHubClient, "github", "all", "", "", false)
89+
repos, err := getRepositories(GitHubClient, "github", "all", []string{}, "", "", false)
9090
if err != nil {
9191
t.Fatalf("%v", err)
9292
}
@@ -105,7 +105,7 @@ func TestGetStarredGitHubRepositories(t *testing.T) {
105105
fmt.Fprint(w, `[{"repo":{"full_name": "test/r1", "id":1, "ssh_url": "https://github.com/u/r1", "name": "r1", "private": true, "fork": false}}]`)
106106
})
107107

108-
repos, err := getRepositories(GitHubClient, "github", "starred", "", "", false)
108+
repos, err := getRepositories(GitHubClient, "github", "starred", []string{}, "", "", false)
109109
if err != nil {
110110
t.Fatalf("%v", err)
111111
}
@@ -116,6 +116,31 @@ func TestGetStarredGitHubRepositories(t *testing.T) {
116116
}
117117
}
118118

119+
func TestGetWhitelistGitHubRepositories(t *testing.T) {
120+
setupRepositoryTests()
121+
defer teardownRepositoryTests()
122+
123+
mux.HandleFunc("/user/repos", func(w http.ResponseWriter, r *http.Request) {
124+
fmt.Fprint(w, `[
125+
{"full_name": "test/r1", "id":1, "ssh_url": "https://github.com/u/r1", "name": "r1", "private": false, "fork": false},
126+
{"full_name": "user1/r1", "id":1, "ssh_url": "https://github.com/u/r1", "name": "r1", "private": false, "fork": false},
127+
{"full_name": "org1/r1", "id":1, "ssh_url": "https://github.com/u/r1", "name": "r1", "private": false, "fork": false}
128+
]`)
129+
})
130+
131+
repos, err := getRepositories(GitHubClient, "github", "all", []string{"test", "user1"}, "", "", false)
132+
if err != nil {
133+
t.Fatalf("%v", err)
134+
}
135+
var expected []*Repository
136+
expected = append(expected, &Repository{Namespace: "test", CloneURL: "https://github.com/u/r1", Name: "r1", Private: false})
137+
expected = append(expected, &Repository{Namespace: "user1", CloneURL: "https://github.com/u/r1", Name: "r1", Private: false})
138+
139+
if !reflect.DeepEqual(repos, expected) {
140+
t.Errorf("Expected %+v, Got %+v", expected, repos)
141+
}
142+
}
143+
119144
func TestGetGitLabRepositories(t *testing.T) {
120145
setupRepositoryTests()
121146
defer teardownRepositoryTests()
@@ -124,7 +149,7 @@ func TestGetGitLabRepositories(t *testing.T) {
124149
fmt.Fprint(w, `[{"path_with_namespace": "test/r1", "id":1, "ssh_url_to_repo": "https://gitlab.com/u/r1", "name": "r1"}]`)
125150
})
126151

127-
repos, err := getRepositories(GitLabClient, "gitlab", "internal", "", "", false)
152+
repos, err := getRepositories(GitLabClient, "gitlab", "internal", []string{}, "", "", false)
128153
if err != nil {
129154
t.Fatalf("%v", err)
130155
}
@@ -149,7 +174,7 @@ func TestGetGitLabPrivateRepositories(t *testing.T) {
149174
})
150175

151176
repos, err := getRepositories(GitLabClient, "gitlab",
152-
"private", "", "", false)
177+
"private", []string{}, "", "", false)
153178
if err != nil {
154179
t.Fatalf("%v", err)
155180
}
@@ -176,7 +201,7 @@ func TestGetStarredGitLabRepositories(t *testing.T) {
176201
fmt.Fprintf(w, `[]`)
177202
})
178203

179-
repos, err := getRepositories(GitLabClient, "gitlab", "", "", "starred", false)
204+
repos, err := getRepositories(GitLabClient, "gitlab", "", []string{}, "", "starred", false)
180205
if err != nil {
181206
t.Fatalf("%v", err)
182207
}
@@ -205,7 +230,7 @@ func TestGetBitbucketRepositories(t *testing.T) {
205230
fmt.Fprint(w, `{"pagelen": 10, "page": 1, "size": 1, "values": [{"full_name":"abc/def", "slug":"def", "is_private":true, "links":{"clone":[{"name":"https", "href":"https://[email protected]/abc/def.git"}, {"name":"ssh", "href":"[email protected]:abc/def.git"}]}}]}`)
206231
})
207232

208-
repos, err := getRepositories(BitbucketClient, "bitbucket", "", "", "", false)
233+
repos, err := getRepositories(BitbucketClient, "bitbucket", "", []string{}, "", "", false)
209234
if err != nil {
210235
t.Fatalf("%v", err)
211236
}

0 commit comments

Comments
 (0)