org.kiwiproject.changelog.github.GitHubPagingHelper.kt Maven / Gradle / Ivy
package org.kiwiproject.changelog.github
import com.google.common.annotations.VisibleForTesting
import org.apache.commons.lang3.StringUtils.abbreviate
import org.kiwiproject.changelog.github.GitHubApi.GitHubResponse
private const val NO_NEXT_PAGE = "none"
class GitHubPagingHelper {
fun paginate(api: GitHubApi, firstPageUrl: String, responseHandler: (Int, GitHubResponse) -> Unit) {
var nextPageUrl = firstPageUrl
var page = 1
while (hasNextPage(nextPageUrl)) {
val response = api.get(nextPageUrl)
checkOkResponse(response)
responseHandler(page, response)
nextPageUrl = getNextPageUrl(response.linkHeader)
++page
}
}
private fun hasNextPage(nextPageUrl: String): Boolean {
return NO_NEXT_PAGE != nextPageUrl
}
@VisibleForTesting
fun checkOkResponse(response: GitHubResponse) {
check(response.statusCode == 200) {
val truncatedContent = abbreviate(response.content, 100)
"GET ${response.requestUri} failed, response code ${response.statusCode}, response body\n:$truncatedContent"
}
}
@VisibleForTesting
fun getNextPageUrl(linkHeader: String?) : String {
if (linkHeader == null) {
return NO_NEXT_PAGE
}
// See GitHub API doc : https://docs.github.com/en/rest/using-the-rest-api/using-pagination-in-the-rest-api
// Example Link header and value:
// Link: ; rel="next",
// ; rel="last"
val linkRel = linkHeader.split(",")
.firstOrNull { url -> url.contains("rel=\"next\"") }
return linkRel?.substring(
startIndex = linkRel.indexOf("http"),
endIndex = linkRel.indexOf(">; rel=\"next\"")
) ?: NO_NEXT_PAGE
}
}