Skip to content

Commit c82c860

Browse files
authored
Merge pull request #2523 from ybasket/feature/pr-labels
Add support for PR labels
2 parents 25814df + 4c09bd2 commit c82c860

20 files changed

+165
-14
lines changed

docs/help.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
All command line arguments for the `scala-steward` application.
44

55
```
6-
Usage: scala-steward --workspace <file> --repos-file <file> [--git-author-name <string>] --git-author-email <string> [--git-author-signing-key <string>] --git-ask-pass <file> [--sign-commits] [--vcs-type <vcs-type>] [--vcs-api-host <uri>] --vcs-login <string> [--do-not-fork] [--ignore-opts-files] [--env-var <name=value>]... [--process-timeout <duration>] [--whitelist <string>]... [--read-only <string>]... [--enable-sandbox | --disable-sandbox] [--max-buffer-size <integer>] [--repo-config <uri>]... [--disable-default-repo-config] [--scalafix-migrations <uri>]... [--disable-default-scalafix-migrations] [--artifact-migrations <uri>]... [--disable-default-artifact-migrations] [--cache-ttl <duration>] [--bitbucket-server-use-default-reviewers] [--gitlab-merge-when-pipeline-succeeds] [--github-app-id <integer> --github-app-key-file <file>] [--url-checker-test-url <uri>] [--default-maven-repo <string>] [--refresh-backoff-period <duration>]
6+
Usage: scala-steward --workspace <file> --repos-file <file> [--git-author-name <string>] --git-author-email <string> [--git-author-signing-key <string>] --git-ask-pass <file> [--sign-commits] [--vcs-type <vcs-type>] [--vcs-api-host <uri>] --vcs-login <string> [--do-not-fork] [--add-labels] [--ignore-opts-files] [--env-var <name=value>]... [--process-timeout <duration>] [--whitelist <string>]... [--read-only <string>]... [--enable-sandbox | --disable-sandbox] [--max-buffer-size <integer>] [--repo-config <uri>]... [--disable-default-repo-config] [--scalafix-migrations <uri>]... [--disable-default-scalafix-migrations] [--artifact-migrations <uri>]... [--disable-default-artifact-migrations] [--cache-ttl <duration>] [--bitbucket-server-use-default-reviewers] [--gitlab-merge-when-pipeline-succeeds] [--github-app-id <integer> --github-app-key-file <file>] [--url-checker-test-url <uri>] [--default-maven-repo <string>] [--refresh-backoff-period <duration>]
77
88
99
@@ -32,6 +32,8 @@ Options and flags:
3232
The user name for the git hoster
3333
--do-not-fork
3434
Whether to not push the update branches to a fork; default: false
35+
--add-labels
36+
Whether to add labels on pull or merge requests (if supported by git hoster)
3537
--ignore-opts-files
3638
Whether to remove ".jvmopts" and ".sbtopts" files before invoking the build tool
3739
--env-var <name=value>

modules/core/src/main/scala/org/scalasteward/core/application/Cli.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,14 @@ object Cli {
108108
private val doNotFork: Opts[Boolean] =
109109
flag("do-not-fork", "Whether to not push the update branches to a fork; default: false").orFalse
110110

111+
private val addPrLabels: Opts[Boolean] =
112+
flag(
113+
"add-labels",
114+
"Whether to add labels on pull or merge requests (if supported by git hoster)"
115+
).orFalse
116+
111117
private val vcsCfg: Opts[VCSCfg] =
112-
(vcsType, vcsApiHost, vcsLogin, doNotFork).mapN(VCSCfg.apply)
118+
(vcsType, vcsApiHost, vcsLogin, doNotFork, addPrLabels).mapN(VCSCfg.apply)
113119

114120
private val ignoreOptsFiles: Opts[Boolean] =
115121
flag(

modules/core/src/main/scala/org/scalasteward/core/application/Config.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ object Config {
9696
tpe: VCSType,
9797
apiHost: Uri,
9898
login: String,
99-
doNotFork: Boolean
99+
doNotFork: Boolean,
100+
addLabels: Boolean
100101
)
101102

102103
final case class ProcessCfg(

modules/core/src/main/scala/org/scalasteward/core/nurture/NurtureAlg.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,9 @@ final class NurtureAlg[F[_]](config: VCSCfg)(implicit
196196
filesWithOldVersion
197197
)
198198
pr <- vcsApiAlg.createPullRequest(data.repo, requestData)
199+
_ <- vcsApiAlg
200+
.labelPullRequest(data.repo, pr.number, requestData.labels)
201+
.whenA(config.addLabels && requestData.labels.nonEmpty)
199202
prData = PullRequestData[Id](
200203
pr.html_url,
201204
data.baseSha1,

modules/core/src/main/scala/org/scalasteward/core/vcs/VCSApiAlg.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ trait VCSApiAlg[F[_]] {
3939

4040
def commentPullRequest(repo: Repo, number: PullRequestNumber, comment: String): F[Comment]
4141

42+
def labelPullRequest(repo: Repo, number: PullRequestNumber, labels: List[String]): F[Unit]
43+
4244
final def createForkOrGetRepo(repo: Repo, doNotFork: Boolean): F[RepoOut] =
4345
if (doNotFork) getRepo(repo) else createFork(repo)
4446

modules/core/src/main/scala/org/scalasteward/core/vcs/VCSSelection.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ final class VCSSelection[F[_]](config: Config, user: AuthenticatedUser)(implicit
3535
F: MonadThrow[F]
3636
) {
3737
private def gitHubApiAlg: GitHubApiAlg[F] =
38-
new GitHubApiAlg[F](config.vcsCfg.apiHost, _ => github.authentication.addCredentials(user))
38+
new GitHubApiAlg[F](
39+
config.vcsCfg.apiHost,
40+
_ => github.authentication.addCredentials(user)
41+
)
3942

4043
private def gitLabApiAlg: GitLabApiAlg[F] =
4144
new GitLabApiAlg[F](

modules/core/src/main/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlg.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,12 @@ import org.scalasteward.core.util.{HttpJsonClient, UnexpectedResponse}
2525
import org.scalasteward.core.vcs.VCSApiAlg
2626
import org.scalasteward.core.vcs.bitbucket.json._
2727
import org.scalasteward.core.vcs.data._
28+
import org.typelevel.log4cats.Logger
2829

2930
/** https://developer.atlassian.com/bitbucket/api/2/reference/ */
3031
class BitbucketApiAlg[F[_]](config: VCSCfg, modify: Repo => Request[F] => F[Request[F]])(implicit
3132
client: HttpJsonClient[F],
33+
logger: Logger[F],
3234
F: MonadThrow[F]
3335
) extends VCSApiAlg[F] {
3436
private val url = new Url(config.apiHost)
@@ -105,4 +107,13 @@ class BitbucketApiAlg[F[_]](config: VCSCfg, modify: Repo => Request[F] => F[Requ
105107
modify(repo)
106108
)
107109
.map((cc: CreateComment) => Comment(cc.content.raw))
110+
111+
override def labelPullRequest(
112+
repo: Repo,
113+
number: PullRequestNumber,
114+
labels: List[String]
115+
): F[Unit] =
116+
logger.warn(
117+
"Bitbucket does not support PR labels, remove --add-labels to make this warning disappear"
118+
)
108119
}

modules/core/src/main/scala/org/scalasteward/core/vcs/bitbucketserver/BitbucketServerApiAlg.scala

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@ import org.scalasteward.core.vcs.VCSApiAlg
2626
import org.scalasteward.core.vcs.bitbucketserver.Json.{PR, Reviewer, User}
2727
import org.scalasteward.core.vcs.data.PullRequestState.Open
2828
import org.scalasteward.core.vcs.data._
29+
import org.typelevel.log4cats.Logger
2930

3031
/** https://docs.atlassian.com/bitbucket-server/rest/latest/bitbucket-rest.html */
3132
final class BitbucketServerApiAlg[F[_]](
3233
bitbucketApiHost: Uri,
3334
config: BitbucketServerCfg,
3435
modify: Repo => Request[F] => F[Request[F]]
35-
)(implicit client: HttpJsonClient[F], F: MonadThrow[F])
36+
)(implicit client: HttpJsonClient[F], logger: Logger[F], F: MonadThrow[F])
3637
extends VCSApiAlg[F] {
3738
private val url = new Url(bitbucketApiHost)
3839

@@ -116,4 +117,13 @@ final class BitbucketServerApiAlg[F[_]](
116117
client
117118
.get[Json.Page[Json.PR]](url.listPullRequests(repo, s"refs/heads/$head"), modify(repo))
118119
.map(_.values.map(_.toPullRequestOut))
120+
121+
override def labelPullRequest(
122+
repo: Repo,
123+
number: PullRequestNumber,
124+
labels: List[String]
125+
): F[Unit] =
126+
logger.warn(
127+
"Bitbucket does not support PR labels, remove --add-labels to make this warning disappear"
128+
)
119129
}

modules/core/src/main/scala/org/scalasteward/core/vcs/data/NewPullRequestData.scala

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ final case class NewPullRequestData(
3333
body: String,
3434
head: String,
3535
base: Branch,
36+
labels: List[String],
3637
draft: Boolean = false
3738
)
3839

@@ -46,7 +47,8 @@ object NewPullRequestData {
4647
artifactIdToUrl: Map[String, Uri],
4748
releaseRelatedUrls: List[ReleaseRelatedUrl],
4849
filesWithOldVersion: List[String],
49-
configParsingError: Option[String]
50+
configParsingError: Option[String],
51+
labels: List[String]
5052
): String = {
5153
val artifacts = artifactsWithOptionalUrl(update, artifactIdToUrl)
5254
val migrations = edits.collect { case scalafixEdit: ScalafixEdit => scalafixEdit }
@@ -72,7 +74,7 @@ object NewPullRequestData {
7274
|
7375
|${details.map(_.toHtml).mkString("\n")}
7476
|
75-
|${labelsFor(update, edits, filesWithOldVersion).mkString("labels: ", ", ", "")}
77+
|${labels.mkString("labels: ", ", ", "")}
7678
|""".stripMargin.trim
7779
}
7880

@@ -181,7 +183,8 @@ object NewPullRequestData {
181183
artifactIdToUrl: Map[String, Uri] = Map.empty,
182184
releaseRelatedUrls: List[ReleaseRelatedUrl] = List.empty,
183185
filesWithOldVersion: List[String] = List.empty
184-
): NewPullRequestData =
186+
): NewPullRequestData = {
187+
val labels = labelsFor(data.update, edits, filesWithOldVersion)
185188
NewPullRequestData(
186189
title = git
187190
.commitMsgFor(data.update, data.repoConfig.commits, data.repoData.repo.branch)
@@ -192,11 +195,14 @@ object NewPullRequestData {
192195
artifactIdToUrl,
193196
releaseRelatedUrls,
194197
filesWithOldVersion,
195-
data.repoData.cache.maybeRepoConfigParsingError
198+
data.repoData.cache.maybeRepoConfigParsingError,
199+
labels
196200
),
197201
head = branchName,
198-
base = data.baseBranch
202+
base = data.baseBranch,
203+
labels = labels
199204
)
205+
}
200206

201207
def updateType(update: Update): String = {
202208
val dependencies = update.dependencies

modules/core/src/main/scala/org/scalasteward/core/vcs/github/GitHubApiAlg.scala

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,18 @@ final class GitHubApiAlg[F[_]](
7777
client
7878
.postWithBody(url.comments(repo, number), Comment(comment), modify(repo))
7979

80+
/** https://docs.github.com/en/rest/reference/issues#add-labels-to-an-issue */
81+
override def labelPullRequest(
82+
repo: Repo,
83+
number: PullRequestNumber,
84+
labels: List[String]
85+
): F[Unit] =
86+
client
87+
.postWithBody[io.circe.Json, GitHubLabels](
88+
url.issueLabels(repo, number),
89+
GitHubLabels(labels),
90+
modify(repo)
91+
)
92+
.adaptErr(SecondaryRateLimitExceeded.fromThrowable)
93+
.void
8094
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright 2018-2022 Scala Steward contributors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.scalasteward.core.vcs.github
18+
19+
import io.circe.Encoder
20+
import io.circe.generic.semiauto.deriveEncoder
21+
22+
case class GitHubLabels(labels: List[String])
23+
24+
object GitHubLabels {
25+
implicit val gitHubLabelsEncoder: Encoder[GitHubLabels] = deriveEncoder
26+
}

modules/core/src/main/scala/org/scalasteward/core/vcs/github/Url.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ class Url(apiHost: Uri) {
3939
def pull(repo: Repo, number: PullRequestNumber): Uri =
4040
repos(repo) / "pulls" / number.toString
4141

42+
def issueLabels(repo: Repo, number: PullRequestNumber): Uri =
43+
repos(repo) / "issues" / number.toString / "labels"
44+
4245
def repos(repo: Repo): Uri =
4346
apiHost / "repos" / repo.owner / repo.repo
4447

modules/core/src/main/scala/org/scalasteward/core/vcs/gitlab/GitLabApiAlg.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,4 +235,17 @@ final class GitLabApiAlg[F[_]](
235235
): F[Comment] =
236236
client.postWithBody(url.comments(repo, number), Comment(comment), modify(repo))
237237

238+
// https://docs.gitlab.com/ee/api/merge_requests.html#update-mr
239+
override def labelPullRequest(
240+
repo: Repo,
241+
number: PullRequestNumber,
242+
labels: List[String]
243+
): F[Unit] =
244+
client
245+
.putWithBody[Json, Json](
246+
url.existingMergeRequest(repo, number),
247+
Json.obj("labels" := labels.mkString(",")),
248+
modify(repo)
249+
)
250+
.void
238251
}

modules/core/src/test/scala/org/scalasteward/core/vcs/VCSExtraAlgTest.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,13 @@ class VCSExtraAlgTest extends FunSuite {
5959
}
6060

6161
test("getBranchCompareUrl: github on prem") {
62-
val config = VCSCfg(VCSType.GitHub, uri"https://github.on-prem.com/", "", doNotFork = false)
62+
val config = VCSCfg(
63+
VCSType.GitHub,
64+
uri"https://github.on-prem.com/",
65+
"",
66+
doNotFork = false,
67+
addLabels = false
68+
)
6369
val githubOnPremVcsExtraAlg = VCSExtraAlg.create[IO](config)
6470

6571
assertEquals(

modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucket/BitbucketApiAlgTest.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import org.http4s.circe._
99
import org.http4s.client.Client
1010
import org.http4s.dsl.io._
1111
import org.http4s.implicits._
12+
import org.scalasteward.core.TestInstances.ioLogger
1213
import org.scalasteward.core.git.Sha1.HexString
1314
import org.scalasteward.core.git._
1415
import org.scalasteward.core.mock.MockConfig.config
@@ -262,7 +263,8 @@ class BitbucketApiAlgTest extends FunSuite {
262263
"scala-steward-pr",
263264
"body",
264265
"master",
265-
master
266+
master,
267+
Nil
266268
)
267269
val pr = bitbucketApiAlg.createPullRequest(repo, data).unsafeRunSync()
268270
assertEquals(pr, pullRequest)

modules/core/src/test/scala/org/scalasteward/core/vcs/bitbucketserver/BitbucketServerApiAlgTest.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import org.http4s.client.Client
77
import org.http4s.dsl.io._
88
import org.http4s.implicits._
99
import org.http4s.{HttpRoutes, Uri}
10+
import org.scalasteward.core.TestInstances.ioLogger
1011
import org.scalasteward.core.application.Config.BitbucketServerCfg
1112
import org.scalasteward.core.git.Branch
1213
import org.scalasteward.core.mock.MockConfig.config

modules/core/src/test/scala/org/scalasteward/core/vcs/data/NewPullRequestDataTest.scala

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ class NewPullRequestDataTest extends FunSuite {
3131
| "body" : "Updates ch.qos.logback:logback-classic from 1.2.0 to 1.2.3.\n\n\nI'll automatically update this PR to resolve conflicts as long as you don't change it yourself.\n\nIf you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.\n\nConfigure Scala Steward for your repository with a [`.scala-steward.conf`](https://github.com/scala-steward-org/scala-steward/blob/${org.scalasteward.core.BuildInfo.gitHeadCommit}/docs/repo-specific-configuration.md) file.\n\nHave a fantastic day writing Scala!\n\n<details>\n<summary>Adjust future updates</summary>\n\nAdd this to your `.scala-steward.conf` file to ignore future updates of this dependency:\n```\nupdates.ignore = [ { groupId = \"ch.qos.logback\", artifactId = \"logback-classic\" } ]\n```\nOr, add this to slow down future updates of this dependency:\n```\ndependencyOverrides = [{\n pullRequests = { frequency = \"@monthly\" },\n dependency = { groupId = \"ch.qos.logback\", artifactId = \"logback-classic\" }\n}]\n```\n</details>\n\nlabels: library-update, early-semver-patch, semver-spec-patch, commit-count:0",
3232
| "head" : "scala-steward:update/logback-classic-1.2.3",
3333
| "base" : "master",
34+
| "labels" : [
35+
| "library-update",
36+
| "early-semver-patch",
37+
| "semver-spec-patch",
38+
| "commit-count:0"
39+
| ],
3440
| "draft" : false
3541
|}""".stripMargin
3642
assertEquals(obtained, expected)
@@ -56,6 +62,12 @@ class NewPullRequestDataTest extends FunSuite {
5662
| "body" : "Updates ch.qos.logback:logback-classic from 1.2.0 to 1.2.3.\n\n\nI'll automatically update this PR to resolve conflicts as long as you don't change it yourself.\n\nIf you'd like to skip this version, you can just close this PR. If you have any feedback, just mention me in the comments below.\n\nConfigure Scala Steward for your repository with a [`.scala-steward.conf`](https://github.com/scala-steward-org/scala-steward/blob/${org.scalasteward.core.BuildInfo.gitHeadCommit}/docs/repo-specific-configuration.md) file.\n\nHave a fantastic day writing Scala!\n\n<details>\n<summary>Adjust future updates</summary>\n\nAdd this to your `.scala-steward.conf` file to ignore future updates of this dependency:\n```\nupdates.ignore = [ { groupId = \"ch.qos.logback\", artifactId = \"logback-classic\" } ]\n```\nOr, add this to slow down future updates of this dependency:\n```\ndependencyOverrides = [{\n pullRequests = { frequency = \"@monthly\" },\n dependency = { groupId = \"ch.qos.logback\", artifactId = \"logback-classic\" }\n}]\n```\n</details>\n<details>\n<summary>Note that the Scala Steward config file `.scala-steward.conf` wasn't parsed correctly</summary>\n\n```\nFailed to parse .scala-steward.conf\n```\n</details>\n\nlabels: library-update, early-semver-patch, semver-spec-patch, commit-count:0",
5763
| "head" : "scala-steward:update/logback-classic-1.2.3",
5864
| "base" : "master",
65+
| "labels" : [
66+
| "library-update",
67+
| "early-semver-patch",
68+
| "semver-spec-patch",
69+
| "commit-count:0"
70+
| ],
5971
| "draft" : false
6072
|}""".stripMargin
6173
assertEquals(obtained, expected)

modules/core/src/test/scala/org/scalasteward/core/vcs/github/GitHubApiAlgTest.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,19 @@ class GitHubApiAlgTest extends FunSuite {
8888
"body": "Superseded by #1234"
8989
} """)
9090

91+
case POST -> Root / "repos" / "fthomas" / "base.g8" / "issues" / IntVar(_) / "labels" =>
92+
// Response taken from https://docs.github.com/en/rest/reference/issues#labels, is ignored
93+
Created(json"""[
94+
{
95+
"id": 208045946,
96+
"node_id": "MDU6TGFiZWwyMDgwNDU5NDY=",
97+
"url": "https://api.github.com/repos/fthomas/base.g8/labels/bug",
98+
"name": "bug",
99+
"description": "Something isn't working",
100+
"color": "f29513",
101+
"default": true
102+
}]""")
103+
91104
case req =>
92105
println(req.toString())
93106
NotFound()
@@ -209,4 +222,12 @@ class GitHubApiAlgTest extends FunSuite {
209222
.unsafeRunSync()
210223
assertEquals(comment, Comment("Superseded by #1234"))
211224
}
225+
226+
test("labelPullRequest") {
227+
val result = gitHubApiAlg
228+
.labelPullRequest(repo, PullRequestNumber(1347), List("A", "B"))
229+
.attempt
230+
.unsafeRunSync()
231+
assert(result.isRight)
232+
}
212233
}

modules/core/src/test/scala/org/scalasteward/core/vcs/gitlab/GitLabApiAlgTest.scala

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ class GitLabApiAlgTest extends FunSuite {
206206
assertEquals(comment, Comment("Superseded by #1234"))
207207
}
208208

209+
test("labelPullRequest") {
210+
val result = gitlabApiAlg
211+
.labelPullRequest(Repo("foo", "bar"), PullRequestNumber(150), List("A", "B"))
212+
.attempt
213+
.unsafeRunSync()
214+
assert(result.isRight)
215+
}
216+
209217
val getMr = json"""
210218
{
211219
"id": 26328,
@@ -253,7 +261,7 @@ class GitLabApiAlgTest extends FunSuite {
253261
],
254262
"source_project_id": 466,
255263
"target_project_id": 466,
256-
"labels": [],
264+
"labels": ["A", "B"],
257265
"work_in_progress": false,
258266
"milestone": null,
259267
"merge_when_pipeline_succeeds": true,

modules/core/src/test/scala/org/scalasteward/core/vcs/gitlab/MergeRequestPayloadTest.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ class MergeRequestPayloadTest extends FunSuite {
1313
"Test MR title",
1414
"Test MR body",
1515
"source",
16-
master
16+
master,
17+
Nil
1718
)
1819
private val id = "123"
1920
private val projectId = 321L

0 commit comments

Comments
 (0)