Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API: Create milestone #391

Merged
merged 6 commits into from
Mar 28, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions docs/docs/issue.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ with Github4s, you can interact with:
- [List available assignees](#list-available-assignees)
- [Milestones](#milestones)
- [List milestones for a respository](#list-milestones-for-a-repository)
- [Create milestone](#create-milestone)

The following examples assume the following code:

Expand Down Expand Up @@ -433,3 +434,32 @@ The `result` on the right is the corresponding [List[Milestone]][milestone-scala
See [the API doc](https://developer.github.com/v3/issues/milestones/#list-milestones-for-a-repository) for full reference.

[milestone-scala]: https://github.com/47degrees/github4s/blob/master/github4s/src/main/scala/github4s/domain/Milestone.scala

### Create milestone

You can create a milestone for a particular organization and repository with `createMilestone`; it takes arguments:

- `owner`: name of the owner for which we want to create the milestones.
- `repo`: name of the repository for which we want to create the milestones.
- `state`: The state of the milestone. Either `open` or `closed`. Default: `open`, optional
- `title`: The title of the milestone.
- `description`: A description of the milestone, optional
- `due_on`: The milestone due date. This is a timestamp in ISO 8601 format: `YYYY-MM-DDTHH:MM:SSZ`, optional.
- `header`: headers to include in the request, optional.

To create a milestone for owner `47deg` and repository `github4s`:

```scala mdoc:compile-only
val milestone = gh.issues.createMilestone("47degrees", "github4s", "New milestone",Some("open"), None, None, None)
val response = milestone.unsafeRunSync()
response.result match {
case Left(e) => println(s"Something went wrong: ${e.getMessage}")
case Right(r) => println(r)
}
```

The `result` on the right is the corresponding [Milestone][milestone-scala]

See [the API doc](https://developer.github.com/v3/issues/milestones/#create-a-milestone) for full reference.

[milestone-scala]: https://github.com/47degrees/github4s/blob/master/github4s/src/main/scala/github4s/domain/Milestone.scala
1 change: 1 addition & 0 deletions github4s/src/main/scala/github4s/Encoders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,5 @@ object Encoders {
implicit val encoderNewReleaseRequest: Encoder[NewReleaseRequest] =
deriveEncoder[NewReleaseRequest]
implicit val encoderNewStatusRequest: Encoder[NewStatusRequest] = deriveEncoder[NewStatusRequest]
implicit val encoderMilestoneData: Encoder[MilestoneData] = deriveEncoder[MilestoneData]
}
20 changes: 20 additions & 0 deletions github4s/src/main/scala/github4s/algebras/Issues.scala
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,24 @@ trait Issues[F[_]] {
headers: Map[String, String] = Map()
): F[GHResponse[List[Milestone]]]

/**
*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing doc

* @param owner repo owner
* @param repo repo name
* @param title The title of the milestone.
* @param state The state of the milestone. Either open or closed. Default: open
* @param description A description of the milestone.
* @param due_on The milestone due date. This is a timestamp in ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ.
* @param headers optional user headers to include in the request
* @return a GHResponse with the created Milestone
*/
def createMilestone(
owner: String,
repo: String,
title: String,
state: Option[String],
description: Option[String],
due_on: Option[String],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if in these cases it wouldn't be better to supply a value of type date and format it ourselves, wdyt? 🤔

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree, it looks like we'll need a ZonedDateTime

headers: Map[String, String] = Map()
): F[GHResponse[Milestone]]
}
7 changes: 7 additions & 0 deletions github4s/src/main/scala/github4s/domain/Issue.scala
Original file line number Diff line number Diff line change
Expand Up @@ -103,3 +103,10 @@ case class Milestone(
closed_at: Option[String],
due_on: String
)

case class MilestoneData(
title: String,
state: Option[String],
description: Option[String],
due_on: Option[String]
)
Original file line number Diff line number Diff line change
Expand Up @@ -214,4 +214,20 @@ class IssuesInterpreter[F[_]](implicit client: HttpClient[F], accessToken: Optio
params =
List(state.map("state" -> _), sort.map("sort" -> _), direction.map("direction" -> _)).flatten.toMap
)

override def createMilestone(
owner: String,
repo: String,
title: String,
state: Option[String],
description: Option[String],
due_on: Option[String],
headers: Map[String, String]
): F[GHResponse[Milestone]] =
client.post[MilestoneData, Milestone](
accessToken,
s"repos/$owner/$repo/milestones",
headers,
MilestoneData(title, state, description, due_on)
)
}
26 changes: 26 additions & 0 deletions github4s/src/test/scala/github4s/unit/IssuesSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -312,4 +312,30 @@ class IssuesSpec extends BaseSpec {
)
}

"Issues.createMilestone" should "call httpClient.post with the right parameters" in {
val response: IO[GHResponse[Milestone]] =
IO(GHResponse(milestone.asRight, createdStatusCode, Map.empty))

val request = MilestoneData(validIssueTitle, None, None, None)

implicit val httpClientMock = httpClientMockPost[MilestoneData, Milestone](
url = s"repos/$validRepoOwner/$validRepoName/milestones",
req = request,
response = response
)

val issues = new IssuesInterpreter[IO]

issues.createMilestone(
validRepoOwner,
validRepoName,
validIssueTitle,
None,
None,
None,
headerUserAgent
)

}

}
40 changes: 40 additions & 0 deletions github4s/src/test/scala/github4s/utils/TestData.scala
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ trait TestData extends DummyGithubUrls {
val validAvatarUrl = "https://github.com/images/error/hubot_happy.gif"
val validNodeId = "MDY6U3RhdHVzMQ=="

val validMilestoneTitle = "Sample Title"

val treeDataList: List[TreeData] = List(
TreeDataSha(validPath, validMode, validBlobType, validTreeSha)
)
Expand Down Expand Up @@ -521,4 +523,42 @@ trait TestData extends DummyGithubUrls {
content_url = None
)

val milestone = Milestone(
url = "https://api.github.com/repos/47deg/github4s/milestones/1",
html_url = "https://github.com/47deg/github4s/milestone/1",
labels_url = "https://api.github.com/repos/47deg/github4s/milestones/1/labels",
id = 5166230,
node_id = "MDk6TWlsZXN0b25lNTE2NjIzMA==",
number = 1,
title = "MVP",
description = "",
creator = Creator(
login = "rafaparadela",
id = 315070,
node_id = "MDQ6VXNlcjMxNTA3MA==",
avatar_url = "https://avatars3.githubusercontent.com/u/315070?v=4",
gravatar_id = None,
url = "https://api.github.com/users/rafaparadela",
html_url = "https://github.com/rafaparadela",
followers_url = "https://api.github.com/users/rafaparadela/followers",
following_url = "https://api.github.com/users/rafaparadela/following{/other_user}",
gists_url = "https://api.github.com/users/rafaparadela/gists{/gist_id}",
starred_url = "https://api.github.com/users/rafaparadela/starred{/owner}{/repo}",
subscriptions_url = "https://api.github.com/users/rafaparadela/subscriptions",
organizations_url = "https://api.github.com/users/rafaparadela/orgs",
repos_url = "https://api.github.com/users/rafaparadela/repos",
events_url = "https://api.github.com/users/rafaparadela/events{/privacy}",
received_events_url = "https://api.github.com/users/rafaparadela/received_events",
`type` = "User",
site_admin = false
),
open_issues = 6,
closed_issues = 6,
state = "open",
created_at = "2020-03-04T06:02:13Z",
updated_at = "2020-03-25T15:59:06Z",
due_on = "2020-03-19T07:00:00Z",
closed_at = None
)

}