Skip to content

Commit

Permalink
First version of Scala samples to use GitHub API
Browse files Browse the repository at this point in the history
  • Loading branch information
Philippe Charrière authored Nov 11, 2016
1 parent 47154a9 commit 92d34db
Show file tree
Hide file tree
Showing 16 changed files with 683 additions and 0 deletions.
3 changes: 3 additions & 0 deletions api/scala.with.sbt/octocat-samples/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.idea/*
project/*
target/*
138 changes: 138 additions & 0 deletions api/scala.with.sbt/octocat-samples/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# GitHub API + Scala

## Setup and Run

- This is a `sbt` project. See http://www.scala-sbt.org/0.13/docs/Setup.html
- Run `sbt` in a Terminal (at the root of this project: `/platform-samples/API/scala.wit.sbt/octocat-samples`)
- Type `run`, and you'll get this:
```shell
> run
[warn] Multiple main classes detected. Run 'show discoveredMainClasses' to see the list

Multiple main classes detected, select one to run:

[1] DemoOrganizations
[2] DemoRepositories
[3] DemoUser
[4] DemoZen

Enter number:
```
- Chose the number of the demo to run
eg, if you choose `4` you'll get something like that:
```shell
[info] Running DemoZen
MMM. .MMM
MMMMMMMMMMMMMMMMMMM
MMMMMMMMMMMMMMMMMMM _____________________
MMMMMMMMMMMMMMMMMMMMM | |
MMMMMMMMMMMMMMMMMMMMMMM | Speak like a human. |
MMMMMMMMMMMMMMMMMMMMMMMM |_ _________________|
MMMM::- -:::::::- -::MMMM |/
MM~:~ 00~:::::~ 00~:~MM
.. MMMMM::.00:::+:::.00::MMMMM ..
.MM::::: ._. :::::MM.
MMMM;:::::;MMMM
-MM MMMMMMM
^ M+ MMMMMMMMM
MMMMMMM MM MM MM
MM MM MM MM
MM MM MM MM
.~~MM~MM~MM~MM~~.
~~~~MM:~MM~~~MM~:MM~~~~
~~~~~~==~==~~~==~==~~~~~~
~~~~~~==~==~==~==~~~~~~
:~==~==~==~==~~
[success] Total time: 112 s, completed Nov 1, 2016 11:31:15 AM
```
## Use `src/main/scala/Client.scala`
This source code can work with :octocat:.com and :octocat: Enterprise
### Create a GitHub client
- First, go to your GitHub profile settings and define a **Personal access token** (https://github.com/settings/tokens)
- Then, add the token to the environment variables (eg: `export TOKEN_GITHUB_DOT_COM=token_string`)
- Now you can get the token like that: `sys.env("TOKEN_GITHUB_DOT_COM")`
```scala
val githubCliEnterprise = new github.Client(
"http://github.at.home/api/v3",
sys.env("TOKEN_GITHUB_ENTERPRISE")
)
val githubCliDotCom = new github.Client(
"https://api.github.com",
sys.env("TOKEN_GITHUB_DOT_COM")
)
```
- if you use GitHub Enterprise, `baseUri` has to be set with `http(s)://your_domain_name/api/v3`
- if you use GitHub.com, `baseUri` has to be set with `https://api.github.com`
### Use the GitHub client
For example, you want to get the information about a user:
(see https://developer.github.com/v3/users/#get-a-single-user)
#### Adding features
You can add "features" to `GitHubClient` using Scala traits:
```scala
val gitHubCli = new github.Client(
"https://api.github.com",
sys.env("TOKEN_GITHUB_DOT_COM")
) with Users
gitHubCli.fetchUser("k33g").fold(
{errorMessage => println(errorMessage)},
{userInformation:Option[Any] =>
println(
userInformation
.map(user => user.asInstanceOf[Map[String, Any]])
.getOrElse("Huston? We've got a problem!")
)
}
)
```
You can add more than one feature:
```scala
val gitHubCli = new github.Client(
"http://github.at.home/api/v3",
sys.env("TOKEN_GITHUB_ENTERPRISE")
) with Organizations
with Repositories
```
## Add features to the GitHub Client
- It's simple: just add a trait to the `github.features` package.
- The trait must extend `RESTMethods` from `github.features`
```scala
trait KillerFeatures extends RESTMethods {
def feature1():Either[String, String] = {
// foo
}
def feature2():Either[String, String] = {
// foo
}
}
```
See the `github.features` package for more samples
## About Models
There is no GitHub Model, data are provided inside `Map[String, Any]`
4 changes: 4 additions & 0 deletions api/scala.with.sbt/octocat-samples/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
name := "octocat-samples"
version := "1.0"
scalaVersion := "2.12.0"
libraryDependencies += "org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4"
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import github.features.{Organizations, Repositories}

/**
* Create an organization and then a repository
*/
object DemoOrganizations extends App {

val gitHubCli = new github.Client(
"http://github.at.home/api/v3",
sys.env("TOKEN_GITHUB_ENTERPRISE")
) with Organizations
with Repositories

gitHubCli.createOrganization(
login = "PlanetEarth",
admin = "k33g",
profile_name = "PlanetEarth Organization"
).fold(
{errorMessage => println(s"Organization Error: $errorMessage")},
{
case Some(organizationData) =>
val organization = organizationData.asInstanceOf[Map[String, Any]]
println(organization)
println(organization.getOrElse("login","???"))

gitHubCli.createOrganizationRepository(
name = "my-little-tools",
description = "foo...",
organization = organization.getOrElse("login","???").toString,
isPrivate = false,
hasIssues = true
).fold(
{errorMessage => println(s"Repository Error: $errorMessage")},
{repositoryInformation:Option[Any] =>
println(
repositoryInformation
.map(repo => repo.asInstanceOf[Map[String, Any]])
.getOrElse("Huston? We've got a problem!")
)
}
)
case None =>
println("Huston? We've got a problem!")
}

)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import github.features.Repositories

/**
* Create a repository
*/
object DemoRepositories extends App {

val gitHubCli = new github.Client(
"https://api.github.com",
sys.env("TOKEN_GITHUB_DOT_COM")
) with Repositories

gitHubCli.createRepository(
name = "hello_earth_africa",
description = "Hello world :heart:",
isPrivate = false,
hasIssues = true
).fold(
{errorMessage => println(s"Error: $errorMessage")},
{repositoryInformation:Option[Any] =>
println(
repositoryInformation
.map(repo => repo.asInstanceOf[Map[String, Any]])
.getOrElse("ouch!")
)
}
)
}
25 changes: 25 additions & 0 deletions api/scala.with.sbt/octocat-samples/src/main/scala/DemoUser.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import github.features.Users

/**
* Display user informations on GitHub
*/
object DemoUser extends App {

val gitHubCli = new github.Client(
"https://api.github.com",
sys.env("TOKEN_GITHUB_DOT_COM")
) with Users


gitHubCli.fetchUser("k33g").fold(
{errorMessage => println(errorMessage)},
{userInformation:Option[Any] =>
println(
userInformation
.map(user => user.asInstanceOf[Map[String, Any]])
.getOrElse("Huston? We've got a problem!")
)
}
)

}
17 changes: 17 additions & 0 deletions api/scala.with.sbt/octocat-samples/src/main/scala/DemoZen.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import github.features.Zen

object DemoZen extends App {
/**
* Display Zen of GitHub
*/
val gitHubCli = new github.Client(
"https://api.github.com"
, sys.env("TOKEN_GITHUB_DOT_COM")
) with Zen

gitHubCli.octocatMessage().fold(
{errorMessage => println(s"Error: $errorMessage")},
{data => println(data)}
)

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package github

import github.features.RESTMethods

/** =Simple GitHub client=
*
* ==Setup==
* {{{
* val gitHubCli = new github.Client(
* "https://api.github.com",
* sys.env("TOKEN_GITHUB_DOT_COM")
* ) with trait1 with trait2
* // trait1, trait2 are features provided in the `features` package
* }}}
*/
class Client(gitHubUrl:String, gitHubToken:String) extends RESTMethods {
override var baseUri: String = gitHubUrl
override var token: String = gitHubToken
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package github.features

import http.Response

import scala.util.{Failure, Success}
import scala.util.parsing.json.JSON

/** =Organizations features=
*
* ==Setup==
*
* instantiate the `github.Client` with `Organizations` trait:
*
* {{{
* val gitHubCli = new github.Client(
* "http://github.at.home/api/v3",
* sys.env("TOKEN_GITHUB_ENTERPRISE")
* ) with Organizations
*
* }}}
*/
trait Organizations extends RESTMethods {

/** this methods creates an organization (only for GitHub Enterprise)
* see: https://developer.github.com/v3/enterprise/orgs/#create-an-organization
*
* @param login The organization's username.
* @param admin The login of the user who will manage this organization.
* @param profile_name The organization's display name.
* @return a Map with organization details inside an Either
*/
def createOrganization(login:String, admin:String, profile_name:String):Either[String, Option[Any]] = {
postData(
"/admin/organizations",
generateHeaders.::(new http.Header("Content-Type", "application/json")),
Map(
"login" -> login,
"admin" -> admin,
"profile_name" -> profile_name
)
) match {
case Success(resp:Response) =>
if (http.isOk(resp.code)) Right(JSON.parseFull(resp.data)) else Left(resp.message)
case Failure(err) => Left(err.getMessage)
}
}

/** `addOrganizationMembership` adds a role for a user of an organization
*
* @param org organization name(login)
* @param userName name of the concerned user
* @param role role of membership
* @return membership information
*/
def addOrganizationMembership(org:String, userName:String, role:String):Either[String, Option[Any]] = {
putData(
s"/orgs/$org/memberships/$userName",
generateHeaders.::(new http.Header("Content-Type", "application/json")),
Map(
"role" -> role // member, maintener
)
) match {
case Success(resp:Response) =>
if (http.isOk(resp.code)) Right(JSON.parseFull(resp.data)) else Left(resp.message)
case Failure(err) => Left(err.getMessage)
}
}
}
Loading

0 comments on commit 92d34db

Please sign in to comment.