-
-
Save tivrfoa/f923669cf426896e82cfd9db719249c2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
///usr/bin/env jbang "$0" "$@" ; exit $? | |
//DEPS info.picocli:picocli:4.5.0 | |
//DEPS io.smallrye.reactive:smallrye-mutiny-vertx-web-client:1.2.1 | |
//DEPS io.quarkus.qute:qute-core:1.8.2.Final | |
package com.gihub.mkouba; | |
import picocli.CommandLine; | |
import picocli.CommandLine.Command; | |
import picocli.CommandLine.Parameters; | |
import java.time.Duration; | |
import java.util.Collections; | |
import java.util.HashMap; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.concurrent.Callable; | |
import java.util.stream.Collectors; | |
import io.quarkus.qute.Engine; | |
import io.quarkus.qute.Template; | |
import io.vertx.core.Vertx; | |
import io.vertx.core.json.JsonArray; | |
import io.vertx.core.json.JsonObject; | |
import io.vertx.ext.web.client.WebClientOptions; | |
import io.vertx.mutiny.ext.web.client.WebClient; | |
@Command(name = "My pull requests", mixinStandardHelpOptions = true, version = "1.0", description = "My pull requests made with jbang") | |
class MyPullRequests implements Callable<Integer> { | |
static final int PAGE_SIZE = 100; | |
static final String GITHUB_API_URL = "api.github.com"; | |
static final String USER_PULLS_QUERY = "query userPulls { \n" | |
+ " user(login: \"{username}\") { \n" | |
+ " pullRequests(first: {first}{#if cursor}, after:\"{cursor}\"{/}) {\n" | |
+ " nodes {\n" | |
+ " repository {\n" | |
+ " nameWithOwner\n" | |
+ " }\n" | |
+ " }\n" | |
+ " pageInfo {\n" | |
+ " endCursor\n" | |
+ " hasNextPage\n" | |
+ " }\n" | |
+ " }\n" | |
+ " }\n" | |
+ "}"; | |
static final String RESULTS = "\nUser {username} contributed {totalPullRequests} pull requests to {results.size} repositories:\n\n" | |
+ "#\tPRs\tRepo\n" | |
+ "---\t---\t---\n" | |
+ "{#each results}" | |
+ "{count}.\t{it.value}\t{it.key}{#if hasNext}\n{/}" | |
+ "{/each}"; | |
@Parameters(index = "0", description = "GitHub username") | |
private String username; | |
@Parameters(index = "1", description = "GitHub personal access token") | |
private String token; | |
public static void main(String... args) { | |
int exitCode = new CommandLine(new MyPullRequests()).execute(args); | |
System.exit(exitCode); | |
} | |
@Override | |
public Integer call() throws Exception { | |
Engine engine = Engine.builder().addDefaults().build(); | |
Template queryTemplate = engine.parse(USER_PULLS_QUERY); | |
Template queryLogtemplate = engine.parse("{count}. query executed in {time} ms [{results} results]"); | |
Vertx vertx = Vertx.vertx(); | |
WebClient client = new WebClient(io.vertx.ext.web.client.WebClient.create(vertx, new WebClientOptions() | |
.setDefaultPort(443) | |
.setDefaultHost(GITHUB_API_URL))); | |
try { | |
// repository.nameWithOwner -> number of pull requests | |
Map<String, Long> resultsMap = new HashMap<>(); | |
String cursor = null; | |
boolean hasNextPage = true; | |
int queryCount = 0; | |
while (hasNextPage) { | |
long start = System.currentTimeMillis(); | |
String query = queryTemplate.data("username", username).data("first", PAGE_SIZE) | |
.data("cursor", cursor).render(); | |
queryCount++; | |
JsonObject response = client.post("/graphql").ssl(true).bearerTokenAuthentication(token) | |
.sendJsonObject(new JsonObject().put("query", query)).await() | |
.atMost(Duration.ofSeconds(10)).bodyAsJsonObject(); | |
long end = System.currentTimeMillis(); | |
JsonObject data = response.getJsonObject("data"); | |
if (data == null) { | |
System.err.println("Unable to obtain the pull request data: " + response); | |
hasNextPage = false; | |
} else { | |
JsonObject pullRequests = data.getJsonObject("user").getJsonObject("pullRequests"); | |
JsonArray nodes = pullRequests.getJsonArray("nodes"); | |
System.out.println(queryLogtemplate.data("count", queryCount).data("time", end - start) | |
.data("results", nodes.size()).render()); | |
for (int i = 0; i < nodes.size(); i++) { | |
JsonObject pullRequest = nodes.getJsonObject(i); | |
String repoNameWithOwner = pullRequest.getJsonObject("repository").getString("nameWithOwner"); | |
resultsMap.compute(repoNameWithOwner, (name, count) -> { | |
if (count == null) { | |
return 1l; | |
} | |
return count + 1; | |
}); | |
} | |
JsonObject pageInfo = pullRequests.getJsonObject("pageInfo"); | |
hasNextPage = pageInfo.getBoolean("hasNextPage"); | |
cursor = pageInfo.getString("endCursor"); | |
} | |
} | |
// Log the results | |
List<Entry<String, Long>> results = resultsMap.entrySet().stream() | |
.sorted(Collections.reverseOrder(Map.Entry.comparingByValue())).collect(Collectors.toList()); | |
long totalPullRequests = results.stream().mapToLong(Entry::getValue).sum(); | |
System.out.println(engine.parse(RESULTS).data("username", username).data("totalPullRequests", totalPullRequests) | |
.data("results", results).render()); | |
} finally { | |
vertx.close(); | |
} | |
return 0; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment