Skip to content

Commit 92d34db

Browse files
author
Philippe Charrière
authored
First version of Scala samples to use GitHub API
1 parent 47154a9 commit 92d34db

File tree

16 files changed

+683
-0
lines changed

16 files changed

+683
-0
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.idea/*
2+
project/*
3+
target/*
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# GitHub API + Scala
2+
3+
## Setup and Run
4+
5+
- This is a `sbt` project. See http://www.scala-sbt.org/0.13/docs/Setup.html
6+
- Run `sbt` in a Terminal (at the root of this project: `/platform-samples/API/scala.wit.sbt/octocat-samples`)
7+
- Type `run`, and you'll get this:
8+
```shell
9+
> run
10+
[warn] Multiple main classes detected. Run 'show discoveredMainClasses' to see the list
11+
12+
Multiple main classes detected, select one to run:
13+
14+
[1] DemoOrganizations
15+
[2] DemoRepositories
16+
[3] DemoUser
17+
[4] DemoZen
18+
19+
Enter number:
20+
```
21+
- Chose the number of the demo to run
22+
23+
eg, if you choose `4` you'll get something like that:
24+
25+
```shell
26+
[info] Running DemoZen
27+
28+
MMM. .MMM
29+
MMMMMMMMMMMMMMMMMMM
30+
MMMMMMMMMMMMMMMMMMM _____________________
31+
MMMMMMMMMMMMMMMMMMMMM | |
32+
MMMMMMMMMMMMMMMMMMMMMMM | Speak like a human. |
33+
MMMMMMMMMMMMMMMMMMMMMMMM |_ _________________|
34+
MMMM::- -:::::::- -::MMMM |/
35+
MM~:~ 00~:::::~ 00~:~MM
36+
.. MMMMM::.00:::+:::.00::MMMMM ..
37+
.MM::::: ._. :::::MM.
38+
MMMM;:::::;MMMM
39+
-MM MMMMMMM
40+
^ M+ MMMMMMMMM
41+
MMMMMMM MM MM MM
42+
MM MM MM MM
43+
MM MM MM MM
44+
.~~MM~MM~MM~MM~~.
45+
~~~~MM:~MM~~~MM~:MM~~~~
46+
~~~~~~==~==~~~==~==~~~~~~
47+
~~~~~~==~==~==~==~~~~~~
48+
:~==~==~==~==~~
49+
50+
[success] Total time: 112 s, completed Nov 1, 2016 11:31:15 AM
51+
```
52+
53+
## Use `src/main/scala/Client.scala`
54+
55+
This source code can work with :octocat:.com and :octocat: Enterprise
56+
57+
### Create a GitHub client
58+
59+
- First, go to your GitHub profile settings and define a **Personal access token** (https://github.com/settings/tokens)
60+
- Then, add the token to the environment variables (eg: `export TOKEN_GITHUB_DOT_COM=token_string`)
61+
- Now you can get the token like that: `sys.env("TOKEN_GITHUB_DOT_COM")`
62+
63+
```scala
64+
val githubCliEnterprise = new github.Client(
65+
"http://github.at.home/api/v3",
66+
sys.env("TOKEN_GITHUB_ENTERPRISE")
67+
)
68+
69+
val githubCliDotCom = new github.Client(
70+
"https://api.github.com",
71+
sys.env("TOKEN_GITHUB_DOT_COM")
72+
)
73+
```
74+
75+
- if you use GitHub Enterprise, `baseUri` has to be set with `http(s)://your_domain_name/api/v3`
76+
- if you use GitHub.com, `baseUri` has to be set with `https://api.github.com`
77+
78+
### Use the GitHub client
79+
80+
For example, you want to get the information about a user:
81+
(see https://developer.github.com/v3/users/#get-a-single-user)
82+
83+
#### Adding features
84+
85+
You can add "features" to `GitHubClient` using Scala traits:
86+
87+
```scala
88+
val gitHubCli = new github.Client(
89+
"https://api.github.com",
90+
sys.env("TOKEN_GITHUB_DOT_COM")
91+
) with Users
92+
93+
94+
gitHubCli.fetchUser("k33g").fold(
95+
{errorMessage => println(errorMessage)},
96+
{userInformation:Option[Any] =>
97+
println(
98+
userInformation
99+
.map(user => user.asInstanceOf[Map[String, Any]])
100+
.getOrElse("Huston? We've got a problem!")
101+
)
102+
}
103+
)
104+
```
105+
106+
You can add more than one feature:
107+
108+
```scala
109+
val gitHubCli = new github.Client(
110+
"http://github.at.home/api/v3",
111+
sys.env("TOKEN_GITHUB_ENTERPRISE")
112+
) with Organizations
113+
with Repositories
114+
```
115+
116+
## Add features to the GitHub Client
117+
118+
- It's simple: just add a trait to the `github.features` package.
119+
- The trait must extend `RESTMethods` from `github.features`
120+
121+
```scala
122+
trait KillerFeatures extends RESTMethods {
123+
124+
def feature1():Either[String, String] = {
125+
// foo
126+
}
127+
128+
def feature2():Either[String, String] = {
129+
// foo
130+
}
131+
}
132+
```
133+
134+
See the `github.features` package for more samples
135+
136+
## About Models
137+
138+
There is no GitHub Model, data are provided inside `Map[String, Any]`
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
name := "octocat-samples"
2+
version := "1.0"
3+
scalaVersion := "2.12.0"
4+
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import github.features.{Organizations, Repositories}
2+
3+
/**
4+
* Create an organization and then a repository
5+
*/
6+
object DemoOrganizations extends App {
7+
8+
val gitHubCli = new github.Client(
9+
"http://github.at.home/api/v3",
10+
sys.env("TOKEN_GITHUB_ENTERPRISE")
11+
) with Organizations
12+
with Repositories
13+
14+
gitHubCli.createOrganization(
15+
login = "PlanetEarth",
16+
admin = "k33g",
17+
profile_name = "PlanetEarth Organization"
18+
).fold(
19+
{errorMessage => println(s"Organization Error: $errorMessage")},
20+
{
21+
case Some(organizationData) =>
22+
val organization = organizationData.asInstanceOf[Map[String, Any]]
23+
println(organization)
24+
println(organization.getOrElse("login","???"))
25+
26+
gitHubCli.createOrganizationRepository(
27+
name = "my-little-tools",
28+
description = "foo...",
29+
organization = organization.getOrElse("login","???").toString,
30+
isPrivate = false,
31+
hasIssues = true
32+
).fold(
33+
{errorMessage => println(s"Repository Error: $errorMessage")},
34+
{repositoryInformation:Option[Any] =>
35+
println(
36+
repositoryInformation
37+
.map(repo => repo.asInstanceOf[Map[String, Any]])
38+
.getOrElse("Huston? We've got a problem!")
39+
)
40+
}
41+
)
42+
case None =>
43+
println("Huston? We've got a problem!")
44+
}
45+
46+
)
47+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import github.features.Repositories
2+
3+
/**
4+
* Create a repository
5+
*/
6+
object DemoRepositories extends App {
7+
8+
val gitHubCli = new github.Client(
9+
"https://api.github.com",
10+
sys.env("TOKEN_GITHUB_DOT_COM")
11+
) with Repositories
12+
13+
gitHubCli.createRepository(
14+
name = "hello_earth_africa",
15+
description = "Hello world :heart:",
16+
isPrivate = false,
17+
hasIssues = true
18+
).fold(
19+
{errorMessage => println(s"Error: $errorMessage")},
20+
{repositoryInformation:Option[Any] =>
21+
println(
22+
repositoryInformation
23+
.map(repo => repo.asInstanceOf[Map[String, Any]])
24+
.getOrElse("ouch!")
25+
)
26+
}
27+
)
28+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import github.features.Users
2+
3+
/**
4+
* Display user informations on GitHub
5+
*/
6+
object DemoUser extends App {
7+
8+
val gitHubCli = new github.Client(
9+
"https://api.github.com",
10+
sys.env("TOKEN_GITHUB_DOT_COM")
11+
) with Users
12+
13+
14+
gitHubCli.fetchUser("k33g").fold(
15+
{errorMessage => println(errorMessage)},
16+
{userInformation:Option[Any] =>
17+
println(
18+
userInformation
19+
.map(user => user.asInstanceOf[Map[String, Any]])
20+
.getOrElse("Huston? We've got a problem!")
21+
)
22+
}
23+
)
24+
25+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import github.features.Zen
2+
3+
object DemoZen extends App {
4+
/**
5+
* Display Zen of GitHub
6+
*/
7+
val gitHubCli = new github.Client(
8+
"https://api.github.com"
9+
, sys.env("TOKEN_GITHUB_DOT_COM")
10+
) with Zen
11+
12+
gitHubCli.octocatMessage().fold(
13+
{errorMessage => println(s"Error: $errorMessage")},
14+
{data => println(data)}
15+
)
16+
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package github
2+
3+
import github.features.RESTMethods
4+
5+
/** =Simple GitHub client=
6+
*
7+
* ==Setup==
8+
* {{{
9+
* val gitHubCli = new github.Client(
10+
* "https://api.github.com",
11+
* sys.env("TOKEN_GITHUB_DOT_COM")
12+
* ) with trait1 with trait2
13+
* // trait1, trait2 are features provided in the `features` package
14+
* }}}
15+
*/
16+
class Client(gitHubUrl:String, gitHubToken:String) extends RESTMethods {
17+
override var baseUri: String = gitHubUrl
18+
override var token: String = gitHubToken
19+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package github.features
2+
3+
import http.Response
4+
5+
import scala.util.{Failure, Success}
6+
import scala.util.parsing.json.JSON
7+
8+
/** =Organizations features=
9+
*
10+
* ==Setup==
11+
*
12+
* instantiate the `github.Client` with `Organizations` trait:
13+
*
14+
* {{{
15+
* val gitHubCli = new github.Client(
16+
* "http://github.at.home/api/v3",
17+
* sys.env("TOKEN_GITHUB_ENTERPRISE")
18+
* ) with Organizations
19+
*
20+
* }}}
21+
*/
22+
trait Organizations extends RESTMethods {
23+
24+
/** this methods creates an organization (only for GitHub Enterprise)
25+
* see: https://developer.github.com/v3/enterprise/orgs/#create-an-organization
26+
*
27+
* @param login The organization's username.
28+
* @param admin The login of the user who will manage this organization.
29+
* @param profile_name The organization's display name.
30+
* @return a Map with organization details inside an Either
31+
*/
32+
def createOrganization(login:String, admin:String, profile_name:String):Either[String, Option[Any]] = {
33+
postData(
34+
"/admin/organizations",
35+
generateHeaders.::(new http.Header("Content-Type", "application/json")),
36+
Map(
37+
"login" -> login,
38+
"admin" -> admin,
39+
"profile_name" -> profile_name
40+
)
41+
) match {
42+
case Success(resp:Response) =>
43+
if (http.isOk(resp.code)) Right(JSON.parseFull(resp.data)) else Left(resp.message)
44+
case Failure(err) => Left(err.getMessage)
45+
}
46+
}
47+
48+
/** `addOrganizationMembership` adds a role for a user of an organization
49+
*
50+
* @param org organization name(login)
51+
* @param userName name of the concerned user
52+
* @param role role of membership
53+
* @return membership information
54+
*/
55+
def addOrganizationMembership(org:String, userName:String, role:String):Either[String, Option[Any]] = {
56+
putData(
57+
s"/orgs/$org/memberships/$userName",
58+
generateHeaders.::(new http.Header("Content-Type", "application/json")),
59+
Map(
60+
"role" -> role // member, maintener
61+
)
62+
) match {
63+
case Success(resp:Response) =>
64+
if (http.isOk(resp.code)) Right(JSON.parseFull(resp.data)) else Left(resp.message)
65+
case Failure(err) => Left(err.getMessage)
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)