@@ -23,13 +23,18 @@ import io.circe._
23
23
import io .circe .generic .semiauto ._
24
24
import io .circe .syntax ._
25
25
import org .http4s .{Request , Status , Uri }
26
- import org .scalasteward .core .application .Config .{ForgeCfg , GitLabCfg }
26
+ import org .scalasteward .core .application .Config .{ForgeCfg , GitLabCfg , MergeRequestApprovalsConfig }
27
27
import org .scalasteward .core .data .Repo
28
28
import org .scalasteward .core .forge .ForgeApiAlg
29
29
import org .scalasteward .core .forge .data ._
30
30
import org .scalasteward .core .git .{Branch , Sha1 }
31
31
import org .scalasteward .core .util .uri .uriDecoder
32
- import org .scalasteward .core .util .{intellijThisImportIsUsed , HttpJsonClient , UnexpectedResponse }
32
+ import org .scalasteward .core .util .{
33
+ intellijThisImportIsUsed ,
34
+ HttpJsonClient ,
35
+ Nel ,
36
+ UnexpectedResponse
37
+ }
33
38
import org .typelevel .log4cats .Logger
34
39
35
40
import scala .concurrent .duration .{Duration , DurationInt }
@@ -48,6 +53,8 @@ final private[gitlab] case class MergeRequestPayload(
48
53
target_branch : Branch
49
54
)
50
55
56
+ final private [gitlab] case class UpdateMergeRequestLevelApprovalRulePayload (approvals_required : Int )
57
+
51
58
private [gitlab] object MergeRequestPayload {
52
59
def apply (
53
60
id : String ,
@@ -87,6 +94,11 @@ final private[gitlab] case class MergeRequestApprovalsOut(
87
94
approvalsRequired : Int
88
95
)
89
96
97
+ final private [gitlab] case class MergeRequestLevelApprovalRuleOut (
98
+ id : Int ,
99
+ name : String
100
+ )
101
+
90
102
final private [gitlab] case class CommitId (id : Sha1 ) {
91
103
val commitOut : CommitOut = CommitOut (id)
92
104
}
@@ -102,6 +114,8 @@ private[gitlab] object GitLabJsonCodec {
102
114
intellijThisImportIsUsed(uriDecoder)
103
115
104
116
implicit val forkPayloadEncoder : Encoder [ForkPayload ] = deriveEncoder
117
+ implicit val updateMergeRequestLevelApprovalRulePayloadEncoder
118
+ : Encoder [UpdateMergeRequestLevelApprovalRulePayload ] = deriveEncoder
105
119
implicit val userOutDecoder : Decoder [UserOut ] = Decoder .instance {
106
120
_.downField(" username" ).as[String ].map(UserOut (_))
107
121
}
@@ -140,6 +154,14 @@ private[gitlab] object GitLabJsonCodec {
140
154
} yield MergeRequestApprovalsOut (requiredReviewers)
141
155
}
142
156
157
+ implicit val mergeRequestLevelApprovalRuleOutDecoder : Decoder [MergeRequestLevelApprovalRuleOut ] =
158
+ Decoder .instance { c =>
159
+ for {
160
+ id <- c.downField(" id" ).as[Int ]
161
+ name <- c.downField(" string" ).as[String ]
162
+ } yield MergeRequestLevelApprovalRuleOut (id, name)
163
+ }
164
+
143
165
implicit val projectIdDecoder : Decoder [ProjectId ] = deriveDecoder
144
166
implicit val mergeRequestPayloadEncoder : Encoder [MergeRequestPayload ] =
145
167
deriveEncoder[MergeRequestPayload ].mapJson(_.dropNullValues)
@@ -240,7 +262,13 @@ final class GitLabApiAlg[F[_]: Parallel](
240
262
for {
241
263
mr <- mergeRequest
242
264
mrWithStatus <- waitForMergeRequestStatus(mr.iid)
243
- _ <- maybeSetReviewers(repo, mrWithStatus)
265
+ _ <- gitLabCfg.requiredReviewers match {
266
+ case Some (Right (approvalRules)) =>
267
+ setApprovalRules(repo, mrWithStatus, approvalRules)
268
+ case Some (Left (requiredReviewers)) =>
269
+ setReviewers(repo, mrWithStatus, requiredReviewers)
270
+ case None => F .unit
271
+ }
244
272
mergedUponSuccess <- mergePipelineUponSuccess(repo, mrWithStatus)
245
273
} yield mergedUponSuccess
246
274
}
@@ -270,29 +298,74 @@ final class GitLabApiAlg[F[_]: Parallel](
270
298
case mr =>
271
299
logger.info(s " Unable to automatically merge ${mr.webUrl}" ).map(_ => mr)
272
300
}
301
+ import cats .implicits ._
273
302
274
- private def maybeSetReviewers (repo : Repo , mrOut : MergeRequestOut ): F [MergeRequestOut ] =
275
- gitLabCfg.requiredReviewers match {
276
- case Some (requiredReviewers) =>
277
- for {
278
- _ <- logger.info(
279
- s " Setting number of required reviewers on ${mrOut.webUrl} to $requiredReviewers"
303
+ private def setReviewers (
304
+ repo : Repo ,
305
+ mrOut : MergeRequestOut ,
306
+ requiredReviewers : Int
307
+ ): F [MergeRequestOut ] =
308
+ for {
309
+ _ <- logger.info(
310
+ s " Setting number of required reviewers on ${mrOut.webUrl} to $requiredReviewers"
311
+ )
312
+ _ <-
313
+ client
314
+ .put[MergeRequestApprovalsOut ](
315
+ url.requiredApprovals(repo, mrOut.iid, requiredReviewers),
316
+ modify(repo)
280
317
)
281
- _ <-
282
- client
283
- .put[MergeRequestApprovalsOut ](
284
- url.requiredApprovals(repo, mrOut.iid, requiredReviewers),
285
- modify(repo)
286
- )
287
- .map(_ => ())
288
- .recoverWith { case UnexpectedResponse (_, _, _, status, body) =>
289
- logger
290
- .warn(s " Unexpected response setting required reviewers: $status: $body" )
291
- .as(())
292
- }
293
- } yield mrOut
294
- case None => F .pure(mrOut)
295
- }
318
+ .map(_ => ())
319
+ .recoverWith { case UnexpectedResponse (_, _, _, status, body) =>
320
+ logger
321
+ .warn(s " Unexpected response setting required reviewers: $status: $body" )
322
+ .as(())
323
+ }
324
+ } yield mrOut
325
+
326
+ private def setApprovalRules (
327
+ repo : Repo ,
328
+ mrOut : MergeRequestOut ,
329
+ approvalsConfig : Nel [MergeRequestApprovalsConfig ]
330
+ ): F [MergeRequestOut ] =
331
+ for {
332
+ _ <- logger.info(
333
+ s " Adjusting merge request approvals rules on ${mrOut.webUrl} with following config: $approvalsConfig"
334
+ )
335
+ activeApprovalRules <-
336
+ client
337
+ .get[List [MergeRequestLevelApprovalRuleOut ]](
338
+ url.listMergeRequestLevelApprovalRules(repo, mrOut.iid),
339
+ modify(repo)
340
+ )
341
+ .recoverWith { case UnexpectedResponse (_, _, _, status, body) =>
342
+ // ToDo better log
343
+ logger
344
+ .warn(s " Unexpected response setting required reviewers: $status: $body" )
345
+ .as(List .empty)
346
+ }
347
+ approvalRuleNamesFromConfig = approvalsConfig.map(_.approvalRuleName)
348
+ approvalRulesToUpdate = activeApprovalRules.intersect(approvalRuleNamesFromConfig.toList)
349
+ _ <-
350
+ approvalRulesToUpdate.map { mergeRequestApprovalConfig =>
351
+ client
352
+ .putWithBody[Unit , UpdateMergeRequestLevelApprovalRulePayload ](
353
+ url.updateMergeRequestLevelApprovalRule(
354
+ repo,
355
+ mrOut.iid,
356
+ mergeRequestApprovalConfig.id
357
+ ),
358
+ UpdateMergeRequestLevelApprovalRulePayload (mergeRequestApprovalConfig.id),
359
+ modify(repo)
360
+ )
361
+ .recoverWith { case UnexpectedResponse (_, _, _, status, body) =>
362
+ // ToDo better log
363
+ logger
364
+ .warn(s " Unexpected response setting required reviewers: $status: $body" )
365
+ .as(List .empty)
366
+ }
367
+ }.sequence
368
+ } yield mrOut
296
369
297
370
private def getUsernameToUserIdsMapping (repo : Repo , usernames : Set [String ]): F [Map [String , Int ]] =
298
371
usernames.toList
0 commit comments