Skip to content

Commit b14badc

Browse files
authored
Merge pull request #97 from jonico/groovy
Adding groovy examples on how to use our API
2 parents bbfb4b1 + c5c6f1f commit b14badc

File tree

3 files changed

+265
-0
lines changed

3 files changed

+265
-0
lines changed

api/groovy/AuditUsers.groovy

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
#!/usr/bin/env groovy
2+
3+
/**
4+
* groovy script to show all repositories that can be accessed by given users on an GitHub Enterprise instance
5+
*
6+
*
7+
* Run 'groovy AuditUsers.groovy' to see the list of command line options
8+
*
9+
* First run may take some time as required dependencies have to get downloaded, then it should be quite fast
10+
*
11+
* If you do not have groovy yet, run 'brew install groovy'
12+
*/
13+
14+
@Grab(group='org.kohsuke', module='github-api', version='1.75')
15+
@Grab(group='org.codehaus.groovy.modules.http-builder', module='http-builder', version='0.7.2' )
16+
import org.kohsuke.github.GitHub
17+
import groovyx.net.http.RESTClient
18+
import static groovyx.net.http.ContentType.*
19+
import groovy.json.JsonOutput
20+
21+
22+
// parsing command line args
23+
cli = new CliBuilder(usage: 'groovy AuditUsers.groovy [options] [user accounts]\nReports all repositories that can be accessed by given users')
24+
cli.t(longOpt: 'token', 'personal access token of a GitHub Enterprise site admin with repo skope (or use GITHUB_TOKEN env variable)', required: false , args: 1 )
25+
cli.u(longOpt: 'url', 'GitHub Enterprise URL (or use GITHUB_URL env variable), e.g. https://myghe.com', required: false , args: 1 )
26+
cli.s(longOpt: 'skipPublicRepos', 'Do not print publicly available repositories at the end of the report', required: false , args: 0 )
27+
cli.h(longOpt: 'help', 'Print this usage info', required: false , args: 0 )
28+
29+
OptionAccessor opt = cli.parse(args)
30+
31+
token = opt.t?opt.t:System.getenv("GITHUB_TOKEN")
32+
url = opt.u?opt.u:System.getenv("GITHUB_URL")
33+
listOnly = opt.l
34+
35+
// bail out if help parameter was supplied or not sufficient input to proceed
36+
if (opt.h || !token || !url || opt.arguments().size() == 0) {
37+
cli.usage()
38+
return
39+
}
40+
41+
// chop potential trailing slash from GitHub Enterprise URL
42+
url = url.replaceAll('/\$', "")
43+
44+
45+
RESTClient restSiteAdmin = getGithubApi(url , token)
46+
47+
// iterate over all supplied users
48+
opt.arguments().each {
49+
user=it
50+
println "Showing repositories accessible for user ${user} ... "
51+
try {
52+
// get temporary access token for given user
53+
resp = restSiteAdmin.post(
54+
path: "/api/v3/admin/users/${user}/authorizations",
55+
body: JsonOutput.toJson( scopes: ["repo"]),
56+
requestContentType: URLENC )
57+
58+
assert resp.data.token != null
59+
userToken = resp.data.token
60+
61+
try {
62+
// list all accessible repositories in organizations and personal repositories of this user
63+
userRepos = GitHub.connectToEnterprise("${url}/api/v3", userToken).getMyself().listAllRepositories()
64+
65+
// further fields available on http://github-api.kohsuke.org/apidocs/org/kohsuke/github/GHRepository.html#method_summary
66+
userRepos.each { println "user: ${user}, repo: ${it.name}, owner: ${it.ownerName}, private: ${it.private}, read: ${it.hasPullAccess()}, write: ${it.hasPushAccess()}, admin: ${it.hasAdminAccess()}, url: ${it.getHtmlUrl()}" }
67+
}
68+
finally {
69+
// delete the personal access token again even if we ran into an exception
70+
resp = restClient.delete(path: "/api/v3/admin/users/${user}/authorizations")
71+
assert resp.status == 204
72+
}
73+
println ""
74+
} catch (Exception e) {
75+
e.printStackTrace()
76+
println "An error occurred while fetching repositories for user ${user}, continuing with the next user ..."
77+
}
78+
}
79+
80+
if (!opt.s) {
81+
println "Showing repositories accessible by any logged in user ..."
82+
publicRepos = GitHub.connectToEnterprise("${url}/api/v3", token).listAllPublicRepositories()
83+
// further fields on http://github-api.kohsuke.org/apidocs/org/kohsuke/github/GHRepository.html#method_summary
84+
publicRepos.each { println "public repo: ${it.name}, owner: ${it.ownerName}, url: ${it.getHtmlUrl()}" }
85+
}
86+
87+
def RESTClient getGithubApi(url, token) {
88+
restClient = new RESTClient(url).with {
89+
headers['Accept'] = 'application/json'
90+
headers['Authorization'] = "token ${token}"
91+
it
92+
}
93+
}

