Skip to content

Commit

Permalink
More work
Browse files Browse the repository at this point in the history
  • Loading branch information
Matyrobbrt committed Aug 8, 2024
1 parent 15996fa commit 087578f
Show file tree
Hide file tree
Showing 20 changed files with 634 additions and 13 deletions.
14 changes: 11 additions & 3 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ plugins {

repositories {
mavenCentral()
maven {
url = 'https://libraries.minecraft.net'
}
}

java.toolchain {
Expand All @@ -30,12 +33,17 @@ dependencies {
implementation 'org.bouncycastle:bcpkix-jdk15on:1.58'
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.13.3'

implementation 'io.jsonwebtoken:jjwt-api:0.10.5'
implementation 'io.jsonwebtoken:jjwt-impl:0.10.5'
implementation 'io.jsonwebtoken:jjwt-jackson:0.10.5'
final jjwt = '0.10.5'
implementation "io.jsonwebtoken:jjwt-api:$jjwt"
implementation "io.jsonwebtoken:jjwt-impl:$jjwt"
implementation "io.jsonwebtoken:jjwt-jackson:$jjwt"

implementation 'com.mojang:brigadier:1.0.18'

implementation 'com.apollographql.apollo:apollo-runtime:2.5.14' // Apollo (GraphQL)
implementation 'com.apollographql.apollo:apollo-rx3-support:2.5.14' // Apollo support for RxJava3

implementation 'org.eclipse.jgit:org.eclipse.jgit:6.10.0.202406032230-r'
}

apollo {
Expand Down
7 changes: 7 additions & 0 deletions src/main/graphql/com/github/api/Comments.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mutation MinimizeComment($reason: ReportedContentClassifiers!, $comment: ID!) {
minimizeComment(input: {classifier: $reason, subjectId: $comment}) {
minimizedComment {
isMinimized
}
}
}
25 changes: 20 additions & 5 deletions src/main/java/net/neoforged/automation/Configuration.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,26 @@
import org.kohsuke.github.GitHub;

import java.io.IOException;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

public record Configuration(
Commands commands,
PRActions prActions,
Map<String, RepoConfiguration> repositories
) {
public record RepoConfiguration(Map<String, LabelLock> labelLocks) {

public record RepoConfiguration(Boolean enabled, Map<String, LabelLock> labelLocks, List<String> formattingTasks) {
public RepoConfiguration {
enabled = enabled == null || enabled;
}
public static final RepoConfiguration DEFAULT = new RepoConfiguration(true, Map.of(), List.of());
}

private static final ObjectMapper MAPPER = new ObjectMapper(new YAMLFactory().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER).enable(YAMLGenerator.Feature.LITERAL_BLOCK_STYLE));

private static volatile Configuration configuration = new Configuration(Map.of());
private static volatile Configuration configuration = new Configuration(new Commands(List.of(), false, false), new PRActions(null, null), Map.of());

public static void load(GitHub gitHub, RepoLocation location) throws IOException {
configuration = getOrCommit(gitHub.getRepository(location.repo()), location.path(), location.branch());
Expand All @@ -41,12 +47,17 @@ private static Configuration getOrCommit(GHRepository repository, String path, S
}

private Configuration sanitize() {
return new Configuration(repositories.entrySet()
return new Configuration(
commands, prActions, repositories.entrySet()
.stream().collect(Collectors.toMap(f -> f.getKey().toLowerCase(Locale.ROOT), Map.Entry::getValue)));
}

public static RepoConfiguration get(GHRepository repository) {
return configuration.repositories().get(repository.getFullName().toLowerCase(Locale.ROOT));
return configuration.repositories().getOrDefault(repository.getFullName().toLowerCase(Locale.ROOT), RepoConfiguration.DEFAULT);
}

public static Configuration get() {
return configuration;
}

public record RepoLocation(String repo, String path, String branch) {
Expand All @@ -63,4 +74,8 @@ public record LabelLock(
boolean close,
@Nullable String message
) {}

public record Commands(List<String> prefixes, boolean reactToComment, boolean minimizeComment) {}

public record PRActions(String repository, String workflow) {}
}
10 changes: 9 additions & 1 deletion src/main/java/net/neoforged/automation/Main.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
package net.neoforged.automation;

import com.mojang.brigadier.CommandDispatcher;
import io.javalin.Javalin;
import net.neoforged.automation.command.Commands;
import net.neoforged.automation.util.AuthUtil;
import net.neoforged.automation.util.GHAction;
import net.neoforged.automation.webhook.handler.CommandHandler;
import net.neoforged.automation.webhook.handler.ConfigurationUpdateHandler;
import net.neoforged.automation.webhook.handler.LabelLockHandler;
import net.neoforged.automation.webhook.handler.MergeConflictCheckHandler;
import net.neoforged.automation.webhook.handler.PRActionRunnerHandler;
import net.neoforged.automation.webhook.handler.ReleaseMessageHandler;
import net.neoforged.automation.webhook.impl.GitHubEvent;
import net.neoforged.automation.webhook.impl.WebhookHandler;
Expand Down Expand Up @@ -50,6 +54,10 @@ public static WebhookHandler setupWebhookHandlers(StartupConfiguration startupCo
ghApp -> ghApp.getInstallationByOrganization(startupConfig.get("releasesGitHubAppOrganization", ""))
))
.build()))
.registerFilteredHandler(GitHubEvent.ISSUES, new LabelLockHandler(), GHAction.LABELED, GHAction.UNLABELED);
.registerFilteredHandler(GitHubEvent.ISSUES, new LabelLockHandler(), GHAction.LABELED, GHAction.UNLABELED)
.registerFilteredHandler(GitHubEvent.WORKFLOW_RUN, new PRActionRunnerHandler(), GHAction.COMPLETED)
.registerFilteredHandler(GitHubEvent.ISSUE_COMMENT, new CommandHandler(
Commands.register(new CommandDispatcher<>())
), GHAction.CREATED);
}
}
62 changes: 62 additions & 0 deletions src/main/java/net/neoforged/automation/command/Commands.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package net.neoforged.automation.command;

import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.ArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import net.neoforged.automation.Configuration;
import net.neoforged.automation.command.api.GHCommandContext;
import net.neoforged.automation.util.FunctionalInterfaces;

public class Commands {
public static CommandDispatcher<GHCommandContext> register(CommandDispatcher<GHCommandContext> dispatcher) {
dispatcher.register(literal("applyFormatting")
.requires(Requirement.IS_PR.and(Requirement.IS_MAINTAINER.or(Requirement.IS_PR)))
.executes(FunctionalInterfaces.throwingCommand(context -> {
var pr = context.getSource().pullRequest();
var config = Configuration.get();
var repoConfig = Configuration.get(context.getSource().repository());
if (!repoConfig.formattingTasks().isEmpty()) {
var comment = pr.comment("Applying formatting...");
FormattingCommand.run(
context.getSource().gitHub(), pr,
config.prActions(), repoConfig,
err -> {
context.getSource().onError().run();
try {
context.getSource().issue()
.comment("Workflow failed: " + err.getHtmlUrl());
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}, () -> {
context.getSource().onSuccess().run();
FunctionalInterfaces.ignoreExceptions(comment::delete);
}
);
}
return GHCommandContext.DEFERRED_RESPONSE;
})));

return dispatcher;
}

private static ExtendedLiteralArgumentBuilder<GHCommandContext> literal(String name) {
return new ExtendedLiteralArgumentBuilder<>(name);
}

private static <T> RequiredArgumentBuilder<GHCommandContext, T> argument(String name, ArgumentType<T> type) {
return RequiredArgumentBuilder.argument(name, type);
}

private static class ExtendedLiteralArgumentBuilder<T> extends LiteralArgumentBuilder<T> {

protected ExtendedLiteralArgumentBuilder(String literal) {
super(literal);
}

public LiteralArgumentBuilder<T> requires(FunctionalInterfaces.PredException<T> requirement) {
return this.requires(FunctionalInterfaces.wrapPred(requirement));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package net.neoforged.automation.command;

import net.neoforged.automation.Configuration;
import net.neoforged.automation.runner.PRActionRunner;
import net.neoforged.automation.runner.PRRunUtils;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHWorkflowRun;
import org.kohsuke.github.GitHub;
import org.kohsuke.github.GitHubAccessor;

import java.io.IOException;
import java.nio.file.Files;
import java.util.function.Consumer;
import java.util.zip.ZipFile;

public class FormattingCommand {

public static void run(GitHub gh, GHPullRequest pr, Configuration.PRActions actions, Configuration.RepoConfiguration repoConfiguration, Consumer<GHWorkflowRun> onFailure, Runnable onSuccess) throws IOException {
PRActionRunner.builder(pr)
.upload("src*/main/java/")
.command(repoConfiguration.formattingTasks())
.onFailed((gitHub, run) -> onFailure.accept(run))
.onFinished((gitHub, run, artifact) -> {
PRRunUtils.setupPR(pr, (dir, git) -> {
try (var file = new ZipFile(artifact.toFile())) {
var enm = file.entries();
while (enm.hasMoreElements()) {
var entry = enm.nextElement();
Files.write(dir.resolve(entry.getName()), file.getInputStream(entry).readAllBytes());
}
} catch (IOException e) {
throw new RuntimeException(e);
}
git.add().addFilepattern(".").call();

var botName = gitHub.getApp().getSlug() + "[bot]";
var user = gitHub.getUser(botName);
var creds = new UsernamePasswordCredentialsProvider(
botName,
GitHubAccessor.getToken(gitHub)
);

git.commit().setCredentialsProvider(creds)
.setCommitter(botName, user.getId() + "+" + botName + "@users.noreply.github.com")
.setMessage("Update formatting")
.setSign(false)
.setNoVerify(true)
.call();
git.push().setRemote("origin").setRefSpecs(new RefSpec("HEAD:refs/heads/" + pr.getHead().getRef())).setCredentialsProvider(creds).call();
onSuccess.run();
});
})
.build()
.queue(gh, actions);
}
}
22 changes: 22 additions & 0 deletions src/main/java/net/neoforged/automation/command/Requirement.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package net.neoforged.automation.command;

import net.neoforged.automation.command.api.GHCommandContext;
import net.neoforged.automation.util.FunctionalInterfaces;
import org.kohsuke.github.GHPermissionType;

public enum Requirement implements FunctionalInterfaces.PredException<GHCommandContext> {
IS_PR(ctx -> ctx.issue().isPullRequest()),
IS_MAINTAINER(ctx -> ctx.repository().hasPermission(ctx.user(), GHPermissionType.WRITE)),
IS_AUTHOR(ctx -> ctx.user().equals(ctx.issue().getUser()));

private final FunctionalInterfaces.PredException<GHCommandContext> test;

Requirement(FunctionalInterfaces.PredException<GHCommandContext> test) {
this.test = test;
}

@Override
public boolean test(GHCommandContext ghCommandContext) throws Exception {
return test.test(ghCommandContext);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package net.neoforged.automation.command.api;

import org.kohsuke.github.GHEventPayload;
import org.kohsuke.github.GHIssue;
import org.kohsuke.github.GHPullRequest;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GHUser;
import org.kohsuke.github.GitHub;

import java.io.IOException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;

public record GHCommandContext(GitHub gitHub, GHEventPayload.IssueComment payload, Runnable onError, Runnable onSuccess) {
public static final int DEFERRED_RESPONSE = 2;

public GHUser user() {
return payload.getSender();
}

public GHRepository repository() {
return issue().getRepository();
}

public GHIssue issue() {
return payload.getIssue();
}

public GHPullRequest pullRequest() throws IOException {
return repository().getPullRequest(issue().getNumber());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package net.neoforged.automation.runner;

import org.kohsuke.github.GHWorkflowRun;
import org.kohsuke.github.GitHub;

@FunctionalInterface
public interface ActionFailedCallback {
void onFailed(GitHub gitHub, GHWorkflowRun run) throws Exception;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package net.neoforged.automation.runner;

import org.kohsuke.github.GHWorkflowRun;
import org.kohsuke.github.GitHub;

import java.nio.file.Path;

@FunctionalInterface
public interface ActionFinishedCallback {
void onFinished(GitHub gitHub, GHWorkflowRun run, Path artifact) throws Exception;
}
Loading

0 comments on commit 087578f

Please sign in to comment.