api/groovy/ListReposInOrg.groovy

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env groovy
2+
3+
// run with groovy ListReposInOrg -t <personal access token> <org name>
4+
5+
package org.kohsuke.github
6+
7+
@Grab(group='org.kohsuke', module='github-api', version='1.75')
8+
import org.kohsuke.github.GitHub
9+
10+
class ListReposInOrg extends GitHub {
11+
12+
static void main(args) {
13+
14+
def cli = new CliBuilder(usage: 'groovy -t <personal access token> ListReposInOrg.groovy <organization>')
15+
cli.t(longOpt: 'token', 'personal access token', required: false , args: 1 )
16+
17+
OptionAccessor opt = cli.parse(args)
18+
19+
if(opt.arguments().size() != 1) {
20+
cli.usage()
21+
return
22+
}
23+
24+
def org = opt.arguments()[0];
25+
def githubCom
26+
27+
if (opt.t) {
28+
githubCom = GitHub.connectUsingOAuth(opt.t);
29+
} else {
30+
githubCom = GitHub.connect();
31+
}
32+
33+
githubCom.getOrganization(org).listRepositories().each {
34+
println it.getFullName();
35+
}
36+
}
37+
}

api/groovy/MigrateRepositories.groovy

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
#!/usr/bin/env groovy
2+
3+
/**
4+
* groovy script to migrate (export) GitHub.com repositories to GitHub Enterprise
5+
*
6+
* Automates steps in https://github.com/blog/2171-migrate-your-repositories-using-ghe-migrator
7+
*
8+
* Run 'groovy MigrateRepositories.groovy' to see the list of command line options
9+
*
10+
* First run may take some time as required dependencies have to get downloaded, then it should be quite fast
11+
*
12+
* If you do not have groovy yet, run 'brew install groovy'
13+
*/
14+
15+
@Grab(group='org.kohsuke', module='github-api', version='1.75')
16+
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7')
17+
@Grab('oauth.signpost:signpost-core:1.2.1.2')
18+
@Grab('oauth.signpost:signpost-commonshttp4:1.2.1.2')
19+
20+
import org.kohsuke.github.GitHub
21+
import groovyx.net.http.RESTClient
22+
import static groovyx.net.http.ContentType.*
23+
import groovy.json.JsonOutput
24+
import groovy.json.JsonSlurper
25+
import java.io.File
26+
import org.apache.http.params.BasicHttpParams
27+
28+
29+
opt = parseArgs(args)
30+
31+
if(!opt) {
32+
return
33+
}
34+
35+
token = opt.t?opt.t:System.getenv("GITHUB_TOKEN")
36+
sleepInterval = opt.s?1000*new Long(opt.s):5000
37+
outputFileName = opt.f?opt.f:"migration_archive.tgz"
38+
org = opt.o
39+
lockRepos = opt.l
40+
41+
repositories = getRepositoriesToMigrate(opt)
42+
43+
if (repositories.empty) {
44+
println "No repository for org ${org} specified, exiting ..."
45+
return
46+
}
47+
println "Going to export the following repositories "+(lockRepos?"with":"without") + " locking to file ${outputFileName}:"
48+
repositories.each { println it}
49+
50+
51+
RESTClient restClient = getGithubApi("https://api.github.com/" , token)
52+
53+
if (!opt.d) {
54+
resp = restClient.post(
55+
path: "orgs/${org}/migrations",
56+
body: JsonOutput.toJson( [lock_repositories: lockRepos, repositories: repositories]),
57+
requestContentType: URLENC )
58+
59+
assert resp.status == 201
60+
assert resp.contentType == JSON.toString()
61+
62+
migrationID = resp.data.id
63+
assert migrationID != null
64+
65+
println "Got migration ID: ${migrationID}, waiting for migration to finish ..."
66+
67+
waitForExportToFinish(sleepInterval, restClient, org, migrationID)
68+
69+
println "Figuring out migration archive URL: /orgs/${org}/migrations/${migrationID}/archive"
70+
resp = restClient.get(path: "/orgs/${org}/migrations/${migrationID}/archive")
71+
assert resp.status == 302
72+
73+
println "Downloading migration archive and storing it as ${outputFileName} ..."
74+
file = new File(outputFileName).newOutputStream()
75+
file << new URL(resp.data.toString()).openStream()
76+
file.close()
77+
78+
deleteMigrationArchive(restClient, org, migrationID)
79+
}
80+
81+
def OptionAccessor parseArgs(args) {
82+
CliBuilder cli = new CliBuilder(usage: 'groovy MigrateRepositories.groovy -o <organization> [options] [reps in org]')
83+
cli.t(longOpt: 'token', 'personal access token (or use GITHUB_TOKEN env variable)', required: false , args: 1 )
84+
cli.o(longOpt: 'organization', 'organization, if no repositories are specified, all repositories will be migrated', required: true , args: 1 )
85+
cli.l(longOpt: 'lock', 'lock repositories (defaults to false)', required: false , args: 1 )
86+
cli.s(longOpt: 'sleep', 'sleep interval between checking export status (defaults to 5 seconds)', required: false , args: 1 )
87+
cli.f(longOpt: 'file', 'file to store exported tgz file (defaults to migration_archive.tar.gz)', required: false , args: 1 )
88+
cli.d(longOpt: 'dry', 'dry-run only, only print what would happen without performing anything', required: false , args: 1 )
89+
90+
OptionAccessor opt = cli.parse(args)
91+
return opt
92+
}
93+
94+
def getRepositoriesToMigrate(opt) {
95+
if (opt.arguments().size() != 0) {
96+
return opt.arguments().findAll {
97+
it.startsWith(org+"/")
98+
}
99+
} else {
100+
githubCom = GitHub.connectUsingOAuth(token);
101+
return githubCom.getOrganization(org).listRepositories().collect { it.getFullName(); }
102+
}
103+
}
104+
105+
def RESTClient getGithubApi(url, token) {
106+
restClient = new RESTClient(url).with {
107+
headers['User-Agent'] = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"
108+
headers.'Accept' = 'application/vnd.github.wyandotte-preview+json'
109+
headers['Authorization'] = "token ${token}"
110+
it
111+
}
112+
// we need to disable redirects as GitHub redirects to Amazon S3 for the download
113+
restClient.client.setParams(new BasicHttpParams().setParameter("http.protocol.handle-redirects",false))
114+
return restClient
115+
}
116+
117+
def waitForExportToFinish(sleepInterval, restClient, org, migrationID) {
118+
String status
119+
while ("exported" != status) {
120+
println "Sleeping ${sleepInterval} ms ..."
121+
sleep sleepInterval
122+
println "Checking migration process ..."
123+
resp = restClient.get( path: "/orgs/${org}/migrations/${migrationID}" )
124+
assert resp.status == 200
125+
assert resp.contentType == JSON.toString()
126+
status=resp.data.state
127+
println "Migration status: ${status}"
128+
}
129+
}
130+
131+
def deleteMigrationArchive(restClient, org, migrationID) {
132+
println "Deleting archive on the server"
133+
resp = restClient.delete(path: "/orgs/${org}/migrations/${migrationID}/archive")
134+
assert resp.status == 204
135+
}

0 commit comments

Comments
 (0